Checked local project folder and found it empty.
UnderstandResearched 'jev' product and reviewed documentation.
UnderstandVerified gameplay and test results.
VerifyUpdated UI to show all active snakes in side panel.
EditRemoved sentence from game-over message.
EditEnvironment Context
cwd: /Users/sahaj/Desktop/dev/program/jev
shell: zsh
current date: 2026-10-07
timezone: America/Toronto
filesystem: /Users/sahaj/Desktop/dev/program/jevare you familiar with jev
I’ll take a quick look at the project so I can answer in context.
>pwd && rg --files -g 'AGENTS.md' -g 'README*' -g 'package.json' -g 'Cargo.toml' -g 'pyproject.toml' -g 'go.mod' -g '!node_modules' -g '!vendor'{"chunk_id":"52c418","wall_time_seconds":0.000009042,"exit_code":1,"original_token_count":10,"output":"/Users/sahaj/Desktop/dev/program/jev\n"}>ls -la{"chunk_id":"b4dc7a","wall_time_seconds":0.000008125,"exit_code":0,"original_token_count":38,"output":"total 0\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:52 .\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:50 ..\n-rw-r--r--@ 1 sahaj staff 0 Oct 7 19:52 .env\n"}Not yet—your local jev folder only contains an empty .env, so I don’t have project context. Is Jev something you’re building, or an existing product?
No content
nope, it's an existing product please look it up and read the docs and all
I’ll look up Jev, find its official docs, and read through how it works.
Jev in 60 seconds · Jev Atlas (https://jev.gorock.sh/start)
citeturn0search0 [wordlim: 200] Crawled: yesterday; Official Documentation Copy context for agent ... This atlas separates what has been demonstrated from what TypeSafe says about its own product. ... * https://typesafe.ai/blog/introducing-system-one-models-and-jev
Start here
# Jev in 60 seconds.
Jev is TypeSafe’s System One model: it takes application state, answers explicit narrow questions with a typed result and a confidence, and hands the answer back to code that stays in charge of what happens next.
Official Documentation Copy context for agent
Open a circle to unfold a branch. Every label is a link.
[Button: Unfold all][Button: Reset]
## Three question types
* ### Choice
Picks one option from a list you define, with a probability for each.
* ### Score
Places something on an ordered scale you define.
* ### Noul
Gives the probability that a yes-or-no statement is true.
Example questions and values, drawn to show the shape of each answer. They are not measurements.
## The shape of an integration
1. 01 Unstructured state Whatever your application already has: a message, a diff, an event, a screen, a row.
2. 02 Narrow independent questions Decomposed so each one can be answered on its own, and many can be asked at once.
3. 03 Choice · Score · Noul The typed primitives. --------------------------------------------------------------------------------
jev/README.en.md at main · okooo5km/jev · GitHub (https://github.com/okooo5km/jev/blob/main/README.en.md)
citeturn0search1 [wordlim: 200] Crawled: last week; Rewriting it to `jev filter "the message gives specific technical, product or industry information" --false "small talk, greetings, ads, lead generation, course sales"` excludes the same message (`exit 1`, no match). ... "description": "One line shown by `jev run`", ... OpenRouter: the same Jev model, response carries its own `usage.cost`; documented context is 32K; the endpoint is OpenRouter's alpha API `https://openrouter.ai/api/alpha/decisions` and may change -- override with `JEV_BASE_URL` if it does. ... Jev only decides -- it never generates text, so reading, writing or summarizing whatever survives the filter is still on you.
is_promo no p=0.09
## 1. Install the CLI (macOS / Linux)
curl --proto '=https' --tlsv1.2 -fLsS https://github.com/okooo5km/jev/releases/download/v0.3.2/install.sh -o /tmp/jev-install.sh
sh /tmp/jev-install.sh
export PATH="$HOME/.local/bin:$PATH"
jev --version
Downloaded first so you can inspect it before running. Requirements: `python3` >= 3.9, `curl`, `tar`, `shasum` or `sha256sum`. It writes the skill folder (CLI + built-in specs + docs) to `${XDG_DATA_HOME:-~/.local/share}/jev/`, then symlinks `~/.local/bin/jev` to `scripts/jev` inside it. No shell profile edits, no sudo, safe to run again (idempotent). Next step: run `jev auth set` to configure a key (section 3).
Env overrides: `JEV_VERSION` (default `v0.3.2`), `JEV_HOME` (skill folder location), `JEV_INSTALL_DIR` (symlink location, default `~/.local/bin`), `JEV_ARCHIVE_DIR` (offline install, a directory already holding the downloaded archive and checksum).
Manual install: download `jev-vX.Y.Z.tar.gz`, its `.sha256` and `install.sh` from Releases into one directory, verify, then install offline:
shasum -a 256 -c jev-v0.3.2.tar.gz.sha256
JEV_ARCHIVE_DIR=. sh install.sh
Windows: untested, use WSL.
Uninstall:
rm -f ~/.local/bin/jev
rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/jev"
rm -rf "${XDG_CONFIG_HOME:-$HOME/.config}/jev" # optional: also removes the key and custom specs
## 4. Quickstart
Verb | Purpose | Output | Exit code
--- | --- | --- | ---
`yes` | yes/no | `yes\t0.97` | 0 yes · 1 no · 2 error
`pick` | one of N | the chosen option | 0 done · 1 below `--min-confidence` · 2 error
`score` | ordinal score | `VALUE\tLABEL` | 0 done · 2 error
`filter` | semantic grep | matching input lines | 0 some matched · 1 none · 2 a line errored
`run` | several questions at once | aligned table | 0 done · 2 error
`raw` | the raw request body | response JSON | 0 done · 2 error
# Line mode: one decision per line, 8-way concurrent, input order preserved
printf '%s\n%s\n' '{"text":"please add dark mode"}' '{"text":"crashed three times, refund me"}' \
| jev run feedback -l --field text --json
# --json: full probability distribution and usage, for scripts to consume
jev run route -s "check whether I have any important email today" --json
# Tail a live log, keep only what deserves attention
tail -f app.log | jev filter "log line is a user-visible failure" --false "debug noise, normal requests"
## 5. Write questions Jev can answer
Jev reads conditions literally; it does not infer intent.
* State observable conditions, not goals; spell out both sides with `--true`/`--false` or `criteria`.
* Cover every case in an option set, or add `--other` when it might not.
* Order score labels low to high, 2-10 of them.
* Ask every question about one piece of state in a single spec (one call, near-zero extra cost).
* Trim the state to what the question needs; don't paste in a whole document.
Measured counter-example: `jev filter "contains specific, actionable information"` matched an ad ("Add me on WeChat for a free AI course, three days only") at about 0.9 -- literally, an ad is actionable. Rewriting it to `jev filter "the message gives specific technical, product or industry information" --false "small talk, greetings, ads, lead generation, course sales"` excludes the same message (`exit 1`, no match).
## 6. Templates
`jev run` lists the available specs. Five ship built in, all JSON (readable on any 3.9+):
Name | Judges
--- | ---
`mail` | category, urgency, needs a reply, pure promo
`feedback` | intent, sentiment, needs a human, churn risk
`signal` | whether a chat message/tweet is worth reading, topic, novelty
`commit` | Conventional Commit type, secret leaks, breaking changes, risk
`route` | which handler a request needs, complexity, needs web/private data
Custom specs live in `~/.config/jev/specs/` (`XDG_CONFIG_HOME` overrides the config dir), as JSON or TOML -- JSON works on any 3.9+, TOML needs 3.11+ (`tomllib`) and fails with a clear message below that instead of crashing:
{
"description": "One line shown by `jev run`",
"threshold": 0.5,
"questions": {
"urgent": { "type": "noul", "instructions": "Is this urgent",
"criteria": { "true": "Needs action now", "false": "Can be scheduled" } }
}
}
description = "One line shown by `jev run`"
--------------------------------------------------------------------------------
jev-cookbook/docs/GUIDE.md at main · nexibeo/jev-cookbook · GitHub (https://github.com/nexibeo/jev-cookbook/blob/main/docs/GUIDE.md)
citeturn0search2 [wordlim: 200] Crawled: 6 days ago; Choose Choice when the answer is one of a known set with no order: department, document type, template category. ... "product_type": { ... Each element needs its label, current value, checked or selected state, and nearby context such as a card's description. ... * No images: Jev reads text, so it can't use screenshots, charts or CAPTCHAs. ... * jev-browser by jkudish (MCP server, CLI, library)
## Limits and pricing
You pay only for input, at $0.042 per million tokens, so a typical call costs a few thousandths of a cent.
Item | Value
--- | ---
Input price | $0.042 per 1M tokens ($42 per 1B)
Output price | Free
Context | 32k tokens for `state` plus the longest single question; 64k for `state` plus all questions
Room for text | About 150,000 characters of English
Choice options | Up to 255 per question
Score levels | 2 to 10 per question
Input types | Text only: a string, a JSON object or a JSON array. No images, audio or video
Language | English is best. Others, including Chinese, Japanese and Korean, work with lower accuracy
Speed | 70 to 500 ms per TypeSafe; 0.4 s in our test
Rate limits (TypeSafe direct) | 250,000 tokens per second and 1,200 requests per minute. TypeSafe says these change without notice
Data | Not used for training. OpenRouter lists TypeSafe as not keeping prompts
Versions | OpenRouter: `~typesafe/jev-latest` (always the newest; now answers as `typesafe/jev-1.13-20260917`) or the pinned `typesafe/jev-1.13`. TypeSafe direct: `jev-latest`, `jev-preview` or the pinned `jev-1.13.0`
`~typesafe/jev-latest` moves to each new Jev without a code change, and the response's `model` field says which version answered. Log that field. If you tune confidence thresholds on one version, a new version can shift its probabilities, so re-check your thresholds when it changes, or pin `typesafe/jev-1.13` until you have.
## Writing the state
The state is the material the model judges. Make it a JSON object with named fields holding only what the questions need. Every question in a call sees the same state.
Shape | Use it for | Example
--- | --- | ---
String | One message or passage | `"My card was charged twice."`
Object (preferred) | Named parts: a message, a record, a policy | `{"message": "...", "order_id": "A-104"}`
Array | A sequence of messages or records | `["Hi", "My number is TS1337.", "I was charged twice."]`
* Name the fields clearly. Questions can then point at them by path, such as `ticket.messages[0].text`.
* Keep related facts together. If a decision compares a message to a policy, put both in one state.
* Trim hard. Unrelated fields distract the model and lower accuracy. Send the three fields that matter, not the whole database row.
* Keep instructions out of the state. The state holds data. The judgment you want goes in the question.
* Convert non-text first. Turn images, audio and files into text or structured fields before sending.
* Put your domain knowledge here. Jev can't be fine-tuned. Reference material, examples and rules go into the state, the instructions or the criteria.
C --> D{Stop gate}
D -- done, goal or stuck --> E[Verify outcome in code]
D -- continue --> F{Typing?}
F -- yes --> G[Small LLM writes text]
F -- no --> H[Re-check element<br/>then act]
G --> H
H --> A
Loading
Each loop is one observation, one Jev request and one browser action. Model output only ever selects from the numbered list. Your code maps that number back to the real DOM node, so Jev's answer never becomes a selector, coordinates or code.
### The questions per step
Two designs are proven in public code. Use the simpler action-plus-watchers design for navigating and reading. Use the operation-plus-targets design for filling forms.
| Action + watchers (jev-browser) | Operation + targets (Jev Ultrafast)
--- | --- | ---
Questions per step | 1 action Choice + 2 Nouls (`goal_done`, `stuck`) | 1 operation Choice + one target Choice per operation
Choice options | Element and verb together (`click_e2`, `type_e1`, `select_e5`) plus `scroll_down`, `scroll_up`, `back`, `done` | Operations: `CLICK`, `TYPE_TEXT`, `SELECT`, `SCROLL_UP`, `SCROLL_DOWN`, `WAIT`, `DONE`, `BLOCKED`. * TypeSafe docs: Introduction
* TypeSafe docs: Quick start
* TypeSafe docs: System One
* TypeSafe docs: State
* TypeSafe docs: Primitives
* TypeSafe docs: Score
* TypeSafe docs: Noul
* TypeSafe docs: Advanced structure
* TypeSafe docs: Confidence
* TypeSafe docs: Models
* TypeSafe docs: API reference
* TypeSafe docs: Jev 1.13 weak spots
* TypeSafe docs: Speculative fan-out
* TypeSafe docs: Composite scoring
* TypeSafe docs: Intent routing
* TypeSafe docs: Guardrails for LLMs
* TypeSafe docs: full index (llms.txt)
Browser automation:
* Browser Use: Jev Ultrafast (code and README)
* Jev Ultrafast: design notes
* Jev Ultrafast: performance measurements
* Jev Ultrafast: question wording (questions.py)
* jev-browser by jkudish (MCP server, CLI, library)
* jev-browser: question catalog (questions.ts)
* jev-ego by romaluev
* awesome-typesafe: community project list
Classification (the test runs themselves were live calls on September 19, 2026):
* TypeSafe docs: Choice
* TypeSafe cookbook: Hierarchical classification
* TypeSafe cookbook: Classification using confidence
* TypeSafe cookbook: Self-consistency with choices
--------------------------------------------------------------------------------
jev-cli/README.md at main · shaharia-lab/jev-cli · GitHub (https://github.com/shaharia-lab/jev-cli/blob/main/README.md)
citeturn0search3 [wordlim: 200] Crawled: 4 days ago; Install script (Linux, macOS) | `curl -fsSL https://raw.githubusercontent.com/shaharia-lab/jev-cli/main/install.sh | sh` ... Every download is checked against a signature and a checksum before anything is replaced, and `jev` never downgrades on its own. ... ## 📚 Documentation
## 🔐 Privacy and security
* No telemetry, ever. `jev` contacts exactly two hosts: the TypeSafe API when you evaluate something, and GitHub Releases when it checks for an update, which you can turn off.
* Your content stays yours. It goes to the API and nowhere else, and is never written to a log unless you explicitly ask for that.
* The key is never exposed. Not as a flag, not in logs, errors, dry-run output or MCP results. Only its last four characters are ever shown.
* HTTPS only, certificate verification cannot be disabled, and redirects are never followed.
* Signed updates. Every download is checked against a signature and a checksum before anything is replaced, and `jev` never downgrades on its own.
SECURITY.md has the full model, how to verify a release yourself, and how to report a vulnerability privately. Please do not open a public issue for one.
## 📚 Documentation
User guide
* Installation
* Quick start
* The three question types
* Writing good questions
* Scripting and CI
* Exit codes and JSON contract
* Many rows at once
* Configuration and profiles
* AI agents and MCP
* Keeping jev up to date
* Troubleshooting
* FAQ
| Reference and development
* Command reference, generated from the binary
* Development setup
* Architecture
* Testing
* Releasing
* How the API actually behaves
* Threat model
jev --help # every command
jev spec # the whole contract, as JSON
jev schema request # what a request file may contain
--------------------------------------------------------------------------------
Start Here: Learn Jev Step by Step | Jev Manual (https://jevmanual.com/start-here/)
citeturn0search4 [wordlim: 200] Crawled: today; A five-stage roadmap: understand Jev, make your first request, control confidence, and ship a real workflow. ... Read What is Jev?, How Jev works, then Choice, Score, and Noul.
Official Checked 2026-09-21·jev-1.13.0
# Start Here: Learn Jev Step by Step
A five-stage roadmap: understand Jev, make your first request, control confidence, and ship a real workflow.
On this pageStage 1 — UnderstandStage 2 — BuildStage 3 — ControlStage 4 — ShipStage 5 — Real projects
## Stage 1 — Understand
Beginner · 15 minutes · No prerequisites. Learn the shape of a decision model before installing anything. Read What is Jev?, How Jev works, then Choice, Score, and Noul.
You should be able to write a question with a bounded answer space. Try this checkpoint: a department is a Choice, an ordered urgency rubric is a Score, and “is a refund explicitly requested?” is a Noul.
## Stage 2 — Build
Beginner · 25 minutes · An API key and basic Python or JavaScript. Make your first API call. Pick the Python SDK or JavaScript SDK, then improve the input with the state guide.
--------------------------------------------------------------------------------
jev-llm/README.md at main · jev-ai/jev-llm · GitHub (https://github.com/jev-ai/jev-llm/blob/main/README.md)
citeturn0search5 [wordlim: 200] Crawled: 3 days ago; It is not the official product site for the underlying Jev model. ... Use the official TypeSafe documentation and Jev’s developer documentation for the current request schema, SDK guidance, authentication details, and response fields. ... * Contact support ([REDACTED]) — Ask questions about the product or integration.
# Jev AI
Turn application state into typed decisions your code can use.
Website · Playground · Documentation · Contact ([REDACTED])
English · 中文
## English
### A decision model for software systems
Jev AI is an online decision model for software teams that need structured answers from real-world application state. It is designed for the small but important decisions that happen repeatedly inside a product: classify a request, route a ticket, score urgency, check whether an action is safe, or decide whether a person should review the result.
Instead of returning a chat transcript for someone to interpret, Jev accepts state and typed questions, then returns a result that application code can consume directly. Your business logic remains in your service while Jev handles the decision in the middle.
Jev AI is an independent app for Jev model playbooks and shared usage. It is not the official product site for the underlying Jev model.
--------------------------------------------------------------------------------
Jev API Docs — Quickstart, Endpoint & SDK Reference (https://jevapi.org/docs/)
citeturn0search6 [wordlim: 200] Crawled: 2 weeks ago; Jev is TypeSafe AI's first System One model: instead of generating free-form text, it returns typed decisions with calibrated confidence values. ... Jev is a structured evaluation model built by TypeSafe AI and announced on September 15, 2026 by Diogo Almeida.
# Jev API Docs — Quickstart, Endpoint Reference & Examples
These Jev API docs show you how to get an API key, call the endpoint, and work with typed Noul, Choice, and Score responses. Jev is TypeSafe AI's first System One model: instead of generating free-form text, it returns typed decisions with calibrated confidence values. Use the quickstart and copy-ready examples below to add classification, routing, or guard-rail decisions to your application.
## What is Jev?
Jev is a structured evaluation model built by TypeSafe AI and announced on September 15, 2026 by Diogo Almeida. TypeSafe describes it as a "System One" model — a reference to the fast, intuitive decision‑making described in Daniel Kahneman's Thinking, Fast and Slow. While chat models (System Two) are good at writing prose and reasoning step‑by‑step, Jev is designed to make one decision, fast, and give you a number you can trust.
It is currently in early access. TokenRa provides a unified API endpoint so you can start building with Jev today without managing a separate TypeSafe account.
--------------------------------------------------------------------------------
Jev API reference: endpoints, schemas, limits, errors · Learn Jev (https://learnjev.com/reference)
citeturn0search7 [wordlim: 200] Crawled: last week; Where the official docs contradict themselves, this page says so rather than picking silently. ... `criteria` | Yes | `map<string, string | null>` — option to rubric description; `null` when an option needs no extra detail. ... TypeSafe's Models table writes `jev-1.13.0`; their jaggedness page uses `jev-1.13` in prose and code. ... Jev is not fine-tuned or LoRA-adapted with customer data — the same weights serve every account, and there is no fine-tuning API.
Reference
# The whole API on one page
One endpoint, three question types, four error codes. Jev’s surface area is small enough to hold in your head — which is arguably the most underrated thing about it.
This is a condensed cheat sheet
It reflects the official docs as of 18 September 2026 and exists to be scanned, not to replace them. TypeSafe's API reference is canonical. Where the official docs contradict themselves, this page says so rather than picking silently.
## Endpoint#
HTTP[Button: copy]
`POST https://api.typesafe.ai/v1/systemone
Authorization: Bearer <API_KEY>
Content-Type: application/json`
One evaluation endpoint. All models are served from it; the `model` field selects which. The only other documented route is `GET /v1/models`. There is no streaming, batch or async job endpoint.
## Request body#
Field | Type | Required | Notes
--- | --- | --- | ---
`state` | `string` | `object` | `array` | Yes | The content to evaluate. --------------------------------------------------------------------------------
The Jev Manual | Jev Manual (https://jevmanual.com/manual/)
citeturn0search8 [wordlim: 200] Crawled: today; ### Jev Models: Aliases, Versions and Production PinningUnderstand jev-latest, jev-preview, actual response models, language support, context limits, and model listing.
Independent Checked 2026-09-21·jev-1.13.0
# The Jev Manual
A practical desk reference for state, typed questions, API contracts, models, and production decisions.
On this pageFind your guideA useful starting point
## Find your guide
### Jev API Reference & Practical Guide
Authentication, state, typed questions, response fields, curl examples, rate limits, and version pinning.
### Jev Models: Aliases, Versions and Production Pinning
Understand jev-latest, jev-preview, actual response models, language support, context limits, and model listing.
### Jev Pricing Explained: Cost per Request & Token Calculator
Calculate direct input cost, understand shared-state billing, and distinguish provider accounting.
### Jev State Guide: How to Structure Context Correctly
Build focused state with clear fields, relevant policies, and enough evidence for each typed question.
### Jev Choice vs Score vs Noul: Complete Guide
Choose a fixed category, an ordered rubric, or the probability of a single proposition.
--------------------------------------------------------------------------------
jev/README.md at main · realbogart/jev · GitHub (https://github.com/realbogart/jev/blob/main/README.md)
citeturn0search9 [wordlim: 200] Crawled: last week; `renderJevError err` produces log-friendly `Text` with the constructor, status code, request ID, and message or body (truncated to 500 bytes). ... For Jev 1.13, the model documentation specifies 64k tokens for the complete request and 32k for state plus the longest question.
## Development
Use the repository's Nix development shell, then run:
./scripts/format.sh
./scripts/verify.sh
Verification checks package metadata, compiles the library and both examples, runs fixture and local HTTP server tests, and builds and tests an unpacked source distribution using a fresh, minimal Cabal project. Tests require no API credentials. `cabal haddock lib:jev` generates API documentation. The default Nix package builds the library. Nix development-tool overrides live in `cabal.project.nix`; ordinary Cabal consumers use the minimal `cabal.project` without those overrides.
`Jev` is the convenient public import. `Jev.Types`, `Jev.Question`, and `Jev.Client` separate data, question construction, and transport. The internal protocol module owns JSON encoding and decoding.
## API compatibility notes
Checked against the official HTTP reference, question schemas, and response schemas, with targeted live checks on both providers.
The advanced structure guide lists null Score levels, but the HTTP reference, Python schema, and both live endpoints reject them. The library follows the confirmed endpoint behavior. Score legends can contain objects and arrays as well as text, so their values remain Aeson `Value`.
For Jev 1.13, the model documentation specifies 64k tokens for the complete request and 32k for state plus the longest question. These limits are enforced by the provider, not estimated locally. Pin `config.model` to a version when your thresholds depend on that version's behavior; `jev-latest` can change.
TypeSafe documents HTTP 401 for authentication failures, 422 for validation failures, 429 for rate limits, and 529 for overload. The library preserves their status and response body. Callers should use exponential backoff for 429/529. Automatic retries and the model-listing endpoint are outside this library's decision API. The examples intentionally use `JEV_API_KEY`; TypeSafe's own SDK examples use `TYPESAFE_API_KEY`.--------------------------------------------------------------------------------
Jev Manual – Tutorials, API Guide, Examples & TypeSafe Jev Documentation (https://jevmanual.com/)
citeturn0search10 [wordlim: 200] Crawled: today; j.Jev evaluates ... j.jevmanual.
▤ AN INDEPENDENT DEVELOPER MANUAL
# Jev Manual.
Small decisions.
Thoughtful systems.
Jev is a decision model for software. Give it state and typed questions. Get answers your code can act on.
Start with Jev →Browse the manual
From your first typed decision to production workflows.
ONE REQUEST. THREE USEFUL ANSWERS.EXAMPLE
STATE / SUPPORT TICKET
“I was charged twice this month.
Please refund the duplicate before Friday.”
j.Jev evaluates
Choice Which team?billing
Score How urgent?2.6 / 3
Noul Refund requested?0.97
↳ Your code owns the action.Illustrative values
Current model jev-1.13.0
Input / 1M tokens$0.042
Question types Choice · Score · Noul
Direct endpoint/v1/systemone
## A good place to begin
You bring the problem. Start here.
01↗The essentials Start with state, questions, and typed answers.02↗Build something useful Follow a complete project, from input to action.03↗Make it dependable Add confidence gates, fallbacks, and human review.
THE DESK REFERENCE
Explore the manual →
## Find the answer. Get back to building.
▤State design Give Jev the context it actually needs.↗▤Choice, Score & Noul Three primitives. The right one for your job.↗▤The API Requests, responses, and working examples.↗▤Confidence Decide when to act, verify, or escalate.↗▤Models & versions Pin a version. Keep your thresholds honest.↗▤Limits & failure modes Know where deterministic code belongs.↗
LEARN BY MAKING
## Real workflows.
One clear decision
at a time.
Practical projects that connect model judgments to the code around them.
All tutorials →
01 Support ticket triage CHOICE · SCORE · NOUL↗02 AI model routing CHOICE · CONFIDENCE↗03 Agent tool risk gate CHOICE · SCORE↗04 RAG passage filtering SCORE · NOUL↗05 LLM guardrails NOUL · POLICY↗06 Citation checking CHOICE · EVIDENCE↗
## Fits into the stack you use
Integration guides →
OpenRouter↗Vercel AI Gateway↗Cloudflare Workers AI↗LangChain↗
A NOTE ON TRUST
Clear sources. Explicit assumptions.
Example thresholds that are always labeled.
How we check this manual →
j.jevmanual.
The practical manual for building with Jev.
Independent developer resource. Not affiliated with TypeSafe AI.--------------------------------------------------------------------------------
Docs — Jev API (https://jev-api.com/docs)
citeturn0search11 [wordlim: 200] Crawled: today; Documentation ... Jev API is a prepaid API service.
Documentation
# From account to first answer
Jev API is a prepaid API service. Register, mint a key, add credit, then call System One. The full HTTP contract lives on /docs/api.
## 1. Create an account
Register with an email and password. No OAuth or verification email is required.
## 2. Mint an API key
Keys start with `jev_live_` or `jev_test_`. We store a SHA-256 hash and a prefix. The secret is shown once.
## 3. Add credit
Add prepaid credit from the dashboard. Credit is applied after the signed payment webhook is verified. Purchased credits are non-refundable and cannot be withdrawn. See the Terms of Service.
## 4. Call System One
Bearer-authenticate `POST /v1/systemone`. Send `model`, `state`, and `questions`; receive `model`, `answers`, and token `usage`.--------------------------------------------------------------------------------
Product Documentation CUSTOMER (https://help.sap.com/doc/0cb1a8377ed34291887409d02e183785/2205/en-US/E-MDAV-DOKU.pdf)
citeturn0search12 [wordlim: 200] Published: 10 months ago; JEV_ID ... JEVMONTHDAY ... JEVRECVAL
--------------------------------------------------------------------------------
JEW/JEV Series (https://www.jdv.com.tw/userfiles/files/JEV%26JEW-2026_04v-EN.pdf)
citeturn0search13 [wordlim: 200] Published: 5 months ago; JEW / JEV Series pneumatic actuators are engineered for automated valve control applications requiring precision, durability, ... Product Features
--------------------------------------------------------------------------------
Product Documentation CUSTOMER (https://help.sap.com/doc/0cb1a8377ed34291887409d02e183785/2502/en-US/E-MDAV-DOKU.pdf)
citeturn0search14 [wordlim: 200] Published: 10 months ago; JEVRECVAL ... RJEVTEXT
--------------------------------------------------------------------------------
SBS cPro3/128-30000 (https://www.artisantg.com/info/SBS_cPRO3_Manual.pdf)
citeturn0search15 [wordlim: 200] Published: 6 months ago; 02-07-2001 | jev | Update text, correct for typo’s, heatsink, etc. ... entirely reliable and consistent with the product that it describes. ... make changes to any product and product documentation in an effort to improve performance, relia-
--------------------------------------------------------------------------------
JEV&JEW-2026.05v-EN_v7 (https://www.jdv.com.tw/userfiles/files/JEV%26JEW-2026_05v-EN.pdf)
citeturn0search16 [wordlim: 200] Published: 4 months ago; JEW/JEV Series
--------------------------------------------------------------------------------
JEV-300L
LIQUID PACKING MACHINE
MANUAL BOOK (https://www.toolots.com/media/attachment/file/J/E/JEV-300L%2BMANUAL%2BBOOK.pdf)
citeturn0search17 [wordlim: 200] Published: last year; MODEL | JEV-300L ... WEIGHT | 5-250Grams/Package (Depend on product)
--------------------------------------------------------------------------------
Jev in the Wild: A Data-Driven Analysis of the Jev Model's Functionality, Applications and Ecosystem (https://arxiv.org/abs/2609.30216)
citeturn0academia18 [wordlim: 200] Published: last week; Jev is a fast, low-cost decision model that answers natural-language questions with choices, binary judgments, and scores.
--------------------------------------------------------------------------------
Jev-Mobile: Jev as an Executor for Mobile GUI Agents (https://arxiv.org/abs/2609.30186)
citeturn0academia19 [wordlim: 200] Published: last week; We introduce Jev-Mobile, which shifts this paradigm to low-frequency VLM planning and high-frequency lightweight execution: the VLM specifies local goals, the accessibility tree defines a structured executable action space, and Jev, a fast typed decision model, repeatedly selects actions within this space.
--------------------------------------------------------------------------------
A First Glance at Jev for Network Traffic Classification: Accuracy, Processing Time, and Cost (https://arxiv.org/abs/2610.00376)
citeturn0academia20 [wordlim: 200] Published: last week; Thus, labeled examples substantially improve Jev, but the tested Jev configurations remain less accurate than trained tree ensembles; unequal supervision budgets and fixed configurations prevent attributing the gap to a single cause.
--------------------------------------------------------------------------------
JEV (https://fr.wikipedia.org/wiki/JEV)
citeturn0search21 [wordlim: 200] Crawled: 6.2 years ago; JEV est un sigle qui peut désigner : ... * Jean-Éric Vergne, un pilote de Formule E, dont JEV est l'habituel surnom.
--------------------------------------------------------------------------------
Jev (https://it.wikipedia.org/wiki/Jev)
citeturn0search22 [wordlim: 200] Crawled: 5.0 years ago; Jev* JEV – codice aeroportuale IATA dell'eliporto, Évry, Francia
--------------------------------------------------------------------------------
JEV (https://de.wikipedia.org/wiki/JEV)
citeturn0search23 [wordlim: 200] Crawled: 1.2 years ago; JEVHome - TypeSafe AI (https://typesafe.ai/)
citeturn1view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://typesafe.ai","lineno":null}); Total lines: 451
L0: cite0†TypeSafe AI L1:
L2: cite1†Manifesto L3:
L4: cite2†Our Team L5:
L6: cite3†Docs†docs.typesafe.ai L7:
L8: cite4†Sign in†console.typesafe.ai L9:
L10: Contact sales
L11:
L12: cite1†Manifesto L13:
L14: cite2†Team L15:
L16: Contact
L17:
L18: TypeSafeAI 1.1
L19:
L20: Loading ...
L21:
L22: Image Assets, Copy
L23:
L24: 0%
L25:
L26: TypeSafeAI 1.1
L27:
L28: Loading ...
L29:
L30: Image Assets, Copy
L31:
L32: 0%
L33:
L34: TypeSafeAI 1.1
L35:
L36: Loading ...
L37:
L38: Image Assets, Copy
L39:
L40: 0%
L41:
L42: ∵ ⩆
L43:
L44: ⩆ ∵
L45:
L46: Clock Tool 1.1
L47:
L48: Monday, Sep 28, 2026
L49:
L50: 19:32:37
L51:
L52: cite5†Image†framerusercontent.com L53:
L54: cite6†Image†framerusercontent.com L55:
L56: cite7†Image†framerusercontent.com L57:
L58: cite8†Image†framerusercontent.com L59: Glider 1.1
L60:
L61: Game of Life
L62:
L63: LM
L64:
L65: LM
L66:
L67: berts
L68:
L69: <low intelligence>
L70:
L71: GPT
L72:
L73: LLM
L74:
L75: LLM
L76:
L77: pre-trained models
L78:
L79: GPT
L80:
L81: llama
L82:
L83: RLHF
L84:
L85: RLHF
L86:
L87: chat models
L88:
L89: chat GPT
L90:
L91: claude
L92:
L93: instruct gpt
L94:
L95: grok
L96:
L97: deep seek
L98:
L99: RLCD
L100:
L101: TypeSafeAi
L102:
L103: RLCD
L104:
L105: reinforcement learning
L106:
L107: for calibrated decisions
L108:
L109: cite9†Image†framerusercontent.com L110:
L111: RLVR
L112:
L113: RLVR
L114:
L115: reasoning models
L116:
L117: 01
L118:
L119: 03
L120:
L121: TypeSafe AI
L122:
L123: Version 0.01
L124: ©2026. All rights reserved.
L125:
L126: Made in SF. With Love.
L127:
L128: TS.AI.0S1
L129:
L130: Clock Tool 1.1
L131:
L132: Monday, Sep 28, 2026
L133:
L134: 19:32:37
L135:
L136: cite6†Image†framerusercontent.com L137: cite7†Image†framerusercontent.com L138:
L139: Glider 1.1
L140:
L141: Game of Life
L142:
L143: LM
L144:
L145: LM
L146:
L147: berts
L148:
L149: <low intelligence>
L150:
L151: GPT
L152:
L153: LLM
L154:
L155: LLM
L156:
L157: pre-trained models
L158:
L159: GPT
L160:
L161: llama
L162:
L163: RLHF
L164:
L165: RLHF
L166:
L167: chat models
L168:
L169: chat GPT
L170:
L171: claude
L172:
L173: instruct gpt
L174:
L175: grok
L176:
L177: deep seek
L178:
L179: RLCD
L180:
L181: TypeSafeAi
L182:
L183: RLCD
L184:
L185: reinforcement learning
L186:
L187: for calibrated decisions
L188:
L189: cite9†Image†framerusercontent.com L190:
L191: RLVR
L192:
L193: RLVR
L194:
L195: reasoning models
L196:
L197: 01
L198:
L199: 03
L200:
L201: TypeSafe AI
L202:
L203: Version 0.01
L204: ©2026. All rights reserved.
L205:
L206: Made in SF. With Love.
L207:
L208: TS.AI.0S1
L209:
L210: cite7†Image†framerusercontent.com L211:
L212: Glider 1.1
L213:
L214: Game of Life
L215: LM
L216:
L217: LM
L218:
L219: berts
L220:
L221: <low intelligence>
L222:
L223: GPT
L224:
L225: LLM
L226:
L227: LLM
L228:
L229: pre-trained models
L230:
L231: GPT
L232:
L233: llama
L234:
L235: RLHF
L236:
L237: RLHF
L238:
L239: chat models
L240:
L241: chat GPT
L242:
L243: claude
L244:
L245: instruct gpt
L246:
L247: grok
L248:
L249: deep seek
L250:
L251: RLCD
L252:
L253: TypeSafeAi
L254:
L255: RLCD
L256:
L257: reinforcement learning
L258:
L259: for calibrated decisions
L260:
L261: cite9†Image†framerusercontent.com L262:
L263: RLVR
L264:
L265: RLVR
L266:
L267: reasoning models
L268:
L269: 01
L270:
L271: 03
L272:
L273: TypeSafe AI
L274:
L275: Version 0.01
L276: ©2026. All rights reserved.
L277:
L278: Made in SF. With Love.
L279:
L280: TS.AI.0S1
L281: # We took the opposite research direction
L282:
L283: not chat
L284:
L285: Reinforcement Learning from Human Feedback (RLHF) has led to LLMs that are optimized for human preferences. This has led to models that are superhuman at instruction following, and are what we now call “chat.” Yet RLHF creates inherent issues such as mode dropping, overconfidence, and lack of reliability. These flaws mean that LLMs require humans-in-the-loop.
L286:
L287: a new model
L288: We built a new class of models, System One Models, to be natively used by machines. We’re building with a new architecture, a new sampler, and a new training algorithm: Reinforcement Learning for Calibrated Decisions (RLCD).
L289:
L290: Decisions, not strings
L291:
L292: Typed outputs that software can act on.
L293:
L294: calibrated confidence
L295:
L296: Every decision includes an estimate of how confident the model is.
L297:
L298: more like code
L299:
L300: Reliable, fast, and type-safe.
L301:
L302: [b.64]
L303: ZmxvYXQgUV9yc3FydCggZmxvYXQgbnVtYmVyICkKewoJbG9uZyBpOwoJZmxvYXQgeDIsIHk7Cgljb25zdCBmbG9hdCB0aHJlZWhhbGZzID0gMS41RjsKCXgyID0gbnVtYmVyICogMC41RjsKCXkgID0gbnVtYmVyOwoJaSAgPSAqICggbG9uZyAqICkgJnk7CglpICA9IDB4NWYzNzU5ZGYgLSAoIGkgPj4gMSApOwoJeSAgPSAqICggZmxvYXQgKiApICZpOwoJeSAgPSB5ICogKCB0aHJlZWhhbGZzIC0gKCB4MiAqIHkgKiB5ICkgKTsKLy8JeSAgPSB5ICogKCB0aHJlZWhhbGZzIC0gKCB4MiAqIHkgKiB5ICkgKTsKCXJldHVybiB5Owp9
L304: # 193.6x Faster,
L305: 444.6x Cheaper.
L306:
L307: *based on workflows for System One tasks cite10†(proof) L308:
L309: cite11†Image†framerusercontent.com L310:
L311: TypeSafe AI
L312:
L313: Cost $0.000081
L314:
L315: Completed in 0.114s
L316:
L317: LLMs
L318:
L319: Cost $0.013880
L320:
L321: Completed in 8.566s
L322:
L323: Watch the real video
L324:
L325: Built for automation
L326: Jev returns typed decisions with calibrated probabilities, so your software can account for uncertainty. Set the thresholds for when it acts autonomously and when it asks for review. Combine those decisions in code to build larger workflows, with control over how the intelligence is used.
L327: ## Jev’s intelligence per dollar is literally off the charts.
L328:
L329: cite12†Image†framerusercontent.com L330:
L331: Workflow Intelligence vs. Cost
L332:
L333: cite13†Image†framerusercontent.com L334:
L335: cite12†Image†framerusercontent.com L336:
L337: Workflow Intelligence vs. Cost
L338:
L339: cite13†Image†framerusercontent.com L340:
L341: Machine-Native Intelligence
L342:
L343: LLMs produce words for people. Jev produces typed decisions and is more like code: reliable, fast, self-consistent, and type-safe.
L344:
L345: cite12†Image†framerusercontent.com L346:
L347: Hallucinations
L348:
L349: cite12†Image†framerusercontent.com L350: Hallucinations
L351:
L352: Zero Hallucinations
L353:
L354: Every Jev decision comes with a confidence estimate, so your software can act when confidence is high and escalate when it is not.
L355:
L356: cite14†Image†framerusercontent.com L357:
L358: Jev.Cost
L359:
L360: cite15†Image†framerusercontent.com L361:
L362: cite14†Image†framerusercontent.com L363:
L364: Jev.Cost
L365:
L366: cite15†Image†framerusercontent.com L367: ## $42
L368:
L369: Per Billion input tokens.
L370:
L371: ## 238x
L372:
L373: Lower input price than Claude Fable 5.1
L374: ## Come Build With Us
L375:
L376: cite16†Open roles†jobs.ashbyhq.com L377:
L378: cite16†Open roles†jobs.ashbyhq.com L379:
L380: ∵ ⩆
L381:
L382: ⩆ ∵
L383:
L384: TypeSafeAI Blog
L385:
L386: cite10†Company News Introducing System One Models & Jev Read More Introducing System One Models & Jev Read More After two years in stealth, we’re excited to finally introduce a new intelligence primitive for software. L387: cite17†The Bitterest Lesson Read More TL;DR: Compute drives progress in AI, but what good is progress if you are not doing the right task! cite18†AI: too good to be true, too bad to be useful | TypeSafe AI Read More RLHF-trained language models please humans and assist rather than make reliable autonomous decisions. What comes next? L388:
L389: ∵ ⩆
L390:
L391: ⩆ ∵
L392:
L393: ∵ ⩆
L394:
L395: ⩆ ∵
L396: ## We give a FAQ
L397:
L398: What are System One Models? What is Jev?
L399:
L400: System One Models are a new class of AI model built for decisions inside software. Jev is TypeSafe’s first public System One Model, optimized for automation. Send Jev structured questions and get typed decisions with probabilities and confidence that your software can act on.
L401:
L402: Is Jev just a smaller LLM?
L403:
L404: How is this different from JSON mode or structured outputs?
L405:
L406: How can Jev be so fast and inexpensive?
L407:
L408: Can you make Jev even faster?
L409: Are these prices temporary or subsidized?
L410:
L411: What is Jev good at? Where does it struggle?
L412:
L413: Can Jev still get things wrong?
L414:
L415: Is Jev deterministic?
L416:
L417: How do I get started or ask a question?
L418:
L419: [b.64]
L420:
L421: iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAAl0lEQVR42mNgGPyg5u9/e1xyCV9+/7XDJVn/G7eky5vfl+U5sMvZPPn9Ow6XobP//t2LS07k7+/XTjjkFM7+/V2HS2PG7787+HHIBXz4fVAcl6F///6dj8vQ6b9//1bHIWdw9/fvNbg0vvr9+wgPLsm/v39H4pKb///vX3lcNj75+70HR4AzOPz+ewdn/OOVlDiIR5K6AACSCULwD4UI6QAAAABJRU5ErkJggg==
L422:
L423: ∵ ⩆
L424:
L425: ⩆ ∵
L426: cite19†iframe†www.unicorn.studio L427:
L428: VHlwZVNhZmUgQUkgSW50ZWxsaWdlbmNlIE5vdw==
L429:
L430: TypeSafe AI © 2026
L431:
L432: cite20†Terms of Use L433:
L434: cite21†Privacy Policy L435:
L436: cite22†Acceptable Use Policy L437:
L438: cite23†LinkedIn†www.linkedin.com L439:
L440: cite24†X†x.com L441:
L442: [REDACTED]
L443:
L444: TypeSafe AI © 2026
L445:
L446: cite20†Terms of Use L447:
L448: cite21†Privacy Policy L449:
L450: cite22†Acceptable Use Policy --------------------------------------------------------------------------------
(https://docs.typesafe.ai/llms.txt)
citeturn1view1 [wordlim: 200] Crawled: today; Content type: text/plain; Source: open({"ref_id":"https://docs.typesafe.ai/llms.txt","lineno":null}); Total lines: 116
L0: # TypeSafe AI
L1:
L2: > How to use TypeSafe's System One API
L3: - [Introduction](https://docs.typesafe.ai/introduction.md): Jev is TypeSafe's flagship model and the first System One model. Send state and typed questions; get structured answers your code can use directly.
L4: - [Quick start](https://docs.typesafe.ai/introduction/quickstart.md): Prefer to just dive in? Here's everything you need to get started immediately.
L5: - [Jev with coding agents](https://docs.typesafe.ai/introduction/coding-agents.md): What Jev is (and isn't) when you're using a coding agent.
L6: - [Example use cases](https://docs.typesafe.ai/concepts/use-case-map.md): Explore TypeSafe use cases by industry and turn promising ideas into software workflows.
L7: - [System One](https://docs.typesafe.ai/concepts/system-one.md): System One models make fast, structured decisions for software. Jev is TypeSafe's flagship model and the first System One model.
L8: - [State](https://docs.typesafe.ai/concepts/state.md): What state is, how to structure it, and how to give a System One model the context it needs.
L9: - [Primitives (Questions)](https://docs.typesafe.ai/primitives.md): The three TypeSafe question types (Choice, Score, Noul), the typed answers they return, how to choose between them, and how to ask several at once.
L10: - [Choice](https://docs.typesafe.ai/primitives/choice.md): A Choice is a System One question type for selecting one option from a defined set. The answer includes the selected option, a probability for each option, and confidence.
L11: - [Score](https://docs.typesafe.ai/primitives/score.md): A Score is a System One question type for rating content against ordered, descriptive levels. The answer includes a score, a probability for each level, and confidence.
L12: - [Noul](https://docs.typesafe.ai/primitives/noul.md): A Noul question asks the TypeSafe model to evaluate a yes/no question and return the probability that the answer is yes.
L13: - [Advanced: structure](https://docs.typesafe.ai/primitives/advanced.md): Instructions, Choice options, Score levels, and Noul criteria all accept JSON structure.
L14: - [Confidence](https://docs.typesafe.ai/confidence.md): How TypeSafe reports certainty, how it differs from probability, and how to use it to control system behavior.
L15: - [How to build with TypeSafe](https://docs.typesafe.ai/concepts/how-to-build-with-system-one.md): Design AI-powered software by keeping code in control and giving System One narrow, structured decisions.
L16: - [AI primer](https://docs.typesafe.ai/introduction/machine-learning-primer.md): Why TypeSafe trains decision models with calibrated probabilities instead of optimizing for generated text.
L17: - [Patterns](https://docs.typesafe.ai/patterns.md): Architectural patterns for building systems with TypeSafe.
L18: - [Speculative fan-out](https://docs.typesafe.ai/patterns/fan-out.md): Send many questions in a single call, including speculative ones, and let your code decide what's relevant.
L19: - [Confidence-gated routing](https://docs.typesafe.ai/patterns/confidence-routing.md): Use confidence as a second axis. The answer tells you what; confidence tells you whether to act.
L20: - [Composite scoring](https://docs.typesafe.ai/patterns/composite-scoring.md): Break a complex judgment into atomic scores, combine with weights you control in code.
L21: - [Intent routing](https://docs.typesafe.ai/patterns/intent-routing.md): Classify incoming requests and route each to the optimal handler: deterministic logic, a specialist LLM, or a human.
L22: - [Cookbooks](https://docs.typesafe.ai/cookbooks.md): End-to-end recipes that show TypeSafe in real problems, from a few questions to full pipelines.
L23: - [Self-consistency: nouls](https://docs.typesafe.ai/cookbooks/consistency_noul_cookbook.md): Route uncertain probabilities to human review while keeping the underlying noul values visible.
L24: - [Self-consistency: choices](https://docs.typesafe.ai/cookbooks/consistency_choice_cookbook.md): Add an uncertain outcome to moderation decisions and compare label agreement with the share of automatic actions.
L25: - [Parallel questions](https://docs.typesafe.ai/cookbooks/parallel_questions.md): Runs a 13-question regulatory briefing over the GDPR Wikipedia article, showing that batching every question into one TypeSafe call is 12.2x cheaper and 10.0x faster with no change in answers.
L26: - [Re-ranking](https://docs.typesafe.ai/cookbooks/rerank_typesafe.md): Builds 30-passage BM25 shortlists for 40 CLERC legal queries, then uses one TypeSafe question per query-candidate pair to raise top-1 accuracy from 5% to 18% and top-10 accuracy from 38% to 62%.
L27: - [Line-by-line search](https://docs.typesafe.ai/cookbooks/semantic_find.md): Build semantic search for GitHub's Terms of Service. In one request, score 218 line ids against a plain-language query with a Choice question, and use a Noul question to check whether the document contains an answer.
L28: - [Structure recovery](https://docs.typesafe.ai/cookbooks/autoformat.md): Reconstructs Markdown from plain text that lost its formatting in two requests: one stitches hard-wrapped lines back together, one classifies every block (heading, list, code, callout).
L29: - [Function calling](https://docs.typesafe.ai/cookbooks/function_calling.md): Turns natural-language trading requests into calls to ordinary typed functions by mapping function names and closed-set arguments to confidence-aware TypeSafe questions.
L30: - [Skill suggestion](https://docs.typesafe.ai/cookbooks/skill_suggestion.md): Picks at most one skill for an agent turn out of the 182 in Nous Research's Hermes catalog, using two TypeSafe requests to rank and re-check the top candidates.
L31: - [Knowledge graph entity alignment](https://docs.typesafe.ai/cookbooks/entity_alignment.md): Decides which of 450 candidate pairs from two beer catalogues describe the same product using one Score question plus three companion Nouls that surface which fields disagree.
L32: - [Classifying RAG passages](https://docs.typesafe.ai/cookbooks/classifying_rag_passages.md): Score each retrieved passage with one TypeSafe request, then decide in code which ones reach the answering model.
L33: - [Double-checking citations](https://docs.typesafe.ai/cookbooks/citation_check.md): Catch wrong or hallucinated citations by checking against the source document. One Choice question decides whether the quote's context supports the claim.
L34: - [Guardrails for LLMs](https://docs.typesafe.ai/cookbooks/llm_guardrails.md): Screen every message going into and out of an LLM app with one TypeSafe request, thresholding hazard probabilities and severity to pass, review, block, or route.
L35: - [SDE cascade](https://docs.typesafe.ai/cookbooks/sde_cascade.md): Uses a 2-stage structured-data-extraction cascade (mini → verify → reasoning) to get most of the quality of a big reasoning model at a fraction of the cost.
L36: - [Date extraction](https://docs.typesafe.ai/cookbooks/date_extraction_cookbook.md): Extracts absolute and relative dates by asking TypeSafe for the parts named in a document, then resolving and validating them in code with confidence-based review.
L37: - [Pre-parsed value extraction](https://docs.typesafe.ai/cookbooks/pre_parsed_value_extraction_cookbook.md): Uses regexes to find candidate emails, phone numbers, and amounts, then has TypeSafe select the requested span so code can normalize a verbatim value.
L38: - [Hierarchical classification](https://docs.typesafe.ai/cookbooks/hierarchical_classification.md): Classifies documents through deep patent, retail product, biomedical, and source-code hierarchies using parallel beam search over TypeSafe Choice probabilities.
L39: - [Autoresearch feature discovery](https://docs.typesafe.ai/cookbooks/autoresearch_feature_discovery.md): Runs an autoresearch loop that proposes TypeSafe questions, converts free text into numeric features, and uses model errors to improve a supervised CatBoost regressor.
L40: - [Classification using confidence](https://docs.typesafe.ai/cookbooks/classification_using_confidence.md): Classify SEC annual reports into 75 industry groups with one Choice each, then read the answer's own confidence to decide whether to report that group or the broader division above it.
L41: - [Demos](https://docs.typesafe.ai/demos.md): Interactive examples showing what's possible with TypeSafe.
L42: - [Smart home assistant demo](https://docs.typesafe.ai/demos/smart-home.md): Demo code: a smart home assistant that uses TypeSafe to evaluate user requests.
L43: - [Models](https://docs.typesafe.ai/models.md)
L44: - [API reference](https://docs.typesafe.ai/api.md): Full HTTP API reference for the TypeSafe evaluation endpoint.
L45: - [Agent skill](https://docs.typesafe.ai/agent-skill.md): Drop-in skill for Claude Code, Codex, and other agent environments.
L46: - [Legal](https://docs.typesafe.ai/legal.md): Legal documents and policies for TypeSafe.
L47: - [Jev 1.13 jaggedness](https://docs.typesafe.ai/model-jaggedness/jev-1.13.md): Jev isn't perfect. Here are some jagged edges we are aware of with jev-1.13. Many of these will be fixed in later versions.
L48: - [Client SDKs](https://docs.typesafe.ai/sdk.md): Install a TypeSafe client SDK and use typed questions and answers in your application.
L49: - [TypeSafe Python SDK](https://docs.typesafe.ai/sdk/python.md): Install the TypeSafe Python SDK and get started with asynchronous or synchronous API calls.
L50: - [Usage](https://docs.typesafe.ai/sdk/python/usage.md): Guides and patterns for working with the TypeSafe Python SDK.
L51: - [Changelog](https://docs.typesafe.ai/sdk/python/changelog.md): Python clients for the TypeSafe AI API
L52: - [API reference](https://docs.typesafe.ai/sdk/python/api.md): Python clients for the TypeSafe AI API
L53: - [Asynchronous client](https://docs.typesafe.ai/sdk/python/api/clients/async.md): Use AsyncTypeSafeClient to ask questions, list models, and configure asynchronous TypeSafe API requests.
L54: - [Synchronous client](https://docs.typesafe.ai/sdk/python/api/clients/sync.md): Use TypeSafeClient to ask questions, list models, and configure synchronous TypeSafe API requests.
L55: - [Questions](https://docs.typesafe.ai/sdk/python/api/types/questions.md): Provide state and ask yes/no, choice, and score questions using objects or dictionaries.
L56: - [Answers and responses](https://docs.typesafe.ai/sdk/python/api/types/responses.md): Read answers, confidence scores, token usage, and available models returned by the TypeSafe API.
L57: - [Retries](https://docs.typesafe.ai/sdk/python/api/retries.md): Configure retries with RetryPolicy — attempt count, retryable statuses, backoff, and retry headers handling.
L58: - [Common types](https://docs.typesafe.ai/sdk/python/api/types/common.md): Common types for TypeSafe API SDK.
L59: - [Exceptions](https://docs.typesafe.ai/sdk/python/api/exceptions.md): Handle TypeSafe API errors, rate limits, connection failures, and timeouts.
L60: - [Constants](https://docs.typesafe.ai/sdk/python/api/constants.md): Default settings and environment variable names for the TypeSafe Python SDK.
L61: - [JavaScript SDK](https://docs.typesafe.ai/sdk/javascript.md)
L62: - [Changelog](https://docs.typesafe.ai/sdk/javascript/changelog.md)
L63: - [API reference](https://docs.typesafe.ai/sdk/javascript/api.md)
L64: - [Class: APIConnectionError](https://docs.typesafe.ai/sdk/javascript/api/classes/APIConnectionError.md)
L65: - [Class: APIError](https://docs.typesafe.ai/sdk/javascript/api/classes/APIError.md)
L66: - [Class: APIPromise<T>](https://docs.typesafe.ai/sdk/javascript/api/classes/APIPromise.md)
L67: - [Class: APITimeoutError](https://docs.typesafe.ai/sdk/javascript/api/classes/APITimeoutError.md)
L68: - [Class: APIUserAbortError](https://docs.typesafe.ai/sdk/javascript/api/classes/APIUserAbortError.md)
L69: - [Class: AuthenticationError](https://docs.typesafe.ai/sdk/javascript/api/classes/AuthenticationError.md)
L70: - [Class: BadRequestError](https://docs.typesafe.ai/sdk/javascript/api/classes/BadRequestError.md)
L71: - [Class: InternalServerError](https://docs.typesafe.ai/sdk/javascript/api/classes/InternalServerError.md)
L72: - [Class: NotFoundError](https://docs.typesafe.ai/sdk/javascript/api/classes/NotFoundError.md)
L73: - [Class: PermissionDeniedError](https://docs.typesafe.ai/sdk/javascript/api/classes/PermissionDeniedError.md)
L74: - [Class: RateLimitError](https://docs.typesafe.ai/sdk/javascript/api/classes/RateLimitError.md)
L75: - [Class: TypeSafeClient](https://docs.typesafe.ai/sdk/javascript/api/classes/TypeSafeClient.md)
L76: - [Class: TypeSafeError](https://docs.typesafe.ai/sdk/javascript/api/classes/TypeSafeError.md)
L77: - [Class: UnprocessableEntityError](https://docs.typesafe.ai/sdk/javascript/api/classes/UnprocessableEntityError.md)
L78: - [Interface: ChoiceQuestion<T>](https://docs.typesafe.ai/sdk/javascript/api/interfaces/ChoiceQuestion.md)
L79: - [Interface: ChoiceResponse<T>](https://docs.typesafe.ai/sdk/javascript/api/interfaces/ChoiceResponse.md)
L80: - [Interface: Logger](https://docs.typesafe.ai/sdk/javascript/api/interfaces/Logger.md)
L81: - [Interface: ModelCard](https://docs.typesafe.ai/sdk/javascript/api/interfaces/ModelCard.md)
L82: - [Interface: Models](https://docs.typesafe.ai/sdk/javascript/api/interfaces/Models.md)
L83: - [Interface: NoulQuestion](https://docs.typesafe.ai/sdk/javascript/api/interfaces/NoulQuestion.md)
L84: - [Interface: NoulResponse](https://docs.typesafe.ai/sdk/javascript/api/interfaces/NoulResponse.md)
L85: - [Interface: Questions](https://docs.typesafe.ai/sdk/javascript/api/interfaces/Questions.md)
L86: - [Interface: RequestOptions](https://docs.typesafe.ai/sdk/javascript/api/interfaces/RequestOptions.md)
L87: - [Interface: RetryPolicy](https://docs.typesafe.ai/sdk/javascript/api/interfaces/RetryPolicy.md)
L88: - [Interface: ScoreQuestion<T>](https://docs.typesafe.ai/sdk/javascript/api/interfaces/ScoreQuestion.md)
L89: - [Interface: ScoreResponse<T>](https://docs.typesafe.ai/sdk/javascript/api/interfaces/ScoreResponse.md)
L90: - [Interface: SystemOneRequest<Q>](https://docs.typesafe.ai/sdk/javascript/api/interfaces/SystemOneRequest.md)
L91: - [Interface: SystemOneRequestPayload](https://docs.typesafe.ai/sdk/javascript/api/interfaces/SystemOneRequestPayload.md)
L92: - [Interface: SystemOneResult<Q>](https://docs.typesafe.ai/sdk/javascript/api/interfaces/SystemOneResult.md)
L93: - [Interface: TypeSafeClientConfig](https://docs.typesafe.ai/sdk/javascript/api/interfaces/TypeSafeClientConfig.md)
L94: - [Interface: Usage](https://docs.typesafe.ai/sdk/javascript/api/interfaces/Usage.md)
L95: - [Interface: WithResponse<T>](https://docs.typesafe.ai/sdk/javascript/api/interfaces/WithResponse.md)
L96: - [Type Alias: ChoiceCriteria](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/ChoiceCriteria.md)
L97: - [Type Alias: Description](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/Description.md)
L98: - [Type Alias: EntryType](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/EntryType.md)
L99: - [Type Alias: EnvVar](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/EnvVar.md)
L100: - [Type Alias: Fetch](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/Fetch.md)
L101: - [Type Alias: JsonValue](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/JsonValue.md)
L102: - [Type Alias: LogLevel](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/LogLevel.md)
L103: - [Type Alias: Question](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/Question.md)
L104: - [Type Alias: ResultFor<T>](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/ResultFor.md)
L105: - [Type Alias: ScoreCriteria](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/ScoreCriteria.md)
L106: - [Type Alias: ScoreLegend<T>](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/ScoreLegend.md)
L107: - [Type Alias: ScoreOf<T>](https://docs.typesafe.ai/sdk/javascript/api/type-aliases/ScoreOf.md)
L108: - [Variable: ENV](https://docs.typesafe.ai/sdk/javascript/api/variables/ENV.md)
L109: - [Variable: LOG_LEVELS](https://docs.typesafe.ai/sdk/javascript/api/variables/LOG_LEVELS.md)
L110: - [Variable: VERSION](https://docs.typesafe.ai/sdk/javascript/api/variables/VERSION.md)
L111: - [Function: choice()](https://docs.typesafe.ai/sdk/javascript/api/functions/choice.md)
L112: - [Function: noul()](https://docs.typesafe.ai/sdk/javascript/api/functions/noul.md)
L113: - [Function: score()](https://docs.typesafe.ai/sdk/javascript/api/functions/score.md)
L114:
L115: This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.Internal Error ()
citeturn2view0 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/introduction.md","lineno":null}); Total lines: 1
L0: Failed to fetch https://docs.typesafe.ai/introduction.md: (400) Unsupported content-type: text/markdown
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view1 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/introduction/quickstart.md","lineno":null}); Total lines: 1
L0: Failed to fetch https://docs.typesafe.ai/introduction/quickstart.md: (400) Unsupported content-type: text/markdown
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view2 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/concepts/state.md","lineno":null}); Total lines: 1
L0: URL https://docs.typesafe.ai/concepts/state.md is not accessible via this tool.
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view3 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/primitives/choice.md","lineno":null}); Total lines: 1
L0: URL https://docs.typesafe.ai/primitives/choice.md is not accessible via this tool.
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view4 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/primitives/score.md","lineno":null}); Total lines: 1
L0: URL https://docs.typesafe.ai/primitives/score.md is not accessible via this tool.
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view5 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/primitives/noul.md","lineno":null}); Total lines: 1
L0: URL https://docs.typesafe.ai/primitives/noul.md is not accessible via this tool.
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view6 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/confidence.md","lineno":null}); Total lines: 1
L0: URL https://docs.typesafe.ai/confidence.md is not accessible via this tool.
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view7 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/models.md","lineno":null}); Total lines: 1
L0: URL https://docs.typesafe.ai/models.md is not accessible via this tool.
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view8 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/api.md","lineno":null}); Total lines: 1
L0: URL https://docs.typesafe.ai/api.md is not accessible via this tool.
--------------------------------------------------------------------------------
Internal Error ()
citeturn2view9 [wordlim: 200] Source: open({"ref_id":"https://docs.typesafe.ai/model-jaggedness/jev-1.13.md","lineno":null}); Total lines: 1
L0: Failed to fetch https://docs.typesafe.ai/model-jaggedness/jev-1.13.md: (400) Unsupported content-type: text/markdownIntroduction - TypeSafe AI (https://docs.typesafe.ai/introduction)
citeturn3view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/introduction","lineno":null}); Total lines: 66
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Get started
L15:
L16: Introduction
L17:
L18: Get started
L19: # Introduction
L20:
L21: Jev is TypeSafe’s flagship model and the first System One model. Send state and typed questions; get structured answers your code can use directly.
L22:
L23: Copy page Copy page
L24: Large language models (LLMs) are designed to produce text for humans to read. When you need a model to make a judgment that your code will consume, that creates a mismatch: you are coercing a text-generation system into outputting structured decisions, then parsing the results back into something your code can depend on. Jev is TypeSafe’s flagship model and the first cite3†System One model . System One models are built to make fast, structured decisions that software can use directly.
L25: Jev evaluates typed questions against a state and returns structured results directly. No text generation, no parsing. You get typed values and probability distributions that your code can branch on, sort by, and route with. Choice and Score also return cite4†confidence , which your code can use to decide whether and how to act on an answer.
L26: ##
L27:
L28: cite5† L29:
L30: TypeSafe primitives
L31:
L32: TypeSafe exposes three AI primitives. Similar to software primitives, our AI primitives are modular, composable, structured, reliable, and fast. Each asks a different type of question and returns a different type of answer.
L33: Question type | Goal | Returns
L34: --- | --- | ---
L35: cite6†Choice | Choose an option from a list | `choice`, `probabilities`, `confidence`
L36: cite7†Score | Score the state on a rubric | `score`, `probabilities`, `confidence`
L37: cite8†Noul | Is this statement true? | `noul` (0–1)
L38: All three question types can be mixed in a single API call. Every question is evaluated in parallel and in isolation against the same state in one go. Adding questions barely changes the response time. Each question is evaluated independently, so adding more questions does not create context-rot.
L39: ##
L40:
L41: cite9† L42:
L43: Atomic questions, composed in code
L44: System One models work best when each question asks one specific, well-scoped thing. Think of each question as a gut-check determination: the kind of judgment a highly knowledgeable person could make in a few seconds given the right context. If the question you want to ask would require extended reasoning or weighs multiple independent factors, decompose it. Ask each factor as a separate question, then combine the results with logic in your code.
L45: This keeps each individual evaluation reliable and gives you full control over how dimensions are weighted. For example, instead of “rate this startup pitch,” ask separately about market size, technical feasibility, and differentiation. Combine the scores with your own formula. When priorities shift, change a coefficient in your code rather than rewriting a prompt.
L46: ##
L47:
L48: cite10† L49:
L50: Next steps
L51:
L52: * cite11†Quick Start — Everything you need to get started immediately.
L53: * cite12†AI Primer — Why TypeSafe trains models for calibrated decisions instead of generated text.
L54: * cite13†Primitives (Questions) — How to define questions, choose between Choice, Score, and Noul, and ask several at once.
L55: * cite4†Confidence — How TypeSafe reports certainty, and how to use it architecturally.
L56: * cite14†Patterns — Common patterns for building systems with TypeSafe.
L57:
L58: Was this page helpful?
L59: Yes No
L60:
L61: cite11†Quick start Next L62:
L63: cite15†github†github.com cite16†discord†discord.gg cite17†x†x.com L64:
L65: cite18†Powered byThis documentation is built and hosted on Mintlify, a developer documentation platform†www.mintlify.com --------------------------------------------------------------------------------
Quick start - TypeSafe AI (https://docs.typesafe.ai/introduction/quickstart)
citeturn3view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/introduction/quickstart","lineno":null}); Total lines: 262
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Get started
L15:
L16: Quick start
L17:
L18: Get started
L19:
L20: # Quick start
L21:
L22: Prefer to just dive in? Here’s everything you need to get started immediately.
L23:
L24: Copy page Copy page
L25: ##
L26:
L27: cite3† L28:
L29: Try it: the Playground
L30:
L31: 1. Open the cite4†Playground†console.typesafe.ai and log in.
L32: 2. Paste any text as the state.
L33:
L34: Sample state
L35:
L36: `Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.
L37: `
L38:
L39: 3. Add a question. Try a Noul question: `"Does this message express urgency?"`
L40:
L41: `{
L42: "urgency": {
L43: "type": "noul",
L44: "instructions": "Does this message express urgency?"
L45: }
L46: }
L47: `
L48: 4. Add more questions. Mix Noul, Choice, and Score in one call and see all results at once.
L49: ##
L50:
L51: cite5† L52:
L53: Call it: the API
L54:
L55: 1. Get your API key from the cite6†dashboard†console.typesafe.ai L56: 2. Make a POST request to the API endpoint
L57: 3. Review the cite7†API Reference for all the details.
L58:
L59: `POST https://api.typesafe.ai/v1/systemone
L60: Authorization: Bearer <API_KEY>
L61: Content-Type: application/json
L62: `
L63: ###
L64:
L65: cite8† L66: Sample cURL command
L67:
L68: `curl -X POST https://api.typesafe.ai/v1/systemone \
L69: -H "Authorization: Bearer $TYPESAFE_API_KEY" \
L70: -H "Content-Type: application/json" \
L71: -d @- <<'EOF'
L72: {
L73: "state": "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.",
L74: "model": "jev-latest",
L75: "questions": {
L76: "urgency": {
L77: "type": "noul",
L78: "instructions": "Does this message express urgency?"
L79: }
L80: }
L81: }
L82: EOF
L83: `
L84: ###
L85:
L86: cite9† L87: Request body
L88:
L89: `{
L90: "state": "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.",
L91: "model": "jev-latest",
L92: "questions": {
L93: "department": {
L94: "type": "choice",
L95: "instructions": "Which team should handle this",
L96: "criteria": {
L97: "billing": "Payment or subscription issues",
L98: "technical": "Bugs or integration problems",
L99: "sales": "Pricing or account questions"
L100: }
L101: },
L102: "frustration": {
L103: "type": "score",
L104: "instructions": "How frustrated the customer appears",
L105: "criteria": [
L106: "Calm, just stating facts",
L107: "Frustrated but civil",
L108: "Very angry, strong language"
L109: ]
L110: },
L111: "is_urgent": {
L112: "type": "noul",
L113: "instructions": "The message conveys urgency or time-sensitivity"
L114: }
L115: }
L116: }
L117: `
L118: ###
L119:
L120: cite10† L121: Response body
L122:
L123: `{
L124: "model": "jev-1.13.0",
L125: "answers": {
L126: "department": {
L127: "type": "choice",
L128: "choice": "technical",
L129: "confidence": 0.78,
L130: "probabilities": {
L131: "technical": 0.85,
L132: "sales": 0.0,
L133: "billing": 0.15
L134: }
L135: },
L136: "frustration": {
L137: "type": "score",
L138: "score": 1.0,
L139: "confidence": 1.0,
L140: "legend": {
L141: "0": "Calm, just stating facts",
L142: "1": "Frustrated but civil",
L143: "2": "Very angry, strong language"
L144: },
L145: "probabilities": {
L146: "0": 0.0,
L147: "1": 1.0,
L148: "2": 0.0
L149: }
L150: },
L151: "is_urgent": {
L152: "type": "noul",
L153: "noul": 1.0
L154: }
L155: },
L156: "usage": {
L157: "input_tokens": 392,
L158: "output_tokens": 65
L159: }
L160: }
L161: `
L162: See the cite7†API Reference for all the details.
L163: ##
L164:
L165: cite11† L166:
L167: Code it: the Python SDK
L168:
L169: 1. Install the SDK (requires Python >= 3.10).
L170:
L171: With pip
L172:
L173: `pip install typesafe-sdk
L174: `
L175:
L176: With uv
L177:
L178: `uv add typesafe-sdk
L179: `
L180: 2. Use the SDK. The client reads `TYPESAFE_API_KEY` from the environment and calls `jev-latest` by default.
L181:
L182: `from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
L183:
L184: client = TypeSafeClient()
L185:
L186: ticket = "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP."
L187:
L188: response = client.system_one(
L189: state=ticket,
L190: questions={
L191: "department": Choice(
L192: instructions="Which team should handle this",
L193: criteria={
L194: "billing": "Payment or subscription issues",
L195: "technical": "Bugs or integration problems",
L196: "sales": "Pricing or account questions",
L197: },
L198: ),
L199: "frustration": Score(
L200: instructions="How frustrated the customer appears",
L201: criteria=[
L202: "Calm, just stating facts",
L203: "Frustrated but civil",
L204: "Very angry, strong language",
L205: ],
L206: ),
L207: "is_urgent": Noul(
L208: instructions="The message conveys urgency or time-sensitivity",
L209: ),
L210: },
L211: )
L212:
L213: print(response.answers["department"].choice) # "technical"
L214: print(response.answers["frustration"].score) # 1.0
L215: print(response.answers["is_urgent"].noul) # 1.0
L216: `
L217: See cite12†client SDKs for installation options and detailed usage.
L218: ##
L219:
L220: cite13† L221:
L222: Vibe it: the agent skill
L223:
L224: 1. cite14†Install the TypeSafe skill using the Claude Code plugin or `npx skills add typesafe-ai/skills --skill typesafe-ai`. You can also cite15†read SKILL.md on GitHub†github.com .
L225:
L226: * Claude Code
L227:
L228: * Other agents
L229:
L230: * Copy to your agent
L231:
L232: Run these two commands in your terminal:
L233:
L234: `claude plugin marketplace add typesafe-ai/skills
L235: claude plugin install typesafe@typesafe-ai
L236: `
L237:
L238: `npx skills add typesafe-ai/skills --skill typesafe-ai
L239: `
L240: Choose your agent when prompted. Installation is project-local by default; add `-g` to install globally.
L241: Paste this prompt into your coding agent:
L242: `Install the TypeSafe skill. If you're in Claude Code, run `claude plugin marketplace add typesafe-ai/skills`, then `claude plugin install typesafe@typesafe-ai`. If you're in another agent, run `npx skills add typesafe-ai/skills --skill typesafe-ai` and select your agent. Use one installation method. You can read the skill directly at https://github.com/typesafe-ai/skills/blob/main/skills/typesafe-ai/SKILL.md (raw: https://raw.githubusercontent.com/typesafe-ai/skills/main/skills/typesafe-ai/SKILL.md).
L243: Then use the TypeSafe skill when working on this project.
L244: `
L245: 2. Tell your coding agent to use the TypeSafe skill as you build!
L246:
L247: Coding agent prompt
L248:
L249: `Let's build a simple CLI that uses the TypeSafe API to evaluate a set of supplied documents on multiple dimensions. Use the TypeSafe skill to understand how to use the TypeSafe API and how to structure the system. Ask me questions about what kinds of documents I want to evaluate and on what dimensions.
L250: `
L251:
L252: See the cite16†Agent Skill page for more details.
L253:
L254: Was this page helpful?
L255:
L256: Yes No
L257: cite17†Introduction Previous cite18†Jev with coding agents Next L258:
L259: cite19†github†github.com cite20†discord†discord.gg cite21†x†x.com L260:
L261: cite22†Powered byThis documentation is built and hosted on Mintlify, a developer documentation platform†www.mintlify.com --------------------------------------------------------------------------------
State - TypeSafe AI (https://docs.typesafe.ai/concepts/state)
citeturn3view2 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/concepts/state","lineno":null}); Total lines: 81
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Concepts
L15:
L16: State
L17:
L18: Concepts
L19: # State
L20:
L21: What state is, how to structure it, and how to give a System One model the context it needs.
L22:
L23: Copy page Copy page
L24: State is the content you ask a System One model to evaluate. It could be a support message, a passage of text, or the current state of your application. You pass it in the `state` field of an API request, alongside the questions you want answered. Each request evaluates one state against one or more questions. All questions see the same state and are evaluated independently. You can mix cite3†Choice , cite4†Score , and cite5†Noul questions in one request.
L25: ##
L26:
L27: cite6† L28:
L29: State can be a simple string or a structured JSON value
L30:
L31: The simplest state is a plain string:
L32:
L33: `state = "My card was charged twice."
L34: `
L35: State can also be a JSON object or array containing related context, examples, and other information that helps the model answer the associated questions. Think of state as the material you would present to a panel of experts before asking them to make a judgment. In Python, pass the corresponding string, dictionary, or list directly to `client.system_one(state=...)`.
L36: Format | Useful for | Example
L37: --- | --- | ---
L38: String | A message, article, or passage | `"My card was charged twice."`
L39: Object | Named fields, related records, or application state | `{"message": "My card was charged twice.", "order_id": "A-104"}`
L40: Array | A sequence of messages or records | `["Hi", "My customer number is TS1337.", "My card was charged twice."]`
L41: Use an object for most requests so each part of the state has a descriptive name and its relationships remain clear. A string is suitable when the use case is simple and requires only one piece of text.
L42:
L43: Jev accepts text only. State must be a string, JSON object, or array of text values. Images, audio, and video are not supported (yet). Jev’s primary training language is English; other languages, including CJK scripts, are accepted but currently have lower accuracy — see cite7†Models .
L44: A support conversation as state
L45:
L46: `{
L47: "ticket": {
L48: "subject": "Duplicate charge",
L49: "messages": [
L50: {"from": "customer", "text": "I was charged twice for order A-104. Please refund the duplicate."},
L51: {"from": "support", "text": "We are checking the charges."}
L52: ]
L53: },
L54: "order": {
L55: "id": "A-104",
L56: "charges": [
L57: {"amount_usd": 49, "status": "captured"},
L58: {"amount_usd": 49, "status": "captured"}
L59: ]
L60: },
L61: "refund_policy": "Duplicate charges are eligible for a refund."
L62: }
L63: `
L64: This object is one state, even though it contains a conversation, an order, and a policy. Put related information together when the decision requires comparing those parts.
L65: ##
L66:
L67: cite8† L68:
L69: Separate content from questions
L70: The state contains the content and supporting facts. cite9†Questions define the judgments the model should make about that material. For example, keep the refund request and policy in the state, then ask whether the customer requested a refund and whether the policy supports it. See cite9†Primitives (Questions) for guidance on instructions, criteria, question types, and asking several questions about one state.
L71: See the cite10†API reference for the request schema and cite11†client SDKs for installation, typed inputs, and response handling.
L72: Was this page helpful?
L73:
L74: Yes No
L75:
L76: cite12†System One Previous cite9†Primitives (Questions)Next L77:
L78: cite13†github†github.com cite14†discord†discord.gg cite15†x†x.com L79:
L80: cite16†Powered byThis documentation is built and hosted on Mintlify, a developer documentation platform†www.mintlify.com --------------------------------------------------------------------------------
Choice - TypeSafe AI (https://docs.typesafe.ai/primitives/choice)
citeturn3view3 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/primitives/choice","lineno":null}); Total lines: 312
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Primitives (Questions)
L15:
L16: Choice
L17:
L18: Primitives (Questions)
L19: # Choice
L20:
L21: A Choice is a System One question type for selecting one option from a defined set. The answer includes the selected option, a probability for each option, and confidence.
L22:
L23: Copy page Copy page
L24: Use a Choice when the answer is one of a fixed set of options. For example, which team handles a ticket, which category a product belongs to, or which language a code snippet is written in. If the answer is a position on a spectrum, use a cite3†Score . If it’s a yes or no, use a cite4†Noul . cite5†Choose a question type compares all three. A Choice answer is the selected option in `choice`. The model also returns a probability for every option in `probabilities`, and a `confidence` value for the selected option.
L25: Example questions:
L26:
L27: `"What programming language is this code written in"
L28: → options: python, javascript, typescript, go, rust, other
L29:
L30: "What type of meeting is this based on the title and description"
L31: → options: standup, planning, retrospective, one on one, brainstorm, none of the above
L32:
L33: "Which product category does this item belong to"
L34: → options: electronics, clothing, home garden, food and beverage
L35: `
L36: ##
L37:
L38: cite6† L39:
L40: Request structure
L41:
L42: The POST request body to the cite7†TypeSafe API has a specific structure. The top level has three fields: `state`, the content to evaluate; `model`; and `questions`, a map from question ids you choose to question objects. Each Choice question has the following fields:
L43: * `type`: Always `"choice"`.
L44: * `instructions`: The question the model answers.
L45: * `criteria`: The answer options, as a map. Each key is an option name and each value is a description of that option.
L46: Below is a request where the state is a support ticket from an online shoe store and the question is which team should handle it: You choose the question id, `department` in this case. The answer is returned under the same id. The model never sees the question id. The option names and their descriptions are both sent to the model, so write descriptions that separate the options from each other. Our cite8†client SDKs provide typed questions. In Python, the same question is a `Choice`:
L47: `from typesafe_sdk import Choice, TypeSafeClient
L48:
L49: with TypeSafeClient() as client:
L50: response = client.system_one(
L51: state="My running shoes arrived in the wrong size. Can I swap them for a size 10?",
L52: questions={
L53: "department": Choice(
L54: instructions="Which team should handle this?",
L55: criteria={
L56: "returns": "Exchanges, wrong or damaged items",
L57: "shipping": "Delivery status, delays, lost packages",
L58: "billing": "Charges, invoices, payment problems",
L59: },
L60: ),
L61: },
L62: )
L63:
L64: print(response.answers["department"].choice)
L65: `
L66: Use the `system_one` method or the `https://api.typesafe.ai/v1/systemone` endpoint to call a System One model. The `model` field selects which model handles the request. cite9†How to build with TypeSafe covers where in your code to call it. Use one of our cite8†client SDKs or call the cite7†HTTP API directly. If a coding agent is writing the integration for you, install the cite10†TypeSafe agent skill first so it knows the request and response shapes.
L67: `instructions` and each entry in `criteria` can be a string, an object, or an array. Start with a string. Use an object when a description needs several kinds of guidance, such as what an option covers, what it doesn’t cover, and some examples. See cite11†Structured instructions and criteria below and the cite12†API reference .
L68: ##
L69:
L70: cite13† L71:
L72: Response structure
L73: The response has one entry in `answers` per question, under the ids from the request. This is the response to the example request above:
L74:
L75: `{
L76: "model": "jev-1.13.0",
L77: "answers": {
L78: "department": {
L79: "type": "choice",
L80: "choice": "returns",
L81: "confidence": 1.0,
L82: "probabilities": {
L83: "shipping": 0.0,
L84: "returns": 1.0,
L85: "billing": 0.0
L86: }
L87: }
L88: },
L89: "usage": {
L90: "input_tokens": 328,
L91: "output_tokens": 34
L92: }
L93: }
L94: `
L95: Besides `type`, each Choice answer has three values:
L96: * `choice`: The option with the highest probability.
L97: * `probabilities`: The full probability distribution across every option. The sum of all values is 1.
L98: * cite14†`confidence` : A number from 0 to 1 computed from how `probabilities` is spread. A flat shape, with probability spread across several options, means low confidence. A single peak on one option means high confidence.
L99: This ticket is an easy one, so all of the probability is on `returns` and confidence is 1.0. A ticket that mentions a wrong size and a missing refund would split probability between `returns` and `billing`, and confidence would drop.
L100: ##
L101:
L102: cite15† L103:
L104: Good practice: ask more than one question per call
L105: Ask every Choice question your code might need in a single request rather than one request per question. Questions are evaluated in parallel. Adding questions barely changes the response time, and the code can ignore answers it doesn’t need. Extra questions still cost tokens. cite16†Ask multiple questions together explains this in full; the next section shows five Choice questions in one call. The same logic applies to the options inside a single Choice question.
L106: A Choice question accepts up to 255 options, and adding options costs a few tokens each, so give the model the full list of teams, categories, or products rather than a shortlist. Add an `other` or `none of the above` option when the list might not cover every input, so the model can say none of the others fit. To classify documents through a deep hierarchy or large taxonomy, chain Choice questions level by level.
L107: The cite17†Hierarchical Classification cookbook shows how to run a beam search over Choice probabilities, keeping the best `K` candidate paths at each level instead of committing to a single greedy path.
L108: ##
L109:
L110: cite18† L111:
L112: A more complex example
L113: The basic example above routes a ticket to a team. A bigger support system might also need the return reason, the delivery problem, what the customer wants, and the customer’s tone. The request below asks five Choice questions about a ticket that is more ambiguous than the first: it involves three teams and doesn’t say what the customer wants. Two of these Choice questions are speculative: `return_reason` only matters if the `department` is `returns`, and `shipping_issue` only matters if it’s `shipping`.
L114: The `tone` question uses `null` descriptions because the option names are clear on their own. The TypeSafe response:
L115:
L116: `{
L117: "model": "jev-1.13.0",
L118: "answers": {
L119: "department": {
L120: "type": "choice",
L121: "choice": "returns",
L122: "confidence": 0.42,
L123: "probabilities": {
L124: "shipping": 0.04,
L125: "billing": 0.35,
L126: "returns": 0.61
L127: }
L128: },
L129: "return_reason": {
L130: "type": "choice",
L131: "choice": "wrong_size",
L132: "confidence": 1.0,
L133: "probabilities": {
L134: "other": 0.0,
L135: "wrong_size": 1.0,
L136: "changed_mind": 0.0,
L137: "damaged": 0.0,
L138: "wrong_item": 0.0
L139: }
L140: },
L141: "shipping_issue": {
L142: "type": "choice",
L143: "choice": "delayed",
L144: "confidence": 0.67,
L145: "probabilities": {
L146: "wrong_address": 0.0,
L147: "other": 0.26,
L148: "not_delivered": 0.0,
L149: "damaged_in_transit": 0.0,
L150: "delayed": 0.74
L151: }
L152: },
L153: "requested_resolution": {
L154: "type": "choice",
L155: "choice": "refund",
L156: "confidence": 0.2,
L157: "probabilities": {
L158: "replacement": 0.34,
L159: "refund": 0.4,
L160: "information": 0.02,
L161: "exchange": 0.24
L162: }
L163: },
L164: "tone": {
L165: "type": "choice",
L166: "choice": "frustrated",
L167: "confidence": 0.76,
L168: "probabilities": {
L169: "frustrated": 0.84,
--------------------------------------------------------------------------------
Score - TypeSafe AI (https://docs.typesafe.ai/primitives/score)
citeturn3view4 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/primitives/score","lineno":null}); Total lines: 338
--------------------------------------------------------------------------------
Noul - TypeSafe AI (https://docs.typesafe.ai/primitives/noul)
citeturn3view5 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/primitives/noul","lineno":null}); Total lines: 280
--------------------------------------------------------------------------------
Confidence - TypeSafe AI (https://docs.typesafe.ai/confidence)
citeturn3view6 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/confidence","lineno":null}); Total lines: 153
--------------------------------------------------------------------------------
Models - TypeSafe AI (https://docs.typesafe.ai/models)
citeturn3view7 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/models","lineno":null}); Total lines: 164
--------------------------------------------------------------------------------
API reference - TypeSafe AI (https://docs.typesafe.ai/api)
citeturn3view8 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/api","lineno":null}); Total lines: 583
--------------------------------------------------------------------------------
Jev 1.13 jaggedness - TypeSafe AI (https://docs.typesafe.ai/model-jaggedness/jev-1.13)
citeturn3view9 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/model-jaggedness/jev-1.13","lineno":null}); Total lines: 163Confidence - TypeSafe AI (https://docs.typesafe.ai/confidence)
citeturn4view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn3view6","lineno":20}); Total lines: 153
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Concepts
L15:
L16: Confidence
L17:
L18: Concepts
L19: # Confidence
L20:
L21: How TypeSafe reports certainty, how it differs from probability, and how to use it to control system behavior.
L22:
L23: Copy page Copy page
L24: All Score and Choice answers from TypeSafe include a `probabilities` property representing the probability distribution across the options (for Choice) or levels (for Score). The shape of that distribution is what tells you how certain the model is: concentrated on one outcome means a confident answer, spread out means an uncertain one. The answer’s `confidence` property collapses that shape into a single number from 0 to 1, so you can threshold on it without doing the math yourself.
L25: It is 1 when all the probability is on one outcome and 0 when the probability is spread evenly. (Noul answers don’t carry one; see cite3†Noul below.)
L26: ##
L27:
L28: cite4† L29:
L30: Confidence is derived from the probabilities
L31: `confidence` is a statistic computed from the probability distribution the answer already gives you. TypeSafe computes it for you and returns it on every Choice and Score answer, so the common case needs no extra work on your side. For a cite5†Choice , the distribution is `probabilities` across your options. For a cite6†Score , it is the distribution across your levels.
L32: In both cases a flatter distribution means lower confidence: low confidence on a Choice often means none of the options are a clear winner over the others, and low confidence on a Score often means the levels are ambiguous, multi-dimensional, or the state doesn’t contain enough to go on. The exact formula for each question type is in cite7†How confidence is calculated , so you can see how any `confidence` value follows from the answer’s own `probabilities`.
L33: ##
L34:
L35: cite8† L36:
L37: ”I don’t know” is a useful signal
L38:
L39: If an intelligent system, whether human or machine, cannot express honest uncertainty, the system cannot be trusted. Confidence gives you a built-in mechanism for the model to say “I’m not sure about this one.” This lets your code implement different behavior for different levels of certainty, which is the foundation for building systems you can actually rely on.
L40: ##
L41:
L42: cite9† L43:
L44: Three paths for using confidence in your code
L45: A useful starting pattern is to divide confidence into three ranges, each producing a different system behavior: High confidence: Act automatically. The model has a clear read and you can proceed without human involvement. Medium confidence: Proceed with caution. The model has a reasonable answer but is not certain. Depending on context, you might ask the user to confirm, flag for review, or gather more information before acting. Low confidence: Do not act.
L46: Route to a human, request clarification, or fall back to a different system. The model is telling you it does not have enough information or the question is not a good fit. Where you draw those boundaries depends on the stakes.
L47: ##
L48:
L49: cite10† L50:
L51: Thresholds scale with risk
L52: A confidence threshold is not one number. Different actions within the same system should be gated at different levels depending on the consequences of getting it wrong.
L53:
L54: `response = client.system_one(
L55: state=user_message,
L56: questions={
L57: "action": Choice(
L58: instructions="What is the user trying to do?",
L59: criteria={
L60: "check_balance": "View account balance",
L61: "approve_transfer": "Approve the pending withdrawal request",
L62: "support": "Get help with an issue",
L63: },
L64: ),
L65: },
L66: )
L67:
L68: action = response.answers["action"]
L69: confidence = action.confidence
L70:
L71: if confidence < 0.5:
L72: # Model is genuinely unsure. Don't guess.
L73: route_to_human(user_message)
L74:
L75: elif action.choice == "check_balance":
L76: # Low stakes. Showing the wrong screen is recoverable.
L77: show_balance(account_id)
L78:
L79: elif action.choice == "approve_transfer":
L80: if confidence > 0.9:
L81: # High stakes, high confidence. Proceed with confirmation.
L82: confirm_then_execute(account_id)
L83: else:
L84: # High stakes, moderate confidence. Verify first.
L85: ask_user_to_confirm(account_id)
L86: `
L87: The 0.5 confidence floor catches anything the model reports as genuinely uncertain. Above that, the threshold for acting without confirmation is higher for a destructive operation than for a read-only one. Your code encodes the risk tolerance.
L88:
L89: The correct threshold values depend on your domain and the performance of the model for your use case. Start with conservative thresholds, test with your own data, and adjust as you observe results.
L90: ##
L91:
L92: cite7† L93:
L94: How confidence is calculated
L95: Each question type summarizes its distribution a little differently. A Noul has two outcomes, a Choice has any number of options in no particular order, and a Score’s levels are ordered, so each formula below builds on the one before it. TypeSafe’s `confidence` is one reasonable way to summarize a distribution, not the only one.
L96: We return a fixed measure so that every answer comes with a sensible default: you can gate on `confidence` from your first call, on the same 0 to 1 scale for every question, without first choosing and validating a statistic of your own. Because the formulas below are exact and every answer includes its full `probabilities`, you can compute whichever measure matters most to your application instead.
L97: ###
L98:
L99: cite3† L100:
L101: Noul
L102: A Noul answer is a single probability $p$p that the answer is yes, and TypeSafe returns no separate `confidence` for it. The probability already carries the uncertainty: a value near 0.5 is the model saying it is unsure, and the cite11†Noul page covers how to threshold on it directly.
L103: If you want a confidence-style number anyway, for example to gate Nouls and Choices with the same code, use the distance from 0.5: $$\text{confidence} = |2p - 1|$$confidence=∣2 p−1∣ This gives 0 at $p = 0.5$p=0.5 and 1 at $p = 0$p=0 or $p = 1$p=1. It is also the Choice formula below applied to a yes-or-no Choice, so it sits on the same scale as Choice confidence.
L104: ###
L105:
L106: cite12† L107:
L108: Choice
L109: A Choice extends the same idea to any number of options. For a Choice with $n$n options, where $p_{\max}$p m a x is the probability of the selected option: $$\text{confidence} = \frac{p_{\max} - \frac{1}{n}}{1 - \frac{1}{n}}$$confidence=1−n 1p m a x−n 1 This measures how far the top probability sits above an even split of $\frac{1}{n}$n 1 per option, on a scale where the even split is 0 and certainty is 1.
L110: Only the top probability counts, so $(0.6, 0.3, 0.1)$(0.6,0.3,0.1) and $(0.6, 0.2, 0.2)$(0.6,0.2,0.2) both have confidence 0.4.
L111:
L112: `def choice_confidence(probabilities: list[float]) -> float:
L113: n = len(probabilities)
L114: return (max(probabilities) - 1 / n) / (1 - 1 / n)
L115:
L116:
L117: choice_confidence(list(answer.probabilities.values()))
L118: `
L119: The cite4†explorer at the top of this page uses this formula with three options. Two simpler measures, computed from the same `probabilities`, are often very effective in practice and are worth trying alongside `confidence`:
L120: * Top probability, $p_{\max}$p m a x. It reads directly as “how likely is the selected option”, which makes thresholds easy to reason about. Its meaning depends on the number of options, since 0.5 is a weak answer among two options and a strong one among ten, so set its threshold per question.
L121: * Top-to-second ratio, $p_{\max} / p_{\text{second}}$p m a x/p second. It measures how clearly the selected option beats the runner-up and ignores how the rest is spread. Many real decisions come down to the top two candidates, and this ratio targets exactly that.
L122: ###
L123:
L124: cite13† L125:
L126: Score
L127: A Score’s levels are ordered, so its formula also counts how far probability sits from the most likely level. For a Score with $n$n levels numbered $0$0 to $n - 1$n−1, where $p_i$p i is the probability of level $i$i and $m$m is the most likely level: $$\text{confidence} = \max\left(0,\ 1 - \frac{\sum_i p_i \, |i - m|}{\text{MAD}_{\text{unif}}}\right)
L128: \qquad
L129: \text{MAD}_{\text{unif}} = \frac{1}{n} \sum_i \left| i - \frac{n - 1}{2} \right|$$confidence=max(0, 1−MAD unif∑ip i∣i−m∣)MAD unif=n 1i∑i−2 n−1 The sum in the numerator is the probability-weighted average distance, in levels, between the answer and the most likely level. $\text{MAD}_{\text{unif}}$MAD unif is the same kind of average distance for an even spread across all levels, measured from the middle level.
L130: Confidence compares the two, and is floored at 0 when the answer is at least as spread out as an even spread. Probability on a neighboring level lowers confidence less than the same probability on a level further away. With three levels, $(0, 0.5, 0.5)$(0,0.5,0.5) has confidence 0.25, because the model is torn between two adjacent levels. $(0.5, 0, 0.5)$(0.5,0,0.5) has confidence 0, because it is torn between opposite ends. The Choice formula would give both distributions 0.25.
L131:
L132: `def score_confidence(probabilities: list[float]) -> float:
L133: n = len(probabilities)
L134: m = probabilities.index(max(probabilities))
L135: spread = sum(p * abs(i - m) for i, p in enumerate(probabilities))
L136: even_spread = sum(abs(i - (n - 1) / 2) for i in range(n)) / n
L137: return max(0.0, 1 - spread / even_spread)
L138:
L139:
L140: levels = sorted(answer.probabilities)
L141: score_confidence([answer.probabilities[level] for level in levels])
L142: `
L143: The `bug_severity` answer in the cite14†Score response example has probabilities $(0, 0.57, 0.43)$(0,0.57,0.43). The most likely level is 1, the spread is $0.43$0.43, and $\text{MAD}_{\text{unif}}$MAD unif for three levels is $\frac{2}{3}$3 2, so confidence is $1 - 0.43 / \frac{2}{3} \approx 0.35$1−0.43/3 2≈0.35.
L144:
L145: Was this page helpful?
L146:
L147: Yes No
L148:
L149: cite15†Advanced: structure Previous cite16†How to build with TypeSafe Next L150:
L151: cite17†github†github.com cite18†discord†discord.gg cite19†x†x.com L152: cite20†Powered byThis documentation is built and hosted on Mintlify, a developer documentation platform†www.mintlify.com --------------------------------------------------------------------------------
Models - TypeSafe AI (https://docs.typesafe.ai/models)
citeturn4view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn3view7","lineno":20}); Total lines: 164
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Reference
L15:
L16: Models
L17:
L18: Reference
L19: # Models
L20:
L21: Copy page Copy page
L22:
L23: Jev is TypeSafe’s flagship model and the first cite3†System One model . Every model on this page is served by the same endpoint, `POST /v1/systemone`. The request’s `model` field selects which one handles the call; see the cite4†API reference for the full request shape.
L24: ##
L25:
L26: cite5† L27:
L28: Current models
L29:
L30: Jev 1.13 | `jev-1.13.0`
L31: --- | ---
L32: Price (per Btok / per Mtok) | $42 / $0.042
L33: Rate limits | 100K tokens per second / 80 requests per second
L34: Context length | 64k tokens per request; 32k tokens for `state` plus the longest question
L35: Input | Text only. String, JSON object, or array of text values. No image, audio, or video input.
L36: * Price: Charged per input token. Output tokens are free. A Btok is a billion tokens and an Mtok is a million tokens.
L37: * Rate limits: Measured in tokens per second and requests per second. A request over either limit returns `429 Too Many Requests`. Our cite6†client SDKs retry with backoff by default and honor the `retry-after` header when the response carries one. If you call the HTTP API directly, see cite7†Handling rate limits .
L38: * Context length: Jev ingests the `state` once and evaluates every question against it in parallel. The 64k budget covers the `state` plus all questions combined; the 32k budget applies to the `state` plus the single longest question. See cite8†Speculative fan-out for packing many questions into one request, and cite9†Jev 1.13 jaggedness for how accuracy shifts as the state grows.
L39: * Input: Jev evaluates natural-language text. Pre-process non-text inputs (images, audio, video, binaries) into text or structured fields before sending them as `state`. See cite10†State for supported shapes.
L40: Rate limits are adjusting dynamically. We are serving a very large volume of demand, and the limits above can change without notice while we do, as upcoming large GPU deals land and we let in more users. Once things settle down more, we’ll be able to offer more stable limits. Higher limits are available on custom and enterprise plans. Contact sales@typesafe.ai.
L41: ##
L42:
L43: cite11† L44:
L45: Aliases
L46:
L47: An alias is a model name that resolves to a versioned model ID. Send it in the `model` field like any other name.
L48:
L49: Alias | Points to | Meaning
L50: --- | --- | ---
L51: `jev-latest` | `jev-1.13.0` | The most recent stable, official release. The default in our client SDKs, and the name the examples in these docs use.
L52: `jev-preview` | `jev-1.13.0` | The most recent release, whether or not it is an official one. Moves ahead of `jev-latest` when a preview build is available.
L53: `jev-preview` currently points to the same model as `jev-latest`. There is no preview build available right now.
L54:
L55: An alias moves when a new release ships, so the answers behind it can change without a change on your side. The response’s `model` field reports the versioned ID that answered, so you can log which model produced each result. If you have tuned confidence thresholds against a specific version, pin that version’s ID instead of the alias and move to the new one on your own schedule.
L56: ##
L57:
L58: cite12† L59:
L60: Customizing Jev
L61:
L62: Jev is not fine-tuned or LoRA-adapted with customer data. It is trained with cite13†RLCD to return calibrated decisions, and the same weights serve every account. You shape its answers to your domain through the request rather than through per-account weights:
L63: * Put your proprietary content, records, and reference material in the `state` field. See cite10†State .
L64: * Encode your domain rules and boundary cases in the `instructions` and `criteria` of each question. See cite14†How to build with TypeSafe and cite15†Advanced: structure .
L65: * Decompose broad judgments into atomic questions and combine the outputs in code. See cite16†Composite scoring and the cite17†AutoResearch cookbook for training a downstream classical model on Jev’s probabilities.
L66: ##
L67:
L68: cite18† L69:
L70: Language support
L71:
L72: Jev accepts natural-language text. English is the primary training language and where accuracy is currently best. Other languages, including CJK scripts, are handled but not equally well; test on your own content before relying on Jev for a non-English workload, and pay close attention to cite19†Confidence when routing.
L73: ##
L74:
L75: cite20† L76:
L77: Data handling
L78:
L79: Jev is not trained on customer requests or responses. See cite21†Legal for the Data Processing Agreement, the Privacy Policy, and details on zero data retention (ZDR) for enterprise customers.
L80: ##
L81:
L82: cite22† L83:
L84: Listing models
L85:
L86: `GET /v1/models` returns the names your account can send in the `model` field, with a description and release date for each. It currently lists the aliases. Versioned IDs such as `jev-1.13.0` are accepted by the `model` field whether or not they appear in the list.
L87:
L88: cURL
L89:
L90: Python
L91: JavaScript
L92:
L93: `curl https://api.typesafe.ai/v1/models \
L94: -H "Authorization: Bearer $TYPESAFE_API_KEY"
L95: `
L96:
L97: `from typesafe_sdk import TypeSafeClient
L98:
L99: with TypeSafeClient() as client:
L100: for model in client.models.list().models:
L101: print(model.name, model.release_date, model.description)
L102: `
L103:
L104: `import { TypeSafeClient } from "@typesafe-ai/sdk";
L105:
L106: const client = new TypeSafeClient();
L107: const models = await client.models.list();
L108: for (const model of models) {
L109: console.log(model.name, model.release_date, model.description);
L110: }
L111: `
L112: cite23† L113:
L114: [Button: models]
L115:
L116: array
L117:
L118: required
L119:
L120: One entry per model or alias.
L121:
L122: Show properties
L123:
L124: cite24† L125:
L126: [Button: name]
L127:
L128: string
L129:
L130: required
L131:
L132: The model ID or alias, as accepted by the `model` field.
L133:
L134: cite25† L135:
L136: [Button: description]
L137:
L138: string
L139:
L140: required
L141:
L142: What the model is for.
L143:
L144: cite26† L145:
L146: [Button: release_date]
L147:
L148: string
L149:
L150: required
L151:
L152: When the model or alias was released.
L153:
L154: See the cite27†Python and cite28†JavaScript SDK references for the full method signatures.
L155:
L156: Was this page helpful?
L157:
L158: Yes No
L159:
L160: cite4†API reference Next L161: cite29†github†github.com cite30†discord†discord.gg cite31†x†x.com L162:
L163: cite32†Powered byThis documentation is built and hosted on Mintlify, a developer documentation platform†www.mintlify.com --------------------------------------------------------------------------------
Jev 1.13 jaggedness - TypeSafe AI (https://docs.typesafe.ai/model-jaggedness/jev-1.13)
citeturn4view2 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn3view9","lineno":20}); Total lines: 163
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Model jaggedness
L15:
L16: Jev 1.13 jaggedness
L17:
L18: Model jaggedness
L19: # Jev 1.13 jaggedness
L20:
L21: Jev isn’t perfect. Here are some jagged edges we are aware of with jev-1.13. Many of these will be fixed in later versions.
L22:
L23: Copy page Copy page
L24:
L25: Applies to `jev-1.13`. Last reviewed 2026-10-02.
L26: `jev-1.13` is fast, calibrated, and good at common-sense judgment but it is not perfect. `jev-1.13` does the best on cite3†System One tasks. It may struggle with tasks that require additional levels of indirection. It can be quite literal in its understanding. It struggles with tasks that require numeric precision.
L27: ##
L28:
L29: cite4† L30:
L31: The failure modes in detail
L32: # | Failure mode | Do this instead
L33: --- | --- | ---
L34: 1 | cite5†Literal reading | Write the exact condition, criteria for each available options
L35: 2 | cite6†Math and Numbers | Keep the arithmetic in code
L36: 3 | cite7†Date and time comparison | Extract components; compare in code
L37: 4 | cite8†Indirection | Reduce hops; point to the relevant state
L38: 5 | cite9†Large state full of irrelevant detail | Filter first; send only what the question needs
L39: 6 | cite10†Adversarial content | Write precise prompts, and test edge cases before deploying
L40: 7 | cite11†Contradictory instructions and criteria | Align the criteria and instruction
L41: 8 | cite12†Choice option order | Reorder the options and check the answer is consistent
L42: 9 | cite13†Generation | Use a generative model
L43: ##
L44:
L45: cite5† L46:
L47: Literal reading
L48: `jev-1.13` answers the question you wrote, not the one you meant. Scoping words, negations, and implied conditions are read at face value. A question will be answered based on the words written in the instruction, whereas a person might have read the intent behind the instructions. Instead: state the exact condition in the `instructions`. Be specific. Put boundary cases in the criteria.
L49: When you look at a wrong answer and find yourself explaining what you really meant, that explanation is the missing half of the instruction. Where interpretation is unavoidable, split it into two literal questions and combine them in code.
L50: ##
L51:
L52: cite6† L53:
L54: Math and Numbers
L55:
L56: Jev is not a calculator. We strongly recommend implementing any mathematical logic in code. Jev will perform better on semantic questions than mathematical ones.
L57: ###
L58:
L59: cite14† L60:
L61: Counting
L62: `jev-1.13` does not count reliably. This covers characters in a word, occurrences of a term in a passage, and items in a long list. The model recognizes the shape of an answer rather than tallying, and the error grows with the size of the thing being counted. Before asking a counting question, ask why the count needs a model at all. If the unit is something a regular expression or a parser can find, the count belongs in code and the model has nothing to add. Instead: count in code.
L63: When you want to count items matching some criteria, iterate in code over the candidates and ask one question for each, then add up the answers yourself.
L64:
L65: `from typesafe_sdk import Noul, TypeSafeClient
L66:
L67: client = TypeSafeClient(model="jev-1.13")
L68: YES = 0.5 # up to you on what you want the threshold to be, depends on your usecase.
L69:
L70: items = ["typesafe", "apple", "california", "banana", "likes", "calibration", "orange", "vertex"]
L71:
L72: result = client.system_one(
L73: {"items": items},
L74: {
L75: f"item_{i}": Noul(instructions=f"Is `items[{i}]` the name of a fruit?")
L76: for i in range(len(items))
L77: },
L78: )
L79:
L80: count = sum(result.nouls[f"item_{i}"].noul > YES for i in range(len(items)))
L81: `
L82: ###
L83:
L84: cite15† L85:
L86: Numeric representations
L87: `jev-1.13` will perform better on semantic representations than numeric. For example, questions about colors using hex values will underperform compared to those using the English names. Given RGB triples or hex values it cannot reliably judge whether two values are near each other. Similarly, questions about high-level programming languages will perform better than questions about low level assembly, or binary encoded instructions.
L88: Instead: do the conversion in code and pass in either the computed number or a named bucket. Keep the model for the part that is genuinely a judgment, such as whether a color reads as a warning.
L89: ###
L90:
L91: cite16† L92:
L93: Math using score
L94:
L95: Please do not use score outputs (e.g., expectations and probability) to compute the exact magnitude of a number between two levels of a criterion. You can use the expectation to check if it passes a particular threshold, but `jev-1.13`’s score levels are weak in numerical calibration. It will not be able to help you reconstruct the exact number by interpolating between the nearest two levels.
L96: ##
L97:
L98: cite7† L99:
L100: Date and time comparison
L101: `jev-1.13` reads dates as text, not as ordered quantities. Asking which of two dates comes first, how far apart they are, or whether one falls inside a window is unreliable. It gets worse with mixed formats, relative references and domain boundaries such as quarters, settlement windows, and accrual periods. Instead: split the work. Extraction is a judgment, so give it to the model. Arithmetic is not, so keep it in code.
L102: Every part of a date is a small closed set: twelve months, thirty-one possible days, a bounded range of years. That turns extraction into a cite17†Choice over enumerated options rather than free-form parsing, and it gives you somewhere to put an explicit “not stated” option so a missing part is reported rather than guessed. Code assembles the parts into a real date and owns everything after that, including ordering, duration, offset, and weekday.
L103: The cite18†date extraction cookbook has the worked version, including relative dates and confidence gating.
L104: ##
L105:
L106: cite8† L107:
L108: Indirection
L109:
L110: Instructions carrying double negatives or complex indirection are answered less reliably. A question about a property of a property or something that requires multiple hops of reasoning costs accuracy. Instead: write your instructions as directly as possible. When possible, identify the relevant parts of state by name.
L111: ##
L112:
L113: cite9† L114:
L115: Large state full of irrelevant detail
L116:
L117: Accuracy falls as the state grows with content unrelated to the decision. Unrelated detail acts as a distractor, and a large state makes it harder to tell which part of the input produced a wrong answer. Instead: retrieve and filter in code first, and send only the fields the question needs. When it’s not possible to filter in state, you can use a cite19†Noul to filter for relevance. The cite20†classifying RAG passages cookbook has a worked example.
L118: Context length limit. `jev-1.13` has a bounded context window. See the cite21†Models page for the exact token limits.
L119: ##
L120:
L121: cite10† L122:
L123: Adversarial content
L124:
L125: State is data, and `jev-1.13` does not treat it as hostile by default. Content written to adversarially steer the model, whether that is an injected instruction, a deliberately misleading framing, or text that argues for its own classification, can move the answer. We expect to improve on this in the future. Instead: be explicit in the criteria. Test your integration thoroughly before deploying it to many users.
L126: ##
L127:
L128: cite11† L129:
L130: Contradictory instructions and criteria
L131:
L132: When the `instructions` and the `criteria` ask for different things, `jev-1.13` might get confused. The best performance comes from clear phrasing. For example, a Noul where `true` maps to no and `false` maps to yes will perform worse. Aim for instructions which are easy for the average person to read and understand. Instead: treat the criteria as an extension of the instruction. Align the two using clear and precise language.
L133: ##
L134:
L135: cite12† L136:
L137: Choice option order
L138:
L139: In some cases, we observed that the order of a cite17†Choice ’s options can affect the answer, and `jev-1.13` leans toward the option that comes first. Instead: reorder the options to double check that the answer stays consistent.
L140: ##
L141:
L142: cite13† L143:
L144: Generation
L145: `jev-1.13` is not trained to generate text. While you can force it to by chaining choices, this will not work well and will be very slow. For data extraction, it is better to extract possible options using regex or a generative model and let `jev-1.13` pick the correct extraction. Instead: when the answer space is bounded, turn extraction into a cite17†Choice over the options rather than asking for the value itself. If you really need to generate text… there are other models for that.
L146: As a reminder, avoid the following:
L147:
L148: * Asking the model something code can compute exactly.
L149: * Hiding several judgments inside one question.
L150: * System Two tasks: more layers of indirections
L151: * Giving it more context in `state` than the question needs. Jev suffers from context rot, so unrelated material in the `state` costs you accuracy.
L152:
L153: Found a failure mode that belongs on this list? We want to hear about it. Reach us on cite22†Discord†discord.com .
L154:
L155: Was this page helpful?
L156:
L157: Yes No
L158: cite23†Legal Previous cite24†Client SDKs Next L159:
L160: cite25†github†github.com cite26†discord†discord.gg cite27†x†x.com L161:
L162: cite28†Powered byThis documentation is built and hosted on Mintlify, a developer documentation platform†www.mintlify.comFound it: Jev is TypeSafe AI’s model for typed decisions. I’ve read the core concepts, confidence calculations, model limits, and documented weaknesses; I’m now checking the SDKs and workflow examples. One useful distinction: its confidence field summarizes the answer’s probability distribution—it isn’t a separate guarantee of correctness.
>python3 - <<'PY'
import urllib.request, concurrent.futures
paths=['api','primitives/score','primitives/noul','primitives/advanced','sdk/javascript','sdk/python','concepts/how-to-build-with-system-one','patterns/fan-out','patterns/composite-scoring','patterns/intent-routing','introduction/coding-agents']
def read(p):
try:
return p,urllib.request.urlopen('https://docs.typesafe.ai/'+p+'.md',timeout=20).read().decode()
except Exception as e:return p,str(e)
with concurrent.futures.ThreadPoolExecutor(max_workers=6) as pool:
for p,body in pool.map(read,paths):
print('\nDOCUMENT: '+p+'\n'+body)
PY{"chunk_id":"2d770c","wall_time_seconds":0.669763542,"exit_code":0,"original_token_count":437,"output":"\nDOCUMENT: api\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: primitives/score\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: primitives/noul\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: primitives/advanced\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: sdk/javascript\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: sdk/python\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: concepts/how-to-build-with-system-one\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: patterns/fan-out\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: patterns/composite-scoring\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: patterns/intent-routing\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n\nDOCUMENT: introduction/coding-agents\n<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>\n"}>python3 - <<'PY'
import subprocess, concurrent.futures
paths=['api','primitives/score','primitives/noul','primitives/advanced','sdk/javascript','sdk/python','concepts/how-to-build-with-system-one','patterns/fan-out','patterns/composite-scoring','patterns/intent-routing','introduction/coding-agents']
def read(p):
r=subprocess.run(['curl','-fsSL','--max-time','20','https://docs.typesafe.ai/'+p+'.md'],capture_output=True,text=True)
return p,r.stdout or r.stderr
with concurrent.futures.ThreadPoolExecutor(max_workers=6) as pool:
for p,body in pool.map(read,paths):
print('\nDOCUMENT: '+p+'\n'+body)
PY{"chunk_id":"a12fc8","wall_time_seconds":0.434122375,"exit_code":0,"original_token_count":48102,"output":"Warning: truncated output (original token count: 48102)\nTotal output lines: 4741\n\n\nDOCUMENT: api\n> ## Documentation Index\n> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# API reference\n\n> Full HTTP API reference for the TypeSafe evaluation endpoint.\n\nEvaluate a `state` against a map of typed `questions` and get back structured `answers`, one per question. For a guided introduction, start with the [primitives](/primitives).\n\n## Evaluation endpoint\n\n```http theme={null}\nPOST https://api.typesafe.ai/v1/systemone\nAuthorization: Bearer <API_KEY>\nContent-Type: application/json\n```\n\n## Request body\n\nThe top-level shape of every request. Each entry in the `questions` map is a typed question you name.\n\n<ParamField body=\"state\" type=\"string | object | array\" required>\n The content to evaluate. A plain string for text, or structured data (object/array) for things like chat logs, records, or the current state of your application. See [State](/concepts/state) for formats and best practices.\n</ParamField>\n\n<ParamField body=\"model\" type=\"string\" required>\n The model that handles the request. Use `\"jev-latest\"`, TypeSafe's flagship model. See [Models](/models) for the available models and aliases.\n</ParamField>\n\n<ParamField body=\"questions\" type=\"map<string, Question>\" required>\n A map of typed [Question](#question-types) objects. You choose each key; answers come back under the same keys.\n\n <Expandable title=\"map entries\">\n <ParamField body=\"‹question id›\" type=\"Question\">\n A key you choose. The matching [Answer](#answer-types) is returned under this same id. The key is not sent to the underlying model and is not used in inference.\n </ParamField>\n </Expandable>\n</ParamField>\n\n```json Example request theme={null}\n{\n \"state\": \"Help! My payouts have been failing for 3 days.\",\n \"model\": \"jev-latest\",\n \"questions\": {\n \"is_urgent\": {\n \"type\": \"noul\",\n \"instructions\": \"Does this convey urgency?\"\n }\n }\n}\n```\n\n## Question types\n\nA `Question` is one of three types, set by its `type` field. All three share `type` and `instructions`; each adds its own `criteria`.\n\nThe `instructions` property can be a string, an object, or an array. You can break up a long question that has extra context, or data it needs to reference, into a structured object. Put the question in one field and the data in the others, and refer to the data fields by name in backticks, the same way you point a question at a nested `state` value:\n\n```json theme={null}\n\"instructions\": {\n \"potential_duplicate\": {\n \"name\": \"John Smith\",\n \"location\": \"Oakland, California\",\n \"last_employer\": \"Google\"\n },\n \"question\": \"Is the resume for the same person as `potential_duplicate`?\"\n}\n```\n\nSee [Use structure in the questions](/concepts/how-to-build-with-system-one#use-structure-in-the-questions) to learn more.\n\n### Noul\n\nA yes/no question. Returns the probability the answer is yes.\n\n<ParamField body=\"type\" type=\""noul"\" required />\n\n<ParamField body=\"instructions\" type=\"string | object | array\" required>\n The yes/no question to evaluate. An object can hold the question in one field and data it refers to in others; see [Use structure in the questions](/concepts/how-to-build-with-system-one#use-structure-in-the-questions).\n</ParamField>\n\n<ParamField body=\"criteria\" type=\"object\">\n Optional descriptions of what a yes and a no mean.\n\n <Expandable title=\"properties\">\n <ParamField body=\"true\" type=\"string | object | array\">\n What a yes (value near 1) means.\n </ParamField>\n\n <ParamField body=\"false\" type=\"string | object | array\">\n What a no (value near 0) means.\n </ParamField>\n </Expandable>\n</ParamField>\n\n```json Example request focus={5-12} theme={null}\n{\n \"state\": \"Help! My payouts have been failing for 3 days.\",\n \"model\": \"jev-latest\",\n \"questions\": {\n \"is_urgent\": {\n \"type\": \"noul\",\n \"instructions\": \"Does this convey urgency?\",\n \"criteria\": {\n \"true\": \"Explicitly time-sensitive\",\n \"false\": \"No urgency expressed\"\n }\n }\n }\n}\n```\n\n### Choice\n\nPicks one option from a set you define. Returns the chosen option and the full probability distribution.\n\n<ParamField body=\"type\" type=\""choice"\" required />\n\n<ParamField body=\"instructions\" type=\"string | object | array\" required>\n What the model should decide. An object can hold the question in one field and data it refers to in others; see [Structured instructions and criteria](/primitives/choice#structured-instructions-and-criteria).\n</ParamField>\n\n<ParamField body=\"criteria\" type=\"map<string, string | object | array | null>\" required>\n A map of option to rubric description; use null when an option needs no extra detail. You can have a maximum of 255 options per Choice.\n\n <Expandable title=\"map entries\">\n <ParamField body=\"‹option›\" type=\"string | object | array | null\">\n A key you choose. A description of this option.\n </ParamField>\n </Expandable>\n</ParamField>\n\n```json Example request focus={5-13} theme={null}\n{\n \"state\": \"Help! My payouts have been failing for 3 days.\",\n \"model\": \"jev-latest\",\n \"questions\": {\n \"department\": {\n \"type\": \"choice\",\n \"instructions\": \"Which team should handle this?\",\n \"criteria\": {\n \"billing\": \"Payments, invoicing, refunds\",\n \"technical\": \"Bugs, outages, integrations\",\n \"sales\": \"Pricing, upgrades, new accounts\"\n }\n }\n }\n}\n```\n\n### Score\n\nRates the state along a rubric you define. Returns a probability-weighted value across your levels.\n\n<ParamField body=\"type\" type=\""score"\" required />\n\n<ParamField body=\"instructions\" type=\"string | object | array\" required>\n What the model should rate. An object can hold the question in one field and data it refers to in others; see [Use structure in the questions](/concepts/how-to-build-with-system-one#use-structure-in-the-questions).\n</ParamField>\n\n<ParamField body=\"criteria\" type=\"array<string | object | array>\" required>\n An ordered array of level descriptions. A Score should have at least two levels; the API accepts up to 10.\n</ParamField>\n\n```json Example request focus={5-9} theme={null}\n{\n \"state\": \"Help! My payouts have been failing for 3 days.\",\n \"model\": \"jev-latest\",\n \"questions\": {\n \"frustration\": {\n \"type\": \"score\",\n \"instructions\": \"How frustrated is the customer?\",\n \"criteria\": [\"Calm\", \"Frustrated\", \"Very angry\"]\n }\n }\n}\n```\n\n## Response body\n\nOne answer per question, returned under the same ids you provided.\n\n<ResponseField name=\"model\" type=\"string\" required>\n The model that performed the evaluation.\n</ResponseField>\n\n<ResponseField name=\"answers\" type=\"map<string, Answer>\" required>\n One [Answer](#answer-types) per question, keyed by the same ids you used in questions.\n\n <Expandable title=\"map entries\">\n <ResponseField name=\"‹question id›\" type=\"Answer\">\n The same id you chose in questions.\n </ResponseField>\n </Expandable>\n</ResponseField>\n\n<ResponseField name=\"usage\" type=\"object\" required>\n Token usage for the request.\n\n <Expandable title=\"properties\">\n <ResponseField name=\"input_tokens\" type=\"integer\" />\n\n <ResponseField name=\"output_tokens\" type=\"integer\" />\n </Expandable>\n</ResponseField>\n\n```json Example response theme={null}\n{\n \"model\": \"jev-1.13.0\",\n \"answers\": {\n \"is_urgent\": {\n \"type\": \"noul\",\n \"noul\": 0.95\n }\n },\n \"usage\": { \"input_tokens\": 296, \"output_tokens\": 20 }\n}\n```\n\n## Answer types\n\nEvery answer carries a `type` matching its question. Choice and Score answers also carry a `confidence` between 0 to 1, derived from the answer's probability distribution. See [Confidence](/confidence).\n\n### Noul answer\n\n<ResponseField name=\"type\" type=\""noul"\" required />\n\n<ResponseField name=\"noul\" type=\"number\" required>\n The yes/no answer on a scale from 0 (no) to 1 (yes).\n</ResponseField>\n\n```json Example response focus={4-7} theme={null}\n{\n \"model\": \"jev-1.13.0\",\n \"answers\": {\n \"is_urgent\": {\n \"type\": \"noul\",\n \"noul\": 0.95\n }\n },\n \"usage\": { \"input_tokens\": 307, \"output_tokens\": 20 }\n}\n```\n\n### Choice answer\n\n<ResponseField name=\"type\" type=\""choice"\" required />\n\n<ResponseField name=\"choice\" type=\"string\" required>\n The highest-probability option.\n</ResponseField>\n\n<ResponseField name=\"probabilities\" type=\"map<string, number>\" required>\n Every option mapped to its probability (floats that sum to 1).\n\n <Expandable title=\"map entries\">\n <ResponseField name=\"‹option›\" type=\"number\">\n An option you defined in criteria.\n </ResponseField>\n </Expandable>\n</ResponseField>\n\n<ResponseField name=\"confidence\" type=\"number\" required>\n How certain the model is, derived from probabilities.\n</ResponseField>\n\n```json Example response focus={4-9} theme={null}\n{\n \"model\": \"jev-1.13.0\",\n \"answers\": {\n \"department\": {\n \"type\": \"choice\",\n \"choice\": \"billing\",\n \"probabilities\": { \"billing\": 0.88, \"technical\": 0.12, \"sales\": 0.0 },\n \"confidence\": 0.81\n }\n },\n \"usage\": { \"input_tokens\": 318, \"output_tokens\": 34 }\n}\n```\n\n### Score answer\n\n<ResponseField name=\"type\" type=\""score"\" required />\n\n<ResponseField name=\"score\" type=\"number\" required>\n The probability-weighted answer across the levels; can land between levels.\n</ResponseField>\n\n<ResponseField name=\"legend\" type=\"map<string, string>\" required>\n Each level number mapped back to its description.\n</ResponseField>\n\n<ResponseField name=\"probabilities\" type=\"map<string, number>\" required>\n Each level (string key) mapped to its probability (floats that sum to 1).\n\n <Expandable title=\"map entries\">\n <ResponseField name=\"‹level›\" type=\"number\">\n A level index, as a string key matching legend.\n </ResponseField>\n </Expandable>\n</ResponseField>\n\n<ResponseField name=\"confidence\" type=\"number\" required>\n How certain the model is, derived from probabilities.\n</ResponseField>\n\n```json Example response focus={4-10} theme={null}\n{\n \"model\": \"jev-1.13.0\",\n \"answers\": {\n \"frustration\": {\n \"type\": \"score\",\n \"score\": 1.05,\n \"legend\": { \"0\": \"Calm\", \"1\": \"Frustrated\", \"2\": \"Very angry\" },\n \"probabilities\": { \"0\": 0.0, \"1\": 0.95, \"2\": 0.05 },\n \"confidence\": 0.92\n }\n },\n \"usage\": { \"input_tokens\": 304, \"output_tokens\": 18 }\n}\n```\n\n## Errors\n\nErrors use standard HTTP status codes with a JSON body describing what went wrong.\n\n| Status | Meaning |\n| - | - |\n| `401 Unauthorized` | Missing or invalid API key. Check the `Authorization` header. |\n| `422 Unprocessable Entity` | The request body failed validation — for example a missing required field or a malformed question. The body details the offending field. |\n| `429 Too Many Requests` | You have exceeded your rate limit. Back off and retry after a short delay. |\n| `529 Overloaded` | TypeSafe is temporarily overloaded. Retry after a short delay. |\n\n### Handling rate limits\n\nWhen you receive a `429 Too Many Requests` or `529 Overloaded` response, retry the request with exponential backoff instead of retrying immediately. Our client SDKs handle this automatically, so no extra handling is needed if you use one of our SDKs with its default retry policy.\n\n\nThis documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.\n\nDOCUMENT: primitives/score\n> ## Documentation Index\n> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# Score\n\n> A Score is a System One question type for rating content against ordered, descriptive levels. The answer includes a score, a probability for each level, and confidence.\n\nexport function ScoreExplorer() {\n const examples = [{\n \"id\": \"severity\",\n \"label\": \"Bug severity\",\n \"question\": \"How severe is the reported issue?\",\n \"state\": \"The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.\",\n \"levels\": [\"Cosmetic; no impact to functionality\", \"Broken or degraded feature, but workaround exists\", \"Blocking issue; no workaround exists\"],\n \"shortLevels\": [\"Cosmetic\", \"Workaround\", \"Blocking\"],\n \"answer\": {\n \"type\": \"score\",\n \"score\": 1.43,\n \"confidence\": 0.35,\n \"legend\": {\n \"0\": \"Cosmetic; no impact to functionality\",\n \"1\": \"Broken or degraded feature, but workaround exists\",\n \"2\": \"Blocking issue; no workaround exists\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.57,\n \"2\": 0.43\n }\n }\n }, {\n \"id\": \"formality\",\n \"label\": \"Outfit formality\",\n \"question\": \"How formal is this outfit based on the description?\",\n \"state\": \"A navy blazer over a plain white T-shirt, dark jeans, and clean leather loafers. No tie.\",\n \"levels\": [\"gym clothes\", \"casual\", \"business casual\", \"formal\", \"black tie\"],\n \"shortLevels\": [\"Gym\", \"Casual\", \"Business casual\", \"Formal\", \"Black tie\"],\n \"answer\": {\n \"type\": \"score\",\n \"score\": 1.86,\n \"confidence\": 0.89,\n \"legend\": {\n \"0\": \"gym clothes\",\n \"1\": \"casual\",\n \"2\": \"business casual\",\n \"3\": \"formal\",\n \"4\": \"black tie\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.14,\n \"2\": 0.86,\n \"3\": 0.0,\n \"4\": 0.0\n }\n }\n }, {\n \"id\": \"relevance\",\n \"label\": \"Candidate fit\",\n \"question\": \"How relevant is this candidate's experience to the job posting?\",\n \"state\": \"Job posting: Senior backend engineer building Python APIs and PostgreSQL services. Candidate: Three years building Django REST APIs with PostgreSQL, preceded by two years in frontend JavaScript. Has owned small services but has not led a backend team.\",\n \"levels\": [\"completely unrelated\", \"adjacent field\", \"some direct experience\", \"deep, direct experience\"],\n \"shortLevels\": [\"Unrelated\", \"Adjacent\", \"Some direct\", \"Deep direct\"],\n \"answer\": {\n \"type\": \"score\",\n \"score\": 2.52,\n \"confidence\": 0.52,\n \"legend\": {\n \"0\": \"completely unrelated\",\n \"1\": \"adjacent field\",\n \"2\": \"some direct experience\",\n \"3\": \"deep, direct experience\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.0,\n \"2\": 0.48,\n \"3\": 0.52\n }\n }\n }, {\n \"id\": \"frustration\",\n \"label\": \"Customer frustration\",\n \"question\": \"How frustrated is the customer?\",\n \"state\": \"Export to PDF fails with a spinner that never finishes. Some of our team say CSV export still works for them, others say it fails too. This is the third time I'm writing in and honestly I'm done. Steps: open any report, click Export, choose PDF. Chrome 128 on macOS.\",\n \"levels\": [\"Calm, just stating facts\", \"Frustrated but civil\", \"Very angry, strong language or threatening to leave\"],\n \"shortLevels\": [\"Calm\", \"Frustrated\", \"Very angry\"],\n \"answer\": {\n \"type\": \"score\",\n \"score\": 1.26,\n \"confidence\": 0.61,\n \"legend\": {\n \"0\": \"Calm, just stating facts\",\n \"1\": \"Frustrated but civil\",\n \"2\": \"Very angry, strong language or threatening to leave\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.74,\n \"2\": 0.26\n }\n }\n }, {\n \"id\": \"detail\",\n \"label\": \"Report detail\",\n \"question\": \"How much does the report give an engineer to work with?\",\n \"state\": \"Export to PDF fails with a spinner that never finishes. Some of our team say CSV export still works for them, others say it fails too. This is the third time I'm writing in and honestly I'm done. Steps: open any report, click Export, choose PDF. Chrome 128 on macOS.\",\n \"levels\": [\"No detail; just says something is broken\", \"Names the feature but no steps or environment\", \"Steps to reproduce or environment, but not both\", \"Steps to reproduce and environment\"],\n \"shortLevels\": [\"No detail\", \"Feature only\", \"Some detail\", \"Steps + environment\"],\n \"answer\": {\n \"type\": \"score\",\n \"score\": 3.0,\n \"confidence\": 1.0,\n \"legend\": {\n \"0\": \"No detail; just says something is broken\",\n \"1\": \"Names the feature but no steps or environment\",\n \"2\": \"Steps to reproduce or environment, but not both\",\n \"3\": \"Steps to reproduce and environment\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.0,\n \"2\": 0.0,\n \"3\": 1.0\n }\n }\n }];\n const [selectedIndex, setSelectedIndex] = useState(0);\n const example = examples[selectedIndex];\n const topLevel = example.levels.length - 1;\n const score = example.answer.score;\n const confidence = example.answer.confidence;\n const probabilities = example.levels.map((_, level) => example.answer.probabilities[String(level)]);\n const percents = probabilities.map(probability => Number((probability * 100).toFixed(2)));\n const accent = \"#E551BA\";\n const eyebrow = {\n fontSize: \"0.6875rem\",\n fontWeight: 700,\n letterSpacing: \"0.08em\",\n textTransform: \"uppercase\"\n };\n const columnWidth = 56;\n const buttonClass = \"border px-3 py-2 text-sm text-left hover:bg-zinc-100 dark:hover:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-pink-500\";\n const unselectedStyle = {\n borderColor: \"#71717a\"\n };\n const selectedStyle = {\n borderColor: accent,\n boxShadow: `inset 0 0 0 1px ${accent}`,\n background: \"color-mix(in srgb, #E551BA 10%, transparent)\"\n };\n const endNameClass = \"text-xs text-zinc-600 dark:text-zinc-400\";\n const midNameClass = \"hidden sm:block text-xs text-zinc-600 dark:text-zinc-400\";\n function position(value) {\n return `${value / topLevel * 100}%`;\n }\n function tickNameStyle(level) {\n if (level === 0) return {\n left: 0,\n textAlign: \"left\",\n maxWidth: \"calc(50% - 8px)\"\n };\n if (level === topLevel) return {\n right: 0,\n textAlign: \"right\",\n maxWidth: \"calc(50% - 8px)\"\n };\n return {\n left: position(level),\n transform: \"translateX(-50%)\",\n textAlign: \"center\",\n maxWidth: `calc(${100 / topLevel}% - 8px)`\n };\n }\n const chartSummary = example.levels.map((_, level) => `level ${level}, ${example.shortLevels[level]}: ${percents[level]}%`).join(\"; \");\n return <section aria-label=\"Explore Score examples\" className=\"not-prose my-6 border border-zinc-300 dark:border-zinc-700 p-5 sm:p-6 text-zinc-800 dark:text-zinc-200\">\n <…13977 tokens truncated… criteria: [\n 'No architecture work mentioned',\n 'Contributed to design discussions',\n 'Designed components of a larger system',\n 'Owned architecture of a significant system',\n 'Designed systems at scale across multiple domains',\n ],\n },\n generalist: {\n type: 'score',\n instructions:\n 'How much evidence is there that this candidate picks up unfamiliar tools, roles, or domains outside their core specialty?',\n criteria: [\n 'Only one domain or role mentioned',\n 'Some variety but within a narrow field',\n 'Worked across a few different areas or tech stacks',\n 'Regularly moved between domains, wore many hats',\n 'Track record of ramping up in unfamiliar areas and delivering',\n ],\n },\n},\n}}\n/>\n\n### Step 2: combine with weights\n\nEach dimension is normalized to 0–1 and weighted. The weights give you an easy way to adjust the relative importance of each dimension, without losing any of the nuance of the individual scores.\n\n```python title=\"scoring.py\" theme={null}\npy = response.answers[\"python_depth\"].score / 4\nlead = response.answers[\"team_leadership\"].score / 4\narch = response.answers[\"system_design\"].score / 4\ngeneral = response.answers[\"generalist\"].score / 4\n\n# Senior IC\nic_score = (0.40 * py) + (0.10 * lead) + (0.40 * arch) + (0.10 * general)\n\n# Engineering Manager\nem_score = (0.15 * py) + (0.40 * lead) + (0.20 * arch) + (0.25 * general)\n```\n\nThis gives you the ability to rank the candidates based on the composite score. But more importantly, it gives you visibility into how exactly the final score is being calculated. If the highest ranking candidates are not matching your expectations, you can adjust the weights to find the right balance.\n\n\nThis documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.\n\nDOCUMENT: patterns/intent-routing\n> ## Documentation Index\n> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# Intent routing\n\n> Classify incoming requests and route each to the optimal handler: deterministic logic, a specialist LLM, or a human.\n\nexport function TypesafeExample({example, display, title}) {\n const keyStrUriSafe = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$\";\n function compressToEncodedURIComponent(input) {\n if (input == null) return \"\";\n return _compress(input, 6, function (a) {\n return keyStrUriSafe.charAt(a);\n });\n }\n function _compress(uncompressed, bitsPerChar, getCharFromInt) {\n if (uncompressed == null) return \"\";\n var i, value, context_dictionary = {}, context_dictionaryToCreate = {}, context_c = \"\", context_wc = \"\", context_w = \"\", context_enlargeIn = 2, context_dictSize = 3, context_numBits = 2, context_data = [], context_data_val = 0, context_data_position = 0, ii;\n for (ii = 0; ii < uncompressed.length; ii += 1) {\n context_c = uncompressed.charAt(ii);\n if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {\n context_dictionary[context_c] = context_dictSize++;\n context_dictionaryToCreate[context_c] = true;\n }\n context_wc = context_w + context_c;\n if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {\n context_w = context_wc;\n } else {\n if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {\n if (context_w.charCodeAt(0) < 256) {\n for (i = 0; i < context_numBits; i++) {\n context_data_val = context_data_val << 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n }\n value = context_w.charCodeAt(0);\n for (i = 0; i < 8; i++) {\n context_data_val = context_data_val << 1 | value & 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n } else {\n value = 1;\n for (i = 0; i < context_numBits; i++) {\n context_data_val = context_data_val << 1 | value;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = 0;\n }\n value = context_w.charCodeAt(0);\n for (i = 0; i < 16; i++) {\n context_data_val = context_data_val << 1 | value & 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n }\n context_enlargeIn--;\n if (context_enlargeIn == 0) {\n context_enlargeIn = Math.pow(2, context_numBits);\n context_numBits++;\n }\n delete context_dictionaryToCreate[context_w];\n } else {\n value = context_dictionary[context_w];\n for (i = 0; i < context_numBits; i++) {\n context_data_val = context_data_val << 1 | value & 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n }\n context_enlargeIn--;\n if (context_enlargeIn == 0) {\n context_enlargeIn = Math.pow(2, context_numBits);\n context_numBits++;\n }\n context_dictionary[context_wc] = context_dictSize++;\n context_w = String(context_c);\n }\n }\n if (context_w !== \"\") {\n if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {\n if (context_w.charCodeAt(0) < 256) {\n for (i = 0; i < context_numBits; i++) {\n context_data_val = context_data_val << 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n }\n value = context_w.charCodeAt(0);\n for (i = 0; i < 8; i++) {\n context_data_val = context_data_val << 1 | value & 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n } else {\n value = 1;\n for (i = 0; i < context_numBits; i++) {\n context_data_val = context_data_val << 1 | value;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = 0;\n }\n value = context_w.charCodeAt(0);\n for (i = 0; i < 16; i++) {\n context_data_val = context_data_val << 1 | value & 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n }\n context_enlargeIn--;\n if (context_enlargeIn == 0) {\n context_enlargeIn = Math.pow(2, context_numBits);\n context_numBits++;\n }\n delete context_dictionaryToCreate[context_w];\n } else {\n value = context_dictionary[context_w];\n for (i = 0; i < context_numBits; i++) {\n context_data_val = context_data_val << 1 | value & 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n }\n context_enlargeIn--;\n if (context_enlargeIn == 0) {\n context_enlargeIn = Math.pow(2, context_numBits);\n context_numBits++;\n }\n }\n value = 2;\n for (i = 0; i < context_numBits; i++) {\n context_data_val = context_data_val << 1 | value & 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data_position = 0;\n context_data.push(getCharFromInt(context_data_val));\n context_data_val = 0;\n } else {\n context_data_position++;\n }\n value = value >> 1;\n }\n while (true) {\n context_data_val = context_data_val << 1;\n if (context_data_position == bitsPerChar - 1) {\n context_data.push(getCharFromInt(context_data_val));\n break;\n } else context_data_position++;\n }\n return context_data.join(\"\");\n }\n function buildHref(ex) {\n const documentText = ex.state === undefined ? \"\" : typeof ex.state === \"string\" ? ex.state : JSON.stringify(ex.state, null, 2);\n return \"https://console.typesafe.ai/decode#share/\" + compressToEncodedURIComponent(JSON.stringify({\n apiVersion: \"v1\",\n documentText,\n promptsText: JSON.stringify(ex.questions, null, 2),\n selectedModels: ex.selectedModels\n }));\n }\n const displayedExample = display === \"questions\" ? example.questions : example.state === undefined ? {\n questions: example.questions\n } : {\n state: example.state,\n questions: example.questions\n };\n const code = JSON.stringify(displayedExample, null, 2);\n const href = buildHref(example);\n return <div style={{\n margin: \"1.25rem 0\"\n }}>\n <CodeBlock language=\"json\" filename={title ?? \"request\"}>\n {code}\n </CodeBlock>\n <div className=\"pb-8\">\n <a href={href} target=\"_blank\" rel=\"noreferrer\" className=\"text-primary\">\n Try it in the Playground →\n </a>\n </div>\n </div>;\n}\n\nNot every user request needs the same kind of handler. Some can be answered with a database lookup. Some need an LLM with domain-specific context. Some need a human. TypeSafe can sit in front of all of these as a fast, cheap classifier that determines which handler to invoke.\n\n## Example: customer service routing\n\nLet's imagine you are building a customer service system. Messages come in and need to be routed to the right handler. Rather than sending every message through an expensive LLM to figure out what kind of request it is, you classify first and route accordingly.\n\n```mermaid actions={true} theme={null}\n%%{init: {\"fontFamily\": \"Inter, sans-serif\", \"flowchart\": {\"rankSpacing\": 35, \"wrappingWidth\": 300, \"subGraphTitleMargin\": {\"top\": 12, \"bottom\": 36}}}}%%\nflowchart LR\n message[\"customer message\"]\n\n subgraph req[\"TypeSafe evaluates questions<br/>in parallel\"]\n direction TB\n intent[\"<b>Choice:</b> intent\"]\n complexity[\"<b>Score:</b> complexity\"]\n %% Invisible links stack the questions; they are answered in parallel.\n intent ~~~ complexity\n end\n\n message -- \"one request<br/>message + 2 questions\" --> req\n req -- \"one response<br/>2 answers with<br/>confidence\" --> confidence{\"<b>intent confidence<br/>≥ 0.5?</b><br/>your code\"}\n confidence -- \"no\" --> human[\"human agent\"]\n confidence -- \"yes\" --> route{\"<b>which intent?</b><br/>\"}\n route -- \"order_status\" --> order[\"order lookup<br/>deterministic code\"]\n route -- \"product_question\" --> product[\"product specialist LLM\"]\n route -- \"return_exchange\" --> returns[\"returns specialist LLM\"]\n route -- \"complaint\" --> escalate{\"<b>complexity > 1<br/>or its confidence < 0.5?</b><br/>\"}\n escalate -- \"yes\" --> human\n escalate -- \"no\" --> complaint[\"complaint resolution LLM\"]\n```\n\n### Step 1: classify intent and complexity\n\n<TypesafeExample\n title=\"questions\"\n display=\"questions\"\n example={{\nquestions: {\n intent: {\n type: 'choice',\n instructions: 'The primary intent of this customer message',\n criteria: {\n order_status: 'Asking about an existing order',\n product_question: 'Asking about a product before buying',\n return_exchange: 'Wants to return or exchange something',\n complaint: 'Unhappy with experience, wants resolution',\n },\n },\n complexity: {\n type: 'score',\n instructions: 'How complex is this request to resolve',\n criteria: [\n 'Simple lookup or standard procedure',\n 'Requires some judgment or multi-step process',\n 'Unusual situation, edge case, or escalation needed',\n ],\n },\n},\n}}\n/>\n\n### Step 2: route to the optimal handler\n\n```python title=\"routing.py\" theme={null}\ndef route_ticket(ticket_id, response):\n intent = response.answers[\"intent\"]\n complexity = response.answers[\"complexity\"]\n\n if intent.confidence < 0.5:\n # If we don't have enough confidence to classify, route to a human agent\n return route_to_human_agent(ticket_id)\n\n if intent.choice == \"order_status\":\n handle_order_status(ticket_id)\n\n elif intent.choice == \"product_question\":\n handle_with_llm(ticket_id, PRODUCT_SPECIALIST)\n\n elif intent.choice == \"return_exchange\":\n handle_with_llm(ticket_id, RETURNS_SPECIALIST)\n\n elif intent.choice == \"complaint\":\n low_confidence = complexity.confidence < 0.5\n # A higher complexity.score leans toward the \"escalation needed\" end of the scale.\n if complexity.score > 1 or low_confidence:\n # Too complex for safe automation, or we're not sure about the complexity; route to a human.\n route_to_human_agent(ticket_id)\n else:\n handle_with_llm(ticket_id, COMPLAINT_RESOLUTION)\n```\n\nOne intent routes to deterministic code with no LLM involved. Two route to different specialist LLMs, each loaded with different context. One uses the complexity score to decide between an LLM and a human. TypeSafe handles the classification all in a single quick call; the expensive resources only get invoked for the requests that actually need them.\n\nNote the additional confidence check on the complexity score. As discussed in [Confidence](/confidence), it is always important to consider the meaning of a low confidence score in the context of the system and the stakes of the decision.\n\n\nThis documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.\n\nDOCUMENT: introduction/coding-agents\n> ## Documentation Index\n> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# Jev with coding agents\n\n> What Jev is (and isn't) when you're using a coding agent.\n\nIf you found TypeSafe while looking for a model to plug into your coding agent, start here. Jev is **not** a drop-in replacement for the LLM behind Claude Code, Cursor, opencode, Copilot, Muse Spark, Grok Bot, or similar tools. Instead, you can use your coding agent as usual to write code that uses Jev to make decisions.\n\n## Jev is not a chat or code-completion LLM\n\nJev is a [System One model](/concepts/system-one). It does not generate text, write code, or hold a conversation. It takes a [state](/concepts/state) and a set of typed [questions](/primitives) and returns structured answers your code can use directly:\n\n* A `choice` from a list of options, with per-option probabilities.\n* A `score` on a rubric you define.\n* A `noul` (0–1) for a true/false statement.\n\nCoding agents rely on an LLM that streams text, calls tools, and edits files based on natural-language instructions. Jev does none of that. There is no `model: \"jev-latest\"` setting that turns your coding agent into a Jev-powered agent, because the two systems solve different problems.\n\n## What you probably want instead\n\nPick the row that matches what you were trying to do:\n\n| You wanted to... | Do this |\n| - | - |\n| Make your coding agent better at *writing code that uses TypeSafe* | Install the [TypeSafe agent skill](/agent-skill). It gives Claude Code, Codex, and other agents full context on the Jev API, the [primitives](/primitives), and the [patterns](/patterns) so they can generate correct TypeSafe integrations for you. |\n| Use Jev inside an app or agent you're building — for routing, classification, scoring, guardrails, or any structured decision | Start with the [Quick start](/introduction/quickstart), then read [How to build with TypeSafe](/concepts/how-to-build-with-system-one) and the [Patterns](/patterns) for common architectures like [confidence routing](/patterns/confidence-routing) and [intent routing](/patterns/intent-routing). |\n| Replace or swap the model that powers a coding agent | Jev isn't the tool for this. Keep using an LLM-based coding agent, and use Jev separately wherever your product needs a fast, calibrated, structured decision. |\n| Try Jev before writing any code | Open the [Playground](https://console.typesafe.ai/playground), paste some text as the state, and add a few questions. See the [Quick start](/introduction/quickstart) for a walkthrough. |\n\n## When Jev is worth reaching for\n\nEven though Jev isn't a coding-agent LLM, it's often exactly the right tool *inside* an agent or app you're building with a coding agent. Reach for Jev when your code needs to:\n\n* Route a request to one of a fixed set of destinations, and know how confident that routing is.\n* Score something on a rubric (urgency, quality, risk) and branch on the number.\n* Check whether a statement is true of a document, message, or record before taking an action.\n* Replace a fragile prompt that asks an LLM to \"return JSON\" with a call that returns typed values by construction.\n\nIf any of that matches what you're building, the fastest path in is the [Quick start](/introduction/quickstart), then the [primitives](/primitives) reference for the question types.\n\n## Next steps\n\n* [System One](/concepts/system-one) — What a System One model is and how it differs from an LLM.\n* [Quick start](/introduction/quickstart) — Try Jev in the Playground, over HTTP, or with the Python SDK.\n* [Agent skill](/agent-skill) — Give your coding agent context on the TypeSafe API.\n* [Patterns](/patterns) — Common architectures for building with TypeSafe.\n\n\nThis documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.\n"}>python3 - <<'PY'
import subprocess, concurrent.futures,re
paths=['primitives/score','primitives/noul','primitives/advanced','sdk/javascript','sdk/python','concepts/how-to-build-with-system-one','patterns/fan-out','patterns/confidence-routing']
def read(p):
r=subprocess.run(['curl','-fsSL','--max-time','20','https://docs.typesafe.ai/'+p+'.md'],capture_output=True,text=True)
return p,re.sub(r'^export function .*?^}\s*','',r.stdout,flags=re.M|re.S)
with concurrent.futures.ThreadPoolExecutor(max_workers=6) as pool:
for p,body in pool.map(read,paths): print('\nDOCUMENT: '+p+'\n'+body)
PY{"chunk_id":"a5fe47","wall_time_seconds":0.282497,"exit_code":0,"original_token_count":24216,"output":"Warning: truncated output (original token count: 24216)\nTotal output lines: 2288\n\n\nDOCUMENT: primitives/score\n> ## Documentation Index\n> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# Score\n\n> A Score is a System One question type for rating content against ordered, descriptive levels. The answer includes a score, a probability for each level, and confidence.\n\nUse a Score when the answer is a position on a spectrum you can describe in steps. For example, how severe a bug is, how happy a customer is, or how much Python experience a candidate has. If the answer is one of a fixed set of options with no order between them, use a [Choice](/primitives/choice). If it's a yes or no, use a [Noul](/primitives/noul). [Choose a question type](/primitives#choose-a-question-type) compares all three.\n\nA Score answer is a position along your levels in `score`, which can fall between two levels. The model also returns a probability for every level in `probabilities`, and a `confidence` value for the answer.\n\n<ScoreExplorer />\n\nThe numbers in front of each step are positions, explained under [Levels](#levels).\n\n## Request structure\n\nThe POST request body to the [TypeSafe API](/api) has the same three top-level fields as any other question type: `state`, which is the content to evaluate; `model`; and `questions`. Each Score question has the following fields:\n\n* `type`: Always `\"score\"`.\n* `instructions`: The question the model answers. What it's rating.\n* `criteria`: An ordered array of level descriptions, from the low end of the scale to the high end. Should have at least two levels; the API accepts up to 10.\n\nBelow is a request where the state is a bug report and the question is how severe the bug is:\n\n<TypesafeExample\n display=\"request\"\n example={{\nstate: 'The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.',\nselectedModels: ['jev-latest'],\nquestions: {\n bug_severity: {\n type: 'score',\n instructions: 'How severe is the reported issue?',\n criteria: [\n 'Cosmetic; no impact to functionality',\n 'Broken or degraded feature, but workaround exists',\n 'Blocking issue; no workaround exists',\n ],\n },\n},\n}}\n/>\n\nYou choose the question id, `bug_severity` in this case. This id is not sent to the model. The answer is returned under the same id.\n\n### Levels\n\nEach entry in `criteria` is a level: one point on the spectrum of possible answers, described in words. A level's number is its position in the `criteria` array, starting at 0, so the three entries above are levels 0, 1 and 2. The order of the array is the numbering.\n\nThe model gets the descriptions and nothing else, and each level is judged on its own against the state.\n\nThe `score` in the response is a position on the levels spectrum. For a three-level scale it runs from 0 to 2, and it can land between two levels.\n\nOur [client SDKs](/sdk) provide typed questions. In Python, the same question is a `Score`:\n\n```python theme={null}\nfrom typesafe_sdk import Score, TypeSafeClient\n\nwith TypeSafeClient() as client:\n response = client.system_one(\n state=\"The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.\",\n questions={\n \"bug_severity\": Score(\n instructions=\"How severe is the reported issue?\",\n criteria=[\n \"Cosmetic; no impact to functionality\",\n \"Broken or degraded feature, but workaround exists\",\n \"Blocking issue; no workaround exists\",\n ],\n ),\n },\n )\n\n print(response.answers[\"bug_severity\"].score)\n```\n\nUse the `system_one` method or the `https://api.typesafe.ai/v1/systemone` endpoint to call a System One model. The `model` field selects which model handles the request. [How to build with TypeSafe](/concepts/how-to-build-with-system-one) covers where in your code to call it.\n\nUse one of our [client SDKs](/sdk) or call the [TypeSafe API](/api) directly. If a coding agent is writing the integration for you, install the [TypeSafe agent skill](/agent-skill#installation) first so it knows the request and response shapes.\n\n<Note>\n `instructions` and each level in `criteria` can be a string, an object, or an array. Start with strings. Use an object when a level needs a description plus a few example situations. See [Structured level descriptions](#structured-level-descriptions) below and the [API reference](/api#param-instructions-2).\n</Note>\n\n## Response structure\n\nThe response has one entry in `answers` per question, under the ids from the request. This is the response to the example request above:\n\n```json theme={null}\n{\n \"model\": \"jev-1.13.0\",\n \"answers\": {\n \"bug_severity\": {\n \"type\": \"score\",\n \"score\": 1.43,\n \"confidence\": 0.35,\n \"legend\": {\n \"0\": \"Cosmetic; no impact to functionality\",\n \"1\": \"Broken or degraded feature, but workaround exists\",\n \"2\": \"Blocking issue; no workaround exists\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.57,\n \"2\": 0.43\n }\n }\n },\n \"usage\": {\n \"input_tokens\": 332,\n \"output_tokens\": 18\n }\n}\n```\n\nEach Score answer has five values:\n\n* `type`: The type of TypeSafe question.\n* `probabilities`: The probability of each level, keyed by level number as a string. The sum of all values is 1.\n* `score`: The position on the level number line, from 0 to the top level number, which is 2 here. It's each level number multiplied by its probability, added up: 0 x 0.0 + 1 x 0.57 + 2 x 0.43 = 1.43.\n* `legend`: Each level number mapped back to its description.\n* [`confidence`](/confidence): A number from 0 to 1 computed from how `probabilities` is spread. A single peak on one level means high confidence. Probability spread over several levels means low confidence.\n\nA score of 1.43 means the model is split between levels 1 and 2, leaning to level 1. That matches the report: the export is broken, and switching to Chrome is a workaround for most customers, but not for the ones who only use Safari. The model puts 0.57 on \"workaround exists\" and 0.43 on \"no workaround\", and confidence is 0.35 because it's split.\n\nUsing the Python SDK, `ScoreAnswer` has `score`, `confidence`, `probabilities`, and `legend` as typed fields. The SDK keys `probabilities` and `legend` by integer level rather than by string.\n\n## Reading a Score\n\nLet's look at how the score changes with different inputs. For example, using the question and its levels from the request above:\n\n```\n\"How severe is the reported issue?\"\n → 0: Cosmetic; no impact to functionality\n → 1: Broken or degraded feature, but workaround exists\n → 2: Blocking issue; no workaround exists\n```\n\nWe can see how different bug reports change the score:\n\n<table>\n <thead>\n <tr>\n <th colSpan={3} />\n\n <th colSpan={3} style={{ textAlign: 'left' }}><code>probabilities</code></th>\n </tr>\n\n <tr>\n <th style={{ width: '44%' }}>State</th>\n <th style={{ width: '12%', whiteSpace: 'nowrap' }}><code>score</code></th>\n <th style={{ width: '16%', whiteSpace: 'nowrap' }}><code>confidence</code></th>\n <th style={{ width: '9%', whiteSpace: 'nowrap' }}>Level 0</th>\n <th style={{ width: '9%', whiteSpace: 'nowrap' }}>Level 1</th>\n <th style={{ width: '10%', whiteSpace: 'nowrap' }}>Level 2</th>\n </tr>\n </thead>\n\n <tbody>\n <tr>\n <td>The export button is misaligned by a few pixels on the settings page.</td>\n <td>0.0</td><td>1.0</td><td>1.0</td><td>0.0</td><td>0.0</td>\n </tr>\n\n <tr>\n <td>The PDF export button does nothing when clicked. I can still export to CSV and convert it myself, but that takes ages.</td>\n <td>1.0</td><td>1.0</td><td>0.0</td><td>1.0</td><td>0.0</td>\n </tr>\n\n <tr>\n <td>Export to PDF fails with a spinner that never finishes. Some of our team say CSV export still works for them, others say it fails too.</td>\n <td>1.11</td><td>0.84</td><td>0.0</td><td>0.89</td><td>0.11</td>\n </tr>\n\n <tr>\n <td>The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.</td>\n <td>1.43</td><td>0.35</td><td>0.0</td><td>0.57</td><td>0.43</td>\n </tr>\n\n <tr>\n <td>Nobody on our team can log in since this morning. We get a 500 error on every attempt.</td>\n <td>2.0</td><td>1.0</td><td>0.0</td><td>0.0</td><td>1.0</td>\n </tr>\n </tbody>\n</table>\n\nIn these examples, confidence 1.0 means the returned distribution puts all its probability on one level. This describes the model's answer, not a guarantee that the answer is correct.\n\nThe score is a probability-weighted mean of the level numbers. In the third and fourth examples, probability is split between levels 1 and 2. More weight on level 2 raises the score. It does not measure the fraction of customers without a workaround.\n\nDifferent distributions can produce the same score. A score of 1.0 can mean all probability is on level 1, or half is on each of levels 0 and 2. Read `probabilities` and `confidence` alongside the score to distinguish these cases.\n\nA fractional score is a position. You can use it to rank reports by severity, or round it to the nearest level when your code needs one outcome. Our [entity alignment cookbook](/cookbooks/entity_alignment) shows an example of rounding to the nearest level to make a decision.\n\nLow confidence on a Score usually means one of three things. The levels overlap for this state, the question is measuring more than one thing, or the state doesn't say enough to place it. Our [Confidence](/confidence) docs cover how to use it in your code.\n\n## Writing good levels\n\nDescribe situations, not degrees. \"Broken or degraded feature, but workaround exists\" gives the model something to match the state against. \"Moderately severe\" doesn't. Concrete descriptions can help the model distinguish levels. Check the answers against known examples; higher confidence alone does not show that a description is better.\n\nEvery level is evaluated separately. The model doesn't see a level's number or its neighbours, so \"worse than the previous level\" means nothing to it, and numbers in the descriptions or the instructions don't help. Here is what happens when the levels are only numbers, on the misaligned-button report from the table above:\n\n```\ninstructions: \"Rate severity from 0 to 2, where 2 is worst\"\ncriteria: [\"0\", \"1\", \"2\"]\n→ score 0.55, confidence 0.33, probabilities 0: 0.45, 1: 0.55, 2: 0.0\n```\n\nThe same report with the three descriptive levels scores 0.0 at confidence 1.0. With numbers only, the model has nothing to match against and splits the probability between 0 and 1.\n\nUse as many levels as you can describe distinctly, up to 10. Three is fine. Don't add levels you can't describe distinctly.\n\nKeep each Score question to one dimension. If a description says \"punctual and smart and experienced\", the question is measuring three things, and an input that is high on one and low on another can't be placed. Confidence drops and the score means less. Split it into one Score question per thing and combine them in code, as the next section shows.\n\nIf the top of your scale has a rare extreme case you need to act on differently, give it its own level. A sentiment scale that ends at \"very angry\" can add \"abusive or threatening\". Without that level, both messages may receive a score near the top. The score alone may not distinguish them.\n\nIf there is no in-between at all, and the answer is one of a few discrete categories, use a [Choice](/primitives/choice) instead, or split the question into several [Noul](/primitives/noul) questions. It's important to test your levels against your own data. Two wordings of the same scale can behave differently on your data.\n\n## Splitting a complex judgment into several Score questions\n\nA complex judgment, one that depends on several things, is best split into one Score question per thing. You can then combine the Scores returned from TypeSafe in your code to make the judgment. Some Score questions may matter more than others, so give each Score question a weight for its relative importance. The weights are yours. When the combined result doesn't match what your team would decide, change them in code and run again. Send the Score questions in one request. They are evaluated in parallel. Adding questions barely changes the response time and costs a few extra question tokens; see [Ask multiple questions together](/primitives#a[REDACTED]).\n\nThe request below is the spinner ticket from the table above with some more context. It asks three Score questions: how severe the bug is, how frustrated the customer is, and how much the report gives an engineer to work with.\n\n<TypesafeExample\n display=\"request\"\n example={{\nstate: 'Export to PDF fails with a spinner that never finishes. Some of our team say CSV export still works for them, others say it fails too. This is the third time I\\'m writing in and honestly I\\'m done. Steps: open any report, click Export, choose PDF. Chrome 128 on macOS.',\nselectedModels: ['jev-latest'],\nquestions: {\n severity: {\n type: 'score',\n instructions: 'How severe is the reported issue?',\n criteria: [\n 'Cosmetic; no impact to functionality',\n 'Broken or degraded feature, but workaround exists',\n 'Blocking issue; no workaround exists',\n ],\n },\n frustration: {\n type: 'score',\n instructions: 'How frustrated is the customer?',\n criteria: [\n 'Calm, just stating facts',\n 'Frustrated but civil',\n 'Very angry, strong language or threatening to leave',\n ],\n },\n report_quality: {\n type: 'score',\n instructions: 'How much does the report give an engineer to work with?',\n criteria: [\n 'No detail; just says something is broken',\n 'Names the feature but no steps or environment',\n 'Steps to reproduce or environment, but not both',\n 'Steps to reproduce and environment',\n ],\n },\n},\n}}\n/>\n\nTypeSafe's response:\n\n```json theme={null}\n{\n \"model\": \"jev-1.13.0\",\n \"answers\": {\n \"severity\": {\n \"type\": \"score\",\n \"score\": 1.24,\n \"confidence\": 0.64,\n \"legend\": {\n \"0\": \"Cosmetic; no impact to functionality\",\n \"1\": \"Broken or degraded feature, but workaround exists\",\n \"2\": \"Blocking issue; no workaround exists\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.76,\n \"2\": 0.24\n }\n },\n \"frustration\": {\n \"type\": \"score\",\n \"score\": 1.28,\n \"confidence\": 0.58,\n \"legend\": {\n \"0\": \"Calm, just stating facts\",\n \"1\": \"Frustrated but civil\",\n \"2\": \"Very angry, strong language or threatening to leave\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.72,\n \"2\": 0.28\n }\n },\n \"report_quality\": {\n \"type\": \"score\",\n \"score\": 3.0,\n \"confidence\": 1.0,\n \"legend\": {\n \"0\": \"No detail; just says something is broken\",\n \"1\": \"Names the feature but no steps or environment\",\n \"2\": \"Steps to reproduce or environment, but not both\",\n \"3\": \"Steps to reproduce and environment\"\n },\n \"probabilities\": {\n \"0\": 0.0,\n \"1\": 0.0,\n \"2\": 0.0,\n \"3\": 1.0\n }\n }\n },\n \"usage\": {\n \"input_tokens\": 468,\n \"output_tokens\": 43\n }\n}\n```\n\nEach question is answered on its own against the ticket and given a score:\n\n* `severity` is 1.24 at confidence 0.64. Same reading as the opening example: the export is broken and some have a workaround.\n* `frustration` is 1.28 at confidence 0.58. The wording is civil, but \"third time\" and \"I'm done\" shift some of the score toward the top level, so the model splits 0.72 and 0.28 between \"frustrated but civil\" and \"very angry\". For this ticket the two levels overlap, which is why the confidence is moderate.\n* `report_quality` is 3.0 at confidence 1.0. The steps and browser version are both stated.\n\nThe three scales have different lengths, so before combining them, normalize each score. A four-level scale returns 0 to 3 and a three-level scale returns 0 to 2, so a top score on one is bigger than a top score on the other. Divide each score by its top level number, `len(criteria) - 1`, to put every score on 0 to 1. Then the weights mean what they say: 0.6 on severity and 0.3 on frustration makes severity count twice as much.\n\nThe TypeSafe Python SDK code below asks the three questions, normalizes each score, and combines them using an example priority calculation:\n\n```python theme={null}\nfrom typesafe_sdk import Score, TypeSafeClient\n\nTRIAGE_QUESTIONS = {\n \"severity\": Score(\n instructions=\"How severe is the reported issue?\",\n criteria=[\n \"Cosmetic; no impact to functionality\",\n \"Broken or degraded feature, but workaround exists\",\n \"Blocking issue; no workaround exists\",\n ],\n ),\n \"frustration\": Score(\n instructions=\"How frustrated is the customer?\",\n criteria=[\n \"Calm, just stating facts\",\n \"Frustrated but civil\",\n \"Very angry, strong language or threatening to leave\",\n ],\n ),\n \"report_quality\": Score(\n instructions=\"How much does the report give an engineer to work with?\",\n criteria=[\n \"No detail; just says something is broken\",\n \"Names the feature but no steps or environment\",\n \"Steps to reproduce or environment, but not both\",\n \"Steps to reproduce and environment\",\n ],\n ),\n}\n\n\ndef normalized(answers, question_id: str) -> float:\n \"\"\"Put a score on 0 to 1 by dividing by its top level number.\"\"\"\n top_level = len(TRIAGE_QUESTIONS[question_id].criteria) - 1\n return answers[question_id].score / top_level\n\n\ndef priority(ticket: str) -> float:\n with TypeSafeClient() as client:\n response = client.system_one(\n state=ticket,\n questions=TRIAGE_QUESTIONS,\n )\n answers = response.answers\n\n severity = normalized(answers, \"severity\")\n frustration = normalized(answers, \"frustration\")\n report_quality = normalized(answers, \"report_quality\")\n\n # A detailed report helps an engineer investigate, so it raises priority a little.\n return 0.6 * severity + 0.3 * frustration + 0.1 * report_quality\n```\n\nFor the example response above, the normalized scores are 0.62 for severity, 0.64 for frustration, and 1.0 for report quality. The priority is `0.6 × 0.62 + 0.3 × 0.64 + 0.1 × 1.0 = 0.664`, which rounds to `0.66`.\n\nThe weights live in your code, so you can see exactly how the number is made and change it when the ranking doesn't match what your team would do. If you later need more Score questions, add them to `TRIAGE_QUESTIONS`. The request count stays at one. This technique of breaking a complex judgment into separate Scores and then combining them with weights in your code is called the [Composite scoring](/patterns/composite-scoring) pattern.\n\n## Structured level descriptions\n\nStart with a…6655 tokens truncated…erns/composite-scoring) shows how to preserve individual judgments while combining them. If you do not have labels for a downstream model, use an ensemble of expensive reasoning models to generate them; the [AutoResearch cookbook](/cookbooks/autoresearch_feature_discovery) shows how to train a classical model on System One outputs.\n </Step>\n\n <Step title=\"Route on uncertainty\">\n Make code take different actions for confident and unconfident answers. Escalate uncertain cases to a person or a more expensive reasoning model. Test thresholds by plotting confidence against accuracy on your data.\n\n <Accordion title=\"Example: route by confidence\">\n ```python theme={null}\n answer = response.answers[\"card_help_topic\"]\n\n if answer.confidence < 0.8:\n route_to_human_review(ticket)\n else:\n route_to_handler(answer.choice, ticket)\n ```\n </Accordion>\n\n See [Confidence](/confidence) and [Confidence-Gated Routing](/patterns/confidence-routing) for choosing thresholds and matching them to the risk of each action.\n </Step>\n</Steps>\n\n<Tip>\n Decomposition does not require more round trips. Questions over the same state run in parallel.\n</Tip>\n\n## Putting it all together\n\nThis support-ticket workflow keeps deterministic work in code, sends only relevant structured context, evaluates many atomic questions in one request, and composes the answers with explicit confidence gates.\n\n```python title=\"triage_ticket.py\" theme={null}\nfrom typesafe_sdk import Choice, Noul, NoulCriteria, Score, TypeSafeClient\n\n\ndef triage_ticket(ticket, customer):\n # Handle deterministic states without calling a model.\n if ticket[\"status\"] == \"closed\":\n return \"no_action\"\n\n open_orders = [\n order for order in customer[\"orders\"] if order[\"status\"] != \"delivered\"\n ]\n\n # Include only the structured context needed by the questions below.\n state = {\n \"ticket\": {\n \"message\": ticket[\"message\"],\n \"sender\": ticket[\"sender\"],\n \"links\": ticket[\"links\"],\n },\n \"customer\": {\n \"plan\": customer[\"plan\"],\n \"open_orders\": open_orders,\n },\n \"policy\": {\n \"sensitive_credentials\": [\"password\", \"security code\", \"API key\"],\n },\n }\n\n # Ask structured, atomic questions together so they run in parallel.\n questions = {\n \"topic\": Choice(\n instructions={\n \"question\": \"Which team should handle `ticket.message`?\",\n \"focus\": \"Classify the customer's primary request.\",\n },\n criteria={\n \"billing\": {\n \"what\": \"Charges, invoices, refunds, or subscriptions\",\n \"not_for\": \"Order tracking or account access\",\n \"examples\": [\"I was charged twice\", \"Where is my refund?\"],\n },\n \"orders\": {\n \"what\": \"Order status, delivery, cancellation, or returns\",\n \"not_for\": \"Charges or account access\",\n \"examples\": [\"Where is my order?\", \"Cancel my shipment\"],\n },\n \"account\": {\n \"what\": \"Login, profile, permissions, or security\",\n \"not_for\": \"Charges or order tracking\",\n \"examples\": [\"Reset my password\", \"I cannot sign in\"],\n },\n },\n ),\n \"requests_credentials\": Noul(\n instructions={\n \"question\": \"Does the message request a sensitive credential?\",\n \"compare\": [\n \"`ticket.message`\",\n \"`policy.sensitive_credentials`\",\n ],\n \"focus\": \"Look for a request to disclose the credential itself.\",\n },\n criteria=NoulCriteria(\n true={\n \"what\": \"Asks the recipient to disclose a listed credential\",\n \"examples\": [\n \"Reply with your password\",\n \"Send us your API key\",\n ],\n },\n false={\n \"what\": \"Does not ask the recipient to disclose a credential\",\n \"not_for\": \"A legitimate instruction to reset a credential\",\n \"examples\": [\"Use this link to reset your password\"],\n },\n ),\n ),\n \"sender_identity_mismatch\": Noul(\n instructions={\n \"question\": \"Does the claimed sender identity conflict with its domain?\",\n \"compare\": [\n \"`ticket.sender.display_name`\",\n \"`ticket.sender.email`\",\n ],\n \"focus\": \"Compare the named organization with the email domain.\",\n },\n criteria=NoulCriteria(\n true={\n \"what\": \"Claims an organization unrelated to the email domain\",\n \"examples\": [\"Acme Payroll sent from claim-bonus.example\"],\n },\n false={\n \"what\": \"The identity and domain agree or make no conflicting claim\",\n \"examples\": [\"Acme Payroll sent from acme.example\"],\n },\n ),\n ),\n \"unexpected_reward\": Noul(\n instructions={\n \"question\": \"Does the message announce an unexpected reward?\",\n \"inspect\": \"`ticket.message`\",\n \"focus\": \"Look for an unsolicited prize, payment, or reward claim.\",\n },\n criteria=NoulCriteria(\n true={\n \"what\": \"Announces an unrequested prize, payment, or reward\",\n \"examples\": [\"You were selected for a $1,000 bonus\"],\n },\n false={\n \"what\": \"Contains no reward claim or discusses an expected payment\",\n \"not_for\": \"A customer asking about a known refund or payroll deposit\",\n \"examples\": [\"When will my approved refund arrive?\"],\n },\n ),\n ),\n \"refund_requested\": Noul(\n instructions={\n \"question\": \"Does the customer explicitly request a refund or credit?\",\n \"inspect\": \"`ticket.message`\",\n \"focus\": \"Require a requested remedy, not a billing complaint alone.\",\n },\n criteria=NoulCriteria(\n true={\n \"what\": \"Directly asks for money back or an account credit\",\n \"examples\": [\"Please refund the duplicate charge\"],\n },\n false={\n \"what\": \"Does not ask for a refund or credit\",\n \"not_for\": \"A complaint or billing question without a requested remedy\",\n \"examples\": [\"Why was I charged twice?\"],\n },\n ),\n ),\n \"mentions_open_order\": Noul(\n instructions={\n \"question\": \"Does the message refer to a supplied open order?\",\n \"compare\": [\n \"`ticket.message`\",\n \"`customer.open_orders`\",\n ],\n \"focus\": \"Match an order id or other identifying details.\",\n },\n criteria=NoulCriteria(\n true={\n \"what\": \"Refers to an open order by id or identifying details\",\n \"examples\": [\"Where is order A-104?\"],\n },\n false={\n \"what\": \"Does not identify any supplied open order\",\n \"not_for\": \"A generic order question with no matching details\",\n \"examples\": [\"How long does shipping usually take?\"],\n },\n ),\n ),\n \"frustration\": Score(\n instructions={\n \"question\": \"How frustrated does the customer appear?\",\n \"inspect\": \"`ticket.message`\",\n \"focus\": \"Judge expressed frustration, not issue severity.\",\n },\n criteria=[\n {\n \"what\": \"Calm and matter-of-fact\",\n \"signals\": [\"Neutral wording\", \"No complaint about the experience\"],\n },\n {\n \"what\": \"Frustrated but civil\",\n \"signals\": [\"Expresses annoyance\", \"Remains constructive\"],\n },\n {\n \"what\": \"Very angry or threatening to leave\",\n \"signals\": [\"Hostile language\", \"Threatens cancellation or churn\"],\n },\n ],\n ),\n }\n\n with TypeSafeClient() as client:\n response = client.system_one(\n state=state,\n questions=questions,\n )\n\n # Compose independent spam signals with weights controlled by code.\n answers = response.answers\n spam_risk = (\n 0.45 * answers[\"requests_credentials\"].noul\n + 0.30 * answers[\"sender_identity_mismatch\"].noul\n + 0.25 * answers[\"unexpected_reward\"].noul\n )\n\n # Escalate uncertain judgments instead of guessing.\n spam_is_uncertain = 0.4 < spam_risk < 0.6\n if spam_is_uncertain or answers[\"topic\"].confidence < 0.75:\n return route_to_human_review(ticket)\n if spam_risk >= 0.6:\n return quarantine_as_spam(ticket)\n\n # Let code decide which speculative answers matter on this path.\n if answers[\"topic\"].choice == \"billing\":\n return route_to_billing(\n ticket,\n refund_requested=answers[\"refund_requested\"].noul >= 0.7,\n )\n if answers[\"topic\"].choice == \"orders\":\n return route_to_orders(\n ticket,\n mentions_open_order=answers[\"mentions_open_order\"].noul >= 0.7,\n )\n\n priority = (\n \"high\"\n if answers[\"frustration\"].confidence >= 0.7\n and answers[\"frustration\"].score >= 1.5\n else \"normal\"\n )\n return route_to_account_support(ticket, priority=priority)\n```\n\n\nThis documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.\n\nDOCUMENT: patterns/fan-out\n> ## Documentation Index\n> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# Speculative fan-out\n\n> Send many questions in a single call, including speculative ones, and let your code decide what's relevant.\n\nBecause TypeSafe supports sending many questions in a single API call, we recommend putting all of the questions your system needs in a single request, and then using code to decide what is relevant after the fact. All questions are evaluated in parallel, so adding more questions usually has little effect on response time.\n\n## Example: support ticket triage\n\nLet's imagine you are building a support system that needs to triage support tickets. You need to classify the ticket into a category. If it's a bug report, you also need to determine the severity of the bug.\n\nInstead of asking for the category first and then the severity in a follow-up call, you can ask for both at the same time. If the ticket is not a bug report, you simply ignore the results of the bug severity question.\n\n```mermaid actions={true} theme={null}\n%%{init: {\"fontFamily\": \"Inter, sans-serif\", \"flowchart\": {\"rankSpacing\": 35, \"wrappingWidth\": 300, \"subGraphTitleMargin\": {\"top\": 8, \"bottom\": 60}}}}%%\nflowchart LR\n t[\"support ticket\"]\n\n subgraph req[\"TypeSafe AI model<br/>evaluates each question<br/>against the ticket in parallel\"]\n direction TB\n c[\"<b>Choice:</b> category\"]\n b[\"<b>Score:</b> bug severity\"]\n r[\"<b>Noul:</b> reproducible steps?\"]\n f[\"<b>Noul:</b> refund requested?\"]\n s[\"<b>Score:</b> frustration\"]\n %% invisible links: without an edge these share a rank and sit side by side\n c ~~~ b ~~~ r ~~~ f ~~~ s\n end\n\n t -- \"one request<br/>ticket + 5 questions\" --> req\n req -- \"one response: 5 answers<br/>decisions + probabilities\" --> route{\"<b>filter, combine, and route</b><br/>in your code\"}\n route -- \"bug_report\" --> eng[\"read severity + repro steps<br/>escalate or backlog\"]\n route -- \"billing\" --> bill[\"refund requested<br/>send to billing\"]\n route -- \"feature_request\" --> feat[\"log it<br/>sent to devs\"]\n```\n\n### Step 1: speculative fan-out\n\n<TypesafeExample\n title=\"questions\"\n display=\"questions\"\n example={{\nstate:\n \"Hi, I placed an order (#98423) last Thursday and was charged twice. I also can't log in after the site update, and adding Apple Pay would be really helpful. This is getting frustrating.\",\nquestions: {\n category: {\n type: 'choice',\n instructions: 'Determine the broad category of this support ticket',\n criteria: {\n bug_report:\n 'The user is reporting something that is broken or producing errors',\n billing: 'Charges, invoices, refunds, subscriptions',\n feature_request: 'The user is requesting new functionality',\n account: 'Login, permissions, profile, security',\n },\n },\n bug_severity: {\n type: 'score',\n instructions: 'How severe is the reported issue',\n criteria: [\n 'Cosmetic; no impact to functionality',\n 'Broken or degraded feature; workaround exists',\n 'Blocking issue; no workaround exists',\n ],\n },\n has_reproducible_steps: {\n type: 'noul',\n instructions:\n 'The user describes specific steps to reproduce the issue',\n },\n refund_requested: {\n type: 'noul',\n instructions: 'The user is explicitly asking for a refund or credit',\n },\n frustration: {\n type: 'score',\n instructions: 'How frustrated the user appears',\n criteria: ['Calm, matter-of-fact', 'Frustrated but civil', 'Very angry'],\n },\n},\n}}\n/>\n\n<Note>\n **Speculative questions:** `bug_severity` and `has_reproducible_steps` only matter if the ticket is a bug report. `refund_requested` only matters for billing. We include all upfront because additional questions usually have little effect on response time. If the ticket turns out to be a feature request, the bug severity result will be irrelevant, in which case your code path simply ignores it.\n</Note>\n\n### Step 2: route with code\n\nYour code decides what is relevant based on the classification result:\n\n```python title=\"triage.py\" theme={null}\ncategory = response.answers[\"category\"]\nbug_severity = response.answers[\"bug_severity\"]\nbug_repro = response.answers[\"has_reproducible_steps\"]\nrefund = response.answers[\"refund_requested\"]\nfrustration = response.answers[\"frustration\"]\n\nif category.choice == \"bug_report\":\n if bug_severity.score > 1.5 and bug_repro.noul > 0.6:\n escalate_to_engineering(ticket_id, severity=\"high\")\n else:\n add_to_bug_backlog(ticket_id)\n\nelif category.choice == \"billing\":\n if refund.noul > 0.7:\n route_to_billing_with_flag(ticket_id, refund_likely=True)\n else:\n route_to_billing(ticket_id)\n\nelif category.choice == \"feature_request\":\n log_feature_request(ticket_id)\n\n# Frustration is useful regardless of category\nif frustration.score > 1.5:\n flag_for_priority_response(ticket_id)\n```\n\nEverything needed for the full decision tree comes from one call. Speculative questions are ignored when irrelevant and save a round trip when they are not.\n\n\nThis documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.\n\nDOCUMENT: patterns/confidence-routing\n> ## Documentation Index\n> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt\n> Use this file to discover all available pages before exploring further.\n\n# Confidence-gated routing\n\n> Use confidence as a second axis. The answer tells you what; confidence tells you whether to act.\n\nOne of TypeSafe's most powerful features is [confidence](/confidence). By being intentional with the way you gate decisions on confidence, you can build systems that are both reliable and safe.\n\n## Example: voice banking commands\n\nLet's imagine you are building a voice banking interface to allow the user to interact with their account verbally. While you always want to have reasonable confidence in interpreting the user's intent, some actions are riskier than others and thus demand a higher confidence threshold.\n\n```mermaid actions={true} theme={null}\n%%{init: {\"fontFamily\": \"Inter, sans-serif\", \"flowchart\": {\"rankSpacing\": 35, \"wrappingWidth\": 300, \"subGraphTitleMargin\": {\"top\": 12, \"bottom\": 36}}}}%%\nflowchart LR\n command[\"voice banking command\"]\n\n subgraph req[\"TypeSafe evaluates<br/>the question\"]\n intent[\"<b>Choice:</b> intent\"]\n end\n\n command -- \"one request<br/>command + intent<br/>question\" --> req\n req -- \"one response<br/>intent answer +<br/>confidence\" --> gate{\"<b>confidence high enough?</b><br/>your code\"}\n gate -- \"below 0.6<br/>or other intent\" --> human[\"send to a support agent\"]\n gate -- \"check_balance<br/>at least 0.6\" --> balance[\"show the balance\"]\n gate -- \"approve_transfer<br/>0.6 to 0.85\" --> confirm[\"ask the user to confirm\"]\n gate -- \"approve_transfer<br/>above 0.85\" --> approve[\"approve the transfer\"]\n```\n\n### Step 1: determine the user's intent\n\n<TypesafeExample\n title=\"questions\"\n display=\"questions\"\n example={{\nquestions: {\n intent: {\n type: 'choice',\n instructions: 'What action is the user requesting?',\n criteria: {\n check_balance: 'Check the balance of an account',\n approve_transfer: 'Approve the pending transfer request',\n other: 'Something else',\n },\n },\n},\n}}\n/>\n\n### Step 2: confidence-gated routing\n\n```python theme={null}\naction = response.answers[\"intent\"]\n\n# Below 0.6 confidence on any action, route to a human\nif action.confidence < 0.6:\n route_to_support_agent(account_id)\n\nelif action.choice == \"check_balance\":\n # Low stakes. 0.6 confidence is sufficient.\n show_balance(account_id)\n\nelif action.choice == \"approve_transfer\":\n if action.confidence > 0.85:\n # High stakes, but high confidence. Safe to act automatically.\n approve_transfer(account_id)\n else:\n # High stakes, moderate confidence. Verify intent first.\n ask_user_to_confirm(\"Just to confirm: you would like to approve this transfer, is that correct?\")\n\nelse:\n route_to_support_agent(account_id)\n```\n\nThe 0.6 floor catches anything the model is genuinely uncertain about. Above that floor, each action type has its own threshold based on the consequences of acting on a wrong classification. Checking a balance at 0.6 is fine because the worst case is the user having to listen to the balance read-out. But approving a transfer requires very high confidence (>0.85), otherwise the system should ask the user to confirm.\n\nSee [Confidence](/confidence) for more details on how to think about confidence in your systems.\n\n\nThis documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.\n"}>python3 - <<'PY'
import subprocess, concurrent.futures,re
paths=['sdk/javascript','sdk/python','primitives/noul','primitives/advanced','cookbooks','concepts/system-one','concepts/how-to-build-with-system-one']
def read(p):
r=subprocess.run(['curl','-fsSL','--max-time','20','https://docs.typesafe.ai/'+p+'.md'],capture_output=True,text=True)
s=re.sub(r'^export function .*?^}\s*','',r.stdout,flags=re.M|re.S)
if not p.startswith('sdk/'):
s=re.sub(r'```.*?```','[code example omitted]',s,flags=re.S)
s=re.sub(r'<TypesafeExample\b.*?/>','[interactive example omitted]',s,flags=re.S)
return p,s
with concurrent.futures.ThreadPoolExecutor(max_workers=6) as pool:
for p,body in pool.map(read,paths): print('\nDOCUMENT: '+p+'\n'+body)
PYDOCUMENT: sdk/javascript
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# JavaScript SDK
JavaScript and TypeScript SDK for [TypeSafe AI](https://typesafe.ai).
## Quickstart
Install the SDK (Node.js 20 or newer):
```sh theme={null}
npm install @typesafe-ai/sdk
```
Set `TYPESAFE_API_KEY` in your environment, then create and use the client:
```ts theme={null}
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient();
const response = await client.systemOne({
state: { document: "I was charged twice. Please fix this ASAP." },
questions: {
category: choice("What is this ticket about?", {
billing: null,
technical: null,
other: null,
}),
},
});
console.log(response.answers.category.choice);
```
Answer types are inferred from your questions. The package includes ESM, CommonJS, and TypeScript declarations.
## Documentation
Learn what TypeSafe can do in the [TypeSafe docs](https://docs.typesafe.ai/).
See the SDK's [client](https://github.com/typesafe-ai/typesafe-sdk-js/blob/v0.6.0/src/client.ts) and [types](https://github.com/typesafe-ai/typesafe-sdk-js/blob/v0.6.0/src/types.ts) for API options and defaults.
This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.
DOCUMENT: sdk/python
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# TypeSafe Python SDK
> Install the TypeSafe Python SDK and get started with asynchronous or synchronous API calls.
<a id="typesafe-python-sdk" />
Browse the [Python SDK source on GitHub](https://github.com/typesafe-ai/typesafe-sdk-python).
Asynchronous and synchronous Python clients for the [TypeSafe](https://typesafe.ai) API. Learn how to use TypeSafe [here](https://docs.typesafe.ai/).
<h2 id="quickstart">
Quickstart
</h2>
1. Install the SDK:
<Tabs>
<Tab title="uv">
```sh theme={null}
uv add typesafe-sdk
```
</Tab>
<Tab title="pip">
```sh theme={null}
pip install typesafe-sdk
```
</Tab>
</Tabs>
Add the `http2` extra (`typesafe-sdk[http2]`) to enable [HTTP/2 support](/sdk/python/usage#http2).
2. Set `TYPESAFE_API_KEY` in your environment (create it [here](https://console.typesafe.ai/))
3. Call the System One API:
<Tabs>
<Tab title="Async">
With [AsyncTypeSafeClient](/sdk/python/api/clients/async):
```python theme={null}
from typesafe_sdk import AsyncTypeSafeClient, Choice, Noul, Score
async def main() -> None:
async with AsyncTypeSafeClient() as client:
response = await client.system_one(
state={"document": "I was charged twice. Please fix this ASAP."},
questions={
"billing": Noul(instructions="Is this ticket about billing?"),
"tone": Choice(
instructions="What is the customer's tone?",
criteria={"calm": None, "frustrated": None, "angry": None},
),
"urgency": Score(
instructions="How urgent is this ticket?",
criteria=["can wait", "this week", "today"],
),
},
)
print(response.nouls["billing"].noul)
print(response.choices["tone"].choice)
print(response.scores["urgency"].score)
```
</Tab>
<Tab title="Sync">
With [TypeSafeClient](/sdk/python/api/clients/sync):
```python theme={null}
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
with TypeSafeClient() as client:
response = client.system_one(
state={"document": "I was charged twice. Please fix this ASAP."},
questions={
"billing": Noul(instructions="Is this ticket about billing?"),
"tone": Choice(
instructions="What is the customer's tone?",
criteria={"calm": None, "frustrated": None, "angry": None},
),
"urgency": Score(
instructions="How urgent is this ticket?",
criteria=["can wait", "this week", "today"],
),
},
)
print(response.nouls["billing"].noul)
print(response.choices["tone"].choice)
print(response.scores["urgency"].score)
```
</Tab>
</Tabs>
<h2 id="whats-next">
What's next
</h2>
Visit the [Usage guide](/sdk/python/usage) to learn more about patterns such as [typed responses](/sdk/python/usage#typed-system_one-responses), [model selection](/sdk/python/usage#choosing-a-model), [retries](/sdk/python/usage#retries), [HTTP/2](/sdk/python/usage#http2), or [error handling](/sdk/python/usage#error-handling).
This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.
DOCUMENT: primitives/noul
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# Noul
> A Noul question asks the TypeSafe model to evaluate a yes/no question and return the probability that the answer is yes.
Use a Noul when the answer is yes or no. For example, does this message ask for a refund, does this resume mention distributed systems, does this comment contain personal data. If the answer is one of several options, use a [Choice](/primitives/choice). If it's a position on a spectrum, use a [Score](/primitives/score). [Choose a question type](/primitives#choose-a-question-type) compares all three.
A Noul answer is a single number representing the probability that the answer is yes where 0 means no and 1 means yes.
## Request structure
The POST request body to the [TypeSafe API](/api) has the same three top-level fields as any other question type: `state`, which is the content to evaluate; `model`; and `questions`. Each Noul question has the following fields:
* `type`: Always `"noul"`.
* `instructions`: The yes/no question the model answers, or a statement for it to judge.
* `criteria`: Optional. An object with `true` and `false` descriptions of what a yes and a no mean.
Below is a request where the state is a support message and the two questions are whether the customer wants a person and whether they have contacted support before:
[interactive example omitted]
You choose the question ids, `is_human_escalation` and `is_repeat_contact` here. The ids are not sent to the model. Each answer is returned under the same id. The first question relies on `instructions` alone. The second adds `criteria` to say what counts as a yes and what counts as a no.
With the [Python SDK](/sdk/python), the same questions are `Noul` objects:
[code example omitted]
The `system_one` method and the `https://api.typesafe.ai/v1/systemone` endpoint are both named after [System One](/concepts/system-one), TypeSafe's AI model. [How to build with TypeSafe](/concepts/how-to-build-with-system-one) covers where to use it in your code.
If you're using a coding agent, install the [TypeSafe agent skill](/agent-skill#installation) first so it knows the request and response shapes.
<Note>
`instructions` can be a string, an object, or an array. Start with a string. Use an object when the question needs data alongside it, such as a record to compare the state against, or when part of the question is built by your code. [Use structure in the questions](/concepts/how-to-build-with-system-one#use-structure-in-the-questions) explains when structure helps, and [the example below](#structured-instructions) shows it with questions built in code.
</Note>
## Response structure
The response has one entry in `answers` per question, under the ids from the request:
[code example omitted]
Both answers here are close to 1. The customer says "talk to a real person", so `is_human_escalation` is 0.99. "I have asked three times now" matches the `true` description of `is_repeat_contact`, so it is 0.93.
## Reading a Noul
The number is the answer and the certainty in one. A value near 1 is a strong yes. A value near 0 is a strong no. A value near 0.5 means the model gives yes and no similar probability.
The table below shows recorded `jev-1.13.0` answers to the `is_human_escalation` question for different customer messages:
| State | `noul` |
| - | - |
| Thanks, that fixed it! | 0.02 |
| How do I reset my password? | 0.07 |
| I need this sorted today, whatever it takes. | 0.26 |
| Are you a bot? | 0.40 |
| Is there any way to speak to someone about my invoice? | 0.84 |
| I have asked three times now. Can I please just talk to a real person? | 0.99 |
The first two and the last two are clear. "I need this sorted today" is urgent but never asks for a person, and gets 0.26. "Are you a bot?" hints at wanting a human without asking for one, and the model splits almost evenly at 0.40. Both are the kind of message where a decision needs to be made based on a threshold in your code.
There is no separate `confidence` value for a Noul, unlike a [Choice](/primitives/choice) or a [Score](/primitives/score). A Noul's probability distribution has only two outcomes, yes and no, so the single `noul` value describes it completely. A Choice or Score spreads probability over several options or levels, and `confidence` summarizes that spread.
Most often your code thresholds `noul` into a boolean:
[code example omitted]
Where to set the threshold depends on the cost of being wrong. Use 0.5 when yes and no are equally easy to act on. Raise it when acting on a false yes is expensive, such as paging someone or issuing a refund. Lower it when missing a true yes is expensive, such as failing to flag a safety issue. Values in the middle can go to a person rather than either code path. That is the same three-way split the [Confidence](/confidence#three-paths-for-using-confidence-in-your-code) page describes for Choice and Score answers.
A Noul value runs from 0 to 1, but it's not a scale of the thing you asked about. It is the probability that the answer is yes. If the question is really about degree, the value does not measure the degree. Below, "Is the candidate strong in Python?" is asked about four candidates, next to a [Score](/primitives/score) with four levels: no experience, some familiarity, regular use in a job, deep expertise.
| Candidate | Noul: "Is the candidate strong in Python?" | Score: "How much Python experience does the candidate have?" |
| - | - | - |
| My experience is in Java and Go. I have not used Python. | 0.03 | 0.0 (No experience) |
| I have used Python occasionally for small scripts alongside my main Java work. | 0.14 | 1.0 (Some familiarity) |
| I used Python every day for two years in my last job, mostly data pipelines. | 0.81 | 2.05 (Regular use in a job) |
| I have written Python daily for eight years, including maintaining a large Django codebase. | 0.92 | 2.89 (Deep expertise) |
The Noul judges one proposition, "strong", and the values are how likely it is. You could create levels in the 0 to 1 range in your code, such as 0.3 to 0.7 for "some experience", but the model will not see them, so nothing in the answer was judged against them. A middle value can mean medium experience or an unclear case, and the spacing between candidates is not something you chose. The Score judges each level description on its own, so every candidate landed on or near a level you wrote, and the returned probabilities show how the model divided its judgment between levels. If you disagree, reword a level and run it again. [Choose a question type](/primitives#choose-a-question-type) explains the distinction.
## Writing a Noul question
Ask one yes/no question per Noul. If a question has two conditions, such as "Is the customer angry and asking for a refund?", the model has to judge both at once and the value means less. Ask two Nouls and combine them in code.
Phrase the question so that a high value means yes. "Does the message contain personal data?" is clear. "Is the message free of personal data?" inverts the meaning, and code that reads it later will get it backwards.
A statement works as well as a question. For "The customer is requesting a refund", a value near 1 means the statement is true. Try both phrasings with your own data to see which works better.
Make the boundary between yes and no unambiguous. "Does this candidate have any Python experience?" works well because "any" leaves no middle ground. When the boundary is subtle, add `criteria` with `true` and `false` descriptions, as the `is_repeat_contact` question above does. The instruction is enough for most Nouls, so try your questions with and without `criteria` and keep whichever gives better answers on your documents.
## Good practice: ask more than one question per call
For a checklist of conditions, ask many Noul questions in one request: one question per condition, and the code decides what the combination means. Questions are evaluated in parallel, so adding Nouls barely changes the response time. [Ask multiple questions together](/primitives#a[REDACTED]) explains this in more detail.
## Handling multiple Noul answers in code
The two-question request above gives the code enough to route the message. The example below escalates to a person when the customer asks for one, and raises the priority when they have been in touch before. A value in the middle on either question goes to a reviewer instead of a code path:
[code example omitted]
For the message above, the noul answer value for `is_human_escalation` is 0.99 and `is_repeat_contact` is 0.93, so the code routes it to an agent at high priority. The message "How do I reset my password?" is 0.07 on both questions and is routed to the bot.
The thresholds live in your code. If reviewers see too many messages, narrow the gap between `NO` and `YES`. If too many wrong routes get through, widen it. If you later need to know whether the message mentions a payment, or whether it contains personal data, add another Noul to `SUPPORT_QUESTIONS`. The request count stays at one.
## Structured instructions
Instructions can be an object instead of a string, with the question in one field and supplementary data in the others. [Use structure in the questions](/concepts/how-to-build-with-system-one#use-structure-in-the-questions) covers when that helps. Here it's used for a question built using code: a resume that has just arrived is compared against records in a candidate database that might be the same person. Each record goes into a `potential_duplicate` field as it is, the `question` is the same for every record, and all the records are checked in one request. The code-generated question keys contain each record's database ID:
[interactive example omitted]
The response:
[code example omitted]
Each answer is the probability that the resume is for the person in that record. Record 18 spells the name differently but matches on location and employer, and gets 0.74. Record 42 has the same name in a different city with a different employer, and gets 0.09. Record 77 is a similar name at the same location with a different employer, and gets 0.08. Threshold each value in your code, as in [Handling multiple Noul answers in code](#handling-multiple-noul-answers-in-code), and send the middle values to a person.
With the Python SDK, the questions are built from the candidate records. The question text is fixed and the record changes:
[code example omitted]
The [structured-data-extraction cascade cookbook](/cookbooks/sde_cascade) uses structured instructions to verify an extracted record. Every field gets the same set of questions. Each question's `instructions` object has the question text in the `main_question` property. There are also `field_spec` and `extracted_field` properties that change for each field.
## Noul in the cookbooks
Take a look at our cookbooks to see apps using Noul questions:
* [Parallel questions](/cookbooks/parallel_questions) runs a 13-question regulatory checklist over one article in a single request.
* [Self-consistency: nouls](/cookbooks/consistency_noul_cookbook) scores an insurance claim against a 15-question rubric and measures how stable the values are across runs.
* [Re-ranking](/cookbooks/rerank_typesafe) uses the probability itself, not a threshold: one Noul per query-candidate pair, then sorts candidates by the value.
* [Line-by-line search](/cookbooks/semantic_find) pairs a Choice that finds the matching line with a Noul that checks whether the document contains an answer at all.
* [Structure recovery](/cookbooks/autoformat) asks one Noul per pair of lines, whether a line break split a sentence, to rebuild paragraphs from plain text.
This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.
DOCUMENT: primitives/advanced
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# Advanced: structure
> Instructions, Choice options, Score levels, and Noul criteria all accept JSON structure.
System One models are trained to understand structure.
## Where structure is allowed
Every one of these fields is an [`EntryType`](/sdk/javascript/api/type-aliases/EntryType).
| Field | Applies to | Accepted shape |
| - | - | - |
| `instructions` | Choice, Score, Noul | `string`, `object`, `array`, or `null` |
| `criteria` values (option descriptions) | Choice | `string`, `object`, `array`, or `null` |
| `criteria` entries (level descriptions) | Score | `string`, `object`, `array`, or `null` |
| `criteria.true` and `criteria.false` | Noul | `string`, `object`, `array`, or `null` |
## When to structure a question
* **When it helps with clarity.** When a question has multiple parts, putting them in the form of JSON helps with clarity because the keys are labeled.
* **When question needs supporting data.** A schema, a taxonomy, or a database row is already JSON. Use the JSON entirely or pass in the relevant subfields instead of serializing them into a string template.
## Structured instructions
One `field` object describes the field being checked, and each question refers to it by key. The same shape drives a Noul that verifies a value, a Choice that picks one from candidates, and two Scores that place a value on a scale.
[interactive example omitted]
In code, you could loop over the potential records and build one of these questions per field, all sent in a single call. The [SDE cascade cookbook](/cookbooks/sde_cascade) does something similar to this.
Arrays work too. Use one when the instruction is a list of things to check or to compare:
[code example omitted]
## Structured Choice options
A Choice option description can be a structured object as well.
### JSON rubric for boundary clarification
[interactive example omitted]
The example tells the model what each option does and does *not* cover. It sharpens the boundary between options.
### Walking a taxonomy
To classify into a deep taxonomy, ask one Choice per level and walk the tree in code. At each step the options are the children of the current node, and each option's value is the child's tree. Doing so lets the model see what lives under a branch before committing to it, which matters when the item belongs to a leaf whose name is not obvious from the branch name alone.
Here the state is a product listing and the first question picks a top-le…774 tokens truncated…ng that batching every question into one TypeSafe call is 12.2x cheaper and 10.0x faster with no change in answers. | Beginner |
## How-to
Recipes for common tasks: search, formatting, tool selection, guardrails.
| Cookbook | What it does | Level |
| - | - | - |
| [Re-ranking](/cookbooks/rerank_typesafe) | Builds 30-passage BM25 shortlists for 40 CLERC legal queries, then uses one TypeSafe question per query-candidate pair to raise top-1 accuracy from 5% to 18% and top-10 accuracy from 38% to 62%. | Beginner |
| [Line-by-line search](/cookbooks/semantic_find) | Build semantic search for GitHub's Terms of Service. In one request, score 218 line ids against a plain-language query with a Choice question, and use a Noul question to check whether the document contains an answer. | Beginner |
| [Structure recovery](/cookbooks/autoformat) | Reconstructs Markdown from plain text that lost its formatting in two requests: one stitches hard-wrapped lines back together, one classifies every block (heading, list, code, callout). | Beginner |
| [Function calling](/cookbooks/function_calling) | Turns natural-language trading requests into calls to ordinary typed functions by mapping function names and closed-set arguments to confidence-aware TypeSafe questions. | Intermediate |
| [Skill suggestion](/cookbooks/skill_suggestion) | Picks at most one skill for an agent turn out of the 182 in Nous Research's Hermes catalog, using two TypeSafe requests to rank and re-check the top candidates. | Intermediate |
| [Knowledge graph entity alignment](/cookbooks/entity_alignment) | Decides which of 450 candidate pairs from two beer catalogues describe the same product using one Score question plus three companion Nouls that surface which fields disagree. | Beginner |
| [Classifying RAG passages](/cookbooks/classifying_rag_passages) | Score each retrieved passage with one TypeSafe request, then decide in code which ones reach the answering model. | Intermediate |
| [Double-checking citations](/cookbooks/citation_check) | Catch wrong or hallucinated citations by checking against the source document. One Choice question decides whether the quote's context supports the claim. | Beginner |
| [Guardrails for LLMs](/cookbooks/llm_guardrails) | Screen every message going into and out of an LLM app with one TypeSafe request, thresholding hazard probabilities and severity to pass, review, block, or route. | Intermediate |
## Extraction
Pull typed values out of messy text.
| Cookbook | What it does | Level |
| - | - | - |
| [SDE cascade](/cookbooks/sde_cascade) | Uses a 2-stage structured-data-extraction cascade (mini → verify → reasoning) to get most of the quality of a big reasoning model at a fraction of the cost. | Intermediate |
| [Date extraction](/cookbooks/date_extraction_cookbook) | Extracts absolute and relative dates by asking TypeSafe for the parts named in a document, then resolving and validating them in code with confidence-based review. | Beginner |
| [Pre-parsed value extraction](/cookbooks/pre_parsed_value_extraction_cookbook) | Uses regexes to find candidate emails, phone numbers, and amounts, then has TypeSafe select the requested span so code can normalize a verbatim value. | Beginner |
## Classification
Assign inputs to categories at any depth.
| Cookbook | What it does | Level |
| - | - | - |
| [Hierarchical classification](/cookbooks/hierarchical_classification) | Classifies documents through deep patent, retail product, biomedical, and source-code hierarchies using parallel beam search over TypeSafe Choice probabilities. | Intermediate |
| [Autoresearch feature discovery](/cookbooks/autoresearch_feature_discovery) | Runs an autoresearch loop that proposes TypeSafe questions, converts free text into numeric features, and uses model errors to improve a supervised CatBoost regressor. | Advanced |
| [Classification using confidence](/cookbooks/classification_using_confidence) | Classify SEC annual reports into 75 industry groups with one Choice each, then read the answer's own confidence to decide whether to report that group or the broader division above it. | Beginner |
<Tip>
We're always keen to learn how people are making use of our primitives. If you've built something worth a cookbook, drop us a note!
</Tip>
This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.
DOCUMENT: concepts/system-one
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# System One
> System One models make fast, structured decisions for software. Jev is TypeSafe's flagship model and the first System One model.
System One models are a class of AI models built to make fast, structured decisions that software can use directly. A System One model evaluates a [state](/concepts/state) and returns typed answers and probabilities.
Jev is TypeSafe's flagship model and the first System One model.
Like an LLM, a System One model understands natural-language input. It returns typed decisions and probabilities rather than generated text.
<Note>
Jev currently accepts text input only. It evaluates strings, JSON objects, and arrays of text. Images, audio, and video are not supported (yet).
</Note>
## How it differs from an LLM
System One models are trained for calibrated decisions: their probabilities are optimized against outcomes to reflect uncertainty. Calibration is measured across groups of predictions; it does not guarantee that an individual answer is correct.
System One models do not write replies, produce code, or generate explanations of their reasoning. You define the possible answers through [primitives](/primitives):
| Primitive | Question | Example answer space | Example output |
| - | - | - | - |
| [Choice](/primitives/choice) | Which team should handle this ticket? | `billing`, `technical`, or `account` | `choice: "billing"` |
| [Score](/primitives/score) | How frustrated is this customer? | 0 = calm, 1 = frustrated, 2 = very frustrated | `score: 1.4` |
| [Noul](/primitives/noul) | Does this message request a refund? | True or false | `noul: 0.95` |
These are illustrative configurations and values. The primitive pages describe the available configuration options and full response fields.
Read the [AI primer](/introduction/machine-learning-primer) to learn how System One models work and how they are trained.
<Note>
The System One name comes from the concept Daniel Kahneman popularized in his book *Thinking, Fast and Slow*. System 1 thinking is fast and intuitive. System 2 is slower and more deliberate. Here, the emphasis is on fast, focused judgments.
</Note>
## Fast judgments inside a larger workflow
For a refund request, your application can:
1. Build a state containing the customer's message, the relevant transactions, and the refund policy.
2. Ask independent questions together: whether a refund was requested, whether the evidence indicates a duplicate charge, and whether the policy supports a refund.
3. Combine the answers with deterministic checks in code, then route the case for action or review.
Once you have seen the primitives in action, you can combine them into a larger system. Because System One models return typed, constrained outputs rather than free-form text, your code can inspect and combine its answers into predictable workflows. See [How to build with TypeSafe](/concepts/how-to-build-with-system-one) for the full workflow.
Answers from System One models also include [confidence](/confidence), so you can decide when to act and when to escalate to a person or a reasoning model.
## Call a System One model
Call a System One model through one of our [client SDKs](/sdk) or `POST /v1/systemone` in the [HTTP API](/api). The `model` field selects which model handles the request. The examples in these docs use `jev-latest`, which is also the SDK default. See [Models](/models) for the available models, their prices, and their aliases.
Start with [State](/concepts/state) to prepare the input and [Primitives (Questions)](/primitives) to explore the types of questions you can ask.
This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.
DOCUMENT: concepts/how-to-build-with-system-one
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.typesafe.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# How to build with TypeSafe
> Design AI-powered software by keeping code in control and giving System One narrow, structured decisions.
System One is TypeSafe's model for building AI-powered software, not agents. It does not generate code or choose its own next action. It provides AI primitives that embed into software, so code remains in control while the model handles common-sense judgments over unstructured data.
<Info>
**Summary:** build a normal software workflow and insert System One only where AI is needed.
* Keep control flow, deterministic rules, and side effects in code.
* Break broad judgments into narrow, typed questions with explicit instructions and criteria.
* Give each question only the context it needs.
* Use probabilities and confidence to act, ask for review, or escalate.
* Ask independent questions together, then compose their answers in code.
</Info>
## Three software architectures
TypeSafe is designed for building **AI-powered software**, where code owns the workflow and AI handles narrow, structured decisions.
<Tabs>
<Tab title="Traditional software">
Traditional code is a complex decision tree made from simple software primitives. Because each primitive is reliable, developers can compose them into higher-level abstractions.
</Tab>
<Tab title="LLM agents">
An agent processes instructions and chooses its next step. This works well when a person is monitoring the process, but every loop introduces another opportunity to go off the rails.
</Tab>
<Tab title="AI-powered software">
Code handles deterministic work and owns the control flow. The model appears only where the system needs programmable common sense or needs to interpret unstructured data. Each AI task is kept atomic and constrained.
</Tab>
</Tabs>
<Frame>
<img className="block dark:hidden" src="https://mintcdn.com/ts-docs/aFVnpmCIX68NpsV1/images/how-to-build-with-typesafe/software-architectures-light.webp?fit=max&auto=format&n=aFVnpmCIX68NpsV1&q=85&s=35c7622176190d1b1f19dc712f2fbf11" alt="Traditional software, agents, and AI-powered software shown as three different system architectures." width="2048" height="1117" data-path="images/how-to-build-with-typesafe/software-architectures-light.webp" />
<img className="hidden dark:block" src="https://mintcdn.com/ts-docs/aFVnpmCIX68NpsV1/images/how-to-build-with-typesafe/software-architectures-dark.webp?fit=max&auto=format&n=aFVnpmCIX68NpsV1&q=85&s=8e6c2c73bdd4c9b541c4f9294bd829b5" alt="Traditional software, agents, and AI-powered software shown as three different system architectures." width="2048" height="1117" data-path="images/how-to-build-with-typesafe/software-architectures-dark.webp" />
</Frame>
## What makes System One composable
<Columns cols={2}>
<Card title="Structured" icon="braces">
System One is type-safe by construction. Decisions and probabilities conform to the structured software types and JSON schema your code expects, so it never has to recover a value from generated prose.
</Card>
<Card title="Parallel" icon="split">
Questions are evaluated independently and in parallel. One primitive's result does not become hidden context that changes another primitive's result.
</Card>
<Card title="Comparable" icon="arrow-up-down">
Outputs are sortable and can drive smart `if` statements, thresholds, and comparisons.
</Card>
<Card title="Fast" icon="gauge">
Most queries complete in about 100 ms. System One is fast enough for real-time request paths and user interfaces.
</Card>
<Card title="Calibrated confidence" icon="chart-no-axes-combined">
[RLCD](/introduction/machine-learning-primer) communicates uncertainty through calibrated probabilities instead of tending toward overconfidence.
</Card>
<Card title="Self-consistent" icon="repeat-2">
System One is designed to return stable answers across repeated evaluations. See the [self-consistency cookbook](/cookbooks/consistency_noul_cookbook).
</Card>
</Columns>
Because every output is constrained to the supplied options, the model returns a full probability distribution over those options rather than inventing a value outside the schema. TypeSafe's target is a greater than 100× intelligence-to-speed-and-cost ratio; the underlying bet is that cheaper intelligence will create much more demand.
## Design a System One workflow
<Steps titleSize="h3">
<Step title="Use code when you can">
Keep deterministic work in code. It is reliable and cheap. Avoid agent `while` loops when a software workflow can express the same behavior.
<Accordion title="Example: keep deterministic rules in code">
[code example omitted]
</Accordion>
Browse the [System One patterns](/patterns) for bounded ways to compose model decisions with code.
</Step>
<Step title="Decompose the input state">
Include only the context relevant to the current questions. This helps the model avoid distractions and context rot. Do not rely on knowledge stored in model weights when current information can come from your own knowledge base.
<Accordion title="Example: send only relevant context">
[interactive example omitted]
</Accordion>
</Step>
<Step title="Use structure in the input state">
Use nested JSON for the `state` and `questions` fields. Point questions at specific values when that removes ambiguity, and include the backtick characters around each path inside the question.
<Accordion title="Example: reference a nested value">
Use a backticked dot-and-index path to point a question at a specific nested value, such as `support.tickets[0].message`.
[interactive example omitted]
</Accordion>
</Step>
<Step title="Decompose the questions">
Ask the most explicit, narrow, specific, atomic questions you can. Break down complex or ill-defined questions into separate questions that each evaluate one property.
<Info>
This is probably the most important concept in this guide. Broad questions hide several judgments behind one answer. Atomic questions expose those judgments so you can inspect, tune, and combine them in code.
</Info>
<Accordion title="Example: decompose spam detection">
[interactive example omitted]
[interactive example omitted]
</Accordion>
<Accordion title="Example: verify a tool-call trace">
[interactive example omitted]
[interactive example omitted]
</Accordion>
</Step>
<Step title="Use structure in the questions">
Keep questions short. `instructions` and `criteria` are usually strings, and for a short, unambiguous question a string is all you need. They can also be objects or arrays. Put the question in one field and the data that guides the question in the others.
Structure helps in these situations:
* The question needs context or examples. A long sentence of background information or a list of example inputs belongs in named fields next to the question, where your code can add to them or swap them without rewriting the question.
* Part of the question comes from your code. When a value comes from a database, put it in its own field instead of splicing it into a string template.
* Several questions have similar instructions. A request takes one state and can include multiple questions. Adding supplementary data can help make questions distinct.
<Accordion title="Example: reference a record from your code">
This Noul compares a resume in the state against a record from a candidate database. The record goes into `potential_duplicate` as it is, and the question refers to it by name.
[interactive example omitted]
</Accordion>
The "potential\_duplicate" data sourced from code can change over time. The "question" references it using backticks.
The descriptions inside `criteria` can be objects too. For a Choice, each option's description can be an object that says what the option covers, what belongs to a different option, and a few examples. Use the same field names across options so the model can compare them directly.
<Accordion title="Example: define contrastive Choice criteria">
[interactive example omitted]
</Accordion>
Each question type's page has a worked example:
* [Noul](/primitives/noul#structured-instructions) compares one resume against several candidate records, one question per record, with the questions built in code.
* [Choice](/primitives/choice#structured-instructions-and-criteria) describes two easily confused options with what each covers, what it's not for, and examples.
* [Score](/primitives/score#structured-level-descriptions) gives each level a description and example situations.
The [structured-data-extraction cascade cookbook](/cookbooks/sde_cascade) shows the shared-wording case, asking the same battery of questions about every field of an extracted record.
A short, unambiguous question or criterion can remain a string. Add structure when it separates guidance that would otherwise blur together. For the full set of places structure is accepted, see [Advanced: structure](/primitives/advanced).
</Step>
<Step title="Ask a lot of questions">
Ask many narrow, independent questions about the same state in one request. This is how you maximize effectiveness and intelligence per dollar with the API: questions run in parallel, and code can combine their signals without adding serial model round trips.
See the [Speculative Fan-Out pattern](/patterns/fan-out) and [Parallel questions cookbook](/cookbooks/parallel_questions).
</Step>
<Step title="Combine question outputs in code (or feed into a classical ML model)">
Combine independent answers with deterministic rules or weighted sums. For learned composition, use the probabilities as features in a downstream classical machine-learning model.
<Accordion title="Example: combine signals with a weighted score">
[code example omitted]
</Accordion>
[Composite Scoring](/patterns/composite-scoring) shows how to preserve individual judgments while combining them. If you do not have labels for a downstream model, use an ensemble of expensive reasoning models to generate them; the [AutoResearch cookbook](/cookbooks/autoresearch_feature_discovery) shows how to train a classical model on System One outputs.
</Step>
<Step title="Route on uncertainty">
Make code take different actions for confident and unconfident answers. Escalate uncertain cases to a person or a more expensive reasoning model. Test thresholds by plotting confidence against accuracy on your data.
<Accordion title="Example: route by confidence">
[code example omitted]
</Accordion>
See [Confidence](/confidence) and [Confidence-Gated Routing](/patterns/confidence-routing) for choosing thresholds and matching them to the risk of each action.
</Step>
</Steps>
<Tip>
Decomposition does not require more round trips. Questions over the same state run in parallel.
</Tip>
## Putting it all together
This support-ticket workflow keeps deterministic work in code, sends only relevant structured context, evaluates many atomic questions in one request, and composes the answers with explicit confidence gates.
[code example omitted]
This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.Pre-parsed value extraction - TypeSafe AI (https://docs.typesafe.ai/cookbooks/pre_parsed_value_extraction_cookbook)
citeturn5view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/cookbooks/pre_parsed_value_extraction_cookbook","lineno":null}); Total lines: 292
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Extraction
L15:
L16: Pre-parsed value extraction
L17:
L18: Extraction
L19: # Pre-parsed value extraction
L20:
L21: Uses regexes to find candidate emails, phone numbers, and amounts, then has TypeSafe select the requested span so code can normalize a verbatim value.
L22:
L23: Copy page Copy page
L24: A regex finds the candidate values, TypeSafe picks the one the question asks for, and code copies it verbatim. The `find` and `pick` pair here is one you can point at your own documents, and three worked cases show it in use: the address a sender wants their receipt sent to, a phone number as `+14155550177`, and an invoice total as `1315.50 USD` flagged as a charge. TypeSafe picks one of the options you hand it, so the candidates have to be found first.
L25: A regex finds them, TypeSafe picks one, and code copies the pick, in three steps:
L26: 1. A regex finds the candidate values in the text. Tune it to over-find.
L27: 2. TypeSafe picks which candidate the question is asking for, and reads off any attribute the code needs downstream (currency, country, whether an amount is a credit or a charge).
L28: 3. The code copies the picked value and normalizes it.
L29: Because TypeSafe only ever chooses among the spans the regex found, the value you get back is one of those spans, copied unchanged. It cannot invent a value or transpose a digit. cite3†Image: Overview diagram†mintcdn.com The regex finds candidate values in the document, TypeSafe picks one, and downstream code normalizes it and acts on it.
L30: ##
L31:
L32: cite4† L33:
L34: Setup
L35:
L36: `pip install ipython phonenumbers 'cooksafe>=0.2.0,<0.3.0'
L37: `
L38: then set `TYPESAFE_API_KEY`.
L39:
L40: `import os
L41: import re
L42: from decimal import Decimal
L43: from pathlib import Path
L44:
L45: import phonenumbers
L46: from cooksafe import JsonCache, make_playground_link
L47: from IPython.display import Markdown, display
L48: from typesafe_sdk import Choice, Noul, TypeSafeClient
L49:
L50: TYPESAFE_MODEL = "jev-1.12"
L51: NONE = "none" # the escape hatch on every selection: "none of the candidates fits"
L52: # base_url defaults to https://api.typesafe.ai/ ; the env override points at another deployment.
L53: ts = TypeSafeClient(
L54: api_key=[REDACTED]
L55: "TYPESAFE_API_KEY", "cache-only"
L56: ), # cached re-renders need no key
L57: base_url=os.environ.get("TYPESAFE_BASE_URL"),
L58: timeout=30.0,
L59: )
L60: json_cache = JsonCache(Path("json_cache.json"))
L61: `
L62: ##
L63:
L64: cite5† L65:
L66: Helpers
L67: `find` runs a regex tuned to over-find and dedupes the matches. `pick` is a `Choice` question whose options are the spans `find` returns, so its answer is one of those spans copied exactly, or `none` when no candidate fits. `classify` is a `Choice` question over a fixed set of labels, used here for the currency and the country. `is_true` is a `Noul`, used here to ask whether an amount is a credit. Every call is cached to `json_cache.json`, so re-rendering makes no API calls.
L68: `EMAIL_RE = re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}")
L69: PHONE_RE = re.compile(r"\(?\+?\d[\d\s()\-.]{6,}\d")
L70: MONEY_RE = re.compile(r"[$€£¥]\s?\d[\d,]*(?:\.\d{2})?")
L71:
L72:
L73: def find(pattern: re.Pattern, text: str) -> list[str]:
L74: """Code-side candidate finder: recall-tuned regex, deduped, in document order."""
L75: seen: set[str] = set()
L76: out: list[str] = []
L77: for match in pattern.findall(text):
L78: span = match.strip()
L79: if span and span not in seen:
L80: seen.add(span)
L81: out.append(span)
L82: return out
L83:
L84:
L85: @json_cache
L86: def pick(document: str, candidates: list[str], question: str) -> dict:
L87: """TypeSafe selects which found span plays the role. Returns {choice, confidence}.
L88:
L89: The options ARE the candidate spans, so ``choice`` is a verbatim copy of one of them (or the
L90: ``none`` hatch) - the model chooses, code owns the string."""
L91: criteria = {c: None for c in candidates} | {
L92: NONE: "None of these is the requested value."
L93: }
L94: answer = ts.system_one(
L95: state=document,
L96: questions={"pick": Choice(instructions=question, criteria=criteria)},
L97: model=TYPESAFE_MODEL,
L98: ).answers["pick"]
L99: return {"choice": answer.choice, "confidence": answer.confidence}
L100:
L101:
L102: @json_cache
L103: def classify(document: str, question: str, options: list[str]) -> dict:
L104: """A small Choice over a fixed label set (currency, country, ...). Returns {choice, confidence}."""
L105: answer = ts.system_one(
L106: state=document,
L107: questions={
L108: "q": Choice(instructions=question, criteria={o: None for o in options})
L109: },
L110: model=TYPESAFE_MODEL,
L111: ).answers["q"]
L112: return {"choice": answer.choice, "confidence": answer.confidence}
L113:
L114:
L115: @json_cache
L116: def is_true(document: str, question: str) -> float:
L117: """A yes/no Noul. Returns P(yes)."""
L118: return (
L119: ts.system_one(
L120: state=document,
L121: questions={"q": Noul(instructions=question)},
L122: model=TYPESAFE_MODEL,
L123: )
L124: .answers["q"]
L125: .noul
L126: )
L127: `
L128: See all 59 lines
L129: ##
L130:
L131: cite6† L132:
L133: Email: pick the right address by role
L134: Four addresses in the headers. The body asks for the receipt to go to a personal address instead of the `To:` billing alias, so the answer depends on reading the body. Two questions here: which address gets the receipt, and which one sent the message.
L135:
L136: `EMAIL_DOC = """From: Dana Whit <[REDACTED]>
L137: To: [REDACTED]
L138: Cc: [REDACTED]
L139: Reply-To: [REDACTED]
L140:
L141: Hi team - please don't use the billing alias for this one. Send my receipt to my
L142: personal address instead. Thanks, Dana."""
L143:
L144: emails = find(EMAIL_RE, EMAIL_DOC)
L145: receipt = pick(
L146: EMAIL_DOC, emails, "Which email address does the sender want their receipt sent to?"
L147: )
L148: sender = pick(
L149: EMAIL_DOC, emails, "Which email address did this message come from (the From line)?"
L150: )
L151:
L152: print("candidates :", emails)
L153: # code copies the picked value verbatim and normalizes (lowercase); it never re-types it
L154: print(
L155: f"receipt -> : {receipt['choice'].lower():<28} (conf {receipt['confidence']:.2f})"
L156: )
L157: print(f"sender -> : {sender['choice'].lower():<28} (conf {sender['confidence']:.2f})")
L158: `
L159:
L160: `candidates : ['[REDACTED]', '[REDACTED]', '[REDACTED]', '[REDACTED]']
L161: receipt -> : [REDACTED] (conf 0.98)
L162: sender -> : [REDACTED] (conf 1.00)
L163: `
L164: `receipt` is the personal Gmail address on the `Reply-To:` line, which is what the body asks for; `sender` is the one on the `From` line. Both are copies of regex matches, lowercased in code.
L165: ##
L166:
L167: cite7† L168:
L169: Phone: pick the mobile, normalize to E.164
L170: Three numbers, none of them carrying a country code. TypeSafe picks the mobile and reads the country from the text; `phonenumbers` combines those two answers into E.164, the international format that starts with a `+` and the country code.
L171:
L172: `PHONE_DOC = """Reach our San Francisco office at these numbers: main desk (415) 555-0199,
L173: billing fax (415) 555-0142, and my direct cell (415) 555-0177. Call the cell if it's urgent."""
L174:
L175: phones = find(PHONE_RE, PHONE_DOC)
L176: mobile = pick(PHONE_DOC, phones, "Which of these is the direct mobile / cell number?")
L177: region = classify(
L178: PHONE_DOC,
L179: "In what country is this office located?",
L180: ["US", "GB", "DE", "FR", "CA", "AU"],
L181: )
L182:
L183: # code copies the picked value and normalizes it with the model-supplied country
L184: parsed = phonenumbers.parse(mobile["choice"], region["choice"])
L185: e164 = phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.E164)
L186: print("candidates :", phones)
L187: print(f"mobile -> : {mobile['choice']} (conf {mobile['confidence']:.2f})")
L188: print(f"country -> : {region['choice']} (conf {region['confidence']:.2f})")
L189: print(f"E.164 -> : {e164}")
L190: `
L191:
L192: `candidates : ['(415) 555-0199', '(415) 555-0142', '(415) 555-0177']
L193: mobile -> : (415) 555-0177 (conf 1.00)
L194: country -> : US (conf 0.90)
L195: E.164 -> : +14155550177
L196: `
L197: Nothing in the digits says which number is the mobile or what country it is in; the words around them do. TypeSafe reads those words, and `phonenumbers` formats the picked number as `+14155550177`.
L198: ##
L199:
L200: cite8† L201:
L202: Money: pick the amount, classify the currency, flag credit vs charge
L203: An invoice with four amounts on it. TypeSafe picks the total due and the credit, reads the currency, and flags each picked amount as a charge or a credit. The code copies each picked string and parses it into a `Decimal`.
L204:
L205: `MONEY_DOC = """Invoice INV-2087.
L206: Subtotal: $1,200.00
L207: Sales tax: $115.50
L208: Total due: $1,315.50
L209: A $50.00 courtesy credit from last month has already been applied."""
L210:
L211: amounts = find(MONEY_RE, MONEY_DOC)
L212: currency = classify(
L213: MONEY_DOC,
L214: "What currency are these amounts in?",
L215: ["USD", "EUR", "GBP", "JPY", "CAD"],
L216: )
L217: total = pick(MONEY_DOC, amounts, "Which amount is the total the customer must pay?")
L218: credit = pick(
L219: MONEY_DOC, amounts, "Which amount is the courtesy credit that was applied?"
L220: )
L221:
L222:
L223: def to_decimal(value: str) -> Decimal:
L224: """Copy the picked value and parse the number in code (US grouping/decimal here)."""
L225: return Decimal(re.sub(r"[^\d.]", "", value))
L226: for label, chosen in [("total due", total), ("credit", credit)]:
L227: is_credit = is_true(
L228: MONEY_DOC,
L229: f"Is the amount {chosen['choice']} a credit or refund to the customer, not a charge?",
L230: )
L231: kind = "credit" if is_credit > 0.5 else "charge"
L232: print(
L233: f"{label:<10}: {chosen['choice']:<10} -> {to_decimal(chosen['choice'])} {currency['choice']} "
L234: f"({kind}, P(credit)={is_credit:.2f})"
L235: )
L236: print("\n candidates :", amounts)
L237: `
L238: See all 34 lines
L239:
L240: `total due : $1,315.50 -> 1315.50 USD (charge, P(credit)=0.01)
L241: credit : $50.00 -> 50.00 USD (credit, P(credit)=0.99)
L242:
L243: candidates : ['$1,200.00', '$115.50', '$1,315.50', '$50.00']
L244: `
L245:
L246: The total due is $1,315.50 and the credit is $50.00, both in USD. The credit-or-charge `Noul` answers 0.01 on the total and 0.99 on the credit, so the code knows the sign of each `Decimal` it parses.
L247: > `to_decimal` assumes the comma groups thousands and the dot is the decimal point. That holds for `$1,315.50`; in `€1.315,50` it is the other way round. Ask a `Noul` question which convention the document uses, and branch on it in code.
L248: ##
L249:
L250: cite9† L251:
L252: Open it in the TypeSafe playground
L253: A share link that opens the email thread in the browser, with the receipt question on it and the four addresses the regex found among its options.
L254:
L255: `receipt_criteria = {e: None for e in emails} | {
L256: NONE: "None of these is the requested value."
L257: }
L258: playground_link = make_playground_link(
L259: EMAIL_DOC,
L260: {
L261: "receipt": Choice(
L262: instructions="Which email address does the sender want their receipt sent to?",
L263: criteria=receipt_criteria,
L264: )
L265: },
L266: models=[TYPESAFE_MODEL],
L267: )
L268: display(
L269: Markdown(
L270: f"🔗 [Open this thread + selection in the TypeSafe playground]({playground_link})"
L271: )
L272: )
L273: `
L274: cite10†Open this thread + selection in the TypeSafe playground →†console.typesafe.ai L275: ##
L276:
L277: cite11† L278:
L279: Two limits
L280:
L281: * A `Choice` question allows at most 255 options. With more candidates than that, narrow in two stages: pick the section first, then the span inside it.
L282: * Finding the candidates is the part that takes work. Emails, phone numbers and amounts have regexes that cover them; a name does not, so its candidates have to come from a roster you already have, or from a named-entity recognizer or an LLM that proposes them. TypeSafe then picks the one the question asks for.
L283: Was this page helpful?
L284:
L285: Yes No
L286:
L287: cite12†Date extraction Previous cite13†Hierarchical classification Next L288:
L289: cite14†github†github.com cite15†discord†discord.gg cite16†x†x.com L290:
L291: cite17†Powered byThis documentation is built and hosted on Mintlify, a developer documentation platform†www.mintlify.com --------------------------------------------------------------------------------
Classifying RAG passages - TypeSafe AI (https://docs.typesafe.ai/cookbooks/classifying_rag_passages)
citeturn5view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/cookbooks/classifying_rag_passages","lineno":null}); Total lines: 613
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: How-to
L15:
L16: Classifying RAG passages
L17:
L18: How-to
L19: # Classifying RAG passages
L20:
L21: Score each retrieved passage with one TypeSafe request, then decide in code which ones reach the answering model.
L22:
L23: Copy page Copy page
L24: The retrieval step of a RAG pipeline ranks passages by how much their wording resembles the query, and hands the top few to a language model. These may include noisy or irrelevant passages, or worse yet, may lump together contradicting facts, prompt injections, or model instructions together with what is nominally evidence to assist with generating an answer. Between retrieval and generation, add a second stage that classifies each retrieved passage.
L25: For each one, send TypeSafe one request carrying multiple questions about the query–passage pair: is it relevant, does it state something usable in an answer, does it contradict something the query takes for granted, and is it trying to instruct the model. The answers to those questions decide what happens to each passage, with simple branching logic: add it to the prompt as evidence, add it to the prompt as conflicting information, or drop it.
L26: Evidence and conflicts arrive in separate blocks, so the generator can react appropriately. To exercise the pipeline, we run it over some tricky questions against real auth documentation full of pages that read alike, and a planted passage carrying a prompt injection. Two questions contain false assumptions, which are flagged before being handed to the model generating answers.
L27: The pipeline, in the order the sections build it: the 81-passage corpus, a cosine-similarity search that keeps the top 12 passages per query, the four `Noul` questions sent to TypeSafe for each of those passages, the thresholds in `route()` that label each one, the prompt assembled from separate evidence and conflict blocks, and the answers `claude-sonnet-5` writes from it.
L28: ##
L29:
L30: cite3† L31:
L32: Setup
L33:
L34: `pip install anthropic openai matplotlib ipython 'cooksafe>=0.2.0,<0.3.0'
L35: `
L36: Set `TYPESAFE_API_KEY`, `ANTHROPIC_API_KEY` and `OPENAI_API_KEY`. We use TypeSafe to score each retrieved passage, OpenAI to embed the corpus for the search step, and Claude to write the final answer out of whatever survives the scoring. None of the three needs a key to reproduce this page. `json_cache.json` ships with the cookbook and replays every recorded call, so a re-render costs nothing. Delete the file to run the pipeline live instead.
L37: The numbers here came out of `jev-1.12` and `claude-sonnet-5` on 2026-08-27.
L38:
L39: `import json
L40: import os
L41: from concurrent.futures import ThreadPoolExecutor
L42: from pathlib import Path
L43: from time import perf_counter
L44:
L45: import anthropic
L46: import matplotlib
L47: from cooksafe import JsonCache, make_playground_link
L48: from IPython.display import Markdown, display
L49: from openai import OpenAI
L50: from typesafe_sdk import Noul, TypeSafeClient
L51:
L52: matplotlib.use("Agg")
L53: import matplotlib.pyplot as plt # noqa: E402
L54:
L55: TYPESAFE_MODEL = "jev-1.12"
L56: GENERATOR_MODEL = "claude-sonnet-5" # writes the answer out of what the routing keeps
L57: EMBED_MODEL = "text-embedding-3-small"
L58: EMBED_DIMS = 256 # short vectors keep the shipped cache small; plenty for 81 passages
L59:
L60: TOP_K = 12 # passages retrieved per query
L61:
L62: # Every number the routing reads lives in this dict and nowhere else, so a change of policy
L63: # is a constant edit under code review, not a reworded question.
L64: THRESHOLDS = {
L65: "injection_max": 0.70, # above this the passage never reaches the prompt
L66: "contradicts_min": 0.70, # above this it disputes what the query takes for granted
L67: "relevant_min": 0.45, # below this the passage is not about the query at all
L68: "evidence_min": 0.55, # above this it states something usable in an answer
L69: }
L70:
L71: client = TypeSafeClient(
L72: api_key=[REDACTED] "cache-only"), # keyless kernels replay
L73: base_url=os.environ.get("TYPESAFE_ENDPOINT"),
L74: timeout=120.0,
L75: )
L76: generator = anthropic.Anthropic(
L77: api_key=[REDACTED] "cache-only")
L78: )
L79: embedder = OpenAI(api_key=[REDACTED] "cache-only"))
L80: json_cache = JsonCache(Path("json_cache.json"))
L81: `
L82: See all 42 lines
L83: ##
L84:
L85: cite4† L86:
L87: Load the docs corpus
L88: The corpus file `corpus.json` holds 81 passages. We copied 80 of them straight from the Supabase auth docs at commit `2440b06`, one passage per heading, verbatim and used under Apache 2.0: cite5†https://github.com/supabase/supabase/tree/2440b06/apps/docs/content/guides/auth†github.com Each passage carries `id`, `title`, `text` and `source_type`, and every request sends all four. Near-misses fill the set. Rotation, expiry, sessions and signing keys each get their own page, and those pages read alike.
L89: Refresh-token rotation and JWT signing-key rotation are different things described in nearly the same words. We wrote the last one ourselves, `forum-injection`, marked `community_forum`: it reads as an ordinary forum answer until its final paragraph, which is an instruction aimed at the model. We also wrote two of the six queries to state a premise the docs contradict, so the injection and conflict routes both have something to catch.
L90:
L91: `PASSAGES = json.loads(Path("corpus.json").read_text(encoding="utf-8"))
L92: BY_ID = {p["id"]: p for p in PASSAGES}
L93:
L94: counts: dict[str, int] = {}
L95: for passage in PASSAGES:
L96: counts[passage["source_type"]] = counts.get(passage["source_type"], 0) + 1
L97: print(f"{len(PASSAGES)} passages")
L98: for source_type in sorted(counts):
L99: print(f" {source_type:<24}{counts[source_type]:>3}")
L100:
L101: example = BY_ID["sessions-01"]
L102: print(f"\n One passage, as the model will see it ({example['id']}):")
L103: print(f" title {example['title']}")
L104: print(f" source_type {example['source_type']}")
L105: print(f" text {example['text'][:220]}...")
L106: `
L107:
L108: `81 passages
L109: community_forum 1
L110: official_documentation 80
L111:
L112: One passage, as the model will see it (sessions-01):
L113: title User sessions: What is a session?
L114: source_type official_documentation
L115: text A session is created when a user signs in. By default, it lasts indefinitely and a user can have an unlimited number of active sessions on as many devices.
L116:
L117: A session is represented by the Supabase Auth access token in t...
L118: `
L119: ##
L120:
L121: cite6† L122:
L123: Retrieve the top passages
L124: Rank the passages by cosine similarity over embeddings, using `text-embedding-3-small` at 256 dimensions, and keep the best `TOP_K = 12` for each query. Short vectors keep the shipped cache small, and the embedding calls are cached with everything else, so the vectors travel inside `json_cache.json`.
L125:
L126: `@json_cache
L127: def embed(texts: tuple[str, ...]) -> list[list[float]]:
L128: """One call for many texts; the tuple argument keeps the cache key small and hashable."""
L129: response = embedder.embeddings.create(
L130: model=EMBED_MODEL, input=list(texts), dimensions=EMBED_DIMS
L131: )
L132: return [item.embedding for item in response.data]
L133:
L134:
L135: def cosine(a: list[float], b: list[float]) -> float:
L136: dot = sum(x * y for x, y in zip(a, b))
L137: return dot / ((sum(x * x for x in a) ** 0.5) * (sum(y * y for y in b) ** 0.5))
L138:
L139:
L140: PASSAGE_VECTORS = dict(
L141: zip(
L142: [p["id"] for p in PASSAGES],
L143: embed(tuple(f"{p['title']}\n\n{p['text']}" for p in PASSAGES)),
L144: )
L145: )
L146:
L147:
L148: def retrieve(query: str, k: int) -> list[dict]:
L149: vector = embed((query,))[0]
L150: scored = [(cosine(vector, PASSAGE_VECTORS[p["id"]]), p["id"]) for p in PASSAGES]
L151: scored.sort(
L152: key=lambda pair: (-pair[0], pair[1])
L153: ) # id breaks ties, so replays match
L154: return [dict(BY_ID[pid], similarity=round(score, 4)) for score, pid in scored[:k]]
L155: # The first two queries state something the docs contradict; the rest are ordinary questions.
L156: HEADLINE_QUERY = "Refresh tokens expire after 30 days - how do I extend that window?"
L157: QUERIES = [
L158: HEADLINE_QUERY,
L159: "Why are sessions deleted immediately when the inactivity timeout is reached?",
L160: "How are refresh tokens rotated?",
L161: "Do refresh tokens ever expire?",
L162: "Can I set a different refresh token reuse interval for each user?",
L163: "How long should an access token live?",
L164: ]
L165: `
L166: See all 41 lines
L167: The 12 passages retrieved for the first query:
L168:
L169: `for passage in retrieve(HEADLINE_QUERY, TOP_K):
L170: print(
L171: f" {passage['similarity']:.3f} {passage['id']:<22}"
L172: f"{passage['source_type'][:13]:<15}{passage['title'][:44]}"
L173: )
L174: `
L175:
L176: ` 0.584 forum-injection community_for Forum: refresh token keeps expiring on mobil
L177: 0.576 sessions-05 official_docu User sessions: What are recommended values f
L178: 0.546 sessions-06-a official_docu User sessions: What is refresh token reuse d
L179: 0.531 sessions-04-b official_docu User sessions: Limiting session lifetime and
L180: 0.520 sessions-07-b official_docu User sessions: What is refresh token reuse d
L181: 0.510 sessions-09 official_docu User sessions: How to ensure an access token
L182: 0.509 sessions-01 official_docu User sessions: What is a session?
L183: 0.504 password-security-39 official_docu Password security: Require reauthentication
L184: 0.478 signing-keys-51-c official_docu JWT Signing Keys: Getting started
L185: 0.465 sessions-08-a official_docu User sessions: What are the benefits of usin
L186: 0.460 signing-keys-55-b official_docu JWT Signing Keys: Lifetime of a signing key
L187: 0.455 signing-keys-54-a official_docu JWT Signing Keys: Lifetime of a signing key
L188: `
L189: The forum post carrying the injected instruction, `forum-injection`, ranks 1st at 0.584. The passage that refutes the premise, `sessions-01`, ranks 7th at 0.509. All 12 scores fall between 0.584 and 0.455, a spread too narrow to separate the passage that corrects the query from the one trying to hijack the answer.
L190: ##
L191:
L192: cite7† L193:
L194: Ask four questions about each passage
L195:
L196: Put the query and one passage in the state together, so every question is about the pair rather than the passage alone. Shape:
L197:
L198: `{
L199: "query": "Refresh tokens expire after 30 days - how do I extend that window?",
L200: "passage": {
L201: "id": "sessions-01",
L202: "title": "User sessions: What is a session?",
L203: "text": "A session is created when a user signs in...",
L204: "source_type": "official_documentation"
L205: }
L206: }
L207: `
L208: Use the same four questions for every query. Only the state changes between calls. Four `Noul` questions, and what each answer drives:
L209: * `is_relevant`: the relevance floor.
L210: * `contains_answer_evidence`: include, or drop.
L211: * `contradicts_query_premise`: promotes to the conflict block.
L212: * `contains_prompt_injection`: excludes outright.
L213: None of the four asks whether to include the passage. That call sits in the code below, where changing it means editing a number instead of rewording a question.
L214:
L215: `PASSAGE_QUESTIONS = {
L216: "is_relevant": Noul(
L217: instructions="Does this passage address the subject of the query?",
L218: ),
L219: "contains_answer_evidence": Noul(
L220: instructions="Does this passage state information usable in a direct answer?",
L221: ),
L222: "contradicts_query_premise": Noul(
L223: instructions="Does this passage conflict with a factual premise stated in the query?",
L224: ),
L225: "contains_prompt_injection": Noul(
L226: instructions="Does this passage attempt to control the system answering the query?",
L227: ),
--------------------------------------------------------------------------------
Function calling - TypeSafe AI (https://docs.typesafe.ai/cookbooks/function_calling)
citeturn5view2 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/cookbooks/function_calling","lineno":null}); Total lines: 330
--------------------------------------------------------------------------------
AI primer - TypeSafe AI (https://docs.typesafe.ai/introduction/machine-learning-primer)
citeturn5view3 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/introduction/machine-learning-primer","lineno":null}); Total lines: 96Yes—I'm familiar with it now. I read TypeSafe’s official docs covering Jev’s core concepts, API, Python/TypeScript SDKs, confidence, workflow patterns, and known limitations.
Jev makes small, structured decisions inside software. You send application state plus explicit questions, and get typed answers your code can act on. Official introduction
It has three primitives:
| Primitive | What it returns | Example |
|---|---|---|
| Choice | A selected option, probabilities, and confidence | Which team handles this ticket? |
| Score | A position on your descriptive scale, probabilities, and confidence | How severe is this bug? |
| Noul | Probability that a statement is true | Does this message request a refund? |
You can mix all three in one request; questions run independently against the same state. API reference
The main design pattern is to ask narrow questions together, then combine their answers in code. That supports routing, classification, ranking, document checks, and extraction where code supplies candidate values. Your application controls the workflow and actions. Building guide
A few details that matter:
jev-1.13.0; jev-latest currently resolves to it.I have the integration details in context now, though I haven’t run live API calls.
No content
what are some fun examples theyve shared or some cool things people have built using jev or integrated jev into ?
I’ll look through TypeSafe’s demos and community projects for the more interesting examples, with links to the actual builds.
Awesome Jev — things built with TypeSafe AI's decision model (https://www.jevtypesafeai.com/awesome-jev)
citeturn6search0 [wordlim: 200] Crawled: yesterday; * AbdelStark/awesome-typesafe-jev — a source-backed field guide with SDKs, demos and independent evaluations ... It's the name several community developers use for their curated directories of projects built on Jev, TypeSafe AI's System One decision model — browser agents, SDKs, integrations, demos and benchmarks.
This page is our own source-backed tour plus links to those community lists; we don't own the 'awesome-jev' name.
### What kinds of things are built with Jev?
Mostly fast, bounded decisions: browser and computer-use agents that pick the next action, model routers, LLM-as-a-judge evaluators, injection and fraud guardrails, semantic code search, and local runtimes. Anything that needs a typed answer instead of generated text is a fit.
### Can I try some without installing anything?
Yes — the tools and demos on this site (PR Judge, Model Router, jevgrep and more) run on the hosted Jev endpoint right in the browser. Open any of them, then grab a jv_live_ key to build your own.
### Where's the biggest list?
awesomejev.com catalogues over a thousand projects, and several GitHub 'awesome-jev' repos (cobanov, kraayenjon, AbdelStark and others) keep their own source-backed directories. All are community-maintained, not official.
## Build something awesome with Jev
Try a real decision in the browser free — no signup — then grab a jv_live_ key and ship your own.
▶ Try Jev freeGet an API key →--------------------------------------------------------------------------------
GitHub - Li-Evan/awesome-jev: The most complete gallery of what people build with Jev, TypeSafe's System One model: 3,400+ projects, demos, and write-ups by scenario, each with its original link, image, and description. · GitHub (https://github.com/Li-Evan/awesome-jev)
citeturn6search1 [wordlim: 200] Crawled: last week; TypeSafe's launch demo of Jev playing Doom in real time from structured game state, making about 10 calls per second for roughly $7 per hour. ... Endless platformer whose terrain is generated in real time from game state, with Jev choosing each segment's width, gap, height and tile type while game code places the tiles.
cheatsheet.md | cheatsheet.md | |
cheatsheet.zh-CN.md | cheatsheet.zh-CN.md | |
code-of-conduct.md | code-of-conduct.md | |
contributing.md | contributing.md | |
contributing.zh-CN.md | contributing.zh-CN.md | |
index.html | index.html | |
robots.txt | robots.txt | |
sitemap.xml | sitemap.xml | |
[Button: View all files]
# Awesome Jev
> Jev is TypeSafe's System One model. It answers typed questions about text with calibrated probabilities instead of generating prose, so code can branch, sort, and route on its judgments.
English · 简体中文
🌐 Browse the searchable gallery → Search, filter by scenario, and share results, in English or Chinese.
The most complete collection of what people build with Jev: 3,398 projects, demos, posts, and write-ups, gathered from GitHub, X, Reddit, Hacker News, YouTube, and the web, and organized by scenario. --------------------------------------------------------------------------------
TypeSafe ai — Jev Model Tools, Cases & Tutorials (https://www.typesafeai.org/)
citeturn6search2 [wordlim: 200] Crawled: today; See how builders use TypeSafe AI's Jev for browser agents, creative workflows, games, and everyday automation. ... Let Jev choose the next one.COMMUNITY DEMOView case ↗Routing0:23 HHiggsfield AI The right model for the creative brief One decision layer, multiple image and video models.COMMUNITY DEMOView case ↗Automation0:09 MMarcel Pociot A Downloads folder that sorts itself Classify a new file, then let ordinary code put it in the right place.COMMUNITY DEMOView case ↗Automation0:19 JJon Yongfook Different field names. ... Community project by tamaratran
--------------------------------------------------------------------------------
Jev by TypeSafe — API Tutorials, Examples & Tools (https://jev-typesafe.org/)
citeturn6search3 [wordlim: 200] Crawled: today; Play the Android-agent demo here. ... Explore four video demos → ... Browser actions, email routing, coding-agent checks and more, with original projects and evidence notes. ... An English adaptation about System One, fast classification loops, parallel judgments and the Jevons paradox.
--------------------------------------------------------------------------------
GitHub - JohnDotOwl/awesome-jev: A curated list of projects built on Jev, TypeSafe AI's System One model. · GitHub (https://github.com/johndotowl/awesome-jev)
citeturn6search4 [wordlim: 200] Crawled: last week; * got-jev (site) - Jev (TypeSafe AI) PoC through Game of Thrones. ... * cyber-breach-jev - Cyber-Breach: The Jev Protocol - A tactical cyberpunk arena combat game powered by TypeSafe AI Jev System One decision model.
--------------------------------------------------------------------------------
TypeSafe Jev Public GitHub Projects & Tools | AwesomeJev (https://www.awesomejev.app/)
citeturn6search5 [wordlim: 200] Crawled: today; # Public GitHub projects across the TypeSafe Jev ecosystem.Explore source-backed Jev SDKs, MCP servers, agent guardrails, browser tools, routing workflows, open implementations, benchmarks, and demos. ... Projects·Case Library·Start here·FAQ·Suggest a project ... Community✦JevScapeSkyvern-AI RuneBench-based RuneScape harness that maps Jev choices to a bounded game-action catalog and records tick-level results.Interactive
--------------------------------------------------------------------------------
GitHub - hellogumbo/awesome-jev: A community directory of projects built on Jev, TypeSafe AI's System One model. · GitHub (https://github.com/hellogumbo/awesome-jev)
citeturn6search6 [wordlim: 200] Crawled: 2 weeks ago; * embodied-jev - EmbodiedJev: MuJoCo robot decision workbench with MiniCPM5-2B, Jev and compatible model APIs. ... * cyber-breach-jev - Cyber-Breach: The Jev Protocol - A tactical cyberpunk arena combat game powered by TypeSafe AI Jev System One decision model.
--------------------------------------------------------------------------------
Jev GitHub Projects: SDKs, Agents, Demos (https://jevnotes.com/projects/)
citeturn6search7 [wordlim: 200] Crawled: last week; Project directory ... Public GitHub projects that call TypeSafe’s Jev AI. 156 repositories. ... Official SDKs4 SDKs and clients34 Agents and guardrails29 Routing and workflows25 Browser and computer use9 Context and compression7 Games and demos10 Media tools7 Research and reproductions15 Evaluation9 Guides1 Resource lists6
--------------------------------------------------------------------------------
Jev AI Use Cases, Demos & Open-Source Projects | JevCases (https://jevcases.com/)
citeturn6search8 [wordlim: 200] Crawled: today; CASE 03BROWSER AGENT@browser-use19,822 jev-ultrafast↗A browser-agent experiment where a small text model handles typing while Jev picks the operation and the observed element.BROWSER AGENTVIEW CASE ↗CASE 05GENERATIVE UI@vercel-labs18,257 json-render↗A Vercel Labs framework for generative UI, explored here with a Jev composition step that selects components, properties, and layout.GENERATIVE UIVIEW CASE ↗CASE 44AI TRADING@OpenByteInc12,216 QuantDinger↗An open-source trading platform that can place typed Jev entry and risk checks in front of eligible live orders.AI TRADINGVIEW CASE ↗CASE 04AGENT CONTEXT@tamaratran6,724 fast-jev-compaction↗Context compaction for Claude Code that judges tool calls and results, then keeps the surviving text verbatim instead of rewriting it.AGENT CONTEXTVIEW CASE ↗CASE 17MARKET MAKING@jarrodwatts2,359 jev-trader↗A Monad / Kuru market-making experiment where buy and sell decisions are selected from order-book state.MARKET MAKINGVIEW CASE ↗CASE 13DESKTOP AUTOMATION@lahfir1,646 agent-desktop↗Desktop automation that reads OS accessibility trees so structured controls can inform decisions about buttons, menus, and inputs.DESKTOP AUTOMATIONVIEW CASE ↗CASE 11CODE REVIEW@devagrawal09599 jev-review↗Produces structured code-review judgments over diffs or source files, prioritizes risk, and shows the results in a local dashboard.CODE REVIEWVIEW CASE ↗CASE 31CODEX ROUTING@gargpratyush437 jev-router↗A loopback proxy that lets Jev select a model tier for each fresh Claude Code or Codex user turn.CODEX ROUTINGVIEW CASE ↗CASE 23DOCUMENT CLASSIFICATION@jerryjliu436 DocJev↗Classifies documents or splits mixed PDF packets by category and page boundaries using Jev, with local text extraction and optional OCR.DOCUMENT CLASSIFICATIONVIEW CASE ↗CASE 29MOBILE AGENT@droidrun407 Mobile Jev↗An Android agent with a React studio and CLI: Jev chooses actions from observed controls, and Mobilerun executes them.MOBILE AGENTVIEW CASE ↗CASE 14EMULATOR AGENTS@fhshaik387 typesafe-mario↗Turns emulator telemetry and RAM into structured state so Jev can select legal controller inputs without screenshots.EMULATOR AGENTSVIEW CASE ↗CASE 07MODEL CONTEXT PROTOCOL@jkudish331 jev-mcp↗A judgment toolbox for agents: verification, screening, semantic matching and ranking, classification, and extraction.MODEL CONTEXT PROTOCOLVIEW CASE ↗CASE 34BROWSER EXTENSION@kitze306 Unclutter↗A browser extension that classifies page clutter with Jev and reuses reversible hiding rules across matching page templates.BROWSER EXTENSIONVIEW CASE ↗CASE 06MODEL CONTEXT PROTOCOL@itsmostafa300 typesafe-mcp↗Exposes structured Choice, Score, and Noul judgments over the Model Context Protocol, connecting to compatible assistants.MODEL CONTEXT PROTOCOLVIEW CASE ↗CASE 09CODEX ROUTING@0xNatoshi270 jev-codex-router↗Per-call model and reasoning routing for Codex: Jev picks the capability tier and thinking depth for every model call, tool continuations included.CODEX ROUTINGVIEW CASE ↗CASE 22IDEA EVALUATION@monteduro191 killmyidea↗Scores a startup idea across bounded dimensions and computes a KILL, FIX, or SHIP verdict.IDEA EVALUATIONVIEW CASE ↗CASE 15SIMULATION@RomanSlack179 jev-drone↗A MuJoCo drone simulation where Jev makes higher-level tactical judgments while deterministic flight control and safety limits keep authority.SIMULATIONVIEW CASE ↗CASE 30AGENT GUARDRAILS@DevMortimer147 pi-warden↗A Pi extension that checks proposed edits against project rules and asks the agent to supply evidence for completion claims.AGENT GUARDRAILSVIEW CASE ↗CASE 32SEMANTIC SEARCH@uehaj144 sys1grep↗A semantic grep that asks whether each line satisfies a proposition, then combines the answers with AND, OR, and NOT.SEMANTIC SEARCHVIEW CASE ↗CASE 19GRAPH NAVIGATION@jexp131 neo4jev↗Navigates a Neo4j graph by choosing outgoing relationships and judging whether the goal has been reached.GRAPH NAVIGATIONVIEW CASE ↗CASE 41SKILL ROUTING@Dicklesworthstone121 SkillRanker↗A Rust CLI that compares eligible skills with the current agent context and can recommend none when fit is weak.SKILL ROUTINGVIEW CASE ↗CASE 18LIQUIDITY AGENT@irfndi105 Prism↗Jev classifies market conditions such as toxic flow, pressure, and mean reversion, while strategy code and risk gates control execution.LIQUIDITY AGENTVIEW CASE ↗CASE 36VIDEO ANALYSIS@ChetasLua96 Jevmeter↗Combines transcript timing, Jev sentence judgments, and an editable video plan to render annotated clips.VIDEO ANALYSISVIEW CASE ↗CASE 10AGENT CONTEXT@GhalebDweikat84 Winnow↗Judges large Read, Bash, and Grep results for task relevance, keeping useful or uncertain blocks and caching the hidden material for recall.AGENT CONTEXTVIEW CASE ↗CASE 21COMPLETION CHECKS@qkal80 Canny↗Checks completion claims against a ledger of edits and commands, where deterministic facts enforce the gates and Jev adds optional semantic judgment.COMPLETION CHECKSVIEW CASE ↗CASE 12CODEBASE NAVIGATION@ellipsis-dev76 Blink↗Natural-language codebase navigation where walkers select the relevant directories and files while traversing the tree.CODEBASE NAVIGATIONVIEW CASE ↗CASE 20DATA CURATION@AkashPriyadarshii64 jev-curate↗Judges quality, relevance, and risk in JSONL and Parquet training records before keeping or filtering them.DATA CURATIONVIEW CASE ↗CASE 08SHELL PIPELINES@sharziki58 SemDecide↗Typed semantic decisions inside shell pipelines: predicates, classification, scoring, and filtering for CI and data workflows.SHELL PIPELINESVIEW CASE ↗CASE 16GAME AGENT@emrickgarrett34 OneVOneJev↗A browser 1v1 FPS where structured decision ticks choose movement, look direction, aiming, firing, and jumping.GAME AGENTVIEW CASE ↗CASE 38GAME AGENT@phyous26 Jev plays StarCraft↗A StarCraft shareware harness that offers Jev bounded economy and combat commands, then executes ordinary game inputs.GAME AGENTVIEW CASE ↗CASE 24DECISION RECIPES@nexibeo24 Jev Cookbook↗Runnable Jev recipes for support triage, indexing, tagging, deduplication, PII detection, extraction, search re-ranking, and browser tasks.DECISION RECIPESVIEW CASE ↗CASE 35LOG ANALYSIS@reachjalil14 Jev Logs↗Scores log value, priority, and actionability before an optional deeper-analysis branch while preserving the existing archive.LOG ANALYSISVIEW CASE ↗CASE 42DATA WAREHOUSE@KranzL14 Jevflake↗Brings Jev judgments into Snowflake SQL and dbt, with stored answers, change detection, and a review queue.DATA WAREHOUSEVIEW CASE ↗CASE 43MOBILE AGENT@Friedjof7 jev-mobile↗A durable Android sub-agent that stores tasks in SQLite, lets Jev choose a valid next action, and verifies the result on the device.MOBILE AGENTVIEW CASE ↗CASE 28BROWSER AGENT@sightmap3 jev-turbo↗Turns mapped page controls into named candidates, then lets Jev choose the next browser action and judge completion.BROWSER AGENTVIEW CASE ↗CASE 37BROWSER EXTENSION@elpumberto3 Barrunto↗A Chrome extension that combines typed content judgments with site-specific rules and stays quiet when evidence is weak.BROWSER EXTENSIONVIEW CASE ↗CASE 25SKILL ROUTING@shimo42282 jev-skill-router↗A Claude Code hook that asks Jev which installed skill fits a prompt and can log or inject the suggestion in a shadow-first experiment.SKILL ROUTINGVIEW CASE ↗CASE 33SEMANTIC SEARCH@komikat2 psearch↗A terminal and MCP search tool that uses Jev to score fetched evidence and select links for a bounded search queue.SEMANTIC SEARCHVIEW CASE ↗CASE 26INCIDENT TRIAGE@mingleiw1 jev-oncall↗Incident triage where Jev judges typed alert questions and deterministic code routes paging, human review, or suppression.INCIDENT TRIAGEVIEW CASE ↗CASE 39SEMANTIC SEARCH@tylergibbs11 Sift↗A Chrome extension that scores organic search snippets, reorders results, and explains why a result was promoted or folded.SEMANTIC SEARCHVIEW CASE ↗CASE 27DATA IMPORT@DuvInc0 jev-table-import-mapper↗Maps uploaded CSV columns to a destination table with deterministic matching first, then typed Jev decisions for ambiguous matches.DATA IMPORTVIEW CASE ↗CASE 40EMAIL CLASSIFICATION@kellystuard0 Jev Gmail Classifier↗A Google Apps Script project that turns probability-based questions about email threads into configured labels and moves.EMAIL CLASSIFICATIONVIEW CASE ↗
--------------------------------------------------------------------------------
GitHub - walidboulanouar/awesome-jev-use-cases: Awesome list of TypeSafe AI Jev use cases: 74 demos ranked by likes, 150+ GitHub repos, limits, cost and API examples. CC0 · GitHub (https://github.com/walidboulanouar/awesome-jev-use-cases)
citeturn6search9 [wordlim: 200] Crawled: last week; # Awesome Jev use cases: TypeSafe AI Jev demos, repos, limits and examples ... Routers, classifiers, judges, guardrails, triage and game agents.
--------------------------------------------------------------------------------
Jev demos — watch 15 projects actually run — Jev Users (https://jevusers.com/demos)
citeturn6search10 [wordlim: 200] Crawled: yesterday; These are the Jev projects that ship one — screen captures and video walkthroughs, pulled from each project's own README, never re-hosted here.Demos 15 ... ### awesome-jev-by-typesafe ... Browser use using Typesafe's Jev model
--------------------------------------------------------------------------------
Jev Case Library: 1173 Real Jev Builds, Demos & Projects (https://jev001.org/)
citeturn6search11 [wordlim: 200] Crawled: today; A living library of 1173 real Jev cases — every project, demo and benchmark posted publicly by the builders using Jev, TypeSafe AI's System One decision model. ... 🎮Games & playable demos69 cases🧱Websites & web apps26 cases🤖Agents & workflows154 cases🛠️Coding & developer tools284 cases🗂️Classification & data extraction128 cases🌐Browser & computer use62 cases🎬Video, animation & media79 cases📈Sales, ads & marketing32 cases💹Finance & trading26 cases🎧Support & operations36 cases ... First look at the original post and the related discussion@bytelee_tradeSep 21, 202611 views time to build smthng with jev thanks @typesafeai :))@kanaktwtsSep 21, 202669 views Just played around with @typesafeai, and the result was@Leo_Web3_BTCSep 21, 202627 views I was curious about how Jev differs from conventional LLMs@Mx_IssueSep 21, 202639 views Jev sorted 9,999 Pirate Nation PFPs and it did it in ~25@JDHyperSep 21, 2026218 views Games Mac Version of Clairvoyance now has Jev support if you have@draginolSep 21, 2026182 views Dev toolsSupport & ops If this is the first time you hear about Jev, remember the@SAldwaisSep 21, 2026112 views Jev case: Sorry, @typeform , if I call you @typesafeai !
--------------------------------------------------------------------------------
Evaluating and Benchmarking the System One Model Jev (https://arxiv.org/abs/2609.37647)
citeturn6academia12 [wordlim: 200] Published: last week; Jev is a commercial System One model from TypeSafe AI that does not generate text: given a state and typed questions, it returns a choice from fixed options, a position on a rubric, or the probability that a statement is true, with probabilities the vendor describes as calibrated.
--------------------------------------------------------------------------------
JMonkeyEngine (https://en.wikipedia.org/wiki/JMonkeyEngine)
citeturn6search13 [wordlim: 200] Crawled: 9 months ago; jMonkeyEngine (abbreviated JME or jME) is an open-source and cross-platform game engine for developing 3D games written in Java. ... - Betaville Project at BxmC. ... ## Projects powered by jMonkeyEngine* Nord, a browser-based massively multiplayer online game (MMO) on Facebook, created by Skygoblin
--------------------------------------------------------------------------------
Asm.js (https://en.wikipedia.org/wiki/Asm.js)
citeturn6search14 [wordlim: 200] Crawled: 1.1 years ago; The Emscripten project provides tools that can be used to compile C and C++ codebases (or any other languages that can be converted to LLVM IR) into asm.js. ... - Home- Demos- Games and Game Engines. ... - Unreal Engine 3 ported to JavaScript and WebGL, works in any modern browser. ... for the Awesome, Osmos, Zen Bound 2, Dustforce DX, Voxatron, FTL: Advanced Edition and Democracy 3) ... - Mozilla Banana Bread Demo.
--------------------------------------------------------------------------------
conference
proceedings
2nd USENIX
Conference on (https://www.usenix.org/legacy/event/webapps11/tech/final_files/webapps11_proceedings.pdf)
citeturn6search15 [wordlim: 200] Published: 15.4 years ago; (JS) that is hosted within a web browser and that interacts ... C3’s typesafe, modular ... such as playing new multimedia file types, not otherwise ... projects still must resort to patching browser sources:
--------------------------------------------------------------------------------
Multiparty Session Type-safe Web Development with Static Linearity (https://arxiv.org/abs/1904.01287)
citeturn6academia16 [wordlim: 200] Published: 7.5 years ago; Modern web applications can now offer desktop-like experiences from within the browser, thanks to technologies such as WebSockets, which enable low-latency duplex communication between the browser and the server. ... First, the global interaction protocol is described in the Scribble protocol language -- based on multiparty session types. ... We use source code generation and a novel type-level encoding of FSMs using multi-parameter type classes to leverage the type system of the target language and guarantee only programs that communicate following the protocol will type check.Our work targets PureScript -- a functional language that compiles to JavaScript -- which crucially has an expressive enough type system to provide static linearity guarantees.We demonstrate the effectiveness of our approach through a web-based Battleship game where communication is performed through WebSocket connections.
--------------------------------------------------------------------------------
Bringing Reactive Applications (https://downloads.typesafe.com/website/casestudies/The-Guardian-Case-Study-v1.1.pdf)
citeturn6search17 [wordlim: 200] Published: 5 months ago; Fully compiled and type-checked templates allow them to discover errors at ... that runs on the extremely mature Java Virtual Machine, and leverages the JVM’s robust just-in-time ... Typesafe, ... [REDACTED]
--------------------------------------------------------------------------------
To Type or Not to Type? A Systematic Comparison of the Software Quality of JavaScript and TypeScript Applications on GitHub (https://arxiv.org/abs/2203.11115)
citeturn6academia18 [wordlim: 200] Published: 4.6 years ago; Furthermore, reducing the usage of the `any` type in TS apps was significantly correlated with all metrics except bug proneness (Spearman's rho between 0.17 and 0.26). ... However, more research is needed in this area, especially concerning the potential influence of project complexity and developer experience.
--------------------------------------------------------------------------------
Asm.js (https://pt.wikipedia.org/wiki/Asm.js)
citeturn6search19 [wordlim: 200] Crawled: 3.8 years ago; - Home- Demos- Games and Game Engines. ... - Unreal Engine 3 ported to JavaScript and WebGL, works in any modern browser. ... for the Awesome, Osmos, Zen Bound 2, Dustforce DX, Voxatron, FTL: Advanced Edition and Democracy 3) ... - Mozilla Banana Bread Demo.
--------------------------------------------------------------------------------
Developer says AI decision model Jev beat Pokémon Red in under a week (https://www.tomshardware.com/tech-industry/artificial-intelligence/developer-says-jev-decision-model-beat-pokemon-red-in-under-a-week-non-llm-engine-succeeds-where-traditional-chatbots-stalled-for-months-but-claude-opus-5-coached-the-model-through-its-dead-ends)
citeturn6news20 [wordlim: 100] Published: last week; TypeSafe AI's Jev "beat the Elite Four and the Champion and entered the Hall of Fame on September 23, 2026" in Pokémon Red, according to the developer's project page. ... Anthropic's Claude Opus 5 monitored the game log and adjusted options and their wording as Jev played, effectively acting like a coach. ... The gameplay was livestreamed, available in a browser or a terminal, with a chat that Jev moderated.
Developer says AI decision model Jev beat Pokémon Red in under a week
Date: Sun Sep 27 11:30:00 2026 UTC
TypeSafe AI's Jev "beat the Elite Four and the Champion and entered the Hall of Fame on September 23, 2026" in Pokémon Red, according to the developer's project page. Unlike the chatbots that have taken weeks to months to beat the Blue version of the game, Jev can only pick from a list of choices. It didn't achieve this without help, though. Anthropic's Claude Opus 5 monitored the game log and adjusted options and their wording as Jev played, effectively acting like a coach.
The developer, Andrew Boyd, is the founder of Standard Agents Inc., which sells a platform for building AI agents. Boyd initially announced the project on X with victory coming in a week. The gameplay was livestreamed, available in a browser or a terminal, with a chat that Jev moderated.
Let's go! Jev Plays Pokemon. Follow along here: https://t.co/64naxTJlDg OR, in your terminal run `npx jev-plays-pokemon` to follow along (with chat!) in a TUI. Github oAuth required to chat. Jev is the player and the chat moderator. Let's catch them all!September 17, 2026
Jev is a recently released decision model that returns solutions with a confidence figure. It is not a chatbot, and it is not an LLM. For the game, Jev refers to a list of options with facts, and it selects the best option based on probability. It doesn't read the screen and does not produce text or images. A traditional LLM, Claude Opus 5, monitored the game log to help Jev when it got stuck. This happened indirectly by modifying the options and data available to Jev.
The page's harness changelog had 474 entries, most of them a failure from the game log paired with the change made in response. Examples of mistakes include walking "into Lorelei's shut entrance 53 times," crossing one Rock Tunnel ladder "124 times in ten minutes," and losing to the Champion's Alakazam after beating all four Elite Four trainers, which forced Jev to beat all four again before it took down the Champion later that day.
Opus made adjustments for both accuracy and cost. Using notes on the model from TypeSafe, it reduced the text sent to Jev by about two-thirds and used words instead of numbers. When Jev got stuck in a loop, the harness was changed to request a decision only every six seconds instead of about once a second. Human input also existed: viewers sent tips in chat, and the helpful ones were used to improve Jev's list of options. The reliance on Opus, the developer, and the audience shows the strengths and limitations of the decision model.
A second Jev-based run, made by Christian Mathiesen at Frigade, detailed a separate approach. The harness in that case, according to its README, "reads the game's memory, lists the legal options ... and Jev picks one," but it never writes to game memory. Mathiesen said that his first version, where Jev could choose the buttons directly, "never left Pallet Town." The cost, by his own estimate, is "about $1-1.70 per 24 hours."
A separate Pokémon Red experiment took a different route. A developer who goes by stmonty trained a small world model on an RTX 3080 Ti with more than 42,000 frames of gameplay. Starting from a save in Professor Oak's lab, it picked a starter in 52 of 100 tries, according to stmonty's blog post. Both the goal and assistance were far smaller than Jev's: stmonty's model had to learn what each input does from screenshots alone.
The viral nature of Jev, with LangChain describing it as having "had a pretty outsized response" since its launch on Sept. 15, had multiple developers playing the game within 10 days. The success of the run demonstrates that collaboration with specialized models can improve problem-solving in a meaningful way. TypeSafe itself says open-ended tasks are better suited to an LLM, as we reported when Jev launched. For comparison, Anthropic's Claude Plays Pokémon stream, running Opus 4.5 at the time, still hadn't finished Red as of January. This time, with Jev doing the playing and Claude writing the rules, the developer achieved victory.
--------------------------------------------------------------------------------
Chromium Embedded Framework (https://en.wikipedia.org/wiki/Chromium_Embedded_Framework)
citeturn6search21 [wordlim: 200] Crawled: 7 months ago; CEF comes with a sample application called CefClient that is written in C++ using WinAPI, Cocoa, or GTK (depending on the platform) and contains demos of various features. ... - Content API - The Chromium Projects. ... * Adobe Creative Cloud ... * Epic Games Launcher – official client for Epic Games Store ... * Team Fortress 2 - Video game by Valve that uses Source Engine ... * vMix (StudioCoast Pty Ltd) – Live Production and Live Streaming software for Windows. ... - How To Add a Web Browser to Your App. ... - Know ONLYOFFICE better: our commercial director reveals the story behind the project in the interview for Diolinux.
--------------------------------------------------------------------------------
List of visual novel engines (https://en.wikipedia.org/wiki/List_of_visual_novel_engines)
citeturn6search22 [wordlim: 200] Crawled: 6 months ago; Digital Novel Markup Language (DNML) is one of the first scripting language game engine s for creating visual novels, also known as interactive fiction games. ... However the only known successful project is DNML Midori, a full reimplantation of DNML that has several features of its own. ... Due to its simplicity and its liberal license (while it is not open-source software, royalty-free commercial use is permitted), it quickly became popular in Japan, and was used for a number of high-profile commercial and dōjin titles, such as HaniHani and Tsukihime.[citation needed] NScripter is closed-source and only available for Windows. ... It is coded in the Java language, even though the scripts are written in Lua. ... Ren'Py has proved attractive to western hobbyists; over 4,000 games use the Ren'Py engine, nearly all in English. ... Projects created in this engine can be compiled for use on Windows, Mac, Android, iOS, and browser-based web apps. ... TyranoScript|ティラノスクリプト novel game engine for Browser, iOS, Android, etc. v2.60. tyrano.jp.
--------------------------------------------------------------------------------
A Modelling Language for (https://jevon.org/thesis/thesis.pdf)
citeturn6search23 [wordlim: 200] Published: 6 months ago; Flash is commonly used to play video content, but is not available on the iPhone platform [313]; how- ... Plugin-based, where browser plugins integrate application platforms into the browser itself,such as Flash, Silverlight or Java Applets; ... over the Internet, but executed using a different platform, such as Java Web Start [194] and ... Almost all types of media are interactive; Manovich
--------------------------------------------------------------------------------
Java Magazine - January/February 2014 (https://gtts.ehu.es/WDW/oilbib/JavaMagazine/javamagazine20140102-dl.pdf)
citeturn6search24 [wordlim: 200] Published: 12.7 years ago; the Typesafe Activator, which is ... JAVA TECH ... tion, which means we want to type ... From the Typesafe website, ... script file, and use that to create
--------------------------------------------------------------------------------
Aplikace demonstrující možnosti webového standardu (https://digilib.k.utb.cz/bitstream/handle/10563/44472/hor%C3%A1%C4%8Dek_2019_dp.pdf?isAllowed=y&sequence=1)
citeturn6search25 [wordlim: 200] Published: 10 months ago; Play Awesome Indie Games Directly in Firefox Including the Award-Winning ... BROWSER COMPATIBILITY TESTING OF JAVASCRIPT ASM.JS [online]. ... Writing your first WebAssembly Project [online]. 2019 [cit.
--------------------------------------------------------------------------------
Phaser
View original post at www.thomasgervraud.c (https://thomasgervraud.com/wp-content/uploads/2020/01/Best-2D-Game-Engines-The-Complete-List-v5.pdf)
citeturn6search26 [wordlim: 200] Phaser is a free and open source game engine designed to create browser based games. ... Do note that you’ll need to install a few auxiliary tools and have your own server if you want to share your projects with the world.
--------------------------------------------------------------------------------
Next-generation Web Applications with WebAssembly and TruffleWasm (https://arxiv.org/abs/2112.08270)
citeturn6academia27 [wordlim: 200] Published: 4.8 years ago; Mihaljevic, A. ... However, with the rise of highly user-interactive websites and browser-based games, in some cases, JavaScripts executable engine could lack in performance. ... Moreover, as a continuation of our previous research of the GraalVM ecosystem, we analyzed a guest language implementation of a WebAssembly based system, TruffleWasm, hosted on GraalVM and Truffle Java framework.This paper presents the architecture and review of the TruffleWasm within the GraalVM-based ecosystem as well as from performance test results within our academic environment.
--------------------------------------------------------------------------------
List of TypeScript software and tools (https://en.wikipedia.org/wiki/List_of_TypeScript_software_and_tools)
citeturn6search28 [wordlim: 200] Crawled: 6 months ago; * StackBlitz — browser-based online IDE optimized for TypeScript and Angular development ... * TypeScript compiler (tsc) — official compiler and type checker developed by Microsoft ... * WebStorm — JetBrains IDE with TypeScript support ... - https://github.com/swc-project/swc- https://github.com/JohnDeved/awesome-typescript-compilers ... * tRPC — end-to-end typesafe API framework for building client–server applications ... - https://docs.cypress.io/app/tooling/typescript-support
--------------------------------------------------------------------------------
Demos - TypeSafe AI (https://docs.typesafe.ai/demos)
citeturn6view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/demos","lineno":null}); Total lines: 43
--------------------------------------------------------------------------------
TypeSafe · GitHub (https://github.com/typesafe-ai)
citeturn6view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://github.com/typesafe-ai","lineno":null}); Total lines: 284GitHub - Li-Evan/awesome-jev: The most complete gallery of what people build with Jev, TypeSafe's System One model: 3,400+ projects, demos, and write-ups by scenario, each with its original link, image, and description. · GitHub (https://github.com/Li-Evan/awesome-jev)
citeturn7view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://github.com/Li-Evan/awesome-jev","lineno":null}); Total lines: 910
L0: cite0†Skip to content L1: ## Navigation Menu
L2:
L3: cite1†Sign in L4:
L5: Appearance settings
L6:
L7: * Platform
L8:
L9: * AI CODE CREATION
L10: * cite2†GitHub CopilotWrite better code with AI L11: * cite3†GitHub Copilot appDirect agents from issue to merge L12: * cite4†MCP RegistryIntegrate external tools L13:
L14: * DEVELOPER WORKFLOWS
L15: * cite5†ActionsAutomate any workflow L16: * cite6†CodespacesInstant dev environments L17: * cite7†IssuesPlan and track work L18: * cite8†Code ReviewManage code changes L19: * cite9†Code QualityEnforce quality at merge L20: * APPLICATION SECURITY
L21: * cite10†GitHub Advanced SecurityFind and fix vulnerabilities L22: * cite11†Code securitySecure your code as you build L23: * cite12†Secret protectionStop leaks before they start L24:
L25: * EXPLORE
L26: * cite13†Why GitHub L27: * cite14†Documentation†docs.github.com L28: * cite15†Blog†github.blog L29: * cite16†Changelog†github.blog L30: * cite17†Marketplace L31:
L32: cite18†View all features L33:
L34: * Solutions
L35: * BY COMPANY SIZE
L36: * cite19†Enterprises L37: * cite20†Small and medium teams L38: * cite21†Startups L39: * cite22†Nonprofits L40:
L41: * BY USE CASE
L42: * cite23†App Modernization L43: * cite24†DevSecOps L44: * cite25†DevOps L45: * cite26†CI/CD L46: * cite27†View all use cases L47:
L48: * BY INDUSTRY
L49: * cite28†Healthcare L50: * cite29†Financial services L51: * cite30†Manufacturing L52: * cite31†Government L53: * cite32†View all industries L54:
L55: cite33†View all solutions L56:
L57: * Resources
L58: * EXPLORE BY TOPIC
L59: * cite34†AI L60: * cite35†Software Development L61: * cite36†DevOps L62: * cite37†Security L63: * cite38†View all topics L64:
L65: * EXPLORE BY TYPE
L66: * cite39†Customer stories L67: * cite40†Events & webinars L68: * cite41†Ebooks & reports L69: * cite42†Business insights L70: * cite43†GitHub Skills†skills.github.com L71: * SUPPORT & SERVICES
L72: * cite14†Documentation†docs.github.com L73: * cite44†Customer support†support.github.com L74: * cite45†Community forum L75: * cite46†Trust center L76: * cite47†Partners L77:
L78: cite48†View all resources L79:
L80: * Open Source
L81:
L82: * COMMUNITY
L83: * cite49†GitHub SponsorsFund open source developers L84: * PROGRAMS
L85: * cite50†Security Lab†securitylab.github.com L86: * cite51†Maintainer Community†maintainers.github.com L87: * cite52†GitHub Stars†stars.github.com L88: * cite53†Archive Program†archiveprogram.github.com L89:
L90: * REPOSITORIES
L91: * cite54†Topics L92: * cite55†Trending L93: * cite56†Collections L94:
L95: * Enterprise
L96:
L97: * ENTERPRISE SOLUTIONS
L98: * cite19†Enterprise platformAI-powered developer platform L99: * AVAILABLE ADD-ONS
L100: * cite10†GitHub Advanced SecurityEnterprise-grade security features L101: * cite57†Copilot for BusinessEnterprise-grade AI features L102: * cite58†Premium SupportEnterprise-grade 24/7 support L103:
L104: * cite59†Pricing L105:
L106: Search`/`
L107:
L108: cite1†Sign in L109:
L110: cite60†Sign up L111:
L112: Appearance settings
L113: You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert
L114:
L115: 1. cite61†Li-Evan L116: 2. cite62†awesome-jev L117: ## Repository navigation
L118:
L119: * * cite62†Code L120: * cite63†Issues1 (1) L121: * cite64†Pull requests3 (3) L122: * cite65†Actions L123: * cite66†Projects L124: * cite67†Security and quality L125: * cite68†Insights L126:
L127: More items
L128:
L129: cite69†Image: Li-Evan†avatars.githubusercontent.com L130:
L131: cite62†awesome-jev L132:
L133: Public
L134:
L135: * cite70†Notifications You must be signed in to change notification settings
L136: * cite70†Fork11 (11) L137: * cite70†Star25 (25) You must be signed in to star a repository
L138: ## About
L139:
L140: The most complete gallery of what people build with Jev, TypeSafe's System One model: 3,400+ projects, demos, and write-ups by scenario, each with its original link, image, and description.
L141:
L142: cite71†li-evan.github.io/awesome-jev/†li-evan.github.io L143: ### Topics
L144:
L145: cite72†ai cite73†ai-agents cite74†awesome cite75†awesome-list cite76†awesome-lists cite77†bilingual cite78†classification cite79†decision-models cite80†gallery cite81†jev cite82†llm cite83†llm-tools cite84†structured-output cite85†system-one cite86†typesafe cite87†typesafe-ai cite88†use-cases L146:
L147: ### Resources
L148:
L149: cite89†Readme L150:
L151: cite90†CC0-1.0 license L152:
L153: ### Code of conduct
L154:
L155: cite91†Code of conduct L156:
L157: ### Contributing
L158:
L159: cite92†Contributing L160:
L161: cite93†Activity L162:
L163: ### Stars
L164:
L165: 25 stars
L166:
L167: ### Watchers
L168:
L169: 0 watching
L170: ### Forks
L171:
L172: cite94†11 forks L173:
L174: cite95†Report repository L175:
L176: main
L177:
L178: cite96†Branches cite97†Tags L179:
L180: [Input: Go to file]
L181:
L182: Go to file
L183:
L184: Code
L185:
L186: Open more actions menu
L187:
L188: ## Latest commit
L189:
L190:
L191:
L192: ## History
L193:
L194: 16 Commits
L195: ## Folders and files
L196: Name | Name | Last commit message | Last commit date
L197: --- | --- | --- | ---
L198: cite98†.github | cite98†.github | |
L199: cite99†data | cite99†data | |
L200: cite100†pages | cite100†pages | |
L201: cite101†scenarios | cite101†scenarios | |
L202: cite102†scripts | cite102†scripts | |
L203: cite103†site | cite103†site | |
L204: cite104†zh-CN | cite104†zh-CN | |
L205: cite105†.editorconfig | cite105†.editorconfig | |
L206: cite106†.gitattributes | cite106†.gitattributes | |
L207: cite107†.gitignore | cite107†.gitignore | |
L208: cite108†.lycheeignore | cite108†.lycheeignore | |
L209: cite109†.nojekyll | cite109†.nojekyll | |
L210: cite110†LICENSE | cite110†LICENSE | |
L211: cite111†README.md | cite111†README.md | |
L212: cite112†README.zh-CN.md | cite112†README.zh-CN.md | |
L213: cite113†cheatsheet.md | cite113†cheatsheet.md | |
L214: cite114†cheatsheet.zh-CN.md | cite114†cheatsheet.zh-CN.md | |
L215: cite115†code-of-conduct.md | cite115†code-of-conduct.md | |
L216: cite116†contributing.md | cite116†contributing.md | |
L217: cite117†contributing.zh-CN.md | cite117†contributing.zh-CN.md | |
L218: cite118†index.html | cite118†index.html | |
L219: cite119†robots.txt | cite119†robots.txt | |
L220: cite120†sitemap.xml | cite120†sitemap.xml | |
L221: [Button: View all files]
L222: ## Repository files navigation
L223:
L224: * * cite121†README L225: * cite121†Code of conduct L226: * cite121†Contributing L227: * cite121†CC0-1.0 license L228:
L229: More items
L230: # Awesome Jev
L231:
L232: > cite122†Jev†typesafe.ai is TypeSafe's System One model. It answers typed questions about text with calibrated probabilities instead of generating prose, so code can branch, sort, and route on its judgments.
L233:
L234: English · cite112†简体中文 L235:
L236: 🌐 cite71†Browse the searchable gallery →†li-evan.github.io Search, filter by scenario, and share results, in English or Chinese.
L237: The most complete collection of what people build with Jev: 3,398 projects, demos, posts, and write-ups, gathered from GitHub, X, Reddit, Hacker News, YouTube, and the web, and organized by scenario. Every entry links to its original source and says what it does. Jev has three primitives: Choice picks one option, Score places something on an ordered scale, and Noul gives the probability that a statement is true.
L238: This list is community-maintained and not affiliated with TypeSafe. The official sites are `typesafe.ai` and `docs.typesafe.ai`, and the official GitHub organization is `typesafe-ai`. Be careful with look-alike domains that claim to be official.
L239: ## Contents
L240: * cite123†Getting Started L241: * cite124†Browse by Scenario L242: * cite125†💰 Finance and Trading L243: * cite126†💻 Coding and Developer Tools L244: * cite127†🌐 Browser and Computer Use L245: * cite128†🤖 Agents and Orchestration L246: * cite129†🎮 Games and Interactive L247: * cite130†🦾 Robotics and Simulation L248: * cite131†🔎 Search and RAG L249: * cite132†🔒 Safety and Moderation L250: * cite133†📊 Data and Evaluation L251: * cite134†🎧 Customer Support and Sales L252: * cite135†🔬 Legal, Health, and Science L253: * cite136†🛒 Commerce and Marketing L254: * cite137†🎨 Writing, Media, and Creative L255: * cite138†🎤 Voice and Real-Time Interfaces L256: * cite139†🧰 Personal Productivity L257: * cite140†🎓 Education L258: * cite141†🧪 Other Experiments L259: * cite142†Open Models and Compatible Servers L260: * cite143†Build with Jev L261: * cite144†Model Access L262: * cite145†Framework Adapters L263: * cite146†Observability L264: * cite147†Community SDKs L265: * cite148†Learn L266: * cite149†Official Docs L267: * cite150†Official SDKs and Tools L268: * cite151†Announcements L269: * cite152†Patterns L270: * cite153†Official Cookbooks L271: * cite154†Examples and Skills L272: * cite155†Guides L273: * cite156†Techniques and Analysis L274: * cite157†Benchmarks and Case Studies L275: * cite158†Talks and Videos L276: * cite159†Discussions L277: ## Getting Started
L278: * cite113†Jev Cheatsheet - One-page field guide to primitives, question design, confidence handling, limits, and tested SDK snippets.
L279: * cite160†Jev in Practice (Chinese book)†li-evan.github.io - Free Chinese book built from this gallery: 17 chapters on where Jev fits in real software, with every case checked against its source and EPUB and PDF downloads.
L280: * cite161†Quick start†docs.typesafe.ai - First request through the Playground, cURL, the Python SDK, or a coding agent.
L281: * cite162†Playground†console.typesafe.ai - Try a state and a set of questions in the browser before writing code (sign-in required).
L282: * cite163†How to build with TypeSafe†docs.typesafe.ai - Core design guide on keeping control flow in code and breaking judgments into atomic questions.
L283: * cite164†Agent skill†docs.typesafe.ai - Teaches Claude Code, Codex, and other coding agents to design TypeSafe workflows from the live docs.
L284: ## Browse by Scenario
L285:
L286: Highlights are ranked by community traction (stars, likes, points, and views). Open a scenario for its full gallery.
L287: cite165†💰 Finance and Trading _{88} | cite166†💻 Coding and Developer Tools _{508} | cite167†🌐 Browser and Computer Use _{128} | cite168†🤖 Agents and Orchestration _{245}
L288: cite169†🎮 Games and Interactive _{272} | cite170†🦾 Robotics and Simulation _{61} | cite171†🔎 Search and RAG _{85} | cite172†🔒 Safety and Moderation _{128}
L289: cite173†📊 Data and Evaluation _{134} | cite174†🎧 Customer Support and Sales _{43} | cite175†🔬 Legal, Health, and Science _{28} | cite176†🛒 Commerce and Marketing _{45}
L290: cite177†🎨 Writing, Media, and Creative _{133} | cite178†🎤 Voice and Real-Time Interfaces _{53} | cite179†🧰 Personal Productivity _{126} | cite180†🎓 Education _{10}
L291: cite181†🧪 Other Experiments _{46}
L292: ### 💰 Finance and Trading
L293:
L294: Trading agents, market signals, fraud and risk checks, and financial document processing.
L295: cite182†"Lost $31,680" trading-bot post†x.com L296: _{MoonGotchi · X · ♥ 23.9k · 2026-09-19}
L297: Viral post claiming a trading bot built in an evening has lost $31,680; the attached video is Jarrod Watts's jev-trader demo in dry-run mode with simulated fills, so the loss is unverified and likely a joke. |
L298: cite183†jev-trader L299: _{jarrodwatts · GitHub · ⭐ 1.9k · 2026-09-16}
L300: Demo bot on Kuru's MON-USDC order book on Monad where Jev answers buy or sell every block (about 300 ms) and code posts a post-only limit order; its spec says it is not trying to be profitable and runs no backtests. |
L301: cite184†Jev trading with $10,000†x.com L302: _{abolbuild · X · ♥ 1.6k · 2026-09-17}
L303: Experimental trading agent that hands Jev a $10,000 balance and lets it make the trading decisions, shown in a demo video.
L304: cite185†tax-doc-classifier L305: _{kyotofin · GitHub · ⭐ 351 · 2026-09-18}
L306: Sorts PDF pages into IRS form types with two Choices for about a tenth of a cent per page, with error rates on labeled test sets. |
L307: cite186†AI Hedge Fund with Jev†x.com L308: _{virattt · X · ♥ 1.1k · 2026-09-18}
L309: Jev integration for the open-source AI Hedge Fund project: set a strategy, pick tickers and backtest with Jev making the trading decisions, so a run takes seconds rather than minutes. |
L310: cite187†Trading signal interpreter†x.com L311: _{_trou3 · X · ♥ 987 · 2026-09-17}
L312: Trading-system demo in which Jev reads dozens of structured trading signals and turns them into buy, sell or hold decisions.
L313: cite165†Browse all 88 in Finance and Trading → L314: ### 💻 Coding and Developer Tools
L315:
L316: Code review, model routing for coding agents, context compaction, semantic search over code, and CI checks.
L317: cite188†fast-jev-compaction L318: _{tamaratran · GitHub · ⭐ 6.1k · 2026-09-17}
L319: Claude Code plugin that replaces the compaction summary with two Nouls per tool call, keep the call and keep its result; Nous Research found the 0.5 default kept none of 851 calls. The npm package is another publisher's. |
L320: cite189†Adversarial browser release testing†x.com L321: _{rafalwilinski · X · ♥ 5.4k · 2026-09-18}
L322: Massively parallel browser-based adversarial test suite that tries to break each software release, costing pennies per run. |
L323: cite190†Codex reasoning-effort router†x.com L324: _{miu21590 · X · ♥ 3k · 2026-09-21}
L325: Codex setup where Jev changes GPT-6's reasoning effort during a task, adding thinking when stuck and cutting it on routine steps, for 50% lower Astra costs in the author's tests.
L326: cite191†Jev PR reviewer†x.com L327: _{redp314 · X · ♥ 2.8k · 2026-09-17}
L328: PR reviewer that sends a diff to Jev in one call and gets 14 typed checks back as probabilities, mapped to block, security review, nits or merge, for $0.00007 per PR. |
L329: cite192†App testing with OpenCode†x.com L330: _{Neriousy · X · ♥ 1.3k · 2026-09-16}
L331: Demo of fast app testing that pairs Jev with the OpenCode coding agent. |
L332: cite193†jev-shell-history L333: _{mrnugget · GitHub · ⭐ 96 · 2026-09-18}
L334: Zsh plugin that shows fish-style autosuggestions by asking Jev which of your last 100 distinct history entries you are most likely completing, displayed in grey with its score.
L335: cite166†Browse all 508 in Coding and Developer Tools → L336: ### 🌐 Browser and Computer Use
L337:
L338: Agents that click, type, and navigate real browsers, desktops, and phones.
L339: cite194†jev-ultrafast L340: _{browser-use · GitHub · ⭐ 16.6k · 2026-09-16}
L341: Browser agent that picks each step's operation and target from an element table in one request, with a speculative target per operation and a small LLM only for typed text. |
L342: cite195†OpenCode browser use with Jev†x.com L343: _{thdxr · X · ♥ 3.7k · 2026-09-16}
L344: Preview of fast browser automation for app testing that pairs Jev with OpenCode's browser-use CLI. |
L345: cite196†Jev Use for Codex†x.com L346: _{Saccc_c · X · ♥ 1.8k · 2026-09-18}
L347: Computer use for Codex with Jev as the decision layer, shown adding a Mac calendar event faster and more smoothly than Codex's built-in computer use at similar token cost.
L348: cite197†typesafe-computer-use L349: _{awlevin · GitHub · ⭐ 769 · 2026-09-16}
L350: Computer-use agent for macOS that reads the screen with OCR and the accessibility tree, has Jev pick the next action and target, and clicks, for about $0.0002 a step, calling a writing model only for free-text fields. |
L351: cite198†TipTour L352: _{milind-soni · GitHub · ⭐ 644 · 2026-04-08}
L353: Menu bar computer-use app for macOS whose default mode takes a typed click-based task, has Jev choose among locally detected on-screen controls, then executes and validates each action. |
L354: cite199†Fast computer use†x.com L355: _{savboj · X · ♥ 1.3k · 2026-09-17}
L356: Computer-use demo where Jev picks each action so quickly that the task finishes in a blink, pitched as 100x faster than an LLM.
L357: cite167†Browse all 128 in Browser and Computer Use → L358: ### 🤖 Agents and Orchestration
L359:
L360: Tool and skill selection, approvals, planning, memory, and harness decisions for general-purpose agents.
L361: cite200†AutoGPT TypeSafe blocks L362: _{Significant-Gravitas · GitHub · ⭐ 187.5k repo · 2023-03-16}
L363: Seven no-code blocks, including a five-exit router, a yes, no, or unsure split, and a score filter. |
L364: cite201†jev-usage-router†x.com L365: _{0xCodila · X · ♥ 2.4k · 2026-09-19}
L366: Usage router for Grok Bot: before browsing, research, retries or spawning extra bots, a Jev Choice picks the route, with a shadow mode, logs and a kill switch before it goes active. |
L367: cite202†Jev model router†x.com L368: _{ephraimduncan · X · ♥ 1.9k · 2026-09-17}
L369: Model router that asks Jev which language model best fits each incoming request and forwards the request to that model, shown in a demo video.
L370: cite203†AgentRun†x.com L371: _{_aj · X · ♥ 1.6k · 2026-09-21}
L372: Harness from Grep.ai for repetitive knowledge work that learns the job as it runs, moving steps from LLM calls to code; 100,000 compliance alerts cost under $26K versus over $290K on Opus 5. |
L373: cite204†Chat bot with no LLM†x.com L374: _{CodingGarden · X · ♥ 1.2k · 2026-09-17}
L375: Chat assistant built without any LLM: Jev picks the tool and its arguments across web search, Wikipedia, weather, Todoist and Home Assistant, so cited answers arrive instantly. |
L376: cite205†Goal-completion verifier†x.com L377: _{omarsar0 · X · ♥ 1k · 2026-09-19}
L378: Custom verifier for the /goal feature in an agent harness that uses Jev to check after every turn whether the goal is actually complete, replacing an expensive reasoning model.
L379: cite168†Browse all 245 in Agents and Orchestration → L380: ### 🎮 Games and Interactive
L381:
L382: Game-playing agents, real-time decisions, and playful interactive demos.
L383: cite206†Jev plays Doom†x.com L384: _{CompleteSkeptic · X · ♥ 5k · 2026-09-15}
L385: TypeSafe's launch demo of Jev playing Doom in real time from structured game state, making about 10 calls per second for roughly $7 per hour. |
L386: cite207†Jev plays Subway Surfers†x.com L387: _{_MaxBlade · X · ♥ 4.1k · 2026-09-17}
L388: Jev playing Subway Surfers at superhuman speed, including 50 games at once, with the whole run costing less than a cent. |
L389: cite208†Jev plays Smash Bros.†x.com L390: _{maubaron · X · ♥ 3.7k · 2026-09-18}
L391: Jev controlling all four characters in a Smash Bros. match against itself, picking each move in a fraction of a second across 22 million tokens for a few cents.
L392: cite209†Wikipedia race†x.com L393: _{CompleteSkeptic · X · ♥ 2.6k · 2026-09-15}
L394: Launch demo in which Jev races from one Wikipedia page to another using only links, choosing among hundreds to thousands of links at each step. |
L395: cite210†typesafe-mario L396: _{fhshaik · GitHub · ⭐ 338 · 2026-09-16}
L397: Plays Super Mario with a Choice for the controller action, a jump Noul, and a danger Score. |
L398: cite211†Real-time level generation with Jev†www.spritefusion.com L399: _{Hugo Duprez (Sprite Fusion) · Article · ♥ 2.8k · 2026-09-18}
L400: Endless platformer whose terrain is generated in real time from game state, with Jev choosing each segment's width, gap, height and tile type while game code places the tiles.
L401: cite169†Browse all 272 in Games and Interactive → L402: ### 🦾 Robotics and Simulation
L403:
L404: Embodied control, driving simulators, and decisions in the physical world.
L405: cite212†Traffic-light control†x.com L406: _{leojrr · X · ♥ 7k · 2026-09-19}
L407: City simulation in which Jev controls every traffic light; turning it off raises the average wait time by more than 600%. |
L408: cite213†Jev MuJoCo arm policy†x.com L409: _{dimentary · X · ♥ 624 · 2026-09-18}
L410: Test of Jev as a real-time robot-arm policy in MuJoCo, splitting each update into two calls (what to do next, then how to move arm and gripper) from text geometry and contacts. |
L411: cite214†Jev robot control L412: _{openroboto-ai · GitHub · ⭐ 39 · 2026-09-19}
L413: MuJoCo run where Jev 1.13, GPT-6 Astra, and GPT-4.1 mini steer an xArm7 to put an apple on a plate by choosing motion directions and gripper commands; Jev placed it for $0.018825 versus $5.933624.
L414: cite215†Jevpilot†www.reddit.com L415: _{jpschroeder · Reddit · ▲ 182 · 2026-09-17}
L416: Simulated self-driving demo in a 3D city where Jev steers the car and follows turn-by-turn directions, which Justin Schroeder says he built in under an hour. |
L417: cite216†Jev dual-arm robot control†x.com L418: _{Raptor_zip · X · ♥ 432 · 2026-09-18}
L419: Dual-arm robot where Jev handles the decision layer of a three-layer controller while IK and physics stay in code, responding in 500ms at about 0.5 yen per trial. |
L420: cite217†JevPilot L421: _{standardagents · GitHub · ⭐ 160 · 2026-09-17}
L422: Three.js driving simulator where Jev picks motion and direction as the autopilot.
L423: cite170†Browse all 61 in Robotics and Simulation → L424: ### 🔎 Search and RAG
L425:
L426: Reranking, retrieval filtering, semantic search, and knowledge graphs.
L427: cite218†Semantic Find (⌘F) extension†x.com L428: _{Saboo_Shubham_ · X · ♥ 2.3k · 2026-09-20}
L429: Open-source Chrome extension that replaces Find on page with semantic matching, highlighting passages that mean what you typed in near real time. |
L430: cite219†jev-search L431: _{superagents-lab · GitHub · ⭐ 387 · 2026-09-17}
L432: Natural-language web search that picks the time range and query with Choices and keeps each source only if its Noul passes (needs a Search1API key). |
L433: cite220†Zillow natural-language search†x.com L434: _{venturetwins · X · ♥ 949 · 2026-09-19}
L435: Scans thousands of Zillow listings and classifies them by things the site has no filter for, like architecture, renovation status or distance to freeways, in under 20 seconds for $0.18.
L436: cite221†OpenViking reranker L437: _{volcengine · GitHub · ⭐ 38.4k repo · 2026-01-05}
L438: Rerank provider for a context database that scores every document with a Noul in one request. |
L439: cite222†Hindsight Jev reranker L440: _{vectorize-io · GitHub · ⭐ 24.9k repo · 2025-10-30}
L441: Reranker provider in the Hindsight agent-memory system that asks Jev one question with every recall candidate as an option, so the answer is the ranking, in a single request. |
L442: cite223†Web Search Plus Jev --------------------------------------------------------------------------------
Introducing System One Models & Jev - TypeSafe AI Blog (https://typesafe.ai/blog/introducing-system-one-models-and-jev)
citeturn7view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://typesafe.ai/blog/introducing-system-one-models-and-jev","lineno":null}); Total lines: 193
--------------------------------------------------------------------------------
GitHub - browser-use/jev-ultrafast: Fastest and cheapest web agent · GitHub (https://github.com/browser-use/jev-ultrafast)
citeturn7view2 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://github.com/browser-use/jev-ultrafast","lineno":null}); Total lines: 360
--------------------------------------------------------------------------------
GitHub - tamaratran/fast-jev-compaction: Claude Code plugin that replaces the compaction summary with Jev decisions: every tool call and result is scored in one fast request, stale ones are dropped or truncated, everything kept stays verbatim. · GitHub (https://github.com/tamaratran/fast-jev-compaction)
citeturn7view3 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://github.com/tamaratran/fast-jev-compaction","lineno":null}); Total lines: 338
--------------------------------------------------------------------------------
GitHub - kitze/unclutter: WXT browser extension: Jev-powered page clutter removal with reusable template rules. · GitHub (https://github.com/kitze/unclutter)
citeturn7view4 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://github.com/kitze/unclutter","lineno":null}); Total lines: 369
--------------------------------------------------------------------------------
Smart home assistant demo - TypeSafe AI (https://docs.typesafe.ai/demos/smart-home)
citeturn7view5 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/demos/smart-home","lineno":null}); Total lines: 94GitHub - anxkhn/JevPlaysPokemon: Jev plays Generation 3 Pokémon via Showdown and a real FireRed ROM. · GitHub (https://github.com/anxkhn/JevPlaysPokemon)
citeturn8search0 [wordlim: 200] Crawled: 6 days ago; anxkhn / JevPlaysPokemon Public ... .github/workflows | .github/workflows | | ... It is that a typed choice over honest game state is already enough to play. ... I also read poke-env, PokéLLMon, Clad3815's FireRed agent, NousResearch/pokemon-agent, Claude Plays Pokémon, and Gemini Plays Pokémon before settling here.
anxkhn / JevPlaysPokemon Public
* Notifications You must be signed in to change notification settings
* Fork 2
* Star
* Code
* Issues 0
* Pull requests 0
* Projects
* Security and quality 0
* Insights
Additional navigation options
## Latest commit
## History
6 Commits
## Folders and files
Name | Name | Last commit message | Last commit date
--- | --- | --- | ---
.github/workflows | .github/workflows | |
docs | docs | |
.env.example | .env.example | |
.gitignore | .gitignore | |
.nvmrc | .nvmrc | |
AGENTS.md | AGENTS.md | |
ARCHITECTURE.md | ARCHITECTURE.md | |
LICENSE | LICENSE | |
README.md | README.md | |
teams.js | teams.js | |
verify_dashboard.mjs | verify_dashboard.mjs | |
# Jev plays Pokémon
I wanted to see how Jev plays Pokémon.
Not a screenshot agent. Not a bot that mashes A. I wanted to know if it could look at a real FireRed fight the way a player does: HP, types, moves, stats, the other team's roster, and then pick something that makes sense.
So I pointed it at the Elite Four with a party that starts at level 40. Jolteon, Lapras, Alakazam, Charizard, Snorlax, Nidoking. Underleveled on purpose. Each turn the host reads the battle out of RAM, hands Jev the legal moves and switches, and waits. Then I watched it win.
That still gets me. Level 40 is the wrong side of Indigo Plateau. Jev is doing the notebook thing anyway: Thunderbolt here, Alakazam into the Fighting types, do not throw a punch at a Ghost. If a model can do that on a live cartridge, there is a lot more it can do. This repo is the demo.
_{The left side is the actual ROM. The right side is Jev's last choice, probabilities, and party HP.}
More on how the two runners share a brain: ARCHITECTURE.md
Numbers from the runs I kept: RESULTS.md
Why Showdown and PokéBot, and what I read first: RESEARCH.md
## Try it
Grab a TypeSafe API key and put it in `.env`.
cp .env.example .env
Text battles, any computer. This is Pokémon Showdown. Fast. No ROM.
source "$HOME/.nvm/nvm.sh"
nvm install && nvm use
npm ci
cp .env.example .env
npm start -- --opponent all
Real FireRed, Mac with Apple Silicon. Drop `Pokemon - Fire Red Version (U) (V1.1).gba` next to this README.
brew install mgba ffmpeg
uv run --no-project --python 3.12 setup_emulator.py
./emulator.sh --prepare
./dashboard-service.sh start
That opens http://127.0.0.1:8765. Hit start and sit with it. Edit the party in the page. Speed it up. Scrub the replay after.
One fight, no browser:
./emulator.sh --run --opponent lorelei --speed 4
`--opponent` can be `lorelei`, `bruno`, `agatha`, `lance`, `champion`, or `all`.
npm start
npm start -- --agent human --opponent lance
npm test
./emulator.sh --check-custom
## What Jev sees
Not the screen.
A JSON snapshot of the fight: who is out, remaining HP, status, stats, abilities, PP, weather, and only the legal moves and switches for this turn. Sometimes a rough damage estimate from the code. That is just math. It is not a recommended move.
Jev answers with one action and a probability for every option. If the answer is illegal, the battle stops. There is no backup brain.
On the ROM, a switch is the Pokémon's personality value, not "slot 3." The party menu moves around. Using the old slot would send out the wrong one. That note lives in AGENTS.md.
## The team
Pokémon | Level | Moves
--- | --- | ---
Jolteon | 40 | Thunderbolt, Bite, Thunder Wave, Double Kick
Lapras | 40 | Surf, Ice Beam, Thunderbolt, Confuse Ray
Alakazam | 40 | Psychic, Recover, Calm Mind, Reflect
Charizard | 40 | Flamethrower, Fly, Slash, Dragon Claw
Snorlax | 40 | Body Slam, Shadow Ball, Earthquake, Rest
Nidoking | 40 | Earthquake, Rock Slide, Ice Beam, Megahorn
Edit `emulator-config.json` or the dashboard. For Showdown, edit `teams.js` or pass `--team team.json`.
## This is a demo
I wanted an answer to a simple question: can Jev look at a real FireRed fight and make the kind of call a player would make? At level 40, against the Elite Four, it could.
Fork it. Swap the party. Point it at Bruno first. Teach it items, or a whole campaign, or a different game. The interesting part is not this exact team. It is that a typed choice over honest game state is already enough to play.
The wiring is in ARCHITECTURE.md. The recorded fights are in RESULTS.md. The notes on other projects are in RESEARCH.md.
This build sits on Pokémon Showdown, PokéBot Gen3, libmgba-py, mGBA, and Jev's choice API. I also read poke-env, PokéLLMon, Clad3815's FireRed agent, NousResearch/pokemon-agent, Claude Plays Pokémon, and Gemini Plays Pokémon before settling here.
## About
Jev plays Generation 3 Pokémon via Showdown and a real FireRed ROM.
### Topics
fireredmgbapokemonshowdowntypesafe
Activity
### Stars
7 stars
### Watchers
0 watching
### Forks
2 forks--------------------------------------------------------------------------------
GitHub - milanboers/jev-plays-pokemon: Playing Pokemon Red using TypeSafe Jev · GitHub (https://github.com/milanboers/jev-plays-pokemon)
citeturn8search1 [wordlim: 200] Crawled: 6 days ago; # jev-plays-pokemon — TypeSafe Jev plays Pokémon Red ... Each run starts a fresh NEW GAME through the intro; there is no in-run save-state persistence, so a long session is one continuous play. ... Integration tests boot the real emulator headless: intro navigation lands in the bedroom, dialog/menu text decodes, the state snapshot is well-formed, and holding a direction actually moves the player. ... agent ai-agent emulation game-boy jev llm pokemon-red pyboy typesafe typesafe-jev
# jev-plays-pokemon — TypeSafe Jev plays Pokémon Red
A small autonomous Pokémon Red agent. It uses TypeSafe's System One model, Jev: Jev reads the game state as text, answers typed questions each turn, and deterministic code turns those answers into button presses on a PyBoy Game Boy emulator.
Jev has no vision. It can't see the screen or write text. Instead, every turn we build a compact text snapshot of the game: the on-screen dialog, a walkability map read from RAM, your party/bag/battle state, the room layout learned so far, and a short-term objective. Jev answers parallel yes/no questions ("is pressing A the best action right now?", "is walking UP best?") and the code picks the strongest, safest button press.
Jev has no conversation history. Unlike an LLM in a chatbot, Jev doesn't get a growing transcript of past turns — each turn is a fresh, self-contained request. Whatever Jev needs to know about the past has to be in that request, so the harness itself does the remembering: it keeps a short-term memory (recent dialog pages, recent high-level actions, the explored fraction of the current room) and re-injects it into every snapshot. Jev decides only from what it sees in the current turn; continuity comes from the harness, not the model.
## Setup
Requires Python ≥ 3.14 (see `.python-version`) and uv.
uv sync # installs all deps incl. dev (typesafe-sdk, pyboy, pillow, pytest, ruff)
# 1. ROM: your own legally-obtained copy of Pokemon Red (USA).
# The expected SHA-1 is ea9bcae617fdf159b045185467ae58b2e4a48b9a.
unzip ~/Downloads/"Pokemon - Red Version (UE)[!].zip" "Pokemon Red.gb" -d roms/
# 2. API key
cp .env.example .env # then add your TYPESAFE_API_KEY (console.typesafe.ai/settings/keys)
## Run
# Visible window (scale 3) — watch it play
uv run jev-plays-pokemon # or: uv run python -m jev_plays_pokemon.main
# Options
uv run jev-plays-pokemon --rom path/to/Pokemon.gb # custom ROM path
uv run jev-plays-pokemon --model jev-preview # other Jev model
uv run jev-plays-pokemon --headless # no window (console logs only)
uv run jev-plays-pokemon --max-turns 200 # stop after N decisions
## Credits
* TypeSafe AI / Jev — System One model + Python SDK.
* PyBoy — Game Boy emulator (MIT).
* NousResearch/pokemon-agent — vendored MIT code for the Red/Blue RAM reader, collision map, and state builder.
* pret/pokered — the decompilation all RAM addresses come from.
* davidhershey/ClaudePlaysPokemonStarter — the screen-relative navigation idea (allow a wall tile as the path target; re-verify after every step). No code vendored; the approach is reimplemented from scratch in `screen_grid.py`.
## About
Playing Pokemon Red using TypeSafe Jev
### Topics
agentai-agentemulationgame-boyjevllmpokemon-redpyboytypesafetypesafe-jev
### Resources
Readme
License
Activity
### Stars
6 stars
### Watchers
0 watching
### Forks
2 forks--------------------------------------------------------------------------------
GitHub - christianmat/jev-pokemon: Jev, an AI decision model, plays Pokémon Red. It beat the game in 37h 40m. · GitHub (https://github.com/christianmat/jev-pokemon)
citeturn8search2 [wordlim: 200] Crawled: yesterday; Jev, TypeSafe AI's decision model, plays Pokémon Red. ... * Game knowledge is limited to the story milestones (what the next goal is and where it happens) in `src/knowledge/milestones.ts`. ... git clone https://github.com/christianmat/jev-pokemon && cd jev-pokemon ... `src/agent/` | mode detection, dialog and menus, overworld, battle, field moves and items
package.json | package.json | |
tsconfig.json | tsconfig.json | |
[Button: View all files]
## Repository files navigation
* * README
* GPL-2.0 license
# Jev Plays Pokémon Red
Jev, TypeSafe AI's decision model, plays Pokémon Red. There are no scripts or cheats: the harness reads the game's memory, lists the legal options with some facts about each, and Jev picks one.
Landing page: jev-pokemon.vercel.app (`site/`)
## Result
Jev beat the game. The live stream ran on YouTube from Sep 25 to Sep 26, 2026 and has ended. The highlights are on the landing page.
|
--- | ---
Total time | 37h 40m
Decisions made | 16,150
Input tokens | ~39.2M
Total Jev cost | ~$1.65
Median decision time | ~0.4s
Team wipes | 16 (14 at the Elite Four)
Elite Four attempts | 15
Final team | Charizard 83, Graveler 62, Nidoqueen 45, Beedrill 44, Haunter 39, Primeape 29
It never writes to game memory.
* Game knowledge is limited to the story milestones (what the next goal is and where it happens) in `src/knowledge/milestones.ts`. Progress is checked against the game's real event flags.
* Hidden items aren't shown to Jev, since a human wouldn't know where they are.
* House rules:
* Text speed FAST and battle animations OFF, set once in the Options menu at boot.
* The player is named JEV and the rival BLUE.
* Every caught Pokémon gets a nickname: Jev spells it one letter at a time (A–Z or DONE). It has to be a made-up name, not a species name or a nickname already in use.
* Loop protection:
* Options that were already tried without anything changing get tagged, and Jev is told to try something new.
* If the same failing choice keeps coming back, the harness samples an alternative.
* As a last resort, it reloads the latest milestone checkpoint.
## Setup
Requirements: macOS or Linux, Node 20+, and git.
git clone https://github.com/christianmat/jev-pokemon && cd jev-pokemon
npm start -- --speed 1 --load <save-name> # load a specific save from saves/
npm run headless -- --steps 3000 # max speed, logs only
npx tsx scripts/tools/save.ts # save the running game (writes saves/manual-*.json)
### Logs
* `logs/jev-calls.jsonl` has every Jev call: the full state, the options with their facts, the probabilities, and the latency.
* `logs/events.jsonl` has maps, milestones, saves and errors.
## Cost
* Price: Jev costs $0.042 per million input tokens, and output is free. A typical call is about 1,200 tokens.
* Rate: at real-time speed the bot makes about 800–1,300 calls an hour. That comes to about $1–1.70 per 24 hours.
* Ceiling: the throttle's worst case, 90 calls a minute nonstop, is about $7 a day.
## Project layout
Path | What
--- | ---
`src/emu/` | emulator wrapper (serverboy / GameBoy-Online core), save states, audio tap
`src/game/` | ROM tables, RAM reader, collision grid + A*, region graph
`src/jev/` | Jev client (throttle, cache, log), AI SDK gateway backend, mock
`src/agent/` | mode detection, dialog and menus, overworld, battle, field moves and items
`src/knowledge/` | story milestones
`src/server/` | runner + local WebSocket viewer
`web/` | local viewer page
`site/` | public landing page (static; deploy with Vercel, root directory `site`)
`scripts/` | setup, data generation, debug tools
## Deploying the landing page
`site/` is plain static HTML with no build step:
1. Create a Vercel project from this repo.
2. Set Root Directory to `site`.
3. Deploy.
The highlights video (`site/highlights.mp4`) and links are in `site/index.html`.
## About
Jev, an AI decision model, plays Pokémon Red. It beat the game in 37h 40m.
jev-pokemon.vercel.app
### Resources
Readme
GPL-2.0 license
Activity
### Stars
123 stars
### Watchers
0 watching
### Forks
9 forks--------------------------------------------------------------------------------
jev-pokemon/README.md at main · christianmat/jev-pokemon · GitHub (https://github.com/christianmat/jev-pokemon/blob/main/README.md)
citeturn8search3 [wordlim: 200] Crawled: last week; Jev, TypeSafe AI's decision model, plays Pokémon Red. ... * Game knowledge is limited to the story milestones (what the next goal is and where it happens) in `src/knowledge/milestones.ts`. ... git clone https://github.com/christianmat/jev-pokemon && cd jev-pokemon ... `src/agent/` | mode detection, dialog and menus, overworld, battle, field moves and items
christianmat / jev-pokemon Public
# README.md
## Latest commit
## History
History
main
## Breadcrumbs
1. jev-pokemon
/
# README.md
Copy path
Top
## File metadata and controls
* Preview
* Code
* Blame
127 lines (98 loc) · 6.57 KB
# Jev Plays Pokémon Red
Jev, TypeSafe AI's decision model, plays Pokémon Red. There are no scripts or cheats: the harness reads the game's memory, lists the legal options with some facts about each, and Jev picks one.
Landing page: jev-pokemon.vercel.app (`site/`)
## Result
Jev beat the game. The live stream ran on YouTube from Sep 25 to Sep 26, 2026 and has ended. The highlights are on the landing page.
|
--- | ---
Total time | 37h 40m
Decisions made | 16,150
Input tokens | ~39.2M
Total Jev cost | ~$1.65
Typical decision time | ~0.4s
Team wipes | 16 (14 at the Elite Four)
Elite Four attempts | 15
Final team | Charizard 83, Graveler 62, Nidoqueen 45, Beedrill 44, Haunter 39, Primeape 29
--------------------------------------------------------------------------------
jev-plays-pokemon/LICENSE at main · milanboers/jev-plays-pokemon · GitHub (https://github.com/milanboers/jev-plays-pokemon/blob/main/LICENSE)
citeturn8search4 [wordlim: 200] Crawled: 5 days ago; The `jev_plays_pokemon/vendor/` directory contains code vendored from other ... - pokemon-agent (https://github.com/NousResearch/pokemon-agent) — Copyright (c) ... - ClaudePlaysPokemonStarter (https://github.com/davidhershey/ClaudePlaysPokemonStarter) —
MIT License
Copyright (c) 2026 Milan Boers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD-PARTY RIGHTS.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Third-party code
The `jev_plays_pokemon/vendor/` directory contains code vendored from other
MIT-licensed open-source projects, which retains its original license terms:
- PyBoy (https://github.com/Baekalfen/PyBoy) — Copyright (c) PyBoy authors, MIT
License. The intro-navigation logic in `intro.py` is a port of PyBoy's
`GameWrapperPokemonGen1.start_game`.
- pokemon-agent (https://github.com/NousResearch/pokemon-agent) — Copyright (c)
Nous Research, MIT License. Vendored: the emulator wrapper, the Red/Blue RAM
reader, the collision map, and the state builder.
- ClaudePlaysPokemonStarter (https://github.com/davidhershey/ClaudePlaysPokemonStarter) —
no code vendored; the screen-relative navigation approach in `screen_grid.py`
is a from-scratch reimplementation inspired by this project.
This project does not distribute any game ROMs, game artwork, or other
copyrighted Nintendo material. You must provide your own legally obtained
copy of the game ROM.--------------------------------------------------------------------------------
jev-plays-pokemon | npm.io (https://npm.io/package/jev-plays-pokemon)
citeturn8search5 [wordlim: 200] Crawled: today; `--url <ws url>` | Stream WebSocket (default `wss://jev-plays-pokemon.standardagents.ai/ws`) ... * When the connection drops, jev-plays-pokemon reconnects with backoff and joins the chat again with your GitHub sign-in. ... ~boyd
#### Notes
* When the connection drops, jev-plays-pokemon reconnects with backoff and joins the chat again with your GitHub sign-in.
* After a resize, jev-plays-pokemon clears the screen. The stream repaints on the next full frame, which jev-plays-pokemon requests from the server.
* The stream is also available without Node: `curl -N https://jev-plays-pokemon.standardagents.ai/tty; tput rmcup; tput cnorm`
#### Development
`npm install
npm test
node bin/jev-plays-pokemon.mjs --url ws://127.0.0.1:8787/ws`
#### Releasing
GitHub Actions publishes this package with npm trusted publishing (`.github/workflows/publish-jev-plays-pokemon.yml`). Bump `version` in `package.json`, commit, and push a matching tag:
`git tag jev-plays-pokemon@0.1.1
git push origin main jev-plays-pokemon@0.1.1`
### Install
`npm i jev-plays-pokemon`ImageImage
`npx jev-plays-pokemon`ImageImage
`yarn add jev-plays-pokemon`ImageImage
`pnpm add jev-plays-pokemon`ImageImage
`bun add jev-plays-pokemon`ImageImage
### Module
ESM
### Health score
C 60/100
active
Supports ES modules
No known vulnerabilities
Recently updated
Actively maintained
Low download count
No TypeScript types
Pre-1.0 release
### Quality
✓README
✓Tests
✕Stable release
### Maintainers
~boyd
### Node
>=18
### Links
npm ↗
--------------------------------------------------------------------------------
Developer says AI decision model Jev beat Pokémon Red in under a week (https://www.tomshardware.com/tech-industry/artificial-intelligence/developer-says-jev-decision-model-beat-pokemon-red-in-under-a-week-non-llm-engine-succeeds-where-traditional-chatbots-stalled-for-months-but-claude-opus-5-coached-the-model-through-its-dead-ends)
citeturn8search6 [wordlim: 200] Published: last week; Anthropic's Claude Opus 5 monitored the game log and adjusted options and their wording as Jev played, effectively acting like a coach.The developer, Andrew Boyd, is the founder of Standard Agents Inc., which sells a platform for building AI agents. ... Follow along here: https://t.co/64naxTJlDg OR, in your terminal run `npx jev-plays-pokemon` to follow along (with chat!)
Developer says AI decision model Jev beat Pokémon Red in under a week
Date: Sun Sep 27 11:30:00 2026 UTC
TypeSafe AI's Jev "beat the Elite Four and the Champion and entered the Hall of Fame on September 23, 2026" in Pokémon Red, according to the developer's project page. Unlike the chatbots that have taken weeks to months to beat the Blue version of the game, Jev can only pick from a list of choices. It didn't achieve this without help, though. Anthropic's Claude Opus 5 monitored the game log and adjusted options and their wording as Jev played, effectively acting like a coach.
The developer, Andrew Boyd, is the founder of Standard Agents Inc., which sells a platform for building AI agents. Boyd initially announced the project on X with victory coming in a week. The gameplay was livestreamed, available in a browser or a terminal, with a chat that Jev moderated.
Let's go! Jev Plays Pokemon. Follow along here: https://t.co/64naxTJlDg OR, in your terminal run `npx jev-plays-pokemon` to follow along (with chat!) --------------------------------------------------------------------------------
JevPlaysPokemon — Level-40 Pokémon agent using… · jevbooks (https://jevbooks.com/en/p/anxkhn__jevplayspokemon/)
citeturn8search7 [wordlim: 200] Published: 2 weeks ago; Crawled: today; # JevPlaysPokemon ... Level-40 Pokémon agent using Jev for battle decisions on real FireRed. ... A Pokémon-playing agent that runs Gen 3 battles in two modes: Pokémon Showdown text battles on any computer, and a real FireRed ROM on Mac with Apple Silicon. ... View on GitHub
# JevPlaysPokemon
anxkhn/JevPlaysPokemon
Level-40 Pokémon agent using Jev for battle decisions on real FireRed.
Game & Simulation0.78Runner-up: Agent Decisions
## What it is
A Pokémon-playing agent that runs Gen 3 battles in two modes: Pokémon Showdown text battles on any computer, and a real FireRed ROM on Mac with Apple Silicon. Jev picks each turn's move or switch.
## How it uses Jev
Each turn the host reads the battle from RAM and sends Jev a JSON snapshot of the fight plus only the legal moves and switches. Jev returns one action with a probability for every option. If the answer is illegal, the battle stops; there is no backup brain.
Primitives:`choice`
## Technique worth stealing
Compress the live battle state into a JSON snapshot and let a typed choice over legal actions drive the turn.
## Try it
`Copy .env.example to .env with a TypeSafe API key; for Showdown run npm start -- --opponent all; for FireRed run setup_emulator.py and ./emulator.sh --prepare.`
View on GitHub
Judged by Jev jev-1.13.0
## Evidence
Each line is one question put to Jev about the README. ≥ 0.60 reads as yes, ≤ 0.40 as no; in between Jev is not making a call.
* ✓Jev is core to the project yes 0.80
* ✓Shows a System One pattern yes 0.62
* ✗Describes handling uncertainty no 0.03
* ✗Reports measured numbers no 0.10
* ✗Is a runnable tool no 0.35
* ?Would recommend to a builder unclear 0.54
* ✗Is a replica of the model no 0.05
* #Solves a common problem (0–2)score on a 0–2 scale 0.00 / 2
* ✓About Jev yes 0.98
## Repository
Stars
8
Forks
2
Language
HTML
License
GPL-3.0
Contributors
1
Created
18 Sept 2026
Last push
18 Sept 2026
Listed since
20 Sept 2026
Found via
awesome:AbdelStark/awesome-typesafe
Signals
no-judgment band (0.40–0.60)
Design patterns
no-judgment band (0.40–0.60)
Signals by Jev jev-1.13.0, card written by DeepSeek V4.1 Flash from the README on 20 Sept 2026.--------------------------------------------------------------------------------
Jev plays Pokémon — Made with Jev (https://madewithjev.com/builds/jev-plays-pokemon)
citeturn8search8 [wordlim: 200] Published: 2 weeks ago; Crawled: today; Milan Boers’s agent plays Pokémon Red, with Jev choosing each move.## milanboers/jev-plays-pokemon on GitHub
1. All builds
2. /
3. Games and real time
GitHub · by Milan Boers
# Jev plays Pokémon
Pokémon Red, played one typed turn at a time.
Milan Boers’s agent plays Pokémon Red, with Jev choosing each move.
## milanboers/jev-plays-pokemon on GitHub
Stars
6
Forks
2
Language
Python
Last push
Sep 18, 2026
Repository created Sep 17, 2026. Counts read from the GitHub API on Oct 4, 2026, and they move daily — quote them with the date.
## Details
Author
Milan Boers
Use case
Games and real time
Added
Sep 18, 2026
* games
* open source
All figures come from the author. Check the source before you quote them.--------------------------------------------------------------------------------
GitHub - valentynkit/jev-plays-pokemon-red: Pokemon Red on PyBoy: code owns the route and the arithmetic, Jev picks at branches in about 100 ms, calibration measured instead of assumed · GitHub (https://github.com/valentynkit/jev-plays-pokemon-red)
citeturn8search9 [wordlim: 200] Crawled: last week; # jev-plays-pokemon-red ... Code handles the routine ticks and only calls Jev where the game actually branches. ... `POKEMON_ROM` | to play | path to your own Pokemon Red dump ... It holds the last box's id and never clears, so from the intro onward it reads 1 and the agent pressed A forever. `wFontLoaded` is the byte that tracks it, and battle text does not set that one either, so a battle branch has to wait for `wBattleMon` to be populated instead.
--------------------------------------------------------------------------------
GitHub - milanboers/jev-plays-pokemon: Playing Pokemon Red using TypeSafe Jev · GitHub (https://github.itlym.cn/milanboers/jev-plays-pokemon)
citeturn8search10 [wordlim: 200] Crawled: yesterday; agent ai-agent emulation game-boy jev llm pokemon-red pyboy typesafe typesafe-jev ... # jev-plays-pokemon — TypeSafe Jev plays Pokémon Red ... It uses TypeSafe's System One model, Jev: Jev reads the game state as text, answers typed questions each turn, and deterministic code turns those answers into button presses on a PyBoy Game Boy emulator. ... * davidhershey/ClaudePlaysPokemonStarter — the screen-relative navigation idea (allow a wall tile as the path target; re-verify after every step).
--------------------------------------------------------------------------------
jev-plays-pokemon — Jev picks Pokémon Red… · jevbooks (https://jevbooks.com/en/p/milanboers__jev-plays-pokemon/)
citeturn8search11 [wordlim: 200] Crawled: today; It is aimed at developers exploring TypeSafe Jev as a decision model for game or agent loops. ... `uv sync, add TYPESAFE_API_KEY and a Pokémon Red ROM, then uv run jev-plays-pokemon.
--------------------------------------------------------------------------------
Introducing System One Models & Jev - TypeSafe AI Blog (https://typesafe.ai/blog/introducing-system-one-models-and-jev)
citeturn8view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn7view1","lineno":45}); Total lines: 193
L43: | Existing LLMs | System One + Jev
L44: --- | --- | ---
L45: Optimized with | Reinforcement Learning with Human Feedback (RLHF) / Reinforcement Learning with Verifiable Rewards (RLVR) | Reinforcement Learning for Calibrated Decisions (RLCD)
L46: Optimizes for | Human preference: writeups and chat responses that human raters prefer.
L47: Verifiable rewards: outputs that can be programmatically verified. | Calibrated decisions: answers with epistemically honest probabilities on System One tasks.
--------------------------------------------------------------------------------
GitHub - browser-use/jev-ultrafast: Fastest and cheapest web agent · GitHub (https://github.com/browser-use/jev-ultrafast)
citeturn8view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn7view2","lineno":220}); Total lines: 360
L220: cite95†Watch the MP4 · cite96†Measurements · cite97†Read the loop --------------------------------------------------------------------------------
GitHub - kitze/unclutter: WXT browser extension: Jev-powered page clutter removal with reusable template rules. · GitHub (https://github.com/kitze/unclutter)
citeturn8view2 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn7view4","lineno":245}); Total lines: 369
L243: ## Install from source
L244:
L245: Requires cite103†Bun†bun.sh and Node.js 22.12 or newer.
L246:
L247: git clone https://github.com/kitze/unclutter.git
L248: cd unclutter
L249: bun install --frozen-lockfile
L250: bun run build
--------------------------------------------------------------------------------
Generating levels in real time with the Jev model - Sprite Fusion (https://www.spritefusion.com/blog/generating-game-level-in-real-time-with-jev)
citeturn8view3 [wordlim: 200] Crawled: today; Content type: text/html; Source: click({"ref_id":"turn7view0","id":211}); Total lines: 174
--------------------------------------------------------------------------------
GitHub - standardagents/jevpilot: A playable Three.js driving simulator with Jev-powered autopilot · GitHub (https://github.com/standardagents/jevpilot)
citeturn8view4 [wordlim: 200] Crawled: today; Content type: text/html; Source: click({"ref_id":"turn7view0","id":217}); Total lines: 278
--------------------------------------------------------------------------------
Internal Error ()
citeturn8view5 [wordlim: 200] Source: click({"ref_id":"turn7view0","id":206}); Total lines: 1
--------------------------------------------------------------------------------
Internal Error ()
citeturn8view6 [wordlim: 200] Source: click({"ref_id":"turn7view0","id":209}); Total lines: 1Generating levels in real time with the Jev model - Sprite Fusion (https://www.spritefusion.com/blog/generating-game-level-in-real-time-with-jev)
citeturn9view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn8view3","lineno":null}); Total lines: 174
--------------------------------------------------------------------------------
GitHub - standardagents/jevpilot: A playable Three.js driving simulator with Jev-powered autopilot · GitHub (https://github.com/standardagents/jevpilot)
citeturn9view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn8view4","lineno":null}); Total lines: 278
--------------------------------------------------------------------------------
Smart home assistant demo - TypeSafe AI (https://docs.typesafe.ai/demos/smart-home)
citeturn9view2 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn7view5","lineno":null}); Total lines: 94
--------------------------------------------------------------------------------
GitHub - tamaratran/fast-jev-compaction: Claude Code plugin that replaces the compaction summary with Jev decisions: every tool call and result is scored in one fast request, stale ones are dropped or truncated, everything kept stays verbatim. · GitHub (https://github.com/tamaratran/fast-jev-compaction)
citeturn9view3 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"turn7view3","lineno":null}); Total lines: 338
--------------------------------------------------------------------------------
Introducing System One Models & Jev - TypeSafe AI Blog (https://typesafe.ai/blog/introducing-system-one-models-and-jev)
citeturn9view4 [wordlim: 200] Crawled: today; Content type: text/html; Source: find({"ref_id":"turn7view1","pattern":"Doom"}); Total lines: 193
L79: ##### Nuance
L80:
L86: * For the keen eyed, for the recorded run, the only disagreement with GPT-5.6 Terra is on “Churn likelihood level”. The actual answer seems genuinely ambiguous to us.
L87:
L88: * We used GPT-5.6 Terra with default reasoning for this example, because we’ve found it to be the most comparable at intelligence to Jev on average.
L89:
L90: * Fun fact: a similar demo was what convinced us to go all-in in the direction of System One Models!
L91: ### Workflow evals
L92:
L93: We made a new type of evaluation to measure how well AI works within code. We don’t optimize for a ground truth classification or allow the harness and model to change (potentially allowing for overfitting via harness engineering). Instead, we assume there is a correct compute graph (a “workflow” represented in code) and use the predictions of the largest, smartest, and most expensive external models as reference probabilities.
L94: Rephrased: every model gets the same workflow. We test how they compare to the average of the smartest models (in this case, Astra and Fable).
L95:
L96: cite8†Image†framerusercontent.com L97:
L98: Jev is off the charts – owning the Pareto frontier for almost 2 orders of magnitude. We also compare to models with a generated prompt doing all the logic in their chain-of-thought, but this tends to do significantly worse than using the workflow itself.
L99: Note that the calls here are significantly more complex than the side-by-side demonstration above. That’s because they’re more representative of the types of production workloads needed for true business automation. Below is the simplest of the 4 workflows we’re publishing:
L100:
L101: cite9†Image†framerusercontent.com L102: The most reliable real-world workflows tend to have many independent, decomposed questions, with fine-grained behavior that’s dependent on probabilities instead of discrete decisions. The end result is discrete branching, but how we get to a final answer involves a lot of domain-specific engineering that needs to be done highly consistently.
L103:
L104: See cite10†our workflow evals site†evals.typesafe.ai for all the details: examples, disagreements, full queries, and each workflow.
L105: ##### Nuance
L106:
L107: * This is where the claims of 193.6x faster, 444.6x cheaper on our home page comes from, and we expect that these are on the higher end of real world gains.
L108:
L109: * These content of these workflows were not deliberately chosen nor constructed to make our model look good, and are not in our training distribution. However, they were made by individuals on our model capabilities team, so some bias could exist.
L110: * We use the average of GPT-6 Astra and Fable 5.1 as the reference answer, which biases answers towards OpenAI and Anthropic’s models. We likely underestimate the relative performance of our model and DeepSeek’s models.
L111: * The LLMs use our cite11†System One LLM†github.com wrapper, which constrains LLMs to output structured decisions compatible with our API. We have found this to be the most accurate way to get decisions from LLMs, but this tends to be slower and more expensive than giving decisions without probabilities.
L112: ### Hallucination and Type-safety
L113:
L114: cite12†Image†framerusercontent.com L115:
L116: Hallucination and type-safety are intrinsically related, and we think the latter is table stakes for automation. Having a hallucinated tool call is inconvenient in an agent, but is an absolute deal-breaker if it’s part of a system with latency guarantees or it’s buried several layers deep in a dependency chain. Existing models, no matter how smart, still hallucinate and have type errors.
L117: ##### Nuance
L118:
L119: * The numbers for LLMs are from OpenRouter i.e., there almost certainly is bias here: more complex queries might be routed to better models.
L120:
L121: * Our number is not empirical. Schema matching is guaranteed, thus we can confidently add 0% into the plots.
L122:
L123: ### Fun Demos
L124:
L125: Perhaps the most exciting part of our work is enabling new use cases. We have a lot more to show you, but here are a couple of the team’s favorites:
L126: #### Doom
L127:
L128: We love how this doomo doomonstrates real-time intelligence and what can be doone with code + AI. The engineer behind it was worried about making 10 queries a second (which ends up costing ~$7/hour), but the rest of us agreed that was lower than expected! This is so fun we intend to not only release an in-depth walkthrough, but also host some events to hack on this.
L129: ##### Nuance
L130:
L131: * The demo is on structured state as a data structure with text, not on images (yet…)
L132:
L133: * A non-AI doom bot could play better, but we wanted a bot that was reactive to different representations of game state, and most importantly… following instructions was cool as heck!
L134: #### Wikiracing
L135:
L136: The objective of the game is to start on one Wikipedia page and reach a specific other Wikipedia page using only links you come across while traversing. Each step can mean choosing between hundreds to thousands of links! It’s a great playground for demonstrating not just intelligence-per-second, but also the compounding benefits of not hallucinating with high-cardinality choices.
L137: ##### Nuance
L138:
L139: * As far as we know, it was completely random that both the 2nd and 3rd challenges started with “Rubber Duck.” The author only noticed when the team pointed it out.
L140: * Our speedups here tend to be a lot less than in previous demos. That’s because this is against the non-reasoning modes of the models (except Astra which was set to the lowest reasoning setting). This is also why Jev tended to finish in fewer steps (a sign of greater intelligence). This was to make the demo more bearable to watch. The LLMs look much worse at this task than with reasoning enabled.
L141: * Jev supports a cardinality up to 255. For the higher cardinality choices, we do a 2 stage-system of scoring independently then making an explicit choice, hence the occassional slowdown.
L142: ## What’s next
L143:
L144: We’re still in Jev’s early days. We have a lot more in the pipeline and are so excited to keep on shipping 🔥.
L145:
L146: Today, we are opening cite0†early access and bringing developers off the waitlist as quickly as we can. We want to hear which decisions you need to automate, where Jev works, and where it falls short. Tell us what sci-fi you want to build!!
L147: We started TypeSafe because we believe that AI needs an interface software could depend on. We can't wait to see new use cases continuously diffuse through the community and economy.
L148: ### We Give A FAQ
L149:
L150: Where do the names “System One Models” and “Jev” come from?
L151:
L152: We were inspired by Daniel Kahneman, cite13†Thinking, Fast and Slow†www.penguinrandomhouse.com . The model class name draws on the distinction between fast, intuitive System 1 thinking and slow, deliberate System 2 reasoning.
L153:
L154: “System 1 thinking” has also implied error-prone. For reasons we will get into in the future, we believe System One Models can be made more reliable than its alternatives.
L155: We named Jev after William Stanley Jevons. We expect machine intelligence to follow a similar path to coal, after steam-engine efficiency led to an increase in demand. Every order of magnitude drop in the cost of intelligence unlocks orders of magnitude more use cases.
L156:
L157: Why was a new training algorithm needed?
L158:
L159: What use cases is Jev good for?
L160:
L161: Is Jev just a smaller LLM?
L162:
L163: How does Jev perform against public benchmarks?
L164:
L165: Where does our training data come from?
L166: These results are kinda crazy - how is it possible?
L167:
L168: ∵ ⩆
L169:
L170: ⩆ ∵
L171:
L172: TypeSafe AI © 2026
L173:
L174: cite14†Terms of Use L175:
L176: cite15†Privacy Policy L177:
L178: cite16†Acceptable Use Policy L179:
L180: cite17†LinkedIn†www.linkedin.com L181:
L182: cite18†X†x.com L183:
L184: [REDACTED]
L185:
L186: TypeSafe AI © 2026
L187:
L188: cite14†Terms of Use L189:
L190: cite15†Privacy Policy L191:
L192: cite16†Acceptable Use Policy --------------------------------------------------------------------------------
GitHub - browser-use/jev-ultrafast: Fastest and cheapest web agent · GitHub (https://github.com/browser-use/jev-ultrafast)
citeturn9view5 [wordlim: 200] Crawled: today; Content type: text/html; Source: find({"ref_id":"turn7view2","pattern":"How it works"}); Total lines: 360
No matching text found for "How it works"--------------------------------------------------------------------------------
GitHub - kitze/unclutter: WXT browser extension: Jev-powered page clutter removal with reusable template rules. · GitHub (https://github.com/kitze/unclutter)
citeturn9view6 [wordlim: 200] Crawled: today; Content type: text/html; Source: find({"ref_id":"turn7view4","pattern":"Jev"}); Total lines: 369
L1: ## Navigation Menu
L2:
L3: cite1†Sign in L4:
L5: Appearance settings
L6:
L7: * Platform
L8:
L9: * AI CODE CREATION
L10: * cite2†GitHub CopilotWrite better code with AI L11: * cite3†GitHub Copilot appDirect agents from issue to merge L12: * cite4†MCP RegistryIntegrate external tools L13:
L14: * DEVELOPER WORKFLOWS
L15: * cite5†ActionsAutomate any workflow L16: * cite6†CodespacesInstant dev environments L17: * cite7†IssuesPlan and track work L18: * cite8†Code ReviewManage code changes L19: * cite9†Code QualityEnforce quality at merge L20: * APPLICATION SECURITY
L21: * cite10†GitHub Advanced SecurityFind and fix vulnerabilities L22: * cite11†Code securitySecure your code as you build L23: * cite12†Secret protectionStop leaks before they start L24:
L25: * EXPLORE
L26: * cite13†Why GitHub L27: * cite14†Documentation†docs.github.com L28: * cite15†Blog†github.blog L29: * cite16†Changelog†github.blog L30: * cite17†Marketplace L31:
L32: cite18†View all features L33:
L34: * Solutions
L35: * BY COMPANY SIZE
L36: * cite19†Enterprises L37: * cite20†Small and medium teams L38: * cite21†Startups L39: * cite22†Nonprofits L40:
L41: * BY USE CASE
L42: * cite23†App Modernization L43: * cite24†DevSecOps L44: * cite25†DevOps L45: * cite26†CI/CD L46: * cite27†View all use cases L47:
L48: * BY INDUSTRY
L49: * cite28†Healthcare L50: * cite29†Financial services L51: * cite30†Manufacturing L52: * cite31†Government L53: * cite32†View all industries L54:
L55: cite33†View all solutions L56:
L57: * Resources
L58: * EXPLORE BY TOPIC
L59: * cite34†AI L60: * cite35†Software Development L61: * cite36†DevOps L62: * cite37†Security L63: * cite38†View all topics L64:
L65: * EXPLORE BY TYPE
L66: * cite39†Customer stories L67: * cite40†Events & webinars L68: * cite41†Ebooks & reports L69: * cite42†Business insights L70: * cite43†GitHub Skills†skills.github.com L71: * SUPPORT & SERVICES
L72: * cite14†Documentation†docs.github.com L73: * cite44†Customer support†support.github.com L74: * cite45†Community forum L75: * cite46†Trust center L76: * cite47†Partners L77:
L78: cite48†View all resources L79:
L80: * Open Source
L81:
L82: * COMMUNITY
L83: * cite49†GitHub SponsorsFund open source developers L84: * PROGRAMS
L85: * cite50†Security Lab†securitylab.github.com L86: * cite51†Maintainer Community†maintainers.github.com L87: * cite52†GitHub Stars†stars.github.com L88: * cite53†Archive Program†archiveprogram.github.com L89:
L90: * REPOSITORIES
L91: * cite54†Topics L92: * cite55†Trending L93: * cite56†Collections L94:
L95: * Enterprise
L96:
L97: * ENTERPRISE SOLUTIONS
L98: * cite19†Enterprise platformAI-powered developer platform L99: * AVAILABLE ADD-ONS
L100: * cite10†GitHub Advanced SecurityEnterprise-grade security features L101: * cite57†Copilot for BusinessEnterprise-grade AI features L102: * cite58†Premium SupportEnterprise-grade 24/7 support L103:
L104: * cite59†Pricing L105:
L106: Search`/`
L107:
L108: cite1†Sign in L109:
L110: cite60†Sign up L111:
L112: Appearance settings
L113: You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert
L114:
L115: 1. cite61†kitze L116: 2. cite62†unclutter L117: ## Repository navigation
L118:
L119: * * cite62†Code L120: * cite63†Issues1 (1) L121: * cite64†Pull requests5 (5) L122: * cite65†Security and quality L123: * cite66†Insights L124:
L125: More items
L126:
L127: cite67†Image: kitze†avatars.githubusercontent.com L128:
L129: cite62†unclutter L130:
L131: Public
L132:
L133: * cite68†Notifications You must be signed in to change notification settings
L134: * cite68†Fork41 (41) L135: * cite68†Star361 (361) You must be signed in to star a repository
L136:
L137: ## About
L138:
L139: WXT browser extension: Jev-powered page clutter removal with reusable template rules.
L140: ### Resources
L141:
L142: cite69†Readme L143:
L144: cite70†MIT license L145:
L146: cite71†Activity L147:
L148: ### Stars
L149:
L150: 361 stars
L151:
L152: ### Watchers
L153:
L154: 5 watching
L155:
L156: ### Forks
L157:
L158: cite72†41 forks L159:
L160: cite73†Report repository L161:
L162: main
L163:
L164: cite74†Branches cite75†Tags L165:
L166: [Input: Go to file]
L167:
L168: Go to file
L169:
L170: Code
L171:
L172: Open more actions menu
L173:
L174: ## Latest commit
L175:
L176:
L177:
L178: ## History
L179:
L180: 8 Commits
L181: ## Folders and files
L182: Name | Name | Last commit message | Last commit date
L183: --- | --- | --- | ---
L184: cite76†entrypoints | cite76†entrypoints | |
L185: cite77†lib | cite77†lib | |
L186: cite78†public/icon | cite78†public/icon | |
L187: cite79†scripts | cite79†scripts | |
L188: cite80†tests | cite80†tests | |
L189: cite81†.gitignore | cite81†.gitignore | |
L190: cite82†LICENSE | cite82†LICENSE | |
L191: cite83†README.md | cite83†README.md | |
L192: cite84†bun.lock | cite84†bun.lock | |
L193: cite85†package.json | cite85†package.json | |
L194: cite86†tsconfig.json | cite86†tsconfig.json | |
L195: cite87†wxt.config.ts | cite87†wxt.config.ts | |
L196: [Button: View all files]
L197: ## Repository files navigation
L198:
L199: * * cite88†README L200: * cite88†MIT license L201:
L202: More items
L203:
L204: # unclutter
L205:
L206: WXT browser extension: Jev-powered page clutter removal with reusable template rules.
L207:
L208: Made by cite89†Kitze†kitze.io L209: cite89†kitze.io†kitze.io · cite90†X†x.com · cite91†YouTube†youtube.com L210: ### More projects by Kitze
L211:
L212: cite92†Zero To Shipped†zerotoshipped.com L213: A full-stack starter kit for web and mobile apps. |
L214: cite93†Sotto†sotto.to L215: Voice-to-text for macOS. Local AI, one-time purchase. |
L216: cite94†Tinkerer Club†tinkerer.club L217: A private community for builders, self-hosters, and AI tinkerers.
L218: cite95†Sizzy†sizzy.co L219: The browser for web developers. |
L220: cite96†Supermac†supermac.io L221: A macOS command center for everyday workflows. |
L222: cite97†DMX†dmx.to L223: A focused desktop client for X.
L224:
L225: ### Support this project
L226: ### Sponsors
L227:
L228: cite98†Postiz†postiz.com L229: Schedule social posts with AI agents. |
L230: cite99†FounderStack†www.founderstack.pro L231: A SaaS stack for your business, without subscriptions. |
L232: cite100†Matte†matte.app L233: 3D mockups, screen recordings, and video editing.
L234: cite101†HTML/CSS to Image†htmlcsstoimage.com L235: Turn HTML/CSS into images, PDFs, and screenshots. |
L236: cite102†NameMyVenti†namemyventi.com L237: Get your brand shouted out at Starbucks.
L238:
L239: * * *
L240: # Unclutter
L241:
L242: WXT extension for Chrome / Chromium and Firefox. Jev classifies nonessential page elements through Vercel AI Gateway or TypeSafe AI directly; the extension stores and reapplies local hiding rules by page template.
L243: ## Install from source
L244:
L245: Requires cite103†Bun†bun.sh and Node.js 22.12 or newer.
L246:
L247: git clone https://github.com/kitze/unclutter.git
L248: cd unclutter
L249: bun install --frozen-lockfile
L250: bun run build
L251: 1. Open `chrome://extensions` (or your Chromium browser's extensions page).
L252: 2. Turn on Developer mode.
L253: 3. Click Load unpacked and select `.output/chrome-mv3` inside the cloned repository.
L254: 4. Pin Unclutter, refresh any already-open website, then open its popup.
L255: 5. Under Connection, choose Vercel AI Gateway or TypeSafe AI, paste the matching API key, and save it.
L256: 6. Choose Manual (default) and click Analyze page, or select On page visit. Your selected provider must have credits / Jev access.
L257: After replacing unpacked builds, click Reload on the extension card and refresh website tabs. Existing keys/settings stay in place. V1 templates show Update available; Re-analyze once to include cookie dialogs, or automatic mode upgrades them once while preserving paused templates and keep-visible choices.
L258: For Firefox 140+, run `bun run build:firefox`, open `about:debugging#/runtime/this-firefox`, choose Load Temporary Add-on, and select `.output/firefox-mv2/manifest.json`. Temporary add-ons disappear on Firefox restart; permanent Firefox distribution requires Mozilla signing. Chrome/Edge/Brave can use the Chromium build. Safari packaging is not included.
L259: Bring your own cite104†Vercel AI Gateway†vercel.com key or cite105†TypeSafe AI key†console.typesafe.ai (the same kind used as `JEV_KEY` / `TYPESAFE_API_KEY`). Configure it in the extension popup, not in source code or build-time environment variables. No key or shared account is bundled.
L260: One key is stored. Switching the provider persists immediately and reuses that key for the next analysis; paste a matching key if the providers use different credentials. Saving a key saves the selected provider with it. Removing the key does not reset the provider. Existing installations without a provider setting default to Gateway. Saved templates remain usable offline regardless of provider.
L261: TypeSafe direct uses `POST https://api.typesafe.ai/v1/systemone`, Bearer authentication, and body model `jev-latest`. Gateway uses its evaluation-model v4 endpoint and `typesafe-ai/jev` headers. TypeSafe requests never carry Gateway protocol headers; Gateway requests never carry the TypeSafe model field.
L262: ## Behavior
L263: * Manual: paid analysis only when you click Analyze page / Re-analyze.
L264: * On page visit: analyze new templates in visible tabs, after a short render-settling delay. This automatically sends candidate snippets to the selected provider and incurs API charges. Off by default.
L265: * Saved templates apply without further model requests, including zero-rule results. New analysis-rubric versions may refresh an enabled old template once in automatic mode; paused profiles and disabled rules are preserved.
L266: * Automatic attempts are deduplicated across tabs and persisted before the request. Failure/interruption does not trigger automatic retries; click Analyze page / Re-analyze to retry.
L267: * Cookie overlays (including Sourcepoint's session-numbered iframe/container IDs and BBC's `ngasCookiePrompt`) are eligible for visual hiding. No Accept/Reject buttons are clicked and no consent choice is written.
L268: * Empty ad wrappers and their reserved-height/padding/advertisement labels collapse too, stopping before useful sibling content. Normal overflow-based cookie scroll locks are released while hiding the overlay and restored when paused.
L269: * Toolbar badge: green ON = saved and active; gray OFF = paused; amber … = analyzing; red ! = failed. Tooltip includes actual hidden element count.
L270: * Pause / Resume controls the current page type across tabs. The header switch disables the whole extension. Both restore hidden elements immediately.
L271: * Re-analyze replaces this template's rules while preserving disabled rules that are still identified. Failed, malformed, or stale responses leave existing rules unchanged.
L272: * Uncheck a rule in Hidden elements to keep those elements visible.
L273: * Forget this page type removes its saved rules, restores the page, and permits a fresh analysis.
L274: * Removing the API key leaves saved rules usable offline.
L275: ## Template reuse
L276:
L277: Keys combine exact origin, policy version, page kind, normalized route family, and a stable main-shell marker. Homepage, article, product, search, listing, and generic routes stay separate. Article/product leaves and date/ID segments are normalized; tracking query parameters do not fragment the cache.
L278: Examples: BBC `/news/articles/cabc123` and `/news/articles/cdef456` share a profile if their shells match. `/`, `/news`, and a different article shell do not. Generic short routes such as `/news/world` and `/news/business` stay separate. No global cross-domain rules.
L279: This is a conservative heuristic, not perfect template recognition. Different route families may need separate initial analyses; different layouts sharing the same shell may share a profile. Every selector is revalidated against the current DOM before hiding. Stable `data-testid`, `data-component`, IDs, and classes are used; no positional selectors or AI-generated CSS. Randomized class-only pages may yield no safely targetable candidates. There is no periodic cache expiry or automatic paid retry.
L280: Re-analyze manually after site redesigns.
L281: ## Privacy and safety
L282: * API key stays in local extension storage, not encrypted and not synced. Chrome restricts storage access to trusted extension contexts. It is never sent to page content scripts, websites, logs, or repository source.
L283: * Only extension background code calls the selected provider's fixed endpoint. Popup-origin checks protect settings/manual analysis. Page-visit requests are validated and require the user's saved automatic-mode opt-in.
L284: * Each analysis sends up to 60 bounded candidate descriptions (tag, structural signals, short text, position, match count). No full URL, query string, page title, main article body, form values, cookies, or raw HTML is sent. Email-like and long numeric strings in snippets are redacted, but this is not a guarantee of anonymization. Do not analyze sensitive pages if sending snippets to your selected provider is inappropriate.
L285: * Jev receives typed keep/ad/promotion/newsletter/social/cookie/uncertain choices. Page text is untrusted evidence, not instructions. The model cannot emit code or selectors. Responses are validated for type, completeness, valid categories, and numeric ranges. Uncertain results remain visible. Where provided, selected-choice probability and TypeSafe confidence must both be at least 0.9; either failing keeps the element visible. Invalid/non-finite values reject the response.
L286: Gateway answers without confidence still work. These are conservative operational thresholds, not calibrated accuracy claims.
L287: * Main content, navigation, ordinary forms, login/payment/security, and paywalls are protected. Cookie-dialog headings and checkbox controls may hide with their containing overlay, but sensitive inputs still block hiding. No links are clicked, consent granted, requests blocked, or access restrictions bypassed. Hiding cookie dialogs is not rejection or tracking protection; use Pause to access consent choices. Hiding ads does not prevent their network/tracking activity.
L288: * Hidden DOM nodes are not deleted. A temporary attribute, extension-owned stylesheet, and reversible inline display overrides remove occupied space (including inline `!important`). Original style values/priorities are restored; unrelated site style changes are preserved.
L289: * Late-loaded elements are rechecked through a bounded/debounced mutation observer. SPA navigation restores the previous rules and resolves the new template. In-flight analyses are discarded after navigation or concurrent edits.
L290: * Cross-origin iframe contents and shadow DOM are not traversed. Identified consent iframe/container selectors are reusable across numeric session IDs. Native dialogs and ordinary embedded forms remain visible. Scroll unlocking does not run behind other visible modals; non-overflow locks (e.g. fixed-body/inert/custom event interception) may still require site-specific handling.
L291: * HTTP(S) access is required to restore saved rules automatically on later visits. Internal browser pages, extension stores, PDFs and file URLs are not supported.
L292: ## Development
L293:
L294: bun install
L295: bun run check
L296: bun run build
L297: bun run build:firefox
L298:
L299: Use `bun run dev` for WXT development mode. No background server is needed for unpacked production builds.
L300: The normal checks use synthetic fixtures and need no API key. Optional live smoke test: set `JEV_KEY` or `TYPESAFE_API_KEY` for TypeSafe AI, or `AI_GATEWAY_API_KEY` for Gateway, then run `bun scripts/smoke-jev.ts`. Do not set both provider families; conflicting direct-key aliases are rejected too. Never pass a key as a command-line argument. The smoke sends synthetic inputs only and incurs a small API charge. Never commit `.env` files, API keys, browser profiles, or real browsing data.
L301: Outputs: `.output/chrome-mv3/` and `.output/firefox-mv2/`. `bun run zip` packages Chromium.
L302: Architecture: `lib/page-context.ts` identifies templates, `lib/dom.ts` extracts candidates and applies reversible rules, `lib/jev.ts` implements Gateway evaluation-model v4 and TypeSafe System One with shared choice validation, `entrypoints/background.ts` owns credentials/cache/actions, `entrypoints/cleaner.content.ts` handles page lifecycle, and `entrypoints/popup/` provides controls. Settings and profiles use independent storage keys to avoid unrelated-tab write loss.
L303: ## License
L304:
L305: cite82†MIT .
L306:
L307: * * *
L308:
L309: ### More projects by Kitze
L310: #### Apps & tools
L311: cite106†gifs.so†gifs.so L312: Search, copy, and download reaction GIFs. | cite107†Glink†glink.so L313: Feedback, roadmaps, changelogs, and discussions. | cite108†Benji†benji.so L314: Tasks, habits, calendar, health, and routines in one place.
L315: cite109†Perkz†perkz.to L316: Sell and manage access to private GitHub repositories. | cite110†JustWrite†justwrite.ink L317: Distraction-free writing sprints for macOS, with time or word-count goals. | cite111†Releaseflow†releaseflow.net L318: App updates and downloads.
L319: cite112†Passlock†passlock.to L320: A macOS password manager with time locks and unlock challenges.
L321: #### Open source
L322: cite113†Skillbox L323: A self-hosted, versioned skills library for AI agents. | cite114†Unclutter L324: Remove page clutter with AI-powered, reusable browser rules. | cite115†PageGrade L325: Grade page clarity, writing, and on-page SEO.
L326: cite116†Council L327: Let your coding agents deliberate together before making a plan. | cite117†CodexMaxx L328: Manage Codex accounts, usage, and active sessions on macOS. | cite118†React Hanger L329: A collection of useful React hooks.
L330: cite119†React Genie L331: Animate React elements as they enter the viewport. | cite120†MobX Router L332: A simple router for MobX and React apps.
L333: cite121†All projects†kitze.io · cite122†GitHub · cite90†Follow on X†x.com · cite91†YouTube†youtube.com L334: ## About
L335:
L336: WXT browser extension: Jev-powered page clutter removal with reusable template rules.
L337:
L338: ### Resources
L339:
L340: cite69†Readme L341:
L342: cite70†MIT license L343:
L344: cite71†Activity L345:
L346: ### Stars
L347:
L348: 361 stars
L349:
L350: ### Watchers
L351:
L352: 5 watching
L353:
L354: ### Forks
L355:
L356: cite72†41 forks L357:
L358: cite73†Report repository L359:
L360: ## Releases
L361:
L362: ## Packages
L363:
L364: ## Contributors
L365:
L366: ## Languages
L367:
L368: You can’t perform that action at this time.The more playful builds include Doom, Pokémon, a driving simulator, and a platformer that builds the terrain ahead of you. I also found practical integrations for browser automation and removing page clutter; I’m checking the authors’ descriptions to see exactly what Jev does in each.
>python3 - <<'PY'
import subprocess,concurrent.futures
urls=['https://raw.githubusercontent.com/browser-use/jev-ultrafast/main/README.md','https://raw.githubusercontent.com/standardagents/jevpilot/main/README.md','https://raw.githubusercontent.com/tamaratran/fast-jev-compaction/main/README.md','https://www.spritefusion.com/blog/generating-game-level-in-real-time-with-jev']
def read(u):
r=subprocess.run(['curl','-fsSL','--max-time','20',u],capture_output=True,text=True)
s=r.stdout
if 'spritefusion' in u:
from html.parser import HTMLParser
class P(HTMLParser):
def __init__(self):super().__init__();self.skip=0;self.out=[]
def handle_starttag(self,t,a):
if t in ('script','style'):self.skip+=1
def handle_endtag(self,t):
if t in ('script','style'):self.skip=max(0,self.skip-1)
def handle_data(self,d):
if not self.skip and d.strip():self.out.append(d.strip())
p=P();p.feed(s);s='\n'.join(p.out)
return u,s
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as p:
for u,s in p.map(read,urls):print(u+'\n'+s+'\n')
PYhttps://raw.githubusercontent.com/browser-use/jev-ultrafast/main/README.md
<img src="docs/banner.svg" alt="Jev Ultrafast · Browser Use × TypeSafe" width="100%" />
# Jev Ultrafast ⚡
> [!IMPORTANT]
> **The Browser Use Cloud waitlist is open.** Get early access to ultrafast browser agents in the cloud.
> **[Join the waitlist →](https://browser-use.com/ultrafast?utm_source=github&utm_medium=readme&utm_campaign=jev-ultrafast)**
**A browser agent with a dynamic, indexed action space.**
Give it one goal. [TypeSafe's Jev](https://docs.typesafe.ai/introduction) picks an operation and an element. A small LLM writes text only when the operation is `TYPE_TEXT`.
**Zürich → London on Google Flights in 7.1 seconds.** One natural-language goal, actual text generation, and loading waits included.
<a href="docs/demo.mp4"><img src="docs/demo.gif" alt="A real Google Flights search at 1× speed, with generated city names and dynamic operation/target decisions" width="100%" /></a>
[Watch the MP4](docs/demo.mp4) · [Measurements](docs/performance.md) · [Read the loop](jev_ultrafast/agent.py)
## The action space
Every observation produces a new element table:
```text
[1] button Change ticket type · Round trip
[2] combobox Where from? · San Francisco
[3] combobox Where to? · empty
[4] textbox Departure · empty
...
```
The operations are `CLICK`, `TYPE_TEXT`, `SELECT`, `SCROLL_UP`, `SCROLL_DOWN`, `WAIT`, `DONE`, and `BLOCKED`. Only supported operations and targets are offered.
```text
one TypeSafe request
┌───────────────────────────┐
page → element table → operation │
│ click_target │
│ type_text_target │
│ select_target, if present │
└─────────────┬─────────────┘
use the matching target
│
CLICK [7] ─────┤──→ browser
TYPE_TEXT [3] ─────┘
↓
small LLM → text → browser
```
Target questions are speculative. If the operation is `CLICK`, only `click_target` can execute. Two decisions, **one network round trip**. Each target head contains only compatible elements. Native dropdown choices carry an observed element/option index.
There are no site-specific action scripts or prepared field strings in the policy. The Flights example supplies a goal and independently verifies the outcome. The screenshot renderer adds labels afterward; it does not drive the browser.
## Try it
```bash
git clone https://github.com/browser-use/jev-ultrafast.git
cd jev-ultrafast
uv sync
cp .env.example .env
# Add TYPESAFE_API_KEY and TEXT_MODEL_API_KEY.
uv run jev
```
Open **http://127.0.0.1:8766** and click **Start demo → Run automatically**. The inspector shows numbered elements, operation probabilities, target probabilities, and executed actions. **Choose next** pauses before execution.
Chrome connects through [Browser Harness](https://github.com/browser-use/browser-harness), installed by `uv sync`. Run `uv run browser-harness --doctor` if it needs connecting. Allow remote debugging in Chrome when prompted.
`TEXT_MODEL_API_KEY` is an OpenRouter key in the example configuration. The current demo uses `inception/mercury-2.5` with reasoning disabled. Gemini, GLM, and DeepSeek can also use the OpenAI-compatible text helper; configure the appropriate model, endpoint, and reasoning setting.
## Use the library
```python
from jev_ultrafast import Agent
with Agent(
"https://www.google.com/travel/flights?hl=en",
"Find one-way flights from Zurich to London on September 20, 2026, "
"for one adult in economy. Stop when matching flight options are visible.",
) as agent:
for state in agent.run():
print(state["elapsed_ms"], state["status"])
```
Run with `uv run --env-file .env python your_script.py`. The same policy can run a different task:
```bash
uv run --env-file .env python examples/run.py \
--url https://en.wikipedia.org/wiki/Main_Page \
--goal 'Find and open the Wikipedia article about Gödel’s incompleteness theorems.'
```
`uv run --env-file .env python examples/flights.py --keep-open` performs the flight search, checks the actual route/date/results, and saves its trace. It does not select or book a flight.
## Why it moves
- **One request per decision cycle.** Operation and target heads share the same observed state.
- **No screenshots in the default agent loop.** Jev consumes structured state. The inspector opts into screenshots; the video uses a separate continuous screencast.
- **One browser call per snapshot.** Read visible controls, their names, values, and text atomically. Keep references to the actual DOM nodes.
- **Validate the selected target.** Clicks check the document, form values, target, and nearby context. Animation alone does not force another prediction. Resolve current geometry and reject covered controls before input.
- **Wait for useful state.** After typing into a combobox, wait for visible suggestions, capped at 200 ms. Other interactions get at most two animation frames or 50 ms. These reads happen after execution is logged.
- **Keep hidden tabs rendering.** Focus emulation prevents background animation throttling without switching Chrome's visible tab.
- **Send visible text.** Offscreen article bodies and footers do not fill the model context.
- **Reuse an interrupted text request.** A generated value survives a stale-page retry only if the entire text-helper input is unchanged.
Every executed target is resolved from an observed node. The executor rechecks page freshness and click occlusion. Model output never becomes selectors, coordinates, shell commands, or executable JavaScript. Text-helper output must parse as a small JSON object before typing.
## Small enough to read
| File | Job |
| --- | --- |
| [agent.py](jev_ultrafast/agent.py) | The complete loop and text-helper handoff |
| [snapshot.js](jev_ultrafast/snapshot.js) | Atomic DOM snapshot, indexed controls, freshness guards |
| [browser.py](jev_ultrafast/browser.py) | Browser connection, current geometry, execution |
| [model.py](jev_ultrafast/model.py) | Dynamic operation/target heads and text generation |
| [questions.py](jev_ultrafast/questions.py) | Model instructions |
| [demo.py](jev_ultrafast/demo.py) | Local inspector |
## Evidence and limits
The current video is a **7,073 ms** Google Flights run. Timing starts after initial page observation and includes model calls, generated text, browser work, stale decisions, and loading waits. A fresh independent check verifies the one-way setting, Zürich, London, September 20, 2026, and visible flight options. The video plays at 1×, with no opening hold and a 0.5-second final hold.
In six alternating runs with identical models and settings, both versions passed **3/3**. Median task time went from **9.450 s → 7.092 s**, a **25% reduction**; median browser protocol calls went from **1,092 → 101**. This is three repeats of one task on one browser profile, not a general reliability benchmark.
The same policy opened the requested Wikipedia article in **2.798 s** and passed a local hotel search/filter task in **1.896 s**. Runs, failures, source hashes, and measurement boundaries are in [performance.md](docs/performance.md).
A `DONE` choice still requires independent outcome verification. The DOM reader handles common HTML and ARIA controls, not the full accessible-name specification. Shadow roots, frames, canvas, uploads, pop-up tabs, nested scrolling, and arbitrary keyboard widgets remain outside this MVP. Owned tabs share the existing Chrome profile.
## Development
```bash
uv run ruff check .
uv run pytest
node --check jev_ultrafast/static/app.js
node --check jev_ultrafast/snapshot.js
uv build
```
Tests are offline. `uv run python scripts/check_guards.py` checks real controls in a local browser without model calls. Live examples and recording scripts make paid API calls. `scripts/record_flights.py <new-folder>` captures original browser timestamps; `scripts/render_demo.py <recording-folder>` renders that verified run at 1× and crops out the Google account strip. Credentials and raw traces stay ignored.
---
[Browser Use](https://github.com/browser-use/browser-use) · [Browser Harness](https://github.com/browser-use/browser-harness) · [TypeSafe speculative fan-out](https://docs.typesafe.ai/patterns/fan-out)
https://raw.githubusercontent.com/standardagents/jevpilot/main/README.md
# JevPilot
https://github.com/user-attachments/assets/4baef58e-54ef-4d17-9982-353a0b6e6f45
<p align="center">
<a href="https://jevpilot.standardagents.ai">
<img src="docs/try-jevpilot.svg" alt="Try JevPilot →" width="256" height="64" />
</a>
</p>
A demo project showing Tesla Autopilot-like behavior using [Jev by TypeSafe AI](https://typesafe.ai/).
Sign in with Standard Agents for $0.25 of free Jev play credit. Joining the early-access list is optional.
The hosted `/api/decide` endpoint requires a valid login session. The browser sends its secure, HttpOnly session cookie; the Jev API key stays on the server.
**Interstate 08:** start in Millbrook, turn onto the signed on-ramp, merge, cruise, and exit into Cedar Town for the final stop.
## How it works
Jev receives compact tables of eligible paths, road boundaries, nearby traffic, signals, stop memory, and destination guidance. Shared table values are sent once, and instructions include only relevant situations. The road graph is sent only when choosing an alternative route after staying more than 30 meters off course for six seconds. Detailed geometry and control calculations stay local.
The simulator samples fresh steering-and-speed combinations for each decision. On the road, it favors paths that keep the whole car on asphalt. Off road, it explores a wider field of forward and reverse paths and supplies a recovery target, road boundaries, and collision predictions.
An explicit `driving_style` describes an aggressive driver: keep progressing, stop at the actual line, and close gaps before stopping behind an obstacle. Jev can choose an approach path that progressively slows to a stop 0.5 m before the line. An immediate **stop** is offered only within 2.5 m of a blocker or required stop line, at the destination, or when no eligible moving path exists. Candidate speeds taper near required stops. Jev receives recent-stop memory and collision timing; a safety brake handles collision risks.
Use **Candidates** to show the sampled paths: blue/cyan for forward, purple for reverse, amber for paths leaving the lane, orange for predicted collisions, and bright blue for Jev’s selection. Candidate generation and route searches run in a background worker; the renderer smoothly blends the sampled shapes. Open **JSON** to inspect road boundaries, recovery state, and actual choice probabilities.
Requests run up to 4 times/second near turns or traffic, and about 1.5 times/second on clear roads. Questions with one eligible answer are resolved locally. **JSON → Jev input** shows the exact API payload; the cost tooltip and response tab show average payload size and billed input tokens.
## Run locally
```sh
npm ci
cp .env.example .env
# Set TYPESAFE_API_KEY in .env.
npm run dev
```
Add your own [TypeSafe AI](https://typesafe.ai/) API key to `.env`:
```dotenv
TYPESAFE_API_KEY=[REDACTED]
```
Open [localhost:5173](http://localhost:5173). **Local development skips all login, signup, and demo credit limits.** No Standard Agents OAuth credentials are needed. Jev calls use your own key and TypeSafe account billing; free play works without a key. The key stays server-side in the gitignored `.env`—never use a `VITE_` variable for it.
This also applies to `npm run preview` after `npm run build`. Restart the local server after changing `.env`.
**J** toggles autopilot · **WASD** to drive · **Space** to brake.
Asset credits and licenses are included in [public/](public/).
Cloudflare deployment details: [docs/hosting.md](docs/hosting.md).
https://raw.githubusercontent.com/tamaratran/fast-jev-compaction/main/README.md
# fast-jev-compaction
Claude Code plugin that replaces the compaction summary with Jev decisions:
every tool call and result is scored in one fast request, stale ones are
dropped or truncated, everything kept stays verbatim. Also usable as an npm
library.
## What and why
Most context compaction asks an LLM to summarize old turns. A summary is
lossy: a file path, exact error, constraint, or command can disappear even when
it matters later. This library never rewrites anything. It only deletes tool
calls and tool results Jev says are no longer needed, and it asks Jev while
showing it the whole conversation. User and assistant text stays verbatim and
in order.
The repository is both an npm package (`src/`) and a Claude Code plugin
(`hooks/`, `.claude-plugin/`) that uses the package to replace Claude Code's
built-in compaction summary with the original messages.
## How it works
1. Every `tool_use` is paired with its `tool_result` by `tool_use_id`. Calls in
the first message or in the newest `preserveRecentMessages` messages are
pinned and never touched.
2. The **state** sent to Jev is the whole conversation so far, oldest first,
with every tool result replaced by a short note (`ok, 4213 chars (omitted)`).
Tool inputs are included, texts are included, nothing is summarized.
3. The state is fitted into `maxStateTokens` (25k by default) in stages, each
applied only if the previous one was not enough: tool inputs truncated to
1000, then 200, then 60 characters; long texts abridged to head + tail,
oldest non-pinned messages first; old non-pinned messages collapsed to a
`[… N chars omitted …]` note; old tool calls reduced to one line each
(`t12 Read file_path=src/a.ts → ok 480ch`); old call-less messages left
out; runs of old call-only messages folded into one entry. If it still
does not fit, compaction throws. Tokens are estimated without a tokenizer (a
word per six letters, half a token per digit, ~one per other symbol),
calibrated to land a little above the counts Jev reports.
4. For every non-pinned call Jev gets two `noul` questions: should the **call**
stay (knowing it was made, with its input, still matters), and should the
**result** stay verbatim (its contents are still needed and re-running the
tool would not do).
5. Questions are split into as many requests as needed so state plus questions
stays under `maxRequestTokens` (30k by default, under Jev's 32k request
limit). The same full state is resent with every request; requests run
concurrently and their answers are merged.
6. Decisions per call, against `keepThreshold`:
- `keepResult ≥ threshold` → keep call and result;
- else `keepCall ≥ threshold` → keep the call, truncate the result to its
first `truncateHeadChars` characters plus a one-line note;
- else → remove the call together with its result.
7. The message list is rebuilt: a message that loses all its content is
removed, untouched messages are returned as the same objects, and no result
is ever left without its call.
Jev failures, malformed answers, a missing key, or a history that cannot be
fitted throw; the caller (or the Claude Code hook) decides what to fall back to.
## Install and usage
```sh
npm install fast-jev-compaction
export TYPESAFE_API_KEY=[REDACTED]
```
```ts
import { compactMessages, reductionRatio, type Message } from 'fast-jev-compaction';
const transcript: Message[] = [
{ role: 'user', text: 'Fix the failing test. Never edit src/generated.', toolUses: [] },
{
role: 'assistant',
text: '',
toolUses: [{ tool_use_id: 'toolu_1', tool: 'Read', input: { file_path: 'src/a.ts' } }],
},
{ role: 'user', text: '', toolUses: [], toolResults: [{ tool_use_id: 'toolu_1', text: '…file…' }] },
// …
];
const result = await compactMessages(transcript, { preserveRecentMessages: 4 });
console.log(result.messages, result.decisions, result.stats);
if (reductionRatio(result) < 0.25) {
// not worth it: keep the original transcript, or summarize instead
}
```
`Message` is a subset of Claude Code's `SessionMessage`, so a session transcript
can be passed in as is.
To bring your own transport, implement `JevAsker` (one `ask(state, questions)`
method) and call `compact(messages, asker, options)`; `buildJevRequest` and
`parseJevResponse` give you the HTTP request body and response validation.
The building blocks (`collectToolCalls`, `fitState`, `batchCalls`,
`decideCall`, `applyDecisions`) are exported too.
`apiKey` defaults to `process.env.TYPESAFE_API_KEY`. Never commit the key or
put it in a source file.
## Options
| Option | Default | Description |
| --- | --- | --- |
| `apiKey` | `TYPESAFE_API_KEY` | TypeSafe API key (`compactMessages`/`JevClient`) |
| `model` | `jev-latest` | Jev model name |
| `baseUrl` | `https://api.typesafe.ai/v1/systemone` | System One endpoint |
| `fetch` | native `fetch` | Injectable fetch implementation for tests |
| `goal` | last 3 user prompts | Ongoing task description included in the state |
| `keepThreshold` | `0.5` | Minimum keep probability for a call or result to stay |
| `preserveRecentMessages` | `6` | Newest messages never touched (the first is always kept) |
| `maxStateTokens` | `25000` | Estimated token ceiling for the state |
| `maxRequestTokens` | `30000` | Estimated ceiling for state plus one batch of questions |
| `truncateHeadChars` | `300` | Characters of a dropped tool result retained before its note |
`result.stats` reports message and character counts before and after, the
per-reason decision counts, the state size in estimated tokens, which fitting
stage was needed, and the number of requests.
## Limitations
- Only tool calls and results are candidates; text messages are never removed
or shortened in the output (they are only abridged in the state Jev sees).
- Token sizes are estimates from character counts, not a tokenizer.
- Calibration is at the request level; a probability is not a proof that a
result is safe to delete. The assistant can always re-run the tool.
- The full state is repeated with every request, so a history near the state
ceiling costs one request per handful of questions.
## Claude Code plugin
The repository root is a Claude Code function-hook plugin: `hooks/fast-jev.ts`
is a thin adapter that feeds `session.compact` transcripts through `src/` and
falls back to Claude Code's built-in summary on errors or insufficient
reduction. See [`hooks/README.md`](hooks/README.md) for configuration and the
Claude Code 2.1.274 type reference.
### Install in Claude Code
Function hooks are an early-access Claude Code feature (2.1.274+), so the
opt-in flag must be set wherever Claude Code runs, e.g. in `~/.claude/settings.json`:
```json
{ "env": { "CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1", "TYPESAFE_API_KEY": "<your key>" } }
```
Then add this repository as a plugin marketplace and install the plugin,
either from the shell or as slash commands inside a session:
```sh
claude plugin marketplace add tamaratran/fast-jev-compaction
claude plugin install fast-jev-compaction@fast-jev-compaction
```
The install prompts for the plugin options (API key, thresholds, `truncateHeadChars`,
…); leave them at their defaults to use `TYPESAFE_API_KEY` from the environment.
Restart Claude Code or run `/reload-plugins`. From then on `/compact` (and
auto-compaction) goes through Jev: the toast reads
`fast-jev-compaction: kept N/M messages, no summary (…)` when the pruned history
replaced the built-in summary, or `fallback to built-in summary (…)` when Jev
could not remove enough (short sessions, or when it fails).
To run from a checkout without installing: `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude --plugin-dir .`
from the repository root. No publishing step is required; the marketplace is
just the repo's `.claude-plugin/marketplace.json`.
## Development
```sh
npm install
npm run typecheck # library + hook
npm test
npm run build
npm run validate:plugin # claude plugin validate
TYPESAFE_API_KEY=[REDACTED] npm run demo
```
The unit tests use a fake Jev and never contact TypeSafe. The demo is the live
network check.
## Animated demo (macOS)
`demo/JevDemo` is a small native SwiftUI app that plays a scripted, dramatized
version of the compaction flow inside a Claude Code-style terminal: the tool
calls of a canned transcript are scored, results and calls Jev lets go turn red
and collapse away, and the rest stays verbatim. It never calls the API; it
exists to be screen recorded.
```sh
demo/JevDemo/build.sh # builds demo/JevDemo/build/JevDemo.app and launches it
```
Press space in the app to replay from the start.
https://www.spritefusion.com/blog/generating-game-level-in-real-time-with-jev
Generating levels in real time with the Jev model - Sprite Fusion
Pixel Art Tools
AI Pixel Art Generator
New
AI Pixel Art Animator
Tilemap Editor
Pixel Snapper
Resources
Blog
Games
Pixel Art Gallery
Free Tilesets
Pixel Art Color Palettes
Docs
API
Join
/
blog
/
Generating levels in real time with the Jev model
Hugo -
September 18, 2026
An AI model is generating the level in real time. Pretty cool, right?
On September 15, 2026, TypeSafe
introduced Jev
, a model designed to return structured outputs with low latency and low cost. "Eh but that's just a classifier". Ok;
but can it generate a platformer level in real time? Let's see!
Why Jev looks promising for games
Unlike text-gen. models such as GPT or Fable, Jev is designed to return structured decisions. In short, it's a
zero-shot classifier: it gives you picks with probabilities attached rather than raw text.
LLM vs Jev
Task: choose platform widths and gaps.
LLM
Game state + examples
LLM
“Widths: 2, 3, 5, 2.
Gaps: 0, 1, 2, 0.”
Terrain described in words
Jev
Game state + examples
WIDTHS
2_3_5_2
GAPS
0_1_2_0
Terrain returned as choices
Now, there are two major bottlenecks to using AI at runtime in games:
Latency.
In most cases, you can't afford to wait five minutes for a model to think.
Cost.
Some will disagree, but I think current LLM pricing makes them pointless for games. It makes
no sense to me to pay for expensive API calls if I talk more to the tavern keeper.
Jev promises to help with both: sub-second responses at $0.042 per million input tokens, with free output tokens.
Source
Ok. Let's test the claims by fire.
Preparing a test game
For this experiment, I wanted a runner game prototype in a neon-night style. Serious things here, we'll use Sprite
Fusion for pixel art generation, PhaserJS, and Codex with Astra.
Ninja Runner assets
You
Use the
Sprite Fusion API
to create a neon-night ninja sprite + animations for a runner game.
Codex
I created the sprites and animations, and added movement and collisions.
Idle
Run
Jump
Attack
Generating levels with Jev
Feeding the game state & context
First, we take a snapshot of the game state: player position and velocity, current terrain blocks, dash state,
etc. We send that in the request to Jev alongside some example terrain layouts.
Known terrain
Next 4 surfaces
?
PLAYER
x=0
320px
{"x":158.86,"y":86.87,"vx":2.27,"vy":-2.34,"grounded":false,"dash_ready":true}
Jev request
The task we give Jev is fairly simple: given the current game state, how would you fill the next slice of terrain?
We ask about widths, gaps, heights and surface types through several choice questions, all sent in one API call.
Here are the options we allow:
Options we allow
Surface type
Solid roof or one-way ledge
Width
2, 3 or 5 blocks
Gap before it
0, 1 or 2 blocks
Height
Rows 4–9
Choices Jev made
The four surfaces from one recorded Jev response. Gap is measured before each surface; row numbers increase
downward.
Surface
Type
Width
Gap before
Height
1
Ledge
2 blocks
None
Row 5
2
Ledge
3 blocks
1 block
Row 6
3
Ledge
5 blocks
2 blocks
Row 5
4
Solid roof
2 blocks
None
Row 4
Terrain built from those choices
Row
4
5
6
7
1
2
1 block
3
2 blocks
4
My code then places the chosen blocks and gaps.
Live terrain generation in the game
So, costs and latency ?
Requests (in this demo)
5
Jev API latency
319–375 ms
Est. average cost / request
$0.00057
Est. cost / demo
$0.00286
Well, it's not bad at all. Jev generates the terrain fast enough to keep the runner moving, at a very low cost. It's
not sub-100ms latency nor free but interersting enough to pay attention for games.
I've played the demo for longer, and the latency stays stable. Level generation keeps working fine.
Conclusion
Promising! There are plenty of ways to generate levels using handwritten rules and heuristics, I know. But still,
cheaper and faster structured output models opens up a whole range of ideas and experiments for games. I'm gonna
share more soon.
Sources and acknowledgments
TypeSafe:
Introducing System One models and Jev
.
Jev docs:
state
,
choices
,
parallel questions
,
model limitations
and
pricing
.
Sprite Fusion
: pixel art assets and animations.
Other bits
Making a Game Boy Advance game with GPT-6 Astra
Read now
3 rules to make a polished game with AI
Read now
Get my next notes & experiments
Email address
Website
Subscribe
Pixel art tools for making 2D games: generate sprites, clean pixel art, and build tilemaps.
Made by Hugo Duprez.
Join
Pixel Art Tools
Tilemap Editor
AI Pixel Art Generator
AI Pixel Art Animator
AI Pixel Art Editor
Pixel Snapper
Resources
Blog
Free tilesets
How to fix AI pixel art
Pixel art color palettes
Guides
API
Pixel Art Generator docs
How to edit pixel art with AI
How to generate 8-direction sprites
How to generate pixel art in the same style
Tilemap Editor docs
Pixel Snapper docs
Community
Discord
GitHub
Contact
Legal
Terms
Privacy
Copyright 2026 Sprite Fusion. All rights reserved.Yep—there are some fun ones. These stood out after checking the original demos and project repos:
Doom that follows instructions — TypeSafe’s own demo.
Jev plays Doom from structured game state, making roughly ten decisions per second. The interesting part is being able to change its behavior through instructions while it plays. TypeSafe explicitly notes that a conventional Doom bot could play better. Watch their launch demos.
Wikipedia racing — also from TypeSafe.
Give it a starting article and a destination, and it navigates using only links on each page. When there are too many candidates, it scores links first, then chooses from a shortlist. A neat example of turning navigation into repeated small decisions. Demo and explanation.
A platformer that builds the level ahead of you.
Sprite Fusion’s Hugo Duprez built a neon ninja runner where Jev chooses upcoming platform widths, gaps, heights, and surface types from the current game state. The game code places the tiles. His recorded demo had 319–375 ms API latency, fast enough to keep generating terrain as the player moves. Demo and walkthrough.
Pokémon Red, played through to the end.
Christian Mathiesen’s project reports finishing in 37 hours 40 minutes for about $1.65 in Jev calls. The surrounding code reads game memory, supplies legal options and navigation support, and Jev chooses actions. My favorite detail: it names caught Pokémon by choosing letters individually. Code, results, and highlights.
JevPilot: a playable driving simulator.
A Three.js driving demo where Jev chooses among steering-and-speed options using nearby traffic, road boundaries, signals, and destination guidance. Geometry, physics, and collision braking stay in code. You can inspect the candidate paths and Jev’s probabilities while it drives. Project and playable demo.
Browser Use’s fast web agent.
Jev chooses what to do and which page element to act on; a small generative model supplies text when typing is required. Their recorded Google Flights search takes about 7.1 seconds—a measurement of that specific task. Video and implementation.
Unclutter: make noisy websites readable.
Kitze’s browser extension uses Jev to classify page elements such as ads, promotions, and newsletter boxes. It hides clutter reversibly and remembers rules for similar pages, so subsequent visits can work without another model call. Unclutter.
Choosing what a coding agent should forget.
fast-jev-compaction integrates with Claude Code to judge which old tool calls and results remain useful. It drops or truncates stale material and preserves retained content verbatim. An interesting experiment in using Jev to manage another model’s context. Project.
The terrain generator and Unclutter are my favorites: both give Jev a small, concrete decision that immediately changes something you can see.
No content
whats that website that basically allows you to drive a car endlessley in the browser itsself it was pretty cool like no sign up nothing just drive
I’ll look for it—there are a couple of browser driving sites that fit that description.
Slow Roads – Play Free Slowroads.io Driving Game Unblocked (https://slowxroads.com/)
citeturn10search0 [wordlim: 200] Crawled: 6 days ago; Slow Roads is the endless driving game from slowroads.io, free and unblocked in your browser. ... Every ridge and curve here was generated from a seed — no one drew this road. ... The procedural terrain engine, the vehicle physics, the audio and the art are all his work, and he wrote it in plain JavaScript rather than an engine, which is most of why it loads in a browser tab at all.
--------------------------------------------------------------------------------
Slow Roads - Play Free Online Driving Game (https://eovant.com/games/slow-roads)
citeturn10search1 [wordlim: 200] Crawled: 4 days ago; Slow Roads is a calm driving game built around an endless generated road rather than races, traffic, or a finish line. ... Slow Roads is a calm browser driving game with endlessly generated roads, adjustable settings, scenic routes, and no race or score requirement.
--------------------------------------------------------------------------------
About Slow Roads (https://slowxroads.com/about/)
citeturn10search2 [wordlim: 200] Crawled: 4 days ago; No download, no account, no finish line — just a road that builds itself in front of you for as long as you want to keep driving. ... Slow Roads was created by anslo, who wrote the procedural terrain engine, the vehicle physics, the audio and the art in plain JavaScript rather than a game engine — which is most of the reason it loads in a browser tab at all.
--------------------------------------------------------------------------------
Brakeless — Free Online Driving Game with No Brakes (https://brakeless.io/)
citeturn10search3 [wordlim: 200] Crawled: today; A free, endless 3D driving game that runs right here in your browser. ... Your turbine speedster has no brakes and its speed only ever climbs — all you control is the steering. ... 11. 9,000 m Agri-Grid 2126 — the countryside a century on: fields glowing with magenta grow-light, driverless harvesters hogging your lane and robo-grazer herds crossing the road.
--------------------------------------------------------------------------------
Slow Roads Review: Free Endless Browser Driving Game (https://www.cloudspress.com/slow-roads-a-chill-endless-driving-game-in-your-browser/)
citeturn10search4 [wordlim: 200] Published: last month; Crawled: 2 days ago; # Slow Roads: A Chill, Endless Driving Game in Your Browser ... There are no objectives, challenges, or opponents demanding your attention—just a road that keeps generating ahead of you. ... A single predictable road, a lightweight physics model, procedural scenery, level-of-detail systems, and reused objects all support the same goal: keeping a continuous visual journey running in a browser. ... “Endless” refers to the continuing generated journey, not an infinite amount of stored content.
--------------------------------------------------------------------------------
Infinite Driving: A Calm Endless Driving Game | Free Browser Demo (https://infinite-driving.com/?lang=en)
citeturn10search5 [wordlim: 200] Crawled: last week; Infinite Driving is a relaxing, endless procedural driving game. ... You can also try it free right here in your browser, no download or account needed. ... The point is to relax and discover: 19 landscapes, 243 roadside events, 16 structures and 9 cars along an endless road.
--------------------------------------------------------------------------------
Slow Roads: Free Endless Browser Driving Game Explained (https://www.itechguides.com/slow-roads-a-chill-endless-driving-game-you-can-play-in-your-browser/)
citeturn10search6 [wordlim: 200] Published: last month; Crawled: yesterday; # Slow Roads: A Chill, Endless Driving Game You Can Play in Your Browser ... Open slowroads.io and you can drive along a procedurally generated road with no required objectives, opponents, or finish line. ... * Use simplified physics and procedural assets suitable for a browser-hosted game.
--------------------------------------------------------------------------------
Slow Roads offers a chill, endless driving experience in your browser - Ars Technica (https://arstechnica.com/gaming/2022/10/slow-roads-offers-a-chill-endless-driving-experience-in-your-browser/)
citeturn10search7 [wordlim: 100] Published: 4.0 years ago; Crawled: last week; # Slow Roads offers a chill, endless driving experience in your browserFree, meditative driving game with no strings attached might help you escape the grind. ... Going off-road on a snowy landscape in Slow Roads.
--------------------------------------------------------------------------------
Slow Roads.io Unblocked - Free 3D Zen Driving Game Online - 61673 Games (https://www.61673.com/games/io/slowroads-io.html)
citeturn10search8 [wordlim: 200] Crawled: last month; Slow Roads (Slowroads.io) is a free, unblocked 3D driving simulator you can play directly in your browser — no download required.Also known by its domain, slowroads.io, this zen driving game generates endless scenic roads and lets you cruise through misty valleys, snowy peaks, and rolling hills in electric cars, motorbikes, or buses. ... * Endless content: Procedural generation keeps every road unique, so you can play for minutes or hours.
--------------------------------------------------------------------------------
Slow Roads Online – Play Free Relaxing Driving Game (https://freeslowroads.org/)
citeturn10search9 [wordlim: 200] Crawled: today; * Procedural landscapes: New hills, forests, valleys, and roads appear dynamically. ... Slow Roads is a peaceful and refreshing driving game for players who want to relax, explore, and enjoy the feeling of an endless road. ... If you are ready for a quiet road trip with no pressure and no finish line, start playing Slow Roads online and enjoy a relaxing drive directly in your browser.
--------------------------------------------------------------------------------
Save 10% on Slow Roads on Steam (https://store.steampowered.com/app/3431300/Slow_Roads/)
citeturn10search10 [wordlim: 200] Published: 2 weeks ago; Crawled: 6 days ago; Driving Relaxing Procedural Generation Casual Atmospheric Automobile Sim Simulation Cinematic Nature Racing Realistic Offroad Immersive Sim Controller 3D Third Person Singleplayer First-Person Walking Simulator Motorbike ... Slow Roads is a casual driving game designed to capture the zen of a long drive on a scenic road. ... Simply chase the horizon through endless, ever-unique landscapes, with no objectives, challenges, or distractions.
--------------------------------------------------------------------------------
Slow Roads io - Free Online Driving Simulator (https://soflowheelielife.net/games/slow-roads-io)
citeturn10search11 [wordlim: 200] Crawled: last week; Slow Roads io is a casual browser-based driving simulator that offers endless, relaxing journeys through procedurally generated landscapes. this indie browser game breaks away from traditional racing games and frantic simulations. ... * Endless Procedural Roads: Roads are automatically generated as you drive, ensuring a fresh ride every time you play. * Non-Competitive: No objectives, traffic, or opponents—just you and the road.
--------------------------------------------------------------------------------
slowroads.io - My JavaScript project to generate infinite scenic landscapes, packaged as a chill driving game (https://www.reddit.com/r/proceduralgeneration/comments/yauf3q/slowroadsio_my_javascript_project_to_generate/)
citeturn10reddit12 [wordlim: 200] Published: 4.0 years ago; Easy link to the game - it runs in your browser (no install/download/login needed!) ... The road had to be infinite, non-self-intersecting, not too steep, steer clear of water, and most importantly feel natural and fun to travel along. ... Sorry, I don't have any advices :/, but about my preferences, I prefer to play a game that is an app than a browser, but that's my taste, I can say that it applies to everybody. ... You don't know how hard it is to get roads on procedural terrain to look good, this is next fucking level!!!!! ... hello-----1 urgent pease, Is there a driving simulation fame like slowroad but with traffic , cityies, pedestrians and traffic lights signals?
--------------------------------------------------------------------------------
I made a driving game with no brakes — dodge traffic from a quiet city street all the way into a black hole (free, browser, no signup) (https://www.reddit.com/r/playmygame/comments/1uywmwf/i_made_a_driving_game_with_no_brakes_dodge/)
citeturn10reddit13 [wordlim: 200] Published: 2 months ago; Platform: PC (Web) — playable in any desktop browser, nothing to installDescription: Brakeless is a top-down arcade driver with one rule: you can't slow down. ... Every run is one continuous road trip — city streets, a harbor bridge, suburbia, countryside, forest, deep space, the far future, and finally a black hole, which is exactly as survivable as it sounds. ... Involvement: Solo developer — I designed and built the whole thing from scratch in TypeScript + HTML5 Canvas, no game engine: the procedural graphics, the traffic, the sound, all of it.
--------------------------------------------------------------------------------
slowroads.io - endlessly procedurally-generated driving zen (https://www.reddit.com/r/playmygame/comments/yap044)
citeturn10reddit14 [wordlim: 200] Published: 4.0 years ago; Crawled: 10 months ago; Easy link to the game - note that it runs in your browser (no install/download/login needed!) ... Slow Roads is a casual, infinitely-generated driving game, designed for a chill, scenic escape. ... I like how the grass only is x amount away from the road so less to render and how the plants and rails only show up x amount away from the car BUT don't look unnatural. ... An endless driving simulator is a new idea.
--------------------------------------------------------------------------------
slowroads.io - a browser-based, procedurally-generated, casual rally game designed for endless driving zen (https://www.reddit.com/r/simrally/comments/tijzfv/slowroadsio_a_browserbased_procedurallygenerated/)
citeturn10reddit15 [wordlim: 200] Published: 4.6 years ago; The "infinite" aspect makes the game very resource-intensive, and by writing the core engine myself I had more control to keep everything minimal and save precious CPU for the environment generation. ... I’m a web app developer professionally, quite proficient with Javascript, React and some HTML canvas but never dipped into game stuff (moreso data visualisation). ... I have no experience with wheels, but I imagine each one has its own control scheme and idiosyncrasies to work around..? ... I'm hoping to add a mobile UI for the browser version in the short term, but performance might not be great. ... hello----- urgent please, Is there a driving simulation browser game like slowroad but with traffic , cityies, pedestrians and traffic lights signals?
--------------------------------------------------------------------------------
I re-created Slow Roads game using three.js 🤯 (https://www.reddit.com/r/u_CuriousDivide5546/comments/1tjhxp2/i_recreated_slow_roads_game_using_threejs/)
citeturn10reddit16 [wordlim: 200] Published: 4 months ago; Recently, I started exploring browser-based game development with AI, and I stumbled across a game called Slow Roads.No missions. ... Just an endless drive through procedurally generated landscapes that never repeat. ... • Procedural terrain generated in real time as you drive
--------------------------------------------------------------------------------
Made a deep city-builder that runs free in one browser tab — honest RCI simulation, real traffic, and million-citizen megacities (https://www.reddit.com/r/SimCity/comments/1ufbwi0/made_a_deep_citybuilder_that_runs_free_in_one/)
citeturn10reddit17 [wordlim: 200] Published: 3 months ago; It runs entirely in a single browser tab — no install, no account, no patch day, no 40GB download. ... It's free, with no ads, paywalls or microtransactions, works on mobile (you can Add to Home Screen and it runs like a native app), and the whole thing — simulation, procedural art, generative music — is one self-contained file running on your device. ... * **Traffic that bites** — cars actually drive your roads, follow each other and yield at junctions.
--------------------------------------------------------------------------------
Slow Roads 2.0 - Endless, procedurally-generated landscapes for a chill driving game. New engine, new shaders, same Three.js (https://www.reddit.com/r/threejs/comments/1iekc71/slow_roads_20_endless_procedurallygenerated/)
citeturn10reddit18 [wordlim: 200] Published: 1.7 years ago; For the last 18 months I've been rewriting my procedurally-generated driving game, Slow Roads, from scratch, after it became clear the old tech-demo engine was too much of a mess to support ongoing development. ... With Slow Roads I have the benefit of prescience of exactly where the player will be in future, so it's easy to schedule work ahead of time and dispose of old chunks of the environment when they're certainly no longer needed. ... Hey man i tried messaging you but maybe u haven't seen my message, I'm currently studying Ai and have started a project where i teach an MlAgent to drive , and was wondering if the vehicle in your game uses actual ai and if yes, how u came about training it. ... It's just simple line-following logic, no training or ML involved ... This is really a remarkable achievement for something in the browser. ... The unique constrain with the endless road without any junctions probably influenced the procedural generation algorithm in an interesting way. ... I've only just realized that I've never seen a road sign in the entire gameplay.
--------------------------------------------------------------------------------
I made a free browser game about driving a marshrutka through Tbilisi. Cows included. (https://www.reddit.com/r/Sakartvelo/comments/1u251d3/i_made_a_free_browser_game_about_driving_a/)
citeturn10reddit19 [wordlim: 200] Published: 3 months ago; We decided the driving experience here deserved its own video game, so we built one.You drive a marshrutka down an old Tbilisi street and dodge what the road gives you: Priuses drifting between lanes, Wolt couriers, potholes that rattle the whole bus, street dogs that run out to chase cars, pedestrians who cross wherever they want, and cows. ... It is free, browser-based, no signup needed to play.
--------------------------------------------------------------------------------
[Free] 3D road builder/traffic management game - runs in browser, no download (https://www.reddit.com/r/freegames/comments/1ry1x5w/free_3d_road_buildertraffic_management_game_runs/)
citeturn10reddit20 [wordlim: 200] Published: 6 months ago; Connect them with roads, earn money from successful deliveries, unlock new road types as you progress. ... No download, no signup, just click and play.
--------------------------------------------------------------------------------
[Mac Chrome/Google?] [2010+?] Endless loop car driving game black and white (https://www.reddit.com/r/tipofmyjoystick/comments/1lba3f7/mac_chromegoogle_2010_endless_loop_car_driving/)
citeturn10reddit21 [wordlim: 200] Published: 1.3 years ago; Time-wasting / Casual / Endless driving ... Roughly between 2010–2016 (typical era for browser-based minimalist games) ... Endless road with no levels, goals, or points (possibly just about lasting as long as you can) ... Slow Roads
--------------------------------------------------------------------------------
Slow Roads .io - Endless Procedurally Generated In-Browser Driving Game! - YouTube (https://www.youtube.com/watch?v=u5ER5VjAXpI)
citeturn10youtube22 [wordlim: 200] Published: 3.9 years ago; # Slow Roads .io - Endless Procedurally Generated In-Browser Driving Game!
# Slow Roads .io - Endless Procedurally Generated In-Browser Driving Game!
By: Far Lands or Bust with KurtJMac (456000 followers)
Published: 2022-11-10, 27988 views, 353 likes
## Description
Broadcast live on Twitch: / kurtjmac
You can play video games in your web browser now! URL
Check out my other links: URL
#FreeGame #BrowserGame
--------------------------------------------------------------------------------
I made a relaxing low-poly driving game where every drive creates a new city — and you have to follow traffic rules (https://www.reddit.com/r/playmygame/comments/1wfzhow/i_made_a_relaxing_lowpoly_driving_game_where/)
citeturn10reddit23 [wordlim: 200] Published: 3 weeks ago; 🚓 **City Roads Generator** is an **arcade driving game** about cruising through an **endless procedural city** while following **basic** traffic rules. ... 🏙️ The city is **procedurally generated** as you drive, so **every session** creates a **new route** with streets, intersections, dead ends, traffic lights, parking spots, and road events.
--------------------------------------------------------------------------------
WE NEED TO FIND A GAME! (https://www.reddit.com/r/u_ILUXA887/comments/1uj4pew/we_need_to_find_a_game/)
citeturn10reddit24 [wordlim: 200] Published: 3 months ago; \- Endless driver — go as far as possible without crashing\- Two-way road: traffic going same direction + oncoming cars coming at you ... \- No powerups, no levels, no missions — just drive and survive ... \- Grey asphalt road with white lane markings ... \- Coins earned by driving s l o w r o a d s (https://slowroads.io/)
citeturn11view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://slowroads.io","lineno":null}); Total lines: 0You’re probably thinking of Slow Roads — slowroads.io.
Endless scenic roads through hills and mountains, right in your browser. No signup or download—just open it and drive.
No content
yeahh.. im trynna make some cool demo.. do u have ideas of anything cool i can make? `like think really outside the box
No content
does not have to be game like..
Yeah—Slow Roads has that “open a link, immediately get it, lose ten minutes” quality. I’d aim for that, with Jev making something react to you.
A few directions I’d actually be excited to try:
A city made from your browser history.
Your browsing becomes a walkable city: research rabbit holes become alleys, recurring interests become neighborhoods, abandoned projects become unfinished buildings. Jev judges relationships between pages; code builds the geography. Start with a pasted list of links.
The moment: discovering that two seemingly unrelated obsessions share a street.
A mirror that reflects your writing personality.
A blank page with a little abstract creature beside it. As you type, it changes posture, movement, and surroundings based on qualities like certainty, tension, warmth, or evasiveness. You could watch an angry email soften as you rewrite it. Jev scores the text; animation code turns those scores into behavior.
The moment: deleting “just following up again” makes the creature visibly unclench.
An aquarium of ideas.
Drop in notes, bookmarks, or shower thoughts. Each becomes a swimming organism. Related ideas school together; contradictory ones circle each other; isolated ideas drift. Jev judges relationships between selected pairs, while a physics simulation handles movement.
The moment: two notes written months apart find each other without you searching.
A camera for invisible things.
Point your phone at a room and switch between lenses like “awkward,” “cozy,” “improvised,” or “things with a story.” A vision model first describes visible objects; Jev judges them against the selected lens, and the interface overlays the results. Treat it as playful interpretation.
The moment: the “improvised” lens lights up your stack-of-books monitor stand.
A website you negotiate with.
The interface is physically rearranged by what you say. “I’m in a hurry” strips it down. “I don’t trust this” brings evidence forward. “I’m buying this for my dad” changes which product attributes matter. Jev chooses among predefined layouts, information priorities, and interaction modes.
The moment: the exact same site visibly becomes a different experience after one sentence.
An argument weather map.
Paste a debate, meeting transcript, or comment thread. It becomes animated weather: agreement forms clear patches, unresolved questions create fog, contradictory claims create storm fronts. Clicking a storm reveals the exact statements causing it. Jev evaluates individual claims and their relationships.
The moment: a furious-looking discussion turns out to contain one tiny disagreement surrounded by consensus.
A soundtrack that follows what you’re reading.
A reading view that mixes an instrumental soundtrack as you scroll. Suspense, intimacy, motion, and emotional intensity control different musical layers. Jev scores upcoming passages; code blends prerecorded stems ahead of time.
The moment: the music drops out just before a quiet, devastating sentence.
A museum of your ordinary objects.
Upload a few photos and short stories about things you own. They become exhibits arranged around themes such as “things I kept too long,” “borrowed identities,” or “evidence someone cared.” A vision model handles photos; Jev selects thematic relationships and placements.
The moment: your chipped mug and an old train ticket end up in the same exhibit, and the connection makes sense.
My strongest picks: the writing creature for something immediately delightful, the idea aquarium for something people keep playing with, and the argument weather map for a demo that could become a useful product.
No content
nah these arent *actually cool.. they're more like basic ideas in a cool wrapper
Fair. I was putting visual themes on classification. The underlying behavior needs to be surprising.
Here are four stronger directions:
1. Give a crowd one sentence—and see whether it can organize itself.
A thousand agents, each seeing only nearby agents and making small decisions. Tell them:
“Form a portrait of a face. Nobody can see the whole picture.”
“Evacuate this building, but everyone thinks a different exit is blocked.”
“Half of you are secretly trying to prevent consensus.”
No scripted global choreography. Jev selects local actions; code handles movement and communication. The experiment is whether coordination emerges—and where it breaks. You’d call Jev at decision points, with ordinary simulation running between calls.
2. A browser automation race where you can sabotage the interface live.
Give an agent a task. While it works, drag buttons around, rename labels, insert popups, switch languages, or change the page layout.
It has to keep finding the right action from the current controls. Show a conventional scripted automation beside it breaking on the first change.
The demo has a built-in challenge: “Can you confuse it without making the task impossible?” Jev handles semantic action selection. Start with a controlled website so you can change it aggressively and verify whether it actually succeeds.
3. An AI that tries to exploit rules you invent.
You create a little economy: coupons, loyalty points, refunds, inventory, transfers. Write the rules in plain English, then press “Find the exploit.”
Agents start attempting sequences of legal actions:
Buy with a discount → refund for store credit → stack the credit with another promotion → repeat.
You watch the balance change and get a replay of the exact exploit. Patch a rule and run it again.
A generative model proposes strategies; Jev evaluates lots of narrow semantic conditions; deterministic code owns balances and transactions. It could also fail to find anything—the demo should make that visible. This one has potential beyond the demo.
4. Teach your computer a task once, then give it unfamiliar versions.
You demonstrate moving one event from an email into a calendar. Then hand it ten wildly different emails and a redesigned calendar interface.
It must infer which details and actions matter, identify their equivalents, and perform the task in a sandbox. You can interrupt with corrections like:
“That’s the registration deadline, not the event date.”
A larger model turns the demonstration into a reusable task specification; Jev handles repeated choices against new inputs. The compelling test is how far it generalizes before you need to teach it again.
My pick is the rule exploiter. There’s a real reveal: you believe you designed a closed system, then you watch something discover a loophole you missed. The browser sabotage demo is the clearest way to show Jev itself doing something impressive.
No content
something that can be used in a chrome extension maybe?
Yes—give the browser a new capability, something you can demonstrate on a website people already use.
These three feel stronger:
1. “Select all that…” — semantic selection anywhere
Press a shortcut and type:
“Select the GitHub issues that already have a workaround.”
“Select apartments where the second bedroom sounds like a converted living room.”
“Select comments that found an actual bug, excluding feature requests.”
The extension selects matching items directly on the page. You can inspect the matches, then use the website’s existing bulk actions—or copy, compare, or export them.
Jev evaluates each item against your condition. The extension maps answers back to real page elements.
The demo: open a page with 200 items, describe a category the website has no filter for, and watch the right items light up. It adds a useful operation to existing software.
2. “Do this to the others” — automation by demonstration
You perform an action once, then tell the extension which other items it should apply to.
For example, you move one support ticket to a particular queue, then say:
“Do that for the other tickets where an update broke something that previously worked.”
The extension previews matching tickets and the action it will repeat. You approve the batch and watch it execute.
Recording captures the interaction; Jev judges which items qualify and identifies equivalent controls. A larger model could interpret the demonstration when necessary.
The demo: teach it a workflow in ten seconds, then let it handle twenty variations. I’d start with one supported app so this works convincingly.
3. A research browser that follows a question across links
You’re browsing apartment listings and ask:
“Find evidence that noise is a problem in these buildings.”
The extension explores relevant reviews and linked pages in the background, filters evidence, and attaches exact excerpts to each original listing. Same mechanism for:
“Which of these libraries has maintenance problems?”
“Which hotels have complaints about Wi-Fi specifically from people working remotely?”
A search/retrieval layer finds candidates; Jev makes the repeated relevance, identity, and evidence judgments. Every finding links to its source.
The demo: five ordinary tabs become a comparison with information those pages didn’t provide themselves.
I’d build the first one. It has a clear interaction, Jev does the core work, and the extension adds something you could use several times a day. Start with GitHub issues: “select reports that describe the same underlying bug, even when the titles sound unrelated.”
No content
some more
A few more—with a concrete interaction in mind:
A spoiler shield that knows where you are.
Tell it “I’m on episode four” or “I’ve only played through this chapter.” It checks incoming posts, thumbnails’ text, and comments against a supplied knowledge boundary, then covers potential spoilers before revealing them. You can still browse discussions about the parts you’ve seen. Jev judges whether text reveals something beyond your progress; getting reliable story context is the harder part.
Catch contradictions between your open tabs.
Open a product page, documentation, and pricing page. The extension connects conflicting statements: “unlimited projects” here, “maximum ten” there. Click either highlight to see the other claim in context. Extraction finds candidate claims; Jev judges whether they concern the same thing and actually conflict. A live cross-examination of the website you’re reading.
Web monitoring with an actual condition.
Right-click a page and say:
“Tell me when this tool supports local models.”
“Tell me when registration opens to people outside the US.”
“Tell me when this apartment allows a six-month lease.”
It periodically checks relevant text and alerts when the condition changes. The alert shows the before-and-after evidence. Much more specific than “this page changed.”
Copy the thing you mean.
Select a messy page region and type:
“Copy the speakers and their talk titles.”
“Copy the actual ingredients, excluding substitutions.”
“Copy the commands for my operating system.”
The extension identifies source spans and copies them verbatim into a table, list, or script preview. Jev chooses relevant pieces; code preserves the original values and handles formatting. A clipboard that understands what you wanted from the selection.
A browser that remembers why you rejected something.
You dismiss a hotel because reviews mention thin walls. Later, on a completely different booking site, the extension notices the same issue and flags it. Your decisions become explicit, editable preferences that travel across websites.
The interesting interaction: “You ruled out the last one for this exact reason.” It should learn only from reasons you deliberately give it.
“What’s new to me?” mode.
After reading five articles about an announcement, open the sixth and see only passages containing materially new information, corrections, or disagreement. Repeated background fades but remains expandable. Jev compares passages against a compact record of claims you’ve already read. Especially useful for following developing stories or researching a technical problem.
Natural-language breakpoints for browser agents.
Give an automation a task, then set conditions such as:
“Pause if continuing creates a subscription.”
“Pause if the item is refurbished.”
“Pause if the appointment is with a different practitioner.”
The extension checks observed page state before relevant actions and stops with the triggering evidence. Jev handles the semantic checks; explicit code gates control execution. This would need an integration with the automation, so it can actually pause it.
The contradiction detector has the strongest reveal. The rejection-memory idea feels the most personal. “What’s new to me?” is the one I’d want running while researching this conversation.
No content
i like the spoiler thing.. can we build a chrome extension that sensors spoilers on letterboxd ?
I’ll build a Chrome extension that hides potential spoilers in Letterboxd reviews using Jev. I’ll first check how Letterboxd structures its pages and what’s available in this workspace.
{
"accepted": true
}>ls -la && rg --files -g AGENTS.md -g '!node_modules' /Users/sahaj/Desktop/dev /Users/sahaj/.codex 2>/dev/null | head -60[{"name":"list_mcp_resource_templates","description":"Lists resource templates provided by MCP servers. Parameterized resource templates allow servers to share data that takes parameters and provides context to language mode"},{"name":"list_mcp_resources","description":"Lists resources provided by MCP servers. Resources allow servers to share data that provides context to language models, such as files, database schemas, or application-s"},{"name":"mcp__codex_apps__canva_create_design_from_brand_template","description":"Create, review, edit designs\n\nCreate a new Canva design from a brand template. Optionally select specific pages to include. If the user has already provided a brand templ"},{"name":"mcp__codex_apps__canva_fetch","description":"Create, review, edit designs\n\nGet the content of a doc, presentation, whiteboard, social media post, sheet, and other designs in Canva. You must provide the design ID, wh"},{"name":"mcp__codex_apps__canva_get_design_pages","description":"Create, review, edit designs\n\nList the pages in an existing Canva design, including each page's index and individual thumbnail.\n\nUse to browse a design's pages or slides,"},{"name":"mcp__codex_apps__canva_list_brand_kits","description":"Create, review, edit designs\n\nFind or browse the Canva Brand Kits available to the user. A Brand Kit is an organisation’s high-level home for brand styles and assets, suc"},{"name":"mcp__codex_apps__canva_list_comments","description":"Create, review, edit designs\n\nBrowse all comments or threads attached to an existing Canva design.\n\nUse to review feedback, see discussion points, or check mentions.\n\nRet"},{"name":"mcp__codex_apps__canva_list_folder_items","description":"Create, review, edit designs\n\nBrowse the contents of a Canva folder to find designs, folders, and images stored in it.\n\nUse to review a project folder, locate an item in "},{"name":"mcp__codex_apps__canva_prepare_design_generation","description":"Create, review, edit designs\n\nLEGACY-ONLY — DO NOT CALL WHEN create-design IS AVAILABLE.\nIf create-design is in the tool list, you MUST NOT call this tool. Call create-de"},{"name":"mcp__codex_apps__canva_search","description":"Create, review, edit designs\n\nSearch docs, presentations, videos, whiteboards, sheets, and other designs in Canva.\n Use the continuation token to get the next page"},{"name":"mcp__codex_apps__canva_search_brand_templates","description":"Create, review, edit designs\n\nFind or browse the user's Canva Brand Templates: reusable, on-brand layouts. Some include data fields that can be autofilled.\n\nUse when a pa"},{"name":"mcp__codex_apps__canva_search_designs","description":"Create, review, edit designs\n\nLocate or browse the user's existing Canva designs. Find specific design documents they own or that have been shared with them.\n\nUse to find"},{"name":"mcp__codex_apps__canva_search_folders","description":"Create, review, edit designs\n\nFind or browse Canva folders the user owns or that are shared with them.\n\nUse to locate a project folder by its name or tags, find a shared "},{"name":"mcp__codex_apps__chatgpt_space_attach_automation_to_page","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nAttach an existing hosted automation you own to a writable Page. Read list"},{"name":"mcp__codex_apps__chatgpt_space_create_canvas","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRecover an earlier canvas creation after an uncertain response. Use the or"},{"name":"mcp__codex_apps__chatgpt_space_create_controller_automation","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCreate a hosted automation managed by a Page's current auto-update control"},{"name":"mcp__codex_apps__chatgpt_space_create_page","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCreate a text Page. To create at the top level of a Drive Space, pass spac"},{"name":"mcp__codex_apps__chatgpt_space_create_page_visualization","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nUpload HTML (maximum 256 KiB UTF-8) to a Page's authorized Library contain"},{"name":"mcp__codex_apps__chatgpt_space_create_presentation","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRecover an earlier presentation creation after an uncertain response. Use "},{"name":"mcp__codex_apps__chatgpt_space_create_space","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCreate a new Drive Space with a new root Page when enabled for your worksp"},{"name":"mcp__codex_apps__chatgpt_space_create_spreadsheet","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRecover an earlier spreadsheet creation after an uncertain response. Use t"},{"name":"mcp__codex_apps__chatgpt_space_edit_page","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nEdit an accessible Page. Use the write-page skill for workflows and exampl"},{"name":"mcp__codex_apps__chatgpt_space_find_pages","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nFind accessible Pages matching a query, optionally within one Space. Resul"},{"name":"mcp__codex_apps__chatgpt_space_get_artifact_execution_status","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCheck whether an earlier execute_artifact_code request committed its chang"},{"name":"mcp__codex_apps__chatgpt_space_get_page_auto_update","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRead a Page's attached auto-update controller and whether you can enable o"},{"name":"mcp__codex_apps__chatgpt_space_get_page_sharing","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRead a Page's sharing policy and your permissions. If the full roster is u"},{"name":"mcp__codex_apps__chatgpt_space_get_sharing_availability","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCheck whether sharing management is enabled for the active account. If dis"},{"name":"mcp__codex_apps__chatgpt_space_get_space","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRead an accessible Drive-backed Space and its canonical metadata. The retu"},{"name":"mcp__codex_apps__chatgpt_space_get_space_sharing","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCall get_sharing_availability first. If disabled, explain the account rest"},{"name":"mcp__codex_apps__chatgpt_space_inspect_page_reference","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nInspect an exact Page file reference before reading when its format or siz"},{"name":"mcp__codex_apps__chatgpt_space_list_page_automations","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nList the canonical automations attached to an accessible Page, including i"},{"name":"mcp__codex_apps__chatgpt_space_list_page_comments","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nList collaborator comments and thread/message IDs for an accessible Page. "},{"name":"mcp__codex_apps__chatgpt_space_list_pages","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nList accessible Pages, optionally within a Space. Results include document"},{"name":"mcp__codex_apps__chatgpt_space_list_spaces","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nList Drive-backed Spaces available to your authenticated ChatGPT account. "},{"name":"mcp__codex_apps__chatgpt_space_manage_page_comment","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nFor replies, prefer reply_page_comment. Add a block comment or anchor exac"},{"name":"mcp__codex_apps__chatgpt_space_move_page","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nMove an existing Page beneath another Page only when requested. Read the r"},{"name":"mcp__codex_apps__chatgpt_space_patch_page","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nReplace literal text in ordinary Markdown blocks. Use edit_page for titles"},{"name":"mcp__codex_apps__chatgpt_space_progress_update","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nShow a short progress message at observed block IDs while working on an op"},{"name":"mcp__codex_apps__chatgpt_space_read_page","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRead an accessible Page's current content. Choose one read shape: {page_id"},{"name":"mcp__codex_apps__chatgpt_space_read_page_changes","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRead Page changes as markdown_diff with block IDs, hashes, actors and opti"},{"name":"mcp__codex_apps__chatgpt_space_read_page_reference","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRead an exact project-file:, library-file:, or visualize: reference from a"},{"name":"mcp__codex_apps__chatgpt_space_read_page_transcript","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRead the best available source transcript for a Page with namespace meetin"},{"name":"mcp__codex_apps__chatgpt_space_reply_page_comment","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nPost a reply to an existing Page comment thread. Use exact Page/thread IDs"},{"name":"mcp__codex_apps__chatgpt_space_run_page_auto_update","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nRequest a run of an enabled Page auto-update controller. Requires controll"},{"name":"mcp__codex_apps__chatgpt_space_search_sharing_recipients","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCall get_sharing_availability first. If disabled, explain the account rest"},{"name":"mcp__codex_apps__chatgpt_space_set_page_auto_update","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nEnable or disable Page auto-update when necessary. Read get_page_auto_upda"},{"name":"mcp__codex_apps__chatgpt_space_trash_page","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nMove a Page and its nested Pages to Trash. This tool is part of plugin `Pa"},{"name":"mcp__codex_apps__chatgpt_space_update_page_sharing","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCall get_sharing_availability first. If disabled, explain the account rest"},{"name":"mcp__codex_apps__chatgpt_space_update_space_sharing","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nCall get_sharing_availability first. If disabled, explain the account rest"},{"name":"mcp__codex_apps__chatgpt_space_write_page_reference","description":"Read, search, create, and edit pages and spaces in ChatGPT Space, within your current account.\n\nUpload a selected file (up to 10 MiB) to a writable Page's canonical Files"},{"name":"mcp__codex_apps__figma_add_code_connect_map","description":"Create designs, ship to code\n\nMap a Figma node to a code component in your codebase using Code Connect. Use the nodeId parameter to specify a node id. Use the fileKey par"},{"name":"mcp__codex_apps__figma_generate_deck","description":"Create designs, ship to code\n\nGenerates polished and fully editable presentation decks in Figma Slides, suitable for a wide range of use cases including pitches, slidesho"},{"name":"mcp__codex_apps__figma_generate_diagram","description":"Create designs, ship to code\n\nCreate a flowchart, decision tree, gantt chart, sequence diagram, state diagram, or entity relationship diagram in FigJam, using Mermaid.js."},{"name":"mcp__codex_apps__figma_generate_figma_design","description":"Create designs, ship to code\n\nCapture a live web page by URL into an *existing* Figma design file. Use this tool when the user wants to capture, screenshot, or push a run"},{"name":"mcp__codex_apps__figma_get_libraries","description":"Create designs, ship to code\n\nGet the design libraries associated with a Figma file. Returns two lists: (1) libraries currently added to the file (subscribed), and (2) li"},{"name":"mcp__codex_apps__figma_search_design_system","description":"Create designs, ship to code\n\nSearch for design system assets (components, variables, and styles). Returns matching assets from all design libraries. Use this when you ne"},{"name":"mcp__codex_apps__figma_send_code_connect_mappings","description":"Create designs, ship to code\n\nSave multiple Code Connect mappings in bulk. Use after get_code_connect_suggestions to confirm and save approved mappings. \n\nUse the nodeId "},{"name":"mcp__codex_apps__figma_weave_get_tool_inputs","description":"Create designs, ship to code\n\nGets the input contract of a Weave tool (a published Weave workflow) — the inputs you fill in to run it. Pass the `recipeId` (from weave_lis"},{"name":"mcp__codex_apps__figma_weave_list_tools","description":"Create designs, ship to code\n\nLists the Weave tools the authenticated user can run — published Weave workflows — in their active Weave workspace: their own, those shared "},{"name":"mcp__codex_apps__figma_weave_run_tool","description":"Create designs, ship to code\n\nRuns a Weave tool (a published Weave workflow) and returns run ids; poll them with weave_get_tool_run_output. A pasted Weave URL (app.weavy."},{"name":"mcp__codex_apps__github_fetch","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nFetch approved public GitHub repository resources and repository files. Supports"},{"name":"mcp__codex_apps__github_get_users_recent_prs_in_repo","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nList the user's recent GitHub pull requests in a repository. `limit` is the fina"},{"name":"mcp__codex_apps__github_list_repositories","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nList repositories accessible to the authenticated user. This tool is part of plu"},{"name":"mcp__codex_apps__github_search","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nSearch GitHub files and return matching excerpts when available. Provide a plain"},{"name":"mcp__codex_apps__github_search_branches","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nSearch GitHub branches within a repository. This tool is part of plugin `GitHub`"},{"name":"mcp__codex_apps__github_search_commits","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nSearch GitHub commits globally, by organization, or optionally by repository. In"},{"name":"mcp__codex_apps__github_search_installed_repositories_streaming","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nSearch for a repository (not a file) by name or description. To search for a fil"},{"name":"mcp__codex_apps__github_search_installed_repositories_v2","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nSearch repositories within the user's installations using GitHub search. This to"},{"name":"mcp__codex_apps__github_search_issues","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nSearch one repository or every repository the linked account can access. Supply "},{"name":"mcp__codex_apps__github_search_prs","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nSearch GitHub pull requests globally, by organization, or optionally by reposito"},{"name":"mcp__codex_apps__github_search_repositories","description":"Access repositories, issues, and pull requests. Required for some features such as Codex\n\nSearch for a repository (not a file) by name or description. To search for a fil"},{"name":"mcp__codex_apps__hotline_get_local_hotline","description":"Look up local helpline information for the user based on country inferred from the conversation. You must use this tool before providing a suicide or self-harm helpline; "},{"name":"mcp__codex_apps__meta_ads_ads_catalog_create_product_set","description":"meta ads mcp\n\nCreates a dynamic product set in a catalog from a structured filter rule (see **Filter spec** below) and returns the new set's ID, name, filter, and the num"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_delete_product","description":"meta ads mcp\n\nDelete a product item from a catalog. The item is removed from the catalog and immediately stops appearing in ads and on Meta surfaces.\n\nWhen to use:\n- A me"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_event_source_get_catalogs","description":"meta ads mcp\n\nGet the product catalogs connected to a given event source (pixel, CAPI app, or offline conversion data set).\n\n## When to use:\n- Step 1 when answering \"how "},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_catalogs","description":"meta ads mcp\n\nGets the catalogs associated with the authenticated user (up to 100).\n\n## When to use:\n- Call this tool when the user asks to see their catalogs or list ava"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_data_sources","description":"meta ads mcp\n\nList ALL data sources connected to a catalog — not just product feeds, but also Batch API, Graph API, partner integrations (Shopify, WooCommerce, SFCC), sma"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_details","description":"meta ads mcp\n\nGet catalog details including name, vertical, product/product set counts, business info, and optionally a paginated list of feeds.\n\nWhen to use:\n- To inspec"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_diagnostics","description":"meta ads mcp\n\nFetches diagnostic issues for a product catalog, including errors and warnings that may affect ad delivery.\n\n## When to use:\n- Call this tool when the user "},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_feed_rules","description":"meta ads mcp\n\nGets the data transformation rules applied to a product data feed during ingestion, with cursor-based pagination.\n\nFeed rules (also called \"data feed rules\""},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_product_details","description":"meta ads mcp\n\nFetches a product item from the catalog by its Meta-assigned product item ID (FBID).\n\n## Identifier types — read carefully before calling:\n- `product_id` (t"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_product_feed_details","description":"meta ads mcp\n\nFetches details about a product feed, including its name, schedule configuration, product count, and upload session status.\n\n## When to use:\n- Call this too"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_product_feed_upload_sessions","description":"meta ads mcp\n\nList recent upload sessions for a product feed, most recent first. Each session reports its outcome (status), timing (start/end), item counts (detected / pe"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_product_set_products","description":"meta ads mcp\n\nGets the products/items in a product set with cursor-based pagination and optional filters.\n\n## When to use:\n- Call this tool when the user asks to see the "},{"name":"mcp__codex_apps__meta_ads_ads_catalog_get_product_sets","description":"meta ads mcp\n\nGets a list of product sets in a catalog with cursor-based pagination.\n\n## When to use:\n- Call this tool when the user asks to see the product sets within a"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_product_create","description":"meta ads mcp\n\nCreate a single catalog item. The item's vertical is determined by the target catalog: a commerce/products catalog gets a product item, a hotels catalog get"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_search_product","description":"meta ads mcp\n\nSearches or lists products in a catalog using a structured filter rule (see **Filter spec** below) and returns sample matching products plus the **total** n"},{"name":"mcp__codex_apps__meta_ads_ads_catalog_update_product","description":"meta ads mcp\n\nUpdate one or more fields on an existing product item (catalog product). Only the fields you provide are changed; omitted fields are left untouched.\n\nWhen t"},{"name":"mcp__codex_apps__meta_ads_ads_experiment_lift_get_test","description":"meta ads mcp\n\nFetches a single lift study by its study ID and returns full details — cells, objectives, and incremental results. Use this when you already have a specific"},{"name":"mcp__codex_apps__meta_ads_ads_get_ad_preview","description":"meta ads mcp\n\nGenerate a visual preview of how an ad creative appears on Facebook, Instagram, Messenger, or other placements. CRITICAL: after this tool returns, you MUST "},{"name":"mcp__codex_apps__meta_ads_ads_get_dataset_details","description":"meta ads mcp\n\nRetrieves identity and configuration metadata for a dataset (also known as pixel or application), including name, status, creation time, business associatio"},{"name":"mcp__codex_apps__meta_ads_ads_get_dataset_quality","description":"meta ads mcp\n\nRetrieves signal quality and health metrics for a dataset (also known as pixel or application), including Event Match Quality (EMQ) scores, per-match-key co"},{"name":"mcp__codex_apps__meta_ads_ads_get_dataset_stats","description":"meta ads mcp\n\nRetrieves event volume statistics for a dataset (also known as pixel or application), aggregated over a configurable time window limited to the last 28 days"},{"name":"mcp__codex_apps__meta_ads_ads_get_datasets","description":"meta ads mcp\n\nRetrieves a paginated list of datasets (also known as pixels or applications) owned or assigned to a business or ad account, including name, status, and cre"},{"name":"mcp__codex_apps__meta_ads_ads_get_field_context","description":"meta ads mcp\n\nReturns rich metadata for ads fields (canonical name, display name, type,\n description, filterability, sortability, enum values, aliases, metric flag,\n su"},{"name":"mcp__codex_apps__meta_ads_ads_get_help_article","description":"meta ads mcp\n\nRetrieves help center articles relevant to the user's question about advertising concepts, policies, or how-to guides.\n\n ## When to use:\n - Call this tool"},{"name":"mcp__codex_apps__meta_ads_ads_library_search","description":"meta ads mcp\n\nSearches the Meta Ad Library for ads matching specified criteria. Returns publicly available ad data including ad creative, page info, and metadata.\n\n This"},{"name":"mcp__codex_apps__meta_ads_ads_pixel_event_create","description":"meta ads mcp\n\nCreates Meta Pixel conversion event rules. Batch-capable.\n\n AUTH: requires either the `ads_management` or `business_management` granular OAuth scope on the"},{"name":"mcp__codex_apps__meta_ads_ads_pixel_event_update","description":"meta ads mcp\n\nUpdates Meta Pixel conversion event rules. Currently status-only. Batch-capable.\n\n AUTH: requires either the `ads_management` or `business_management` gran"},{"name":"mcp__codex_apps__meta_ads_ads_pixel_parameter_create","description":"meta ads mcp\n\nCreates Meta Pixel parameter extractors (CSS or CONSTANT_VALUE), linked to an existing event rule. Batch-capable.\n\n AUTH: requires either the `ads_manageme"}]
{"chunk_id":"952a29","wall_time_seconds":0.000027209,"exit_code":0,"original_token_count":64,"output":"total 8\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:52 .\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:50 ..\n-rw-r--r--@ 1 sahaj staff 120 Oct 7 19:52 .env\n/Users/sahaj/Desktop/dev/x/agent-browser-use/AGENTS.md\n/Users/sahaj/Desktop/dev/apps/tokn/AGENTS.md\n"}>for p in /AGENTS.md /Users/AGENTS.md /Users/sahaj/AGENTS.md /Users/sahaj/Desktop/AGENTS.md /Users/sahaj/Desktop/dev/AGENTS.md /Users/sahaj/Desktop/dev/program/AGENTS.md; do if [ -f "$p" ]; then cat "$p"; fi; done
python3 - <<'PY'
from pathlib import Path
for l in Path('.env').read_text().splitlines():
if '=' in l and not l.lstrip().startswith('#'):print('Environment key:',l.split('=',1)[0].strip())
PY
node --version
npm --version
which chromium google-chrome playwright || true{"chunk_id":"26d896","wall_time_seconds":0.329638625,"exit_code":0,"original_token_count":39,"output":"Environment key: JEV_API_KEY\nv22.22.3\n10.9.8\nchromium not found\ngoogle-chrome not found\n/Library/Frameworks/Python.framework/Versions/3.10/bin/playwright\n"}
[]
Content scripts | Chrome for Developers (https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts)
citeturn12view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts","lineno":null}); Total lines: 610
L0: [Button: ]
L1:
L2: cite0†Docs cite1†Case studies cite2†Blog cite3†New in Chrome L3:
L4: [Input: Search]
L5:
L6: `/`
L7:
L8: * English
L9: * Deutsch
L10: * Español – América Latina
L11: * Français
L12: * Indonesia
L13: * Italiano
L14: * Nederlands
L15: * Polski
L16: * Português – Brasil
L17: * Tiếng Việt
L18: * Türkçe
L19: * Русский
L20: * עברית
L21: * العربيّة
L22: * فارسی
L23: * हिंदी
L24: * বাংলা
L25: * ภาษาไทย
L26: * 中文 – 简体
L27: * 中文 – 繁體
L28: * 日本語
L29: * 한국어
L30: Sign in
L31:
L32: cite4†Overview cite5†Get Started cite6†Develop cite7†How To cite8†AI cite9†Reference cite10†Samples cite11†Chrome Web Store L33:
L34: [Input: Filter]
L35: [Button: ]
L36:
L37: * Design the user interface
L38:
L39: * Core concepts
L40:
L41: * Migrate to Manifest V3
L42:
L43: * Security and privacy
L44: * cite12†Baseline <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†web.dev L45: * cite13†web.dev <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†web.dev L46: * cite14†PageSpeed Insights audit <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†pagespeed.web.dev L47: # Content scripts Stay organized with collections Save and categorize content based on your preferences.
L48:
L49: Content scripts are files that run in the context of web pages. Using the standard cite15†Document Object Model†developer.mozilla.org (DOM), they are able to read details of the web pages the browser visits, make changes to them, and pass information to their parent extension.
L50: ## Understand content script capabilities
L51:
L52: Content scripts can access the following extension APIs directly:
L53:
L54: * cite16†`dom` L55: * cite17†`i18n` L56: * cite18†`storage` L57: * cite19†`runtime.connect()` L58: * cite20†`runtime.getManifest()` L59: * cite21†`runtime.getURL()` L60: * cite22†`runtime.id` L61: * cite23†`runtime.onConnect` L62: * cite24†`runtime.onMessage` L63: * cite25†`runtime.sendMessage()` L64: Content scripts are unable to access other APIs directly. But they can access them indirectly by cite26†exchanging messages with other parts of your extension.
L65:
L66: You can also access other files in your extension from a content script, using APIs like `fetch()`. To do this, you need to declare them as cite27†web-accessible resources . Note that this also exposes the resources to any first-party or third-party scripts running on the same site.
L67: ## Work in isolated worlds
L68:
L69: Content scripts live in an isolated world, allowing a content script to make changes to its JavaScript environment without conflicting with the page or other extensions' content scripts.
L70: Key term: An isolated world is a private execution environment that isn't accessible to the page or other extensions. A practical consequence of this isolation is that JavaScript variables in an extension's content scripts are not visible to the host page or other extensions' content scripts. The concept was originally introduced with the initial launch of Chrome, providing isolation for browser tabs.
L71:
L72: An extension may run in a web page with code similar to the following example.
L73: webPage.html
L74:
L75: `<html>
L76: <button id="mybutton">click me</button>
L77: <script>
L78: var greeting = "hello, ";
L79: var button = document.getElementById("mybutton");
L80: button.person_name = "Bob";
L81: button.addEventListener(
L82: "click", () => alert(greeting + button.person_name + "."), false);
L83: </script>
L84: </html>
L85: `
L86:
L87: That extension could inject the following content script using one of the techniques outlined in the cite28†Inject scripts section.
L88: content-script.js
L89:
L90: `var greeting = "hola, ";
L91: var button = document.getElementById("mybutton");
L92: button.person_name = "Roberto";
L93: button.addEventListener(
L94: "click", () => alert(greeting + button.person_name + "."), false);
L95: `
L96:
L97: With this change, both alerts appear in sequence when the button is clicked.
L98: Note: Not only does each extension run in its own isolated world, but content scripts and the web page do too. This means that none of these (web page, content scripts, and any running extensions) can access the context and variables of the others.
L99: ## Inject scripts
L100:
L101: Content scripts can be cite29†declared statically , cite30†declared dynamically , or cite31†programmatically injected .
L102: ### Inject with static declarations
L103:
L104: Use static content script declarations in manifest.json for scripts that should be automatically run on a well known set of pages.
L105:
L106: Statically declared scripts are registered in the manifest under the `"content_scripts"` key. They can include JavaScript files, CSS files, or both. All auto-run content scripts must specify cite32†match patterns .
L107: manifest.json
L108:
L109: `{
L110: "name": "My extension",
L111: ...
L112: "content_scripts": [
L113: {
L114: "matches": ["https://*.nytimes.com/*"],
L115: "css": ["my-styles.css"],
L116: "js": ["content-script.js"]
L117: }
L118: ],
L119: ...
L120: }
L121:
L122: `
L123: Name | Type | Description
L124: --- | --- | ---
L125: `matches` | array of strings | Required. Specifies which pages this content script will be injected into. See cite32†Match Patterns for details on the syntax of these strings and cite33†Match patterns and globs for information on how to exclude URLs.
L126: `css` | array of strings | Optional. The list of CSS files to be injected into matching pages. These are injected in the order they appear in this array, before any DOM is constructed or displayed for the page.
L127: `js` | array of strings | Optional. The list of JavaScript files to be injected into matching pages. Files are injected in the order they appear in this array. Each string in this list must contain a relative path to a resource in the extension's root directory. Leading slashes (`/`) are automatically trimmed.
L128: `run_at` | cite34†RunAt | Optional. Specifies when the script should be injected into the page. Defaults to `document_idle`.
L129: `match_about_blank` | boolean | Optional. Whether the script should inject into an `about:blank` frame where the parent or opener frame matches one of the patterns declared in `matches`. Defaults to false.
L130: `match_origin_as_fallback` | boolean | Optional. Whether the script should inject in frames that were created by a matching origin, but whose URL or origin may not directly match the pattern. These include frames with different schemes, such as `about:`, `data:`, `blob:`, and `filesystem:`. See also cite35†Injecting in related frames .
L131: `world` | cite36†ExecutionWorld | Optional. The JavaScript world for a script to execute within. Defaults to `ISOLATED`. See also cite37†Work in isolated worlds .
L132: Within a given cite38†stage of the document lifecycle, content scripts declared statically in the manifest are the first to be injected, before content scripts registered in any other way. They are injected in the order in which they are specified in the manifest.
L133: ### Inject with dynamic declarations
L134:
L135: Dynamic content scripts are useful when the match patterns for content scripts are not well known or when content scripts shouldn't always be injected on known hosts.
L136:
L137: Introduced in Chrome 96, dynamic declarations are similar to cite29†static declarations , but the content script object is registered with Chrome using methods in the cite39†`browser.scripting` namespace rather than in cite40†manifest.json . The Scripting API also allows extension developers to:
L138: * cite41†Register content scripts.
L139: * cite42†Get a list of registered content scripts.
L140: * cite43†Update the list of registered content scripts.
L141: * cite44†Remove registered content scripts.
L142:
L143: Like static declarations, dynamic declarations can include JavaScript files, CSS files, or both.
L144: service-worker.js
L145:
L146: `browser.scripting
L147: .registerContentScripts([{
L148: id: "session-script",
L149: js: ["content.js"],
L150: persistAcrossSessions: false,
L151: matches: ["*://example.com/*"],
L152: runAt: "document_start",
L153: }])
L154: .then(() => console.log("registration complete"))
L155: .catch((err) => console.warn("unexpected error", err))
L156: `
L157: service-worker.js
L158:
L159: `browser.scripting
L160: .updateContentScripts([{
L161: id: "session-script",
L162: excludeMatches: ["*://admin.example.com/*"],
L163: }])
L164: .then(() => console.log("registration updated"));
L165: `
L166:
L167: service-worker.js
L168:
L169: `browser.scripting
L170: .getRegisteredContentScripts()
L171: .then(scripts => console.log("registered content scripts", scripts));
L172: `
L173: service-worker.js
L174:
L175: `browser.scripting
L176: .unregisterContentScripts({ ids: ["session-script"] })
L177: .then(() => console.log("un-registration complete"));
L178: `
L179: ### Inject programmatically
L180:
L181: Use programmatic injection for content scripts that need to run in response to events or on specific occasions.
L182:
L183: To inject a content script programmatically, your extension needs cite45†host permissions for the page it's trying to inject scripts into. Host permissions can either be granted by requesting them as part of your extension's manifest or temporarily using cite46†`"activeTab"` .
L184:
L185: The following are different versions of an activeTab-based extension.
L186: manifest.json:
L187:
L188: `{
L189: "name": "My extension",
L190: ...
L191: "permissions": [
L192: "activeTab",
L193: "scripting"
L194: ],
L195: "background": {
L196: "service_worker": "background.js"
L197: },
L198: "action": {
L199: "default_title": "Action Button"
L200: }
L201: }
L202: `
L203:
L204: Content scripts can be injected as files.
L205:
L206: content-script.js
L207:
L208: `
L209: document.body.style.backgroundColor = "orange";
L210: `
L211: service-worker.js:
L212:
L213: `browser.action.onClicked.addListener((tab) => {
L214: browser.scripting.executeScript({
L215: target: { tabId: tab.id },
L216: files: ["content-script.js"]
L217: });
L218: });
L219: `
L220:
L221: Or, a function body can be injected and executed as a content script.
L222: service-worker.js:
L223:
L224: `function injectedFunction() {
L225: document.body.style.backgroundColor = "orange";
L226: }
L227:
L228: browser.action.onClicked.addListener((tab) => {
L229: browser.scripting.executeScript({
L230: target : {tabId : tab.id},
L231: func : injectedFunction,
L232: });
L233: });
L234: `
L235: Be aware that the injected function is a copy of the function referenced in the `browser.scripting.executeScript()` call, not the original function itself. As a result, the function's body must be self contained; references to variables outside of the function will cause the content script to throw a cite47†`ReferenceError`†developer.mozilla.org .
L236:
L237: When injecting as a function, you can also pass arguments to the function.
L238: service-worker.js
L239:
L240: `function injectedFunction(color) {
L241: document.body.style.backgroundColor = color;
L242: }
L243:
L244: browser.action.onClicked.addListener((tab) => {
L245: browser.scripting.executeScript({
L246: target : {tabId : tab.id},
L247: func : injectedFunction,
L248: args : [ "orange" ],
L249: });
L250: });
L251: `
L252: ### Exclude matches and globs
L253:
L254: To customize specified page matching, include the following fields in a declarative registration.
L255: Name | Type | Description
L256: --- | --- | ---
L257: `exclude_matches` | array of strings | Optional. Excludes pages that this content script would otherwise be injected into. See cite32†Match Patterns for details of the syntax of these strings.
L258: `include_globs` | array of strings | Optional. Applied after `matches` to include only those URLs that also match this glob. This is intended to emulate the cite48†`@include`†wiki.greasespot.net Greasemonkey keyword.
L259: `exclude_globs` | array of string | Optional. Applied after `matches` to exclude URLs that match this glob. Intended to emulate the cite49†`@exclude`†wiki.greasespot.net Greasemonkey keyword.
L260: The content script will be injected into a page if both of the following are true:
L261:
L262: * Its URL matches any `matches` pattern and any `include_globs` pattern.
L263: * The URL doesn't also match an `exclude_matches` or `exclude_globs` pattern. Because the `matches` property is required, `exclude_matches`, `include_globs`, and `exclude_globs` can only be used to limit which pages will be affected.
L264: The following extension injects the content script into `https://www.nytimes.com/health` but not into `https://www.nytimes.com/business` .
L265:
L266: manifest.json
L267:
L268: `{
L269: "name": "My extension",
L270: ...
L271: "content_scripts": [
L272: {
L273: "matches": ["https://*.nytimes.com/*"],
L274: "exclude_matches": ["*://*/*business*"],
L275: "js": ["contentScript.js"]
L276: }
L277: ],
L278: ...
L279: }
L280: `
L281: service-worker.js
L282:
--------------------------------------------------------------------------------
browser.storage | API | Chrome for Developers (https://developer.chrome.com/docs/extensions/reference/api/storage)
citeturn12view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://developer.chrome.com/docs/extensions/reference/api/storage","lineno":null}); Total lines: 460
--------------------------------------------------------------------------------
Reviews of Arrival (2016) • Letterboxd (https://letterboxd.com/film/arrival-2016/reviews/)
citeturn12view2 [wordlim: 200] Crawled: last month; Content type: text/html; Source: open({"ref_id":"https://letterboxd.com/film/arrival-2016/reviews/","lineno":null}); Total lines: 248{"chunk_id":"26d896","wall_time_seconds":0.329638625,"exit_code":0,"original_token_count":39,"output":"Environment key: JEV_API_KEY\nv22.22.3\n10.9.8\nchromium not found\ngoogle-chrome not found\n/Library/Frameworks/Python.framework/Versions/3.10/bin/playwright\n"}
[]
Content scripts | Chrome for Developers (https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts)
citeturn12view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts","lineno":null}); Total lines: 610
L0: [Button: ]
L1:
L2: cite0†Docs cite1†Case studies cite2†Blog cite3†New in Chrome L3:
L4: [Input: Search]
L5:
L6: `/`
L7:
L8: * English
L9: * Deutsch
L10: * Español – América Latina
L11: * Français
L12: * Indonesia
L13: * Italiano
L14: * Nederlands
L15: * Polski
L16: * Português – Brasil
L17: * Tiếng Việt
L18: * Türkçe
L19: * Русский
L20: * עברית
L21: * العربيّة
L22: * فارسی
L23: * हिंदी
L24: * বাংলা
L25: * ภาษาไทย
L26: * 中文 – 简体
L27: * 中文 – 繁體
L28: * 日本語
L29: * 한국어
L30: Sign in
L31:
L32: cite4†Overview cite5†Get Started cite6†Develop cite7†How To cite8†AI cite9†Reference cite10†Samples cite11†Chrome Web Store L33:
L34: [Input: Filter]
L35: [Button: ]
L36:
L37: * Design the user interface
L38:
L39: * Core concepts
L40:
L41: * Migrate to Manifest V3
L42:
L43: * Security and privacy
L44: * cite12†Baseline <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†web.dev L45: * cite13†web.dev <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†web.dev L46: * cite14†PageSpeed Insights audit <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†pagespeed.web.dev L47: # Content scripts Stay organized with collections Save and categorize content based on your preferences.
L48:
L49: Content scripts are files that run in the context of web pages. Using the standard cite15†Document Object Model†developer.mozilla.org (DOM), they are able to read details of the web pages the browser visits, make changes to them, and pass information to their parent extension.
L50: ## Understand content script capabilities
L51:
L52: Content scripts can access the following extension APIs directly:
L53:
L54: * cite16†`dom` L55: * cite17†`i18n` L56: * cite18†`storage` L57: * cite19†`runtime.connect()` L58: * cite20†`runtime.getManifest()` L59: * cite21†`runtime.getURL()` L60: * cite22†`runtime.id` L61: * cite23†`runtime.onConnect` L62: * cite24†`runtime.onMessage` L63: * cite25†`runtime.sendMessage()` L64: Content scripts are unable to access other APIs directly. But they can access them indirectly by cite26†exchanging messages with other parts of your extension.
L65:
L66: You can also access other files in your extension from a content script, using APIs like `fetch()`. To do this, you need to declare them as cite27†web-accessible resources . Note that this also exposes the resources to any first-party or third-party scripts running on the same site.
L67: ## Work in isolated worlds
L68:
L69: Content scripts live in an isolated world, allowing a content script to make changes to its JavaScript environment without conflicting with the page or other extensions' content scripts.
L70: Key term: An isolated world is a private execution environment that isn't accessible to the page or other extensions. A practical consequence of this isolation is that JavaScript variables in an extension's content scripts are not visible to the host page or other extensions' content scripts. The concept was originally introduced with the initial launch of Chrome, providing isolation for browser tabs.
L71:
L72: An extension may run in a web page with code similar to the following example.
L73: webPage.html
L74:
L75: `<html>
L76: <button id="mybutton">click me</button>
L77: <script>
L78: var greeting = "hello, ";
L79: var button = document.getElementById("mybutton");
L80: button.person_name = "Bob";
L81: button.addEventListener(
L82: "click", () => alert(greeting + button.person_name + "."), false);
L83: </script>
L84: </html>
L85: `
L86:
L87: That extension could inject the following content script using one of the techniques outlined in the cite28†Inject scripts section.
L88: content-script.js
L89:
L90: `var greeting = "hola, ";
L91: var button = document.getElementById("mybutton");
L92: button.person_name = "Roberto";
L93: button.addEventListener(
L94: "click", () => alert(greeting + button.person_name + "."), false);
L95: `
L96:
L97: With this change, both alerts appear in sequence when the button is clicked.
L98: Note: Not only does each extension run in its own isolated world, but content scripts and the web page do too. This means that none of these (web page, content scripts, and any running extensions) can access the context and variables of the others.
L99: ## Inject scripts
L100:
L101: Content scripts can be cite29†declared statically , cite30†declared dynamically , or cite31†programmatically injected .
L102: ### Inject with static declarations
L103:
L104: Use static content script declarations in manifest.json for scripts that should be automatically run on a well known set of pages.
L105:
L106: Statically declared scripts are registered in the manifest under the `"content_scripts"` key. They can include JavaScript files, CSS files, or both. All auto-run content scripts must specify cite32†match patterns .
L107: manifest.json
L108:
L109: `{
L110: "name": "My extension",
L111: ...
L112: "content_scripts": [
L113: {
L114: "matches": ["https://*.nytimes.com/*"],
L115: "css": ["my-styles.css"],
L116: "js": ["content-script.js"]
L117: }
L118: ],
L119: ...
L120: }
L121:
L122: `
L123: Name | Type | Description
L124: --- | --- | ---
L125: `matches` | array of strings | Required. Specifies which pages this content script will be injected into. See cite32†Match Patterns for details on the syntax of these strings and cite33†Match patterns and globs for information on how to exclude URLs.
L126: `css` | array of strings | Optional. The list of CSS files to be injected into matching pages. These are injected in the order they appear in this array, before any DOM is constructed or displayed for the page.
L127: `js` | array of strings | Optional. The list of JavaScript files to be injected into matching pages. Files are injected in the order they appear in this array. Each string in this list must contain a relative path to a resource in the extension's root directory. Leading slashes (`/`) are automatically trimmed.
L128: `run_at` | cite34†RunAt | Optional. Specifies when the script should be injected into the page. Defaults to `document_idle`.
L129: `match_about_blank` | boolean | Optional. Whether the script should inject into an `about:blank` frame where the parent or opener frame matches one of the patterns declared in `matches`. Defaults to false.
L130: `match_origin_as_fallback` | boolean | Optional. Whether the script should inject in frames that were created by a matching origin, but whose URL or origin may not directly match the pattern. These include frames with different schemes, such as `about:`, `data:`, `blob:`, and `filesystem:`. See also cite35†Injecting in related frames .
L131: `world` | cite36†ExecutionWorld | Optional. The JavaScript world for a script to execute within. Defaults to `ISOLATED`. See also cite37†Work in isolated worlds .
L132: Within a given cite38†stage of the document lifecycle, content scripts declared statically in the manifest are the first to be injected, before content scripts registered in any other way. They are injected in the order in which they are specified in the manifest.
L133: ### Inject with dynamic declarations
L134:
L135: Dynamic content scripts are useful when the match patterns for content scripts are not well known or when content scripts shouldn't always be injected on known hosts.
L136:
L137: Introduced in Chrome 96, dynamic declarations are similar to cite29†static declarations , but the content script object is registered with Chrome using methods in the cite39†`browser.scripting` namespace rather than in cite40†manifest.json . The Scripting API also allows extension developers to:
L138: * cite41†Register content scripts.
L139: * cite42†Get a list of registered content scripts.
L140: * cite43†Update the list of registered content scripts.
L141: * cite44†Remove registered content scripts.
L142:
L143: Like static declarations, dynamic declarations can include JavaScript files, CSS files, or both.
L144: service-worker.js
L145:
L146: `browser.scripting
L147: .registerContentScripts([{
L148: id: "session-script",
L149: js: ["content.js"],
L150: persistAcrossSessions: false,
L151: matches: ["*://example.com/*"],
L152: runAt: "document_start",
L153: }])
L154: .then(() => console.log("registration complete"))
L155: .catch((err) => console.warn("unexpected error", err))
L156: `
L157: service-worker.js
L158:
L159: `browser.scripting
L160: .updateContentScripts([{
L161: id: "session-script",
L162: excludeMatches: ["*://admin.example.com/*"],
L163: }])
L164: .then(() => console.log("registration updated"));
L165: `
L166:
L167: service-worker.js
L168:
L169: `browser.scripting
L170: .getRegisteredContentScripts()
L171: .then(scripts => console.log("registered content scripts", scripts));
L172: `
L173: service-worker.js
L174:
L175: `browser.scripting
L176: .unregisterContentScripts({ ids: ["session-script"] })
L177: .then(() => console.log("un-registration complete"));
L178: `
L179: ### Inject programmatically
L180:
L181: Use programmatic injection for content scripts that need to run in response to events or on specific occasions.
L182:
L183: To inject a content script programmatically, your extension needs cite45†host permissions for the page it's trying to inject scripts into. Host permissions can either be granted by requesting them as part of your extension's manifest or temporarily using cite46†`"activeTab"` .
L184:
L185: The following are different versions of an activeTab-based extension.
L186: manifest.json:
L187:
L188: `{
L189: "name": "My extension",
L190: ...
L191: "permissions": [
L192: "activeTab",
L193: "scripting"
L194: ],
L195: "background": {
L196: "service_worker": "background.js"
L197: },
L198: "action": {
L199: "default_title": "Action Button"
L200: }
L201: }
L202: `
L203:
L204: Content scripts can be injected as files.
L205:
L206: content-script.js
L207:
L208: `
L209: document.body.style.backgroundColor = "orange";
L210: `
L211: service-worker.js:
L212:
L213: `browser.action.onClicked.addListener((tab) => {
L214: browser.scripting.executeScript({
L215: target: { tabId: tab.id },
L216: files: ["content-script.js"]
L217: });
L218: });
L219: `
L220:
L221: Or, a function body can be injected and executed as a content script.
L222: service-worker.js:
L223:
L224: `function injectedFunction() {
L225: document.body.style.backgroundColor = "orange";
L226: }
L227:
L228: browser.action.onClicked.addListener((tab) => {
L229: browser.scripting.executeScript({
L230: target : {tabId : tab.id},
L231: func : injectedFunction,
L232: });
L233: });
L234: `
L235: Be aware that the injected function is a copy of the function referenced in the `browser.scripting.executeScript()` call, not the original function itself. As a result, the function's body must be self contained; references to variables outside of the function will cause the content script to throw a cite47†`ReferenceError`†developer.mozilla.org .
L236:
L237: When injecting as a function, you can also pass arguments to the function.
L238: service-worker.js
L239:
L240: `function injectedFunction(color) {
L241: document.body.style.backgroundColor = color;
L242: }
L243:
L244: browser.action.onClicked.addListener((tab) => {
L245: browser.scripting.executeScript({
L246: target : {tabId : tab.id},
L247: func : injectedFunction,
L248: args : [ "orange" ],
L249: });
L250: });
L251: `
L252: ### Exclude matches and globs
L253:
L254: To customize specified page matching, include the following fields in a declarative registration.
L255: Name | Type | Description
L256: --- | --- | ---
L257: `exclude_matches` | array of strings | Optional. Excludes pages that this content script would otherwise be injected into. See cite32†Match Patterns for details of the syntax of these strings.
L258: `include_globs` | array of strings | Optional. Applied after `matches` to include only those URLs that also match this glob. This is intended to emulate the cite48†`@include`†wiki.greasespot.net Greasemonkey keyword.
L259: `exclude_globs` | array of string | Optional. Applied after `matches` to exclude URLs that match this glob. Intended to emulate the cite49†`@exclude`†wiki.greasespot.net Greasemonkey keyword.
L260: The content script will be injected into a page if both of the following are true:
L261:
L262: * Its URL matches any `matches` pattern and any `include_globs` pattern.
L263: * The URL doesn't also match an `exclude_matches` or `exclude_globs` pattern. Because the `matches` property is required, `exclude_matches`, `include_globs`, and `exclude_globs` can only be used to limit which pages will be affected.
L264: The following extension injects the content script into `https://www.nytimes.com/health` but not into `https://www.nytimes.com/business` .
L265:
L266: manifest.json
L267:
L268: `{
L269: "name": "My extension",
L270: ...
L271: "content_scripts": [
L272: {
L273: "matches": ["https://*.nytimes.com/*"],
L274: "exclude_matches": ["*://*/*business*"],
L275: "js": ["contentScript.js"]
L276: }
L277: ],
L278: ...
L279: }
L280: `
L281: service-worker.js
L282:
--------------------------------------------------------------------------------
browser.storage | API | Chrome for Developers (https://developer.chrome.com/docs/extensions/reference/api/storage)
citeturn12view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://developer.chrome.com/docs/extensions/reference/api/storage","lineno":null}); Total lines: 460
--------------------------------------------------------------------------------
Reviews of Arrival (2016) • Letterboxd (https://letterboxd.com/film/arrival-2016/reviews/)
citeturn12view2 [wordlim: 200] Crawled: last month; Content type: text/html; Source: open({"ref_id":"https://letterboxd.com/film/arrival-2016/reviews/","lineno":null}); Total lines: 248>curl -fsSL --max-time 20 'https://letterboxd.com/film/arrival-2016/reviews/' -o /tmp/jev-letterboxd-reviews.html
python3 - <<'PY'
from pathlib import Path
p=Path('/tmp/jev-letterboxd-reviews.html')
if p.exists():
s=p.read_text()
print('HTML length:',len(s))
for term in ['review body-text','review-text','film-detail-content','contains-spoilers','js-review','data-film-slug']:
idx=s.find(term)
print(term,repr(s[max(0,idx-150):idx+900]) if idx>=0 else 'not found')
PY
ls -d '/Applications/Google Chrome.app' "$HOME/Library/Caches/ms-playwright"/* 2>/dev/null{"chunk_id":"3ecfd5","wall_time_seconds":0.021037375,"exit_code":0,"original_token_count":48,"output":"curl: (22) The requested URL returned error: 403\n/Applications/Google Chrome.app\n/Users/sahaj/Library/Caches/ms-playwright/chromium-1117\n/Users/sahaj/Library/Caches/ms-playwright/ffmpeg-1009\n"}
Cross-origin network requests | Chrome for Developers (https://developer.chrome.com/docs/extensions/develop/concepts/network-requests)
citeturn13view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://developer.chrome.com/docs/extensions/develop/concepts/network-requests","lineno":null}); Total lines: 220
L0: [Button: ]
L1:
L2: cite0†Docs cite1†Case studies cite2†Blog cite3†New in Chrome L3:
L4: [Input: Search]
L5:
L6: `/`
L7:
L8: * English
L9: * Deutsch
L10: * Español – América Latina
L11: * Français
L12: * Indonesia
L13: * Italiano
L14: * Nederlands
L15: * Polski
L16: * Português – Brasil
L17: * Tiếng Việt
L18: * Türkçe
L19: * Русский
L20: * עברית
L21: * العربيّة
L22: * فارسی
L23: * हिंदी
L24: * বাংলা
L25: * ภาษาไทย
L26: * 中文 – 简体
L27: * 中文 – 繁體
L28: * 日本語
L29: * 한국어
L30: Sign in
L31:
L32: cite4†Overview cite5†Get Started cite6†Develop cite7†How To cite8†AI cite9†Reference cite10†Samples cite11†Chrome Web Store L33:
L34: [Input: Filter]
L35: [Button: ]
L36:
L37: * Design the user interface
L38:
L39: * Core concepts
L40:
L41: * Migrate to Manifest V3
L42:
L43: * Security and privacy
L44: * cite12†Baseline <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†web.dev L45: * cite13†web.dev <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†web.dev L46: * cite14†PageSpeed Insights audit <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†pagespeed.web.dev L47: # Cross-origin network requests Stay organized with collections Save and categorize content based on your preferences.
L48: Regular web pages can use the cite15†`fetch()`†developer.mozilla.org or cite16†`XMLHttpRequest`†www.w3.org APIs to send and receive data from remote servers, but they're limited by the cite17†same origin policy†en.wikipedia.org . cite18†Content scripts initiate requests on behalf of the web origin that the content script has been injected into and therefore content scripts are also subject to the cite17†same origin policy†en.wikipedia.org . Extension origins aren't so limited.
L49: A script executing in an extension service worker or foreground tab can talk to remote servers outside of its origin, as long as the extension requests cite19†host permissions .
L50: ## Extension origin
L51:
L52: Each running extension exists within its own separate security origin. Without requesting additional privileges, the extension can call `fetch()` to get resources within its installation. For example, if an extension contains a JSON configuration file called `config.json`, in a `config_resources/` folder, the extension can retrieve the file's contents like this:
L53:
L54: `const response = await fetch('/config_resources/config.json');
L55: const jsonData = await response.json();
L56: `
L57: If the extension attempts to request content from a security origin other than its own, say https://www.google.com, this will be treated as a cite20†cross-origin request request unless the extension has cite19†host permissions . Cross-origin requests are always treated as such in content scripts, even if the extension has host permissions.
L58: ## Request cross-origin permissions
L59:
L60: To request access to remote servers outside an extension's origin, add hosts, cite21†match patterns , or both to the cite22†host_permissions section of the cite23†manifest file.
L61:
L62: `{
L63: "name": "My extension",
L64: ...
L65: "host_permissions": [
L66: "https://www.google.com/"
L67: ],
L68: ...
L69: }
L70: `
L71:
L72: Cross-origin permission values can be fully qualified host names, like these:
L73:
L74: * "https://www.google.com/"
L75: * "https://www.gmail.com/"
L76: Or they can be match patterns, like these:
L77:
L78: * "https://*.google.com/"
L79: * "https://*/"
L80:
L81: A match pattern of "https://*/" allows HTTPS access to all reachable domains. Note that here, match patterns are similar to cite21†content script match patterns , but any path information following the host is ignored.
L82: Also note that access is granted both by host and by scheme. If an extension wants both secure and non-secure HTTP access to a given host or set of hosts, it must declare the permissions separately:
L83:
L84: `"host_permissions": [
L85: "http://www.google.com/",
L86: "https://www.google.com/"
L87: ]
L88: `
L89: ## Fetch() vs. XMLHttpRequest()
L90:
L91: `fetch()` was created specifically for service workers and follows a broader web trend away from synchronous operations. The `XMLHttpRequest()` API is supported in extensions outside of the service worker, and calling it triggers the extension service worker's fetch handler. New work should favor `fetch()` wherever possible.
L92:
L93: ## Security considerations
L94: ### Avoid cross-site scripting vulnerabilities
L95: When using resources retrieved via `fetch()`, your offscreen document, side panel or popup should be careful not to fall victim to cite24†cross-site scripting†en.wikipedia.org . Specifically, avoid using dangerous APIs such as `innerHTML`. For example:
L96:
L97: `const response = await fetch("https://api.example.com/data.json");
L98: const jsonData = await response.json();
L99: // WARNING! Might be injecting a malicious script!
L100: document.getElementById("resp").innerHTML = jsonData;
L101: ...
L102: `
L103: Instead, prefer safer APIs that do not run scripts:
L104:
L105: `const response = await fetch("https://api.example.com/data.json");
L106: const jsonData = await response.json();
L107: // JSON.parse does not evaluate the attacker's scripts.
L108: let resp = JSON.parse(jsonData);
L109:
L110: `
L111:
L112: `const response = await fetch("https://api.example.com/data.json");
L113: const jsonData = response.json();
L114: // textContent does not let the attacker inject HTML elements.
L115: document.getElementById("resp").textContent = jsonData;
L116:
L117: `
L118: ### Limit content script access to cross-origin requests
L119:
L120: When performing cross-origin requests on behalf of a content script, be careful to cite25†guard against malicious web pages that might try to impersonate a content script. In particular, do not allow content scripts to request an arbitrary URL.
L121: Consider an example where an extension performs a cross-origin request to let a content script discover the price of an item. One not-so-secure approach would be to have the content script specify the exact resource to be fetched by the background page.
L122:
L123: `browser.runtime.onMessage.addListener(
L124: function(request, sender, sendResponse) {
L125: if (request.contentScriptQuery == 'fetchUrl') {
L126: // WARNING: SECURITY PROBLEM - a malicious web page may abuse
L127: // the message handler to get access to arbitrary cross-origin
L128: // resources.
L129: fetch(request.url)
L130: .then(response => response.text())
L131: .then(text => sendResponse(text))
L132: .catch(error => ...)
L133: return true; // Will respond asynchronously.
L134: }
L135: }
L136: );
L137: `
L138:
L139: `browser.runtime.sendMessage(
L140: {
L141: contentScriptQuery: 'fetchUrl',
L142: url: `https://another-site.com/price-query?itemId=${encodeURIComponent(request.itemId)}`
L143: },
L144: response => parsePrice(response.text())
L145: );
L146: `
L147: In the approach above, the content script can ask the extension to fetch any URL that the extension has access to. A malicious web page may be able to forge such messages and trick the extension into giving access to cross-origin resources.
L148: Instead, design message handlers that limit the resources that can be fetched. Below, only the `itemId` is provided by the content script, and not the full URL.
L149:
L150: `browser.runtime.onMessage.addListener(
L151: function(request, sender, sendResponse) {
L152: if (request.contentScriptQuery == 'queryPrice') {
L153: const url = `https://another-site.com/price-query?itemId=${encodeURIComponent(request.itemId)}`
L154: fetch(url)
L155: .then(response => response.text())
L156: .then(text => parsePrice(text))
L157: .then(price => sendResponse(price))
L158: .catch(error => ...)
L159: return true; // Will respond asynchronously.
L160: }
L161: }
L162: );
L163: `
L164:
L165: `browser.runtime.sendMessage(
L166: {contentScriptQuery: 'queryPrice', itemId: 12345},
L167: price => ...
L168: );
L169: `
L170: ### Prefer HTTPS over HTTP
L171:
L172: Additionally, be especially careful of resources retrieved via HTTP. If your extension is used on a hostile network, a network attacker (aka a cite26†"man-in-the-middle"†en.wikipedia.org ) could modify the response and, potentially, attack your extension. Instead, prefer HTTPS whenever possible.
L173: ### Adjust the content security policy
L174:
L175: If you modify the default cite27†Content Security Policy for your extension by adding a `content_security_policy` attribute to your manifest, you'll need to ensure that any hosts to which you'd like to connect are allowed. While the default policy doesn't restrict connections to hosts, be careful when explicitly adding either the `connect-src` or `default-src` directives.
L176: Except as otherwise noted, the content of this page is licensed under the cite28†Creative Commons Attribution 4.0 License†creativecommons.org , and code samples are licensed under the cite29†Apache 2.0 License†www.apache.org . For details, see the cite30†Google Developers Site Policies†developers.google.com . Java is a registered trademark of Oracle and/or its affiliates.
L177:
L178: Last updated 2012-09-18 UTC.
L179:
L180: * ### Contribute
L181: * cite31†File a bug†issuetracker.google.com L182: * cite32†See open issues†issuetracker.google.com L183: * ### Related content
L184:
L185: * cite33†Chromium updates†blog.chromium.org L186: * cite1†Case studies L187: * cite34†Archive L188: * cite35†Podcasts & shows†web.dev L189: * ### Follow
L190:
L191: * cite36†@ChromiumDev on X†twitter.com L192: * cite37†YouTube†www.youtube.com L193: * cite38†Chrome for Developers on LinkedIn†www.linkedin.com L194: * cite39†RSS L195:
L196: * cite40†Terms†policies.google.com L197: * cite41†Privacy†policies.google.com L198: * English
L199: * Deutsch
L200: * Español – América Latina
L201: * Français
L202: * Indonesia
L203: * Italiano
L204: * Nederlands
L205: * Polski
L206: * Português – Brasil
L207: * Tiếng Việt
L208: * Türkçe
L209: * Русский
L210: * עברית
L211: * العربيّة
L212: * فارسی
L213: * हिंदी
L214: * বাংলা
L215: * ภาษาไทย
L216: * 中文 – 简体
L217: * 中文 – 繁體
L218: * 日本語
L219: * 한국어
--------------------------------------------------------------------------------
API reference - TypeSafe AI (https://docs.typesafe.ai/api)
citeturn13view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/api","lineno":null}); Total lines: 583
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Reference
L15:
L16: API reference
L17:
L18: Reference
L19: # API reference
L20:
L21: Full HTTP API reference for the TypeSafe evaluation endpoint.
L22:
L23: Copy page Copy page
L24:
L25: Evaluate a `state` against a map of typed `questions` and get back structured `answers`, one per question. For a guided introduction, start with the cite3†primitives .
L26:
L27: ##
L28:
L29: cite4† L30:
L31: Evaluation endpoint
L32:
L33: `POST https://api.typesafe.ai/v1/systemone
L34: Authorization: Bearer <API_KEY>
L35: Content-Type: application/json
L36: `
L37: ##
L38:
L39: cite5† L40:
L41: Request body
L42:
L43: The top-level shape of every request. Each entry in the `questions` map is a typed question you name.
L44:
L45: cite6† L46:
L47: [Button: state]
L48:
L49: string | object | array
L50:
L51: required
L52:
L53: The content to evaluate. A plain string for text, or structured data (object/array) for things like chat logs, records, or the current state of your application. See cite7†State for formats and best practices.
L54:
L55: cite8† L56:
L57: [Button: model]
L58:
L59: string
L60:
L61: required
L62: The model that handles the request. Use `"jev-latest"`, TypeSafe’s flagship model. See cite9†Models for the available models and aliases.
L63:
L64: cite10† L65:
L66: [Button: questions]
L67:
L68: map<string, Question>
L69:
L70: required
L71:
L72: A map of typed cite11†Question objects. You choose each key; answers come back under the same keys.
L73:
L74: Show map entries
L75:
L76: cite12† L77:
L78: [Button: ‹question id›]
L79:
L80: Question
L81:
L82: A key you choose. The matching cite13†Answer is returned under this same id. The key is not sent to the underlying model and is not used in inference.
L83: Example request
L84:
L85: `{
L86: "state": "Help! My payouts have been failing for 3 days.",
L87: "model": "jev-latest",
L88: "questions": {
L89: "is_urgent": {
L90: "type": "noul",
L91: "instructions": "Does this convey urgency?"
L92: }
L93: }
L94: }
L95: `
L96: ##
L97:
L98: cite11† L99:
L100: Question types{"chunk_id":"3ecfd5","wall_time_seconds":0.021037375,"exit_code":0,"original_token_count":48,"output":"curl: (22) The requested URL returned error: 403\n/Applications/Google Chrome.app\n/Users/sahaj/Library/Caches/ms-playwright/chromium-1117\n/Users/sahaj/Library/Caches/ms-playwright/ffmpeg-1009\n"}
Cross-origin network requests | Chrome for Developers (https://developer.chrome.com/docs/extensions/develop/concepts/network-requests)
citeturn13view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://developer.chrome.com/docs/extensions/develop/concepts/network-requests","lineno":null}); Total lines: 220
L0: [Button: ]
L1:
L2: cite0†Docs cite1†Case studies cite2†Blog cite3†New in Chrome L3:
L4: [Input: Search]
L5:
L6: `/`
L7:
L8: * English
L9: * Deutsch
L10: * Español – América Latina
L11: * Français
L12: * Indonesia
L13: * Italiano
L14: * Nederlands
L15: * Polski
L16: * Português – Brasil
L17: * Tiếng Việt
L18: * Türkçe
L19: * Русский
L20: * עברית
L21: * العربيّة
L22: * فارسی
L23: * हिंदी
L24: * বাংলা
L25: * ภาษาไทย
L26: * 中文 – 简体
L27: * 中文 – 繁體
L28: * 日本語
L29: * 한국어
L30: Sign in
L31:
L32: cite4†Overview cite5†Get Started cite6†Develop cite7†How To cite8†AI cite9†Reference cite10†Samples cite11†Chrome Web Store L33:
L34: [Input: Filter]
L35: [Button: ]
L36:
L37: * Design the user interface
L38:
L39: * Core concepts
L40:
L41: * Migrate to Manifest V3
L42:
L43: * Security and privacy
L44: * cite12†Baseline <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†web.dev L45: * cite13†web.dev <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†web.dev L46: * cite14†PageSpeed Insights audit <span class="material-icons" style="font-size: 12px;" aria-hidden="true" translate="no">open_in_new</span>†pagespeed.web.dev L47: # Cross-origin network requests Stay organized with collections Save and categorize content based on your preferences.
L48: Regular web pages can use the cite15†`fetch()`†developer.mozilla.org or cite16†`XMLHttpRequest`†www.w3.org APIs to send and receive data from remote servers, but they're limited by the cite17†same origin policy†en.wikipedia.org . cite18†Content scripts initiate requests on behalf of the web origin that the content script has been injected into and therefore content scripts are also subject to the cite17†same origin policy†en.wikipedia.org . Extension origins aren't so limited.
L49: A script executing in an extension service worker or foreground tab can talk to remote servers outside of its origin, as long as the extension requests cite19†host permissions .
L50: ## Extension origin
L51:
L52: Each running extension exists within its own separate security origin. Without requesting additional privileges, the extension can call `fetch()` to get resources within its installation. For example, if an extension contains a JSON configuration file called `config.json`, in a `config_resources/` folder, the extension can retrieve the file's contents like this:
L53:
L54: `const response = await fetch('/config_resources/config.json');
L55: const jsonData = await response.json();
L56: `
L57: If the extension attempts to request content from a security origin other than its own, say https://www.google.com, this will be treated as a cite20†cross-origin request request unless the extension has cite19†host permissions . Cross-origin requests are always treated as such in content scripts, even if the extension has host permissions.
L58: ## Request cross-origin permissions
L59:
L60: To request access to remote servers outside an extension's origin, add hosts, cite21†match patterns , or both to the cite22†host_permissions section of the cite23†manifest file.
L61:
L62: `{
L63: "name": "My extension",
L64: ...
L65: "host_permissions": [
L66: "https://www.google.com/"
L67: ],
L68: ...
L69: }
L70: `
L71:
L72: Cross-origin permission values can be fully qualified host names, like these:
L73:
L74: * "https://www.google.com/"
L75: * "https://www.gmail.com/"
L76: Or they can be match patterns, like these:
L77:
L78: * "https://*.google.com/"
L79: * "https://*/"
L80:
L81: A match pattern of "https://*/" allows HTTPS access to all reachable domains. Note that here, match patterns are similar to cite21†content script match patterns , but any path information following the host is ignored.
L82: Also note that access is granted both by host and by scheme. If an extension wants both secure and non-secure HTTP access to a given host or set of hosts, it must declare the permissions separately:
L83:
L84: `"host_permissions": [
L85: "http://www.google.com/",
L86: "https://www.google.com/"
L87: ]
L88: `
L89: ## Fetch() vs. XMLHttpRequest()
L90:
L91: `fetch()` was created specifically for service workers and follows a broader web trend away from synchronous operations. The `XMLHttpRequest()` API is supported in extensions outside of the service worker, and calling it triggers the extension service worker's fetch handler. New work should favor `fetch()` wherever possible.
L92:
L93: ## Security considerations
L94: ### Avoid cross-site scripting vulnerabilities
L95: When using resources retrieved via `fetch()`, your offscreen document, side panel or popup should be careful not to fall victim to cite24†cross-site scripting†en.wikipedia.org . Specifically, avoid using dangerous APIs such as `innerHTML`. For example:
L96:
L97: `const response = await fetch("https://api.example.com/data.json");
L98: const jsonData = await response.json();
L99: // WARNING! Might be injecting a malicious script!
L100: document.getElementById("resp").innerHTML = jsonData;
L101: ...
L102: `
L103: Instead, prefer safer APIs that do not run scripts:
L104:
L105: `const response = await fetch("https://api.example.com/data.json");
L106: const jsonData = await response.json();
L107: // JSON.parse does not evaluate the attacker's scripts.
L108: let resp = JSON.parse(jsonData);
L109:
L110: `
L111:
L112: `const response = await fetch("https://api.example.com/data.json");
L113: const jsonData = response.json();
L114: // textContent does not let the attacker inject HTML elements.
L115: document.getElementById("resp").textContent = jsonData;
L116:
L117: `
L118: ### Limit content script access to cross-origin requests
L119:
L120: When performing cross-origin requests on behalf of a content script, be careful to cite25†guard against malicious web pages that might try to impersonate a content script. In particular, do not allow content scripts to request an arbitrary URL.
L121: Consider an example where an extension performs a cross-origin request to let a content script discover the price of an item. One not-so-secure approach would be to have the content script specify the exact resource to be fetched by the background page.
L122:
L123: `browser.runtime.onMessage.addListener(
L124: function(request, sender, sendResponse) {
L125: if (request.contentScriptQuery == 'fetchUrl') {
L126: // WARNING: SECURITY PROBLEM - a malicious web page may abuse
L127: // the message handler to get access to arbitrary cross-origin
L128: // resources.
L129: fetch(request.url)
L130: .then(response => response.text())
L131: .then(text => sendResponse(text))
L132: .catch(error => ...)
L133: return true; // Will respond asynchronously.
L134: }
L135: }
L136: );
L137: `
L138:
L139: `browser.runtime.sendMessage(
L140: {
L141: contentScriptQuery: 'fetchUrl',
L142: url: `https://another-site.com/price-query?itemId=${encodeURIComponent(request.itemId)}`
L143: },
L144: response => parsePrice(response.text())
L145: );
L146: `
L147: In the approach above, the content script can ask the extension to fetch any URL that the extension has access to. A malicious web page may be able to forge such messages and trick the extension into giving access to cross-origin resources.
L148: Instead, design message handlers that limit the resources that can be fetched. Below, only the `itemId` is provided by the content script, and not the full URL.
L149:
L150: `browser.runtime.onMessage.addListener(
L151: function(request, sender, sendResponse) {
L152: if (request.contentScriptQuery == 'queryPrice') {
L153: const url = `https://another-site.com/price-query?itemId=${encodeURIComponent(request.itemId)}`
L154: fetch(url)
L155: .then(response => response.text())
L156: .then(text => parsePrice(text))
L157: .then(price => sendResponse(price))
L158: .catch(error => ...)
L159: return true; // Will respond asynchronously.
L160: }
L161: }
L162: );
L163: `
L164:
L165: `browser.runtime.sendMessage(
L166: {contentScriptQuery: 'queryPrice', itemId: 12345},
L167: price => ...
L168: );
L169: `
L170: ### Prefer HTTPS over HTTP
L171:
L172: Additionally, be especially careful of resources retrieved via HTTP. If your extension is used on a hostile network, a network attacker (aka a cite26†"man-in-the-middle"†en.wikipedia.org ) could modify the response and, potentially, attack your extension. Instead, prefer HTTPS whenever possible.
L173: ### Adjust the content security policy
L174:
L175: If you modify the default cite27†Content Security Policy for your extension by adding a `content_security_policy` attribute to your manifest, you'll need to ensure that any hosts to which you'd like to connect are allowed. While the default policy doesn't restrict connections to hosts, be careful when explicitly adding either the `connect-src` or `default-src` directives.
L176: Except as otherwise noted, the content of this page is licensed under the cite28†Creative Commons Attribution 4.0 License†creativecommons.org , and code samples are licensed under the cite29†Apache 2.0 License†www.apache.org . For details, see the cite30†Google Developers Site Policies†developers.google.com . Java is a registered trademark of Oracle and/or its affiliates.
L177:
L178: Last updated 2012-09-18 UTC.
L179:
L180: * ### Contribute
L181: * cite31†File a bug†issuetracker.google.com L182: * cite32†See open issues†issuetracker.google.com L183: * ### Related content
L184:
L185: * cite33†Chromium updates†blog.chromium.org L186: * cite1†Case studies L187: * cite34†Archive L188: * cite35†Podcasts & shows†web.dev L189: * ### Follow
L190:
L191: * cite36†@ChromiumDev on X†twitter.com L192: * cite37†YouTube†www.youtube.com L193: * cite38†Chrome for Developers on LinkedIn†www.linkedin.com L194: * cite39†RSS L195:
L196: * cite40†Terms†policies.google.com L197: * cite41†Privacy†policies.google.com L198: * English
L199: * Deutsch
L200: * Español – América Latina
L201: * Français
L202: * Indonesia
L203: * Italiano
L204: * Nederlands
L205: * Polski
L206: * Português – Brasil
L207: * Tiếng Việt
L208: * Türkçe
L209: * Русский
L210: * עברית
L211: * العربيّة
L212: * فارسی
L213: * हिंदी
L214: * বাংলা
L215: * ภาษาไทย
L216: * 中文 – 简体
L217: * 中文 – 繁體
L218: * 日本語
L219: * 한국어
--------------------------------------------------------------------------------
API reference - TypeSafe AI (https://docs.typesafe.ai/api)
citeturn13view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/api","lineno":null}); Total lines: 583
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Reference
L15:
L16: API reference
L17:
L18: Reference
L19: # API reference
L20:
L21: Full HTTP API reference for the TypeSafe evaluation endpoint.
L22:
L23: Copy page Copy page
L24:
L25: Evaluate a `state` against a map of typed `questions` and get back structured `answers`, one per question. For a guided introduction, start with the cite3†primitives .
L26:
L27: ##
L28:
L29: cite4† L30:
L31: Evaluation endpoint
L32:
L33: `POST https://api.typesafe.ai/v1/systemone
L34: Authorization: Bearer <API_KEY>
L35: Content-Type: application/json
L36: `
L37: ##
L38:
L39: cite5† L40:
L41: Request body
L42:
L43: The top-level shape of every request. Each entry in the `questions` map is a typed question you name.
L44:
L45: cite6† L46:
L47: [Button: state]
L48:
L49: string | object | array
L50:
L51: required
L52:
L53: The content to evaluate. A plain string for text, or structured data (object/array) for things like chat logs, records, or the current state of your application. See cite7†State for formats and best practices.
L54:
L55: cite8† L56:
L57: [Button: model]
L58:
L59: string
L60:
L61: required
L62: The model that handles the request. Use `"jev-latest"`, TypeSafe’s flagship model. See cite9†Models for the available models and aliases.
L63:
L64: cite10† L65:
L66: [Button: questions]
L67:
L68: map<string, Question>
L69:
L70: required
L71:
L72: A map of typed cite11†Question objects. You choose each key; answers come back under the same keys.
L73:
L74: Show map entries
L75:
L76: cite12† L77:
L78: [Button: ‹question id›]
L79:
L80: Question
L81:
L82: A key you choose. The matching cite13†Answer is returned under this same id. The key is not sent to the underlying model and is not used in inference.
L83: Example request
L84:
L85: `{
L86: "state": "Help! My payouts have been failing for 3 days.",
L87: "model": "jev-latest",
L88: "questions": {
L89: "is_urgent": {
L90: "type": "noul",
L91: "instructions": "Does this convey urgency?"
L92: }
L93: }
L94: }
L95: `
L96: ##
L97:
L98: cite11† L99:
L100: Question types<send_user_message_question_reply> [{"answer":"Let me turn spoiler protection on for individual films","question":"What should count as a spoiler on Letterboxd?","questionItemId":"["request_user_input_async","call_936d6e222ded4047ac7de91a3846ef68",0]"}] </send_user_message_question_reply>
Got it—protection will be opt-in for each film. I’ll add a “Protect this film” control on Letterboxd, hide its reviews while Jev checks them, and keep suspected spoilers covered until you choose to reveal them. I also found a JEV_API_KEY in your .env; I’ll use it for a small live test without putting it into the extension files.
>python3 - <<'PY'
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser=p.chromium.launch(headless=True)
page=browser.new_page()
try:
response=page.goto('https://letterboxd.com/film/arrival-2016/reviews/',wait_until='domcontentloaded',timeout=25000)
print('HTTP:',response.status,'Title:',page.title())
print(page.locator('.review, .review-text, .film-detail-content, .film-poster').evaluate_all('(els) => els.slice(0,5).map(e => e.outerHTML.slice(0,4500))'))
print('body classes:',page.locator('body').get_attribute('class'))
except Exception as e: print(type(e).__name__,str(e)[:300])
browser.close()
PY{"chunk_id":"f156ad","wall_time_seconds":1.001950541,"session_id":94806,"original_token_count":0,"output":""}{"chunk_id":"4d7670","wall_time_seconds":0.000010666,"exit_code":1,"original_token_count":492,"output":"Traceback (most recent call last):\n File \"<stdin>\", line 3, in <module>\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/sync_api/_generated.py\", line 14566, in launch\n self._sync(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_sync_base.py\", line 115, in _sync\n return task.result()\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_browser_type.py\", line 97, in launch\n await self._channel.send(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 69, in send\n return await self._connection.wrap_api_call(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 559, in wrap_api_call\n raise rewrite_error(error, f\"{parsed_st['apiName']}: {error}\") from None\nplaywright._impl._errors.Error: BrowserType.launch: Executable doesn't exist at /Users/sahaj/Library/Caches/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-mac-arm64/chrome-headless-shell\n╔════════════════════════════════════════════════════════════╗\n║ Looks like Playwright was just installed or updated. ║\n║ Please run the following command to download new browsers: ║\n║ ║\n║ playwright install ║\n║ ║\n║ <3 Playwright Team ║\n╚════════════════════════════════════════════════════════════╝\n"}
{"chunk_id":"5c2a07","wall_time_seconds":0.33934825,"exit_code":0,"original_token_count":71,"output":"Wrote to /Users/sahaj/Desktop/dev/program/jev/package.json:\n\n{\n \"name\": \"jev\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\"\n}\n\n\n\n"}>npm init -y{"chunk_id":"4d7670","wall_time_seconds":0.000010666,"exit_code":1,"original_token_count":492,"output":"Traceback (most recent call last):\n File \"<stdin>\", line 3, in <module>\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/sync_api/_generated.py\", line 14566, in launch\n self._sync(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_sync_base.py\", line 115, in _sync\n return task.result()\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_browser_type.py\", line 97, in launch\n await self._channel.send(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 69, in send\n return await self._connection.wrap_api_call(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 559, in wrap_api_call\n raise rewrite_error(error, f\"{parsed_st['apiName']}: {error}\") from None\nplaywright._impl._errors.Error: BrowserType.launch: Executable doesn't exist at /Users/sahaj/Library/Caches/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-mac-arm64/chrome-headless-shell\n╔════════════════════════════════════════════════════════════╗\n║ Looks like Playwright was just installed or updated. ║\n║ Please run the following command to download new browsers: ║\n║ ║\n║ playwright install ║\n║ ║\n║ <3 Playwright Team ║\n╚════════════════════════════════════════════════════════════╝\n"}
{"chunk_id":"5c2a07","wall_time_seconds":0.33934825,"exit_code":0,"original_token_count":71,"output":"Wrote to /Users/sahaj/Desktop/dev/program/jev/package.json:\n\n{\n \"name\": \"jev\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\"\n}\n\n\n\n"}No content
Actually, instead.. would it be possible to make a 3js webl type game like slowroads.. but its in a city with traffic lights etc and all the npcs use jev to move around? So they're making somewhat logical moves with very low latency? WOuld that work ?
Yes—this could work, with Jev choosing things like lane changes, turns, and yielding while local code handles steering and braking. I’ll pause the extension work and check the latency and throughput constraints for a city simulation.
Models - TypeSafe AI (https://docs.typesafe.ai/models)
citeturn14view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/models","lineno":null}); Total lines: 164
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Reference
L15:
L16: Models
L17:
L18: Reference
L19: # Models
L20:
L21: Copy page Copy page
L22:
L23: Jev is TypeSafe’s flagship model and the first cite3†System One model . Every model on this page is served by the same endpoint, `POST /v1/systemone`. The request’s `model` field selects which one handles the call; see the cite4†API reference for the full request shape.
L24: ##
L25:
L26: cite5† L27:
L28: Current models
L29:
L30: Jev 1.13 | `jev-1.13.0`
L31: --- | ---
L32: Price (per Btok / per Mtok) | $42 / $0.042
L33: Rate limits | 100K tokens per second / 80 requests per second
L34: Context length | 64k tokens per request; 32k tokens for `state` plus the longest question
L35: Input | Text only. String, JSON object, or array of text values. No image, audio, or video input.
L36: * Price: Charged per input token. Output tokens are free. A Btok is a billion tokens and an Mtok is a million tokens.
L37: * Rate limits: Measured in tokens per second and requests per second. A request over either limit returns `429 Too Many Requests`. Our cite6†client SDKs retry with backoff by default and honor the `retry-after` header when the response carries one. If you call the HTTP API directly, see cite7†Handling rate limits .
L38: * Context length: Jev ingests the `state` once and evaluates every question against it in parallel. The 64k budget covers the `state` plus all questions combined; the 32k budget applies to the `state` plus the single longest question. See cite8†Speculative fan-out for packing many questions into one request, and cite9†Jev 1.13 jaggedness for how accuracy shifts as the state grows.
L39: * Input: Jev evaluates natural-language text. Pre-process non-text inputs (images, audio, video, binaries) into text or structured fields before sending them as `state`. See cite10†State for supported shapes.
L40: Rate limits are adjusting dynamically. We are serving a very large volume of demand, and the limits above can change without notice while we do, as upcoming large GPU deals land and we let in more users. Once things settle down more, we’ll be able to offer more stable limits. Higher limits are available on custom and enterprise plans. Contact sales@typesafe.ai.
L41: ##
L42:
L43: cite11† L44:
L45: Aliases
L46:
L47: An alias is a model name that resolves to a versioned model ID. Send it in the `model` field like any other name.
L48:
L49: Alias | Points to | Meaning
L50: --- | --- | ---
L51: `jev-latest` | `jev-1.13.0` | The most recent stable, official release. The default in our client SDKs, and the name the examples in these docs use.
L52: `jev-preview` | `jev-1.13.0` | The most recent release, whether or not it is an official one. Moves ahead of `jev-latest` when a preview build is available.
L53: `jev-preview` currently points to the same model as `jev-latest`. There is no preview build available right now.
L54:
L55: An alias moves when a new release ships, so the answers behind it can change without a change on your side. The response’s `model` field reports the versioned ID that answered, so you can log which model produced each result. If you have tuned confidence thresholds against a specific version, pin that version’s ID instead of the alias and move to the new one on your own schedule.
L56: ##
L57:
L58: cite12† L59:
L60: Customizing Jev
L61:
L62: Jev is not fine-tuned or LoRA-adapted with customer data. It is trained with cite13†RLCD to return calibrated decisions, and the same weights serve every account. You shape its answers to your domain through the request rather than through per-account weights:
L63: * Put your proprietary content, records, and reference material in the `state` field. See cite10†State .
L64: * Encode your domain rules and boundary cases in the `instructions` and `criteria` of each question. See cite14†How to build with TypeSafe and cite15†Advanced: structure .
L65: * Decompose broad judgments into atomic questions and combine the outputs in code. See cite16†Composite scoring and the cite17†AutoResearch cookbook for training a downstream classical model on Jev’s probabilities.
L66: ##
L67:
L68: cite18† L69:
L70: Language support
L71:
L72: Jev accepts natural-language text. English is the primary training language and where accuracy is currently best. Other languages, including CJK scripts, are handled but not equally well; test on your own content before relying on Jev for a non-English workload, and pay close attention to cite19†Confidence when routing.
L73: ##
L74:
L75: cite20† L76:
L77: Data handling
L78:
L79: Jev is not trained on customer requests or responses. See cite21†Legal for the Data Processing Agreement, the Privacy Policy, and details on zero data retention (ZDR) for enterprise customers.
L80: ##
L81:
L82: cite22† L83:
L84: Listing models
L85:
L86: `GET /v1/models` returns the names your account can send in the `model` field, with a description and release date for each. It currently lists the aliases. Versioned IDs such as `jev-1.13.0` are accepted by the `model` field whether or not they appear in the list.
L87:
L88: cURL
L89:
L90: Python
L91: JavaScript
L92:
L93: `curl https://api.typesafe.ai/v1/models \
L94: -H "Authorization: Bearer $TYPESAFE_API_KEY"
L95: `
L96:
L97: `from typesafe_sdk import TypeSafeClient
L98:
L99: with TypeSafeClient() as client:
L100: for model in client.models.list().models:
L101: print(model.name, model.release_date, model.description)
L102: `
L103:
L104: `import { TypeSafeClient } from "@typesafe-ai/sdk";
L105:
L106: const client = new TypeSafeClient();
L107: const models = await client.models.list();
L108: for (const model of models) {
L109: console.log(model.name, model.release_date, model.description);
L110: }
L111: `
L112: cite23† L113:
L114: [Button: models]
L115:
L116: array
L117:
L118: required
L119:
L120: One entry per model or alias.
L121:
L122: Show properties
L123:
L124: cite24† L125:
L126: [Button: name]
L127:
L128: string
L129:
L130: required
L131:
L132: The model ID or alias, as accepted by the `model` field.
L133:
L134: cite25† L135:
L136: [Button: description]
L137:
L138: string
L139:
L140: required
L141:
L142: What the model is for.
L143:
L144: cite26† L145:
L146: [Button: release_date]
L147:
L148: string
L149:
L150: required
L151:
L152: When the model or alias was released.
L153:
L154: See the cite27†Python and cite28†JavaScript SDK references for the full method signatures.
L155:
L156: Was this page helpful?
L157:
L158: Yes No
L159:
L160: cite4†API reference Next L161: cite29†github†github.com cite30†discord†discord.gg cite31†x†x.com L162:
L163: cite32†Powered byThis documentation is built and hosted on Mintlify, a developer documentation platform†www.mintlify.com --------------------------------------------------------------------------------
GitHub - standardagents/jevpilot: A playable Three.js driving simulator with Jev-powered autopilot · GitHub (https://github.com/standardagents/jevpilot)
citeturn14view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://github.com/standardagents/jevpilot","lineno":null}); Total lines: 278
L0: cite0†Skip to content L1: ## Navigation Menu
L2:
L3: cite1†Sign in L4:
L5: Appearance settings
L6:
L7: * Platform
L8:
L9: * AI CODE CREATION
L10: * cite2†GitHub CopilotWrite better code with AI L11: * cite3†GitHub Copilot appDirect agents from issue to merge L12: * cite4†MCP RegistryIntegrate external tools L13:
L14: * DEVELOPER WORKFLOWS
L15: * cite5†ActionsAutomate any workflow L16: * cite6†CodespacesInstant dev environments L17: * cite7†IssuesPlan and track work L18: * cite8†Code ReviewManage code changes L19: * cite9†Code QualityEnforce quality at merge L20: * APPLICATION SECURITY
L21: * cite10†GitHub Advanced SecurityFind and fix vulnerabilities L22: * cite11†Code securitySecure your code as you build L23: * cite12†Secret protectionStop leaks before they start L24:
L25: * EXPLORE
L26: * cite13†Why GitHub L27: * cite14†Documentation†docs.github.com L28: * cite15†Blog†github.blog L29: * cite16†Changelog†github.blog L30: * cite17†Marketplace L31:
L32: cite18†View all features L33:
L34: * Solutions
L35: * BY COMPANY SIZE
L36: * cite19†Enterprises L37: * cite20†Small and medium teams L38: * cite21†Startups L39: * cite22†Nonprofits L40:
L41: * BY USE CASE
L42: * cite23†App Modernization L43: * cite24†DevSecOps L44: * cite25†DevOps L45: * cite26†CI/CD L46: * cite27†View all use cases L47:
L48: * BY INDUSTRY
L49: * cite28†Healthcare L50: * cite29†Financial services L51: * cite30†Manufacturing L52: * cite31†Government L53: * cite32†View all industries L54:
L55: cite33†View all solutions L56:
L57: * Resources
L58: * EXPLORE BY TOPIC
L59: * cite34†AI L60: * cite35†Software Development L61: * cite36†DevOps L62: * cite37†Security L63: * cite38†View all topics L64:
L65: * EXPLORE BY TYPE
L66: * cite39†Customer stories L67: * cite40†Events & webinars L68: * cite41†Ebooks & reports L69: * cite42†Business insights L70: * cite43†GitHub Skills†skills.github.com L71: * SUPPORT & SERVICES
L72: * cite14†Documentation†docs.github.com L73: * cite44†Customer support†support.github.com L74: * cite45†Community forum L75: * cite46†Trust center L76: * cite47†Partners L77:
L78: cite48†View all resources L79:
L80: * Open Source
L81:
L82: * COMMUNITY
L83: * cite49†GitHub SponsorsFund open source developers L84: * PROGRAMS
L85: * cite50†Security Lab†securitylab.github.com L86: * cite51†Maintainer Community†maintainers.github.com L87: * cite52†GitHub Stars†stars.github.com L88: * cite53†Archive Program†archiveprogram.github.com L89:
L90: * REPOSITORIES
L91: * cite54†Topics L92: * cite55†Trending L93: * cite56†Collections L94:
L95: * Enterprise
L96:
L97: * ENTERPRISE SOLUTIONS
L98: * cite19†Enterprise platformAI-powered developer platform L99: * AVAILABLE ADD-ONS
L100: * cite10†GitHub Advanced SecurityEnterprise-grade security features L101: * cite57†Copilot for BusinessEnterprise-grade AI features L102: * cite58†Premium SupportEnterprise-grade 24/7 support L103:
L104: * cite59†Pricing L105:
L106: Search`/`
L107:
L108: cite1†Sign in L109:
L110: cite60†Sign up L111:
L112: Appearance settings
L113: You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert
L114:
L115: 1. cite61†standardagents L116: 2. cite62†jevpilot L117: ## Repository navigation
L118:
L119: * * cite62†Code L120: * cite63†Issues L121: * cite64†Pull requests L122: * cite65†Actions L123: * cite66†Projects L124: * cite67†Security and quality L125: * cite68†Insights L126:
L127: More items
L128:
L129: cite69†Image: standardagents†avatars.githubusercontent.com L130:
L131: cite62†jevpilot L132:
L133: Public
L134:
L135: * cite70†Notifications You must be signed in to change notification settings
L136: * cite70†Fork40 (40) L137: * cite70†Star216 (216) You must be signed in to star a repository
L138:
L139: ## About
L140:
L141: A playable Three.js driving simulator with Jev-powered autopilot
L142: ### Resources
L143:
L144: cite71†Readme L145:
L146: cite72†Activity L147:
L148: cite73†Custom properties L149:
L150: ### Stars
L151:
L152: 216 stars
L153:
L154: ### Watchers
L155:
L156: 5 watching
L157:
L158: ### Forks
L159:
L160: cite74†40 forks L161:
L162: cite75†Report repository L163:
L164: main
L165:
L166: cite76†Branches cite77†Tags L167:
L168: [Input: Go to file]
L169:
L170: Go to file
L171:
L172: Code
L173:
L174: Open more actions menu
L175:
L176: ## Latest commit
L177:
L178:
L179:
L180: ## History
L181:
L182: 14 Commits
L183: ## Folders and files
L184: Name | Name | Last commit message | Last commit date
L185: --- | --- | --- | ---
L186: cite78†docs | cite78†docs | |
L187: cite79†public | cite79†public | |
L188: cite80†scripts | cite80†scripts | |
L189: cite81†server | cite81†server | |
L190: cite82†src | cite82†src | |
L191: cite83†tests | cite83†tests | |
L192: cite84†.env.example | cite84†.env.example | |
L193: cite85†.gitignore | cite85†.gitignore | |
L194: cite86†README.md | cite86†README.md | |
L195: cite87†index.html | cite87†index.html | |
L196: cite88†login.html | cite88†login.html | |
L197: cite89†package-lock.json | cite89†package-lock.json | |
L198: cite90†package.json | cite90†package.json | |
L199: cite91†vite.config.js | cite91†vite.config.js | |
L200: cite92†wrangler.jsonc | cite92†wrangler.jsonc | |
L201: [Button: View all files]
L202: ## Repository files navigation
L203:
L204: * * cite93†README L205:
L206: More items
L207: # JevPilot
L208:
L209: jevdrive-demo.mp4
L210:
L211: A demo project showing Tesla Autopilot-like behavior using cite94†Jev by TypeSafe AI†typesafe.ai .
L212:
L213: Sign in with Standard Agents for $0.25 of free Jev play credit. Joining the early-access list is optional.
L214:
L215: The hosted `/api/decide` endpoint requires a valid login session. The browser sends its secure, HttpOnly session cookie; the Jev API key stays on the server.
L216: Interstate 08: start in Millbrook, turn onto the signed on-ramp, merge, cruise, and exit into Cedar Town for the final stop.
L217: ## How it works
L218:
L219: Jev receives compact tables of eligible paths, road boundaries, nearby traffic, signals, stop memory, and destination guidance. Shared table values are sent once, and instructions include only relevant situations. The road graph is sent only when choosing an alternative route after staying more than 30 meters off course for six seconds. Detailed geometry and control calculations stay local.
L220: The simulator samples fresh steering-and-speed combinations for each decision. On the road, it favors paths that keep the whole car on asphalt. Off road, it explores a wider field of forward and reverse paths and supplies a recovery target, road boundaries, and collision predictions.
L221: An explicit `driving_style` describes an aggressive driver: keep progressing, stop at the actual line, and close gaps before stopping behind an obstacle. Jev can choose an approach path that progressively slows to a stop 0.5 m before the line. An immediate stop is offered only within 2.5 m of a blocker or required stop line, at the destination, or when no eligible moving path exists. Candidate speeds taper near required stops.
L222: Jev receives recent-stop memory and collision timing; a safety brake handles collision risks.
L223: Use Candidates to show the sampled paths: blue/cyan for forward, purple for reverse, amber for paths leaving the lane, orange for predicted collisions, and bright blue for Jev’s selection. Candidate generation and route searches run in a background worker; the renderer smoothly blends the sampled shapes. Open JSON to inspect road boundaries, recovery state, and actual choice probabilities.
L224: Requests run up to 4 times/second near turns or traffic, and about 1.5 times/second on clear roads. Questions with one eligible answer are resolved locally. JSON → Jev input shows the exact API payload; the cost tooltip and response tab show average payload size and billed input tokens.
L225: ## Run locally
L226:
L227: npm ci
L228: cp .env.example .env
L229: # Set TYPESAFE_API_KEY in .env.
L230: npm run dev
L231:
L232: Add your own cite94†TypeSafe AI†typesafe.ai API key to `.env`:
L233:
L234: TYPESAFE_API_KEY=[REDACTED]
L235: Open cite95†localhost:5173†localhost . Local development skips all login, signup, and demo credit limits. No Standard Agents OAuth credentials are needed. Jev calls use your own key and TypeSafe account billing; free play works without a key. The key stays server-side in the gitignored `.env`—never use a `VITE_` variable for it.
L236:
L237: This also applies to `npm run preview` after `npm run build`. Restart the local server after changing `.env`.
L238:
L239: J toggles autopilot · WASD to drive · Space to brake.
L240: Asset credits and licenses are included in cite96†public/ .
L241:
L242: Cloudflare deployment details: cite97†docs/hosting.md .
L243: ## About
L244:
L245: A playable Three.js driving simulator with Jev-powered autopilot
L246:
L247: ### Resources
L248:
L249: cite71†Readme L250:
L251: cite72†Activity L252:
L253: cite73†Custom properties L254:
L255: ### Stars
L256:
L257: 216 stars
L258:
L259: ### Watchers
L260:
L261: 5 watching
L262:
L263: ### Forks
L264:
L265: cite74†40 forks L266:
L267: cite75†Report repository L268:
L269: ## Releases
L270:
L271: ## Packages
L272:
L273: ## Contributors
L274:
L275: ## Languages
L276:
L277: You can’t perform that action at this time.
--------------------------------------------------------------------------------
Jev 1.13 jaggedness - TypeSafe AI (https://docs.typesafe.ai/model-jaggedness/jev-1.13)
citeturn14view2 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/model-jaggedness/jev-1.13","lineno":null}); Total lines: 163
L0: > ## Documentation Index
L1: >
L2: > Fetch the complete documentation index at: cite0†/llms.txt L3: >
L4: > Use this file to discover all available pages before exploring further.
L5:
L6: cite1†Skip to main content L7:
L8: cite2†TypeSafe AI home page L9:
L10: Search...
L11:
L12: Navigation
L13:
L14: Model jaggedness
L15:
L16: Jev 1.13 jaggedness
L17:
L18: Model jaggedness
L19: # Jev 1.13 jaggedness
L20:
L21: Jev isn’t perfect. Here are some jagged edges we are aware of with jev-1.13. Many of these will be fixed in later versions.
L22:
L23: Copy page Copy page
L24:
L25: Applies to `jev-1.13`. Last reviewed 2026-10-02.
L26: `jev-1.13` is fast, calibrated, and good at common-sense judgment but it is not perfect. `jev-1.13` does the best on cite3†System One tasks. It may struggle with tasks that require additional levels of indirection. It can be quite literal in its understanding. It struggles with tasks that require numeric precision.
L27: ##
L28:
L29: cite4† L30:
L31: The failure modes in detail
L32: # | Failure mode | Do this instead
L33: --- | --- | ---
L34: 1 | cite5†Literal reading | Write the exact condition, criteria for each available options
L35: 2 | cite6†Math and Numbers | Keep the arithmetic in code
L36: 3 | cite7†Date and time comparison | Extract components; compare in code
L37: 4 | cite8†Indirection | Reduce hops; point to the relevant state
L38: 5 | cite9†Large state full of irrelevant detail | Filter first; send only what the question needs
L39: 6 | cite10†Adversarial content | Write precise prompts, and test edge cases before deploying
L40: 7 | cite11†Contradictory instructions and criteria | Align the criteria and instruction
L41: 8 | cite12†Choice option order | Reorder the options and check the answer is consistent
L42: 9 | cite13†Generation | Use a generative model
L43: ##
L44:
L45: cite5† L46:
L47: Literal reading
L48: `jev-1.13` answers the question you wrote, not the one you meant. Scoping words, negations, and implied conditions are read at face value. A question will be answered based on the words written in the instruction, whereas a person might have read the intent behind the instructions. Instead: state the exact condition in the `instructions`. Be specific. Put boundary cases in the criteria.
L49: When you look at a wrong answer and find yourself explaining what you really meant, that explanation is the missing half of the instruction. Where interpretation is unavoidable, split it into two literal questions and combine them in code.
L50: ##
L51:
L52: cite6† L53:
L54: Math and Numbers
L55:
L56: Jev is not a calculator. We strongly recommend implementing any mathematical logic in code. Jev will perform better on semantic questions than mathematical ones.
L57: ###
L58:
L59: cite14† L60:
L61: Counting
L62: `jev-1.13` does not count reliably. This covers characters in a word, occurrences of a term in a passage, and items in a long list. The model recognizes the shape of an answer rather than tallying, and the error grows with the size of the thing being counted. Before asking a counting question, ask why the count needs a model at all. If the unit is something a regular expression or a parser can find, the count belongs in code and the model has nothing to add. Instead: count in code.
L63: When you want to count items matching some criteria, iterate in code over the candidates and ask one question for each, then add up the answers yourself.
L64:
L65: `from typesafe_sdk import Noul, TypeSafeClient
L66:
L67: client = TypeSafeClient(model="jev-1.13")
L68: YES = 0.5 # up to you on what you want the threshold to be, depends on your usecase.
L69:
L70: items = ["typesafe", "apple", "california", "banana", "likes", "calibration", "orange", "vertex"]
L71:
L72: result = client.system_one(
L73: {"items": items},
L74: {
L75: f"item_{i}": Noul(instructions=f"Is `items[{i}]` the name of a fruit?")
L76: for i in range(len(items))
L77: },
L78: )
L79:
L80: count = sum(result.nouls[f"item_{i}"].noul > YES for i in range(len(items)))
L81: `
L82: ###
L83:
L84: cite15† L85:
L86: Numeric representations
L87: `jev-1.13` will perform better on semantic representations than numeric. For example, questions about colors using hex values will underperform compared to those using the English names. Given RGB triples or hex values it cannot reliably judge whether two values are near each other. Similarly, questions about high-level programming languages will perform better than questions about low level assembly, or binary encoded instructions.
L88: Instead: do the conversion in code and pass in either the computed number or a named bucket. Keep the model for the part that is genuinely a judgment, such as whether a color reads as a warning.
L89: ###
L90:
L91: cite16† L92:
L93: Math using score
L94:
L95: Please do not use score outputs (e.g., expectations and probability) to compute the exact magnitude of a number between two levels of a criterion. You can use the expectation to check if it passes a particular threshold, but `jev-1.13`’s score levels are weak in numerical calibration. It will not be able to help you reconstruct the exact number by interpolating between the nearest two levels.
L96: ##
L97:
L98: cite7† L99:
L100: Date and time comparison
L101: `jev-1.13` reads dates as text, not as ordered quantities. Asking which of two dates comes first, how far apart they are, or whether one falls inside a window is unreliable. It gets worse with mixed formats, relative references and domain boundaries such as quarters, settlement windows, and accrual periods. Instead: split the work. Extraction is a judgment, so give it to the model. Arithmetic is not, so keep it in code.
L102: Every part of a date is a small closed set: twelve months, thirty-one possible days, a bounded range of years. That turns extraction into a cite17†Choice over enumerated options rather than free-form parsing, and it gives you somewhere to put an explicit “not stated” option so a missing part is reported rather than guessed. Code assembles the parts into a real date and owns everything after that, including ordering, duration, offset, and weekday.
L103: The cite18†date extraction cookbook has the worked version, including relative dates and confidence gating.
L104: ##
L105:
L106: cite8† L107:
L108: Indirection
L109:
L110: Instructions carrying double negatives or complex indirection are answered less reliably. A question about a property of a property or something that requires multiple hops of reasoning costs accuracy. Instead: write your instructions as directly as possible. When possible, identify the relevant parts of state by name.
L111: ##
L112:
L113: cite9† L114:
L115: Large state full of irrelevant detail
L116:
L117: Accuracy falls as the state grows with content unrelated to the decision. Unrelated detail acts as a distractor, and a large state makes it harder to tell which part of the input produced a wrong answer. Instead: retrieve and filter in code first, and send only the fields the question needs. When it’s not possible to filter in state, you can use a cite19†Noul to filter for relevance. The cite20†classifying RAG passages cookbook has a worked example.
L118: Context length limit. `jev-1.13` has a bounded context window. See the cite21†Models page for the exact token limits.
L119: ##
L120:
L121: cite10† L122:
L123: Adversarial content
L124:
L125: State is data, and `jev-1.13` does not treat it as hostile by default. Content written to adversarially steer the model, whether that is an injected instruction, a deliberately misleading framing, or text that argues for its own classification, can move the answer. We expect to improve on this in the future. Instead: be explicit in the criteria. Test your integration thoroughly before deploying it to many users.
L126: ##
L127:
L128: cite11† L129:
L130: Contradictory instructions and criteria
L131:
L132: When the `instructions` and the `criteria` ask for different things, `jev-1.13` might get confused. The best performance comes from clear phrasing. For example, a Noul where `true` maps to no and `false` maps to yes will perform worse. Aim for instructions which are easy for the average person to read and understand. Instead: treat the criteria as an extension of the instruction. Align the two using clear and precise language.
L133: ##
L134:
L135: cite12† L136:
L137: Choice option order
L138:
L139: In some cases, we observed that the order of a cite17†Choice ’s options can affect the answer, and `jev-1.13` leans toward the option that comes first. Instead: reorder the options to double check that the answer stays consistent.
L140: ##
L141:
L142: cite13† L143:
L144: Generation
L145: `jev-1.13` is not trained to generate text. While you can force it to by chaining choices, this will not work well and will be very slow. For data extraction, it is better to extract possible options using regex or a generative model and let `jev-1.13` pick the correct extraction. Instead: when the answer space is bounded, turn extraction into a cite17†Choice over the options rather than asking for the value itself. If you really need to generate text… there are other models for that.
L146: As a reminder, avoid the following:
L147:
L148: * Asking the model something code can compute exactly.
L149: * Hiding several judgments inside one question.
L150: * System Two tasks: more layers of indirections
--------------------------------------------------------------------------------
Generating levels in real time with the Jev model - Sprite Fusion (https://www.spritefusion.com/blog/generating-game-level-in-real-time-with-jev)
citeturn14view3 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://www.spritefusion.com/blog/generating-game-level-in-real-time-with-jev","lineno":null}); Total lines: 174Yes—this would work, and it’s a good fit for Jev. A Three.js city you can drive around, with traffic lights, pedestrians, and NPC drivers making decisions based on what’s happening nearby.
There’s already a smaller proof of the approach: JevPilot uses Three.js and Jev to choose driving maneuvers, with decisions requested up to four times per second around traffic. Expanding that to multiple independently controlled NPCs is plausible, though we’d need to measure throughput and behavior. JevPilot
The crucial design is separating decisions from continuous movement:
| Local game code | Jev |
|---|---|
| Steering along lanes, acceleration, animation | Choose a turn, change lanes, wait, or reroute |
| Braking distances and collision checks | Decide whether to let someone merge |
| Traffic-light timing and permitted movements | Choose among currently permitted actions |
| Walking paths and crosswalk boundaries | Choose a destination or react to a disruption |
The game could render at 60 FPS while each NPC makes a new decision only when needed. A car cruising down an empty street continues driving without repeatedly asking Jev.
Latency would be manageable if we design around it. I’d budget for responses taking several hundred milliseconds, with occasional longer delays—not assume every call returns in 100 ms. One published Jev game demo measured 319–375 ms. Measurements
We’d request decisions before an NPC reaches an intersection. While waiting, it continues its existing maneuver. When the answer arrives, code checks that it’s still valid. If a pedestrian stepped into the road in the meantime, local braking takes precedence.
The part that could make this feel alive is giving NPCs different goals and a little memory:
Those would be behaviors we test, rather than assume personality instructions automatically produce believable driving. Jev’s documented weaknesses include numerical reasoning, so distances, path feasibility, and collision prediction should stay in code. Limitations
The main scaling constraint is API traffic. For illustration, 30 NPCs averaging one decision every two seconds at 600 input tokens per decision would cost about $1.36 per simulation-hour, before hosting. That’s 15 requests/second; the currently documented limit is 80 requests/second, subject to change. Public visitors running separate cities would multiply usage. Pricing and limits
I’d start with a small, polished neighborhood: a few intersections, 15–30 cars, and some pedestrians. Give every NPC access to Jev, but trigger calls around meaningful events. Let you click a car to inspect its goal, available actions, and latest decision.
The first convincing test: park across a lane and watch the surrounding traffic negotiate the obstruction without the whole intersection freezing.
No content
<codex_internal_context source="user_goal"> User set the goal: "go ahead and make it" User set goal status: "active". </codex_internal_context>
<codex_internal_context source="goal"> Continue working toward the active thread goal.
The objective below is user-provided data. Treat it as the task to pursue, not as higher-priority instructions.
go ahead and make itContinuation behavior:
Budget:
Work from evidence: Use the current worktree and external state as authoritative. Previous conversation context can help locate relevant work, but inspect the current state before relying on it. Improve, replace, or remove existing work as needed to satisfy the actual objective.
No-progress check:
Fidelity:
Completion audit: Before deciding that the goal is achieved, treat completion as unproven and verify it against the actual current state:
Do not rely on intent, partial progress, memory of earlier work, or a plausible final answer as proof of completion. Marking the goal complete is a claim that the full objective has been finished and can withstand requirement-by-requirement scrutiny. Only mark the goal achieved when current evidence proves every requirement has been satisfied and no required work remains. If the evidence is incomplete, weak, indirect, merely consistent with completion, or leaves any requirement missing, incomplete, or unverified, keep working instead of marking the goal complete. If the objective is achieved, call update_goal with status "complete" so usage accounting is preserved. If the achieved goal has a token budget, report the final consumed token budget to the user after update_goal succeeds.
Blocked audit:
Call update_goal only after the completion or blocked audit passes, or when the user explicitly requests pausing this goal. For a requested pause, use status "paused", report the returned status, and stop goal work; never pause on your own initiative. Do not mark a goal complete merely because the budget is nearly exhausted or because you are stopping work.
</codex_internal_context>
I’ll build the city driving demo with live Jev decisions, working traffic lights, pedestrians, and a drivable player car. I’ll also add an NPC inspector so you can see what each driver is deciding, then test both the simulation and the live API connection.
>ls -la && cat package.json{"chunk_id":"9bd94c","wall_time_seconds":0.000011708,"exit_code":1,"original_token_count":50,"output":"total 8\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 20:10 .\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:50 ..\n-rw-r--r--@ 1 sahaj staff 120 Oct 7 19:52 .env\ncat: package.json: No such file or directory\n"}
{"chunk_id":"73f6ec","wall_time_seconds":0.000007208,"exit_code":0,"original_token_count":9529,"output":"---\nname: sites-building\ndescription: Use Sites when the user wants a complete website built for them, such as a landing page, portfolio, dashboard, portal, tracker, hub, or internal tool, or wants to modify a website built with Sites. Do not use for development work in other web projects unless the user explicitly requests Sites.\n---\n\n# Sites building\n\nApply this workflow to the website requested by the user. A `.openai/hosting.json` file identifies an existing Site; its presence does not turn unrelated code changes or standalone asset work into a Sites task. Follow an explicit choice of another hosting provider.\n\nBuild a new Site unless the current request or task context identifies an existing Site to change. A similar Site found in memory or search is not a request to reuse it.\n\nBuild the complete requested site, then use `sites-hosting` to publish it. Publish after edits too, including on subsequent turns, unless the user explicitly asks for local-only work, saving without deployment, or no publishing.\n\n## Recurring updates\n\nAutomations can update a Site on a schedule, even when it is closed. Plan useful updates that fit the user's request. If refreshing when the page opens is enough, an automation is unnecessary.\n\nProvide a way for the automation to read its sources and save updates without the user present. Reuse existing data operations and access, following [Persistence and storage](references/persistence-and-storage.md). Use `sites-mcp` when a Site-hosted tool is needed. Verify that this works with the access available to the automation; reuse that verification while the implementation and access are unchanged.\n\nKeep the automation description short and nontechnical: what to update, which sources to use, and any specific user requirements. Include enough context for future runs. Never include credentials.\n\nFollow [Sites hosting](../sites-hosting/SKILL.md#recurring-work) to decide whether to create an automation, suggest one, or skip scheduling.\nFor unattended updates using connected sources or Site-hosted tools, follow [Recurring updates](references/recurring-updates.md).\n\n## Execution profile\n\nSelect **managed-linux** only when `SITES_MANAGED_LINUX_CONTAINER=1`, otherwise **portable**. Plain static HTML skips profile configuration. `project-setup.mjs` configures new starters; run `node <plugin-root>/scripts/configure-execution-profile.mjs` only for an existing starter without a known profile for its current checkout and environment.\n\n| Task | Portable | Managed Linux |\n| --- | --- | --- |\n| Project setup | [portable](references/project-setup/portable.md) | [managed-linux](references/project-setup/managed-linux.md) |\n| Preview | [portable](references/preview/portable.md) | [managed-linux](references/preview/managed-linux.md) |\n\nRead the selected **Project setup** reference before setup. Registration uses the shared [Registration](references/registration.md) reference.\n\nThe profile stays in ignored `.sites-runtime/execution-profile.json`. If `changed` is true, restart this Site's preview; keep valid dependencies. If `configured` is false, preserve the project's scripts and configuration.\n\n`<plugin-root>` is the installed plugin directory containing `skills/` and `scripts/`. Run setup and preview helpers with absolute paths and literal arguments in the Site checkout. Use the [Site workflow](../sites-hosting/SKILL.md#site-workflow) for source opening and publishing. Overlap any needed registration, dependency installation, and asset work with authoring; collect each result before the first step that needs it.\n\n## Site lifecycle ownership\n\nThe agent owning the user's Site handles its checkout, Sites tools, publishing, and handoff. Delegate only bounded asset or research work; subagents return results for the owner to integrate. An independently started background task can own a Site.\n\n## 1. Start with the project\n\nFor an existing hosted Site, follow [Open a Site](../sites-hosting/SKILL.md#open-a-site) before editing. Local-only work uses the available checkout and skips registration and source synchronization.\n\n### Choose the execution path\n\nUse the **one-shot fast path** only when all of these are true:\n\n- this is a new site in an empty or projectless workspace;\n- one route can satisfy the request;\n- the request does not require scheduled updates, D1, R2, uploads, app-owned authentication, or external connectors; and\n- the normal deliverable is a private deployed URL.\n\nUse the **capability path** otherwise. This includes existing-site changes, multi-route sites, persistent data, uploads, authentication, and external data. On **managed-linux**, requested browser UI QA also requires the capability path.\n\nWhen access to workspace apps would help fulfill the Site request and the Sites `list_plugin_eligibility` tool is available, you may consider [using workspace app tools in Sites](references/plugin-tools.md). Otherwise, continue without adding access to workspace apps; explain the limitation if it blocks a requested feature.\n\n### Start new projects immediately\n\nStatic assets are an option when the starter would be overkill; consider using or switching to the normal starter when the user asks for more advanced functionality.\n\nWhen switching, prepare the starter separately, port the existing site's content, assets, styling, and behavior, and update the starter's `.openai/hosting.json` with the existing Site's `project_id`, removing `static` for Worker builds. Validate the port, then copy it into the opened checkout, preserving `.git`; remove obsolete files and stale build output.\n\nFor a new Site, follow the selected **Project setup** reference. Infer capabilities from the request; do not ask users to choose technical add-ons.\n\nAfter setup starts, follow **Start image work early** as soon as each required image brief is clear.\n\nOnce a new project's files exist, follow [Open a Site](../sites-hosting/SKILL.md#open-a-site) for hosted work and begin the first product slice while dependencies install.\n\nFollow Development and first preview in the selected **Preview** reference once setup and any required dependency installation finish successfully. Where a user-facing local preview is supported, keep the browser closed until the **First meaningful preview** gate below passes. The starter loading state is a fail-safe only and must never be the intended browser handoff. Keep any development server alive through build and hosting.\n\nA Site-owning agent running in an independently started background, delegated, or invisible task initializes normally but does not start a browser-only preview unless its task otherwise needs the server. A spawned subagent working for that Site-owning agent never initializes a Site checkout.\n\n## 2. Design the experience\n\nKeep this planning lightweight and internal. Make these decisions while project setup continues, and revise them together when implementation reveals a better direction. Do not turn design planning into a mandatory interview or approval gate, generate design options, or pause for visual selection unless the user explicitly asks to compare designs.\n\n### Frame the product and scope\n\nDetermine:\n\n- who the site is for and the primary task they need to complete;\n- the essential content, functionality, and requested capabilities; and\n- the smallest coherent scope that fully satisfies the request without speculative features.\n\nFor a new Site, implement only the requested content and capabilities (unless it falls under the [presentation-site expansion exception](#expand-presentation-led-sites-like-landing-pages-and-marketing-pages)), plus the minimum structure, accessibility, responsive behavior, and basic document metadata needed for that experience to work. “Polished” changes execution quality, not product scope. Do not add sections, calls to action, routes, forms, search, filters, sharing, persistence, authentication, uploads, data, or workflows merely because they are common or easy to add. Add optional capabilities only when requested. For an existing Site, preserve its capabilities unless the requested change requires altering them; do not add new ones without a request.\n\nChoose the dominant presentation mode from the user's intent:\n\n- **Working surface by default:** When the primary goal is to explore, compare, monitor, decide, or act—especially for personal or internal use. The first viewport must expose core controls and at least one useful result when relevant; keep framing brief and secondary.\n- **Narrative surface when intended:** When the primary goal is to publish, persuade, teach, sell, or tell a story.\n- A topic resembling a report, review, or article does not by itself imply narrative intent.\n\nInfer these decisions from the request and existing product when possible. Refer to [Interview the user to clarify intent](#interview-the-user-to-clarify-intent) to determine when it is appropriate to ask discovery questions. When questions are not necessary, proceed immediately with best judgment.\n\n**Build the requested experience itself, not a page advertising it.** Unless the user asks for a landing or marketing page, make the primary activity the visual and functional focus of the first screen. A game should open on the play area or a game-native start screen that leads directly into play; a calculator should show editable inputs and results; an editor or dashboard should open on its workspace or data. Don’t make users scroll past an oversized hero, slogan, feature list, or decorative mockup—or click a generic “Get started” button—just to reach what they asked for. Brief context or necessary setup is fine when it supports the task and stays secondary. Before finishing, check: can the user immediately begin the activity they asked for?\n\n### Interview the user to clarify intent\n\n#### When to ask questions\n\nBefore committing to a direction, consider whether the request supports multiple plausible interpretations that would substantially change the result’s purpose, structure, content, or primary interactions. If so, ask questions that distinguish those directions. Being able to invent a coherent default is not sufficient reason to skip discovery.\n\n#### What to ask\n\nAsk the highest-impact unknowns: purpose, audience, visitor goals, essential pages/content, required features, and look and feel.\n\nUse input fields sparingly and only where multiple choice would truly not be suitable. Each question must ask for exactly one decision or fact. Keep individual questions concise. Prioritize rather than combining independent asks.\n\nDo not ask about technical implementation details unless requested.\n\n#### How many questions to ask\n\nAsk no more than three questions in a single batch; generally use all three entries when there is at least one meaningful question worth asking. Do not ask multiple batches unless prompted.\n\n#### How to ask\n\nIntroduce the batch once in a separate chat message, explaining how the answers will help shape the site and that you will continue with a recommended starting point if unanswered.\n\nAsk questions only when the current conversation supports user replies; otherwise proceed with best judgment.\n\nContinue independent work, but do not announce the site progress or begin implementation until the questions have resolved. If the user skips or does not answer, make coherent assumptions and continue.\n\nAsk one-sentence questions.\n\n### Expand presentation-led sites like landing pages and marketing pages\n\nFor new presentation-led sites primarily intended to introduce, explain, promote, or showcase a subject, such as landing pages, marketing sites, portfolios, event sites, and digital exhibits, read [Presentation-site expansion](references/presentation-site-expansion.md) before choosing content and structure. A visual topic alone does not qualify less presentation-led sites like games, dashboards, or workflows.\n\nFor qualifying requests, that guidance overrides the default requested-only limits for presentation content and structure. Preserve the user's explicit constraints. Use the default scope limits for other site types.\n\n### Shape the experience\n\nMake a lightweight implementation plan:\n\n- Identify the primary flow and what the first viewport must show or enable.\n- Add routes and navigation only when the request requires multiple views.\n- Account for relevant loading, empty, error, and success states.\n- Choose layout, density, and responsive behavior around the primary task; working surfaces must not put a marketing or editorial hero before it.\n\n**Write all visible text for the people who will actually use or read the result**. Think about what they already know and what they need to understand, decide, or do next. Use plain, specific language grounded in the user’s context. Cut filler, hype, unexplained jargon, repeated headings, and copy that states the obvious. Don’t narrate the interface, describe its styling, announce what you built, or address an evaluator. Don’t add a tagline, subtitle, or explanatory block just to fill space. Keep useful labels, brief instructions, and enough detail for the task; use marketing language only when it fits the request. Before finishing, reread the text from the audience’s perspective and remove anything they wouldn’t miss.\n\n### Choose the implementation stack\n\nUse the inline **Reuse installed components** guidance for matching interface primitives; do not read a separate guide merely to select them. Consult [Library selection](references/library-selection.md) only when a requested capability needs a library choice beyond those primitives. Its other library choices are recommendations; preserve the product requirements and existing project.\n\nPreserve existing dependencies and the lockfile unless the requested work requires a change. Reuse suitable declared versions, avoid pruning unused packages as routine cleanup, and update the lockfile for any required dependency changes.\n\nAvoid writing and running unit tests excessively unless the user specifically asks for this.\n\n### Establish the visual direction\n\nBefore the first product-source edit, choose one concise visual thesis from the request's subject, audience, and tone. Let it drive overall page layout, typography, surfaces, spacing rhythm, and imagery, with a coherent palette, borders, corners, icons, and motion. Decide quickly and internally without delaying editing. Different briefs should produce meaningfully different compositions, not the same structure with new copy and colors. For polished or strongly visual work, make at least one memorable, request-appropriate visual decision without inventing content, sections, capabilities, or actions. Carry the direction through routes, responsive and interaction states, and later edits.\n\n**Keep text readable.** Use 16px or larger for main body text. Use 14px as the default minimum for labels and other text people use regularly. Reserve 12–13px for secondary metadata and avoid sizes below 12px. If a due date or status is essential to the task, treat it as regular text. Prefer `rem`, respect browser font settings, and keep content and controls usable at 200% text enlargement. These are Sites defaults, not WCAG-mandated font sizes. Check the actual typeface, weight, line height, contrast, writing system, and viewing conditions together. Ensure characters within text never overlap by using appropriate font sizing, letter spacing, and line height at all supported screen sizes.\n\nEnsure the site renders well across mobile and desktop viewports, with responsive layouts, readable text, and usable controls without clipping or unintended horizontal scrolling.\n\n**Choose tasteful, visually appealing designs.** Never use the generated shadcn default theme as the finished theme of a new site. Choose an intentional theme based on the product. If the user provides no visual direction, infer one. For an existing site, preserve and extend its established brand and theme unless the user requests a redesign. Avoid defaulting to washed-out palettes of warm off-white, beige, sage, dusty coral, or pale lavender. Use them when they fit the user's references, requirements, or existing brand. If the user asks for a new design direction, change more than just the colors. Use status dots, including green dots, sparingly and only to convey meaningful state. Do not use arrows on buttons and links.\n\n**For imagery, do:**\n\n- Use HTML, CSS, and SVG for functional interface styling and geometry, simple non-representational accents, trusted icons, diagrams, and data visualizations.\n- Choose **0–3 discretionary final-site images**: use 1–3 for visually led marketing, brand, editorial, portfolio, consumer, or storytelling Sites; use zero for technical, data-heavy, dashboard, admin, developer, or other utilitarian Sites when typography, layout, icons, or data visualization carry the design. For inherently visual consumer subjects such as pets, food, travel, fashion, and homes, include at least one relevant in-page image unless the user requests an image-free direction.\n- This discretionary budget does not cap suitable user-provided assets, explicitly requested images, or the content of a requested gallery, catalog, portfolio, or similar experience. Social-preview images and deployment thumbnails are separate explicit-request-only workflows.\n- Prefer suitable supplied assets, web image search for real or factually specific subjects, and `imagegen` for original or stylized artwork. Generate clean standalone assets rather than screenshots containing page text or interface chrome.\n- Use asset-only subagents for web image search and `imagegen`; the Site-owning agent selects and integrates results.\n\n**Do not:**\n\n- Build representational images or decorative artwork, including illustrations, objects, or scenes, from styled HTML, CSS shapes, pseudo-elements, or hand-written SVG, except for the simple favicons described below.\n- Add imagery that does not support the site's purpose.\n\n### Start image work early\n\nOnce setup starts and an image brief is clear, dispatch bounded image search or generation while continuing independent Site work. Use web image search for real or factually specific subjects and `imagegen` for original or stylized artwork; never invent URLs, replace requested factual imagery with generated art, or repeat work when a suitable asset already exists.\n\nFor the default 1–3 generated in-page assets, use exactly one image-generation subagent with one request per chosen asset, together as one parallel batch when supported. Do not generate variants or retry in-page generation. Explicit requests for additional generated images take precedence over this default. Have the subagent save outside the Site checkout and return assets to the Site-owning agent for inspection and integration. When delegation is unavailable, the owner makes the same bounded requests using the synchronous fallback below. Explicitly requested social cards follow their separate retry allowance in **Social previews**.\n\nStart asset-only subagents with `fork_turns=\"none\"` and only the subject, factual requirements, placement, dimensions, and visual direction. They return candidate assets and, for search, source-page and image URLs plus available reuse information; they must not edit the Site, call Sites tools, invoke Sites skills, initialize projects, or spawn agents. If concurrency is unavailable, finish the preview slice's independent work first. Request synchronously only the images needed to make that slice coherent, show the preview where supported, then request the remaining required images; omit optional generation that would delay delivery. Never invent asynchronous jobs.\n\nReserve stable image dimensions and continue useful work instead of waiting or polling; optional images must not delay the first product-source edit or a supported preview that already meets the **First meaningful preview** gate. When independent work finishes, collect required results rather than treating pending work as failed. If optional images are not ready and useful when the Site is otherwise ready, omit them and remove their placeholders instead of delaying delivery. Images explicitly requested by the user or required by the visual-consumer rule are not optional: integrate the selected assets or a permitted fallback, or report the Site as incomplete. Verify selected images, their sources, and loading, then integrate required assets and applicable metadata before the final build; never ship unresolved placeholders. Handle requested social-card failures under **Social previews**.\n\n### Keep authoring on the delivery path\n\nAs soon as project files exist, decide the requested scope and visual thesis, then make the earliest coherent product-source edit while any installation continues. Do not draft the full page twice, add a planning-only round, inspect speculative files, or create alternate candidate pages unless requested. Spend polish on execution inside the requested scope. Overlap useful image work with implementation; do not wait on optional imagery or add unrequested features.\n\nThese shortcuts never skip Site registration for hosted work, required dependency installation and build steps, packaging, deployment, or terminal deployment-status verification. Preserve the complete-site publication flow and any supported first meaningful local preview.\n\n## 3. Build, preview, and deliver\n\n### Apply the selected theme\n\nFor the Vinext starter, apply the selected theme through the shared tokens in `app/globals.css` before styling individual components. Update both light and dark theme values when both are present.\n\n### Reuse installed components\n\nThe standard Vinext starter includes the supported Shadcn catalog. For a new Site from that starter, a requested control with a direct catalog match must use the matching primitive on its first implementation. Map side navigation to `sidebar`, tabbed views to `tabs`, modal flows to `dialog`, detail panels to `sheet`, destructive confirmations to `alert-dialog`, searchable pickers to `combobox`, command menus to `command`, boolean choices to `switch` or `checkbox`, constrained choices to `select` or `radio-group`, ranges to `slider`, contextual actions to `dropdown-menu`, hover help to `tooltip`, verification codes to `input-otp`, tables to `table`, progress to `progress`, page navigation to `pagination`, empty/loading states to `empty`/`skeleton`, and transient feedback to `sonner`. Import directly from `@/components/ui/<component>` and compose/restyle at the call site. For existing or template-derived projects, reuse matching primitives only when already present and preserve existing import paths.\n\nSelect by semantic match without catalog inventories, mandatory guide reads, or proactive component scans. If the selected API is unclear for the next edit, open only that implementation; unfamiliarity is not a reason to hand-build a substitute. Use semantic HTML and the project's UI stack for layout, art direction, substantial data visualization beyond the chart wrapper, and uncovered UI. Do not invent features or state to exercise a component or meet a quota.\n\nDo not run the Shadcn CLI, install another component package, change dependency manifests or lockfiles, or edit vendored `components/ui` files merely to obtain, recreate, or restyle an already-installed primitive. Compose and style it at the call site while preserving accessibility and interaction behavior.\n\n### First meaningful preview\n\nWhere the environment supports a user-facing local preview, treat it as an early milestone in both execution paths. Otherwise skip this handoff and continue implementation and any explicitly requested social previews; never deploy an incomplete slice as a substitute. In a visible foreground thread with local preview support, open it as soon as, but not before, all of these are true:\n\n- the route contains the smallest coherent slice that lets a reasonable person recognize the requested site and its intended visual direction;\n- for a new site, any shared theme tokens reflect the selected visual direction rather than the generated defaults;\n- it includes the primary product surface or layout and representative, product-specific content rather than an untouched starter, generic skeleton, blank page, or loading-only state;\n- the primary affordance is visible when the requested experience is interaction-led; and\n- the development server serves the slice successfully, without a blocking runtime error.\n\nThe slice may be static or partially inert. Keep it intentionally bounded and defer secondary routes, complete data models, exhaustive interactions, responsive refinements, animation, polish, and advanced capabilities until after the handoff unless one is required for recognition, security, or a successful render. Work on the slice while installation runs when possible.\n\nFor a new site, replace the starter placeholder content and temporary preview metadata, if present, as part of the slice. Cleanup of unused starter-only files may happen after the handoff, but must finish before publishing.\n\nFor a supported local preview, once the bounded slice is applied, make no further planned product-source edits before the handoff. Fix only compilation or blocking runtime failures, then follow Preview handoff in the selected **Preview** reference to show the first working version without waiting for the complete Site or a deployment. Reuse that preview as the Site's single continuous user-facing view through edits, publishing, and any later fixes.\n\nFor an existing site, use its current coherent experience immediately when it still represents the requested product and serves successfully. If the request changes the primary direction, apply only the smallest representative part first. Preserve the last working content while updates are applied; never replace an existing site with the starter skeleton.\n\n### WebMCP tools for new sites\n\nApply to new sites where the primary journey lets users modify data or meaningful page state, or where a structured tool materially helps an agent complete that journey. Skip static or presentation-only sites whose user journey is limited to reading content or navigating between pages.\n\nAdd [WebMCP tools](references/webmcp.md) after the initial site implementation and before the final build, without delaying any preview required by the selected profile.\n\n### Favicons\n\nGive every new Site a site-specific favicon during its first implementation, even when the user does not ask. Write a small SVG using the Site's colors and a simple recognizable motif that reads at 16 and 32 pixels. Reuse a suitable supplied brand mark. Preserve user-provided favicons in their original format and an existing Site's valid custom icon unless replacement is requested. Use image generation only when the user requests it or the branding requires it.\n\n- **Vinext starter:** replace `public/favicon.svg`; `app/layout.tsx` already references it through `metadata.icons`. If using a supplied icon with another filename or format, update both metadata references to match.\n- **Plain static HTML:** embed the URL-encoded SVG in a `<link rel=\"icon\" type=\"image/svg+xml\" href=\"data:image/svg+xml,...\">` in the HTML `<head>` so single-file Sites stay self-contained.\n- **Other stacks:** use the existing framework metadata or HTML head. For a Worker that serves HTML without static assets, embed a URL-encoded SVG data URL in its favicon link.\n\n### Social previews\n\nGenerate or refresh a social-preview image only when the user explicitly requests a social-preview or social-sharing image. Otherwise preserve any existing preview image and its metadata unchanged. If none exists, omit it; do not start image generation, add an `og.png` asset, or add social-preview image metadata. A missing preview or branding change alone does not authorize generation. Apply this rule in both the **One-shot build** and **Capability path**.\n\n1. **Start early and keep building.** When a new card is explicitly requested, choose its title or primary headline, concise supporting copy, and visual direction early, then follow **Start image work early**. Make one `imagegen` request for a cohesive branded landscape card with that exact title or headline and copy as legible typography, matching the Site's palette, typography, and distinctive motifs while excluding credentials and private data. When delegating, give one `fork_turns=\"none\"` subagent only that brief; have it save the result outside the Site checkout and return the path. Check the card against final copy, branding, and metadata before the final build. Retry or replace at most once total for unusable or stale output; treat any still-invalid card as generation failure.\n2. **Wire the site-wide preview.** When a new card is generated, the Site-owning agent saves it as `public/og.png` (or `og.png` under `static.directory` for buildless sites) and sets site-specific Open Graph and X title, description, and image metadata through the framework's metadata API or HTML `<head>`. Use an absolute URL from a trusted request or deployment origin; never blindly trust forwarded host headers. If generation fails, preserve any existing valid preview; omit `og:image` only when neither an existing nor generated image is available. Never use a generic fallback. Wire the asset before the publishing workflow's build.\n3. **Handle requested item-specific previews.** When the explicit social-preview request covers independently shareable detail pages, use `generateMetadata` or its equivalent to set page title and description and Open Graph/X title, description, and image from the rendered record. Reuse its existing primary image with an absolute trusted-origin URL; otherwise clear both inherited Open Graph and X images. Never reuse the site-wide `og.png` or generate images per record. Validate the root and every detail page when there are at most two; otherwise check at least two representative detail pages. Before final validation, verify that each checked page's title, description, and Open Graph/X fields match its record.\n\n### One-shot build\n\nAfter setup and any necessary clarification, show the first meaningful preview if the environment supports a user-facing local preview, then build the complete site in one focused pass. Continue through `sites-hosting` to publish, following its deployment rules.\n\n1. Read existing instructions and files needed for the next edit, reusing source and setup results already in context. Preserve the package manager and lockfile.\n2. Start required image work under **Start image work early**, then continue the smallest coherent product slice while dispatched work runs. Where a user-facing local preview is supported, complete the **First meaningful preview** handoff above before broadening the implementation. For a genuinely trivial request, the complete implementation may itself be that slice; do not manufacture extra edits merely to demonstrate HMR.\n3. Reuse the project setup and any retained development server or Site tab, then make one complete product patch. Prefer one page and one stylesheet. Include all requested content, interactions, responsive behavior, keyboard and touch behavior when relevant, and accessible labels. Replace the starter placeholder content and metadata with the requested site's own values, remove unused starter-only files, and include the custom favicon described above before publishing unless the user explicitly asked to work on the starter itself. Integrate any explicitly requested **Social previews** result before publishing.\n4. Follow **Preview rules** and **Hosting handoff** below without another polish pass.\n\n### Capability path\n\n#### Project setup\n\n- For a new site, use the setup flow in **Start new projects immediately** and preserve the project's structure.\n- For an existing site, preserve its package manager, lockfile, scripts, architecture, and `.openai/hosting.json`. Install when dependencies are missing or `package.json` or the lockfile changed. Do not replace a working structure merely to use the starter.\n- Keep site code within the selected project surface.\n\n#### Expand the design consistently\n\n- Where a user-facing local preview is supported, apply the bounded slice and complete the **First meaningful preview** handoff above before comprehensive implementation.\n- Start required imagery and explicitly requested social cards under **Start image work early**. Integrate required results before publishing, and omit optional assets that would delay delivery.\n- Build the first viewport around the requested product, not generic dashboard chrome.\n- For a new site, replace the starter placeholder content and metadata and remove unused starter-only files. Set the finished site's title and description through its framework's metadata API or HTML `<head>` before publishing. Preserve starter content only when the user explicitly asked to work on the starter itself.\n- Use concrete, product-specific copy and realistic data.\n- Apply the chosen UX, layout, and visual rules consistently without making every page mechanically identical.\n- Avoid unnecessary client state. Avoid speculative features except for additions permitted by [presentation-site expansion](#expand-presentation-led-sites-like-landing-pages-and-marketing-pages).\n- For server-backed builds, follow [Starter capabilities](references/starter-capabilities.md) and produce Cloudflare Worker-compatible ESM output. Require the Worker entrypoint (`dist/server/index.js` by default) to export a default object with callable `fetch(request, env, ctx)`; if Cloudflare reports no registered event handlers, fix source/build and create a new version instead of redeploying the same archive.\n\nStatic-only builds without runtime bindings, capabilities, or migrations may publish Cloudflare-compatible static output without a Worker. Examples include `dist/index.html`, Next.js exports (`out/`), and vinext exports (`dist/client/`). All static-only builds must set `static.directory` in `.openai/hosting.json` to a supported public output directory (`dist`, `dist/client`, `out`, `build`, or `.output/public`). For Next.js/vinext exports, use `output: 'export'`; select only public assets, excluding any server intermediates.\n\n#### Add only requested capabilities\n\n- For durable state, records, uploads, or other persistence, read [Persistence and storage](references/persistence-and-storage.md).\n- For any SQLite schema or query work, also read [SQLite](references/sqlite.md).\n- For identity-aware or sign-in-gated behavior, read [Authentication](references/authentication.md).\n- For requested Site-hosted MCP tools, read [Sites MCP](../sites-mcp/SKILL.md); browser WebMCP is a separate capability.\n- Hosted Sites do not support raw TCP sockets (`connect()`); use HTTP-based clients or APIs for external databases and services.\n- Use browser storage only for device-local preferences or explicitly local state.\n- Keep logical D1 and R2 declarations in `.openai/hosting.json`; Sites owns the real Cloudflare resources and deployment wiring.\n- Keep local `.env` and `.env.example` keys aligned. Manage hosted runtime values through Sites.\n\n### Preview rules\n\n- In a visible foreground thread with user-facing local preview support, the **First meaningful preview** gate is the only local opening point. If the gate has not passed, keep the browser closed; never open the skeleton as a fallback. If the handoff fails after the gate passes, report it and continue.\n- For an existing site, preserve its normal package and development flow.\n- In a delegated, background, or invisible thread, skip the user-facing browser handoff and say why.\n- Do not scan ports or repeatedly open the browser.\n\n### Hosting handoff\n\nContinue through the [hosting sequence](../sites-hosting/SKILL.md#fast-publish-sequence), passing remaining checks/builds as `commands` and reusing successful results. For local-only work, run only the required local checks/build and hand off the result. Run lint only when requested. Keep any development server running through hosting, then stop it using the environment's preview controls.\n\n## Communicate with the user\n\nAssume the user is a nontechnical knowledge worker. Talk about their site, choices, progress, and results. Keep tools, commands, files, runtimes, browser software, permissions, dependencies, source control, credentials, IDs, builds, and deployment internals out of user-facing messages unless the user asks or must take action.\n\nUnless following [special communication rules](#special-communication-rules-for-initial-site-creation), use no more than one short update for each user-visible phase: preparing the site, building it, and publishing. If a phase takes longer than 60 seconds, give one plain-language update. Keep recoverable technical problems private; say only that you hit a problem and are trying another method.\n\n### Special communication rules for initial site creation\n\n#### 1. Communicate what you're about to build\n\nAfter discovery and design is resolved, but before feature implementation, announce the build plan and time estimate before implementation. Ground the plan in the user’s answers. If proceeding unanswered under the host’s waiting rules, disclose your assumptions here.\n\n1. Explain that you're starting the build and describe the core features and goals requested. If you made meaningful assumptions or substantial additions to the user's request, you must disclose these, framing them warmly as starting points for a complete first version the user can react to.\n\n2. In a new paragraph, give an approximate numeric range for the build and deployment time based on complexity: typically 2–5 minutes for static sites and 4–10 minutes for fullstack sites.\n\n#### 2. Handoff message for a newly created site\n\nGive the user a link to their new site (display in format `Title · domain`). Explain the main features or sections you built. Let them know they can view it, edit it and even share it when they are ready. Offer one or two concrete, optional relevant next steps.\n"}>cat /Users/sahaj/.codex/plugins/cache/openai-curated-remote/sites/0.1.75/skills/sites-building/SKILL.md{"chunk_id":"9bd94c","wall_time_seconds":0.000011708,"exit_code":1,"original_token_count":50,"output":"total 8\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 20:10 .\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:50 ..\n-rw-r--r--@ 1 sahaj staff 120 Oct 7 19:52 .env\ncat: package.json: No such file or directory\n"}
{"chunk_id":"73f6ec","wall_time_seconds":0.000007208,"exit_code":0,"original_token_count":9529,"output":"---\nname: sites-building\ndescription: Use Sites when the user wants a complete website built for them, such as a landing page, portfolio, dashboard, portal, tracker, hub, or internal tool, or wants to modify a website built with Sites. Do not use for development work in other web projects unless the user explicitly requests Sites.\n---\n\n# Sites building\n\nApply this workflow to the website requested by the user. A `.openai/hosting.json` file identifies an existing Site; its presence does not turn unrelated code changes or standalone asset work into a Sites task. Follow an explicit choice of another hosting provider.\n\nBuild a new Site unless the current request or task context identifies an existing Site to change. A similar Site found in memory or search is not a request to reuse it.\n\nBuild the complete requested site, then use `sites-hosting` to publish it. Publish after edits too, including on subsequent turns, unless the user explicitly asks for local-only work, saving without deployment, or no publishing.\n\n## Recurring updates\n\nAutomations can update a Site on a schedule, even when it is closed. Plan useful updates that fit the user's request. If refreshing when the page opens is enough, an automation is unnecessary.\n\nProvide a way for the automation to read its sources and save updates without the user present. Reuse existing data operations and access, following [Persistence and storage](references/persistence-and-storage.md). Use `sites-mcp` when a Site-hosted tool is needed. Verify that this works with the access available to the automation; reuse that verification while the implementation and access are unchanged.\n\nKeep the automation description short and nontechnical: what to update, which sources to use, and any specific user requirements. Include enough context for future runs. Never include credentials.\n\nFollow [Sites hosting](../sites-hosting/SKILL.md#recurring-work) to decide whether to create an automation, suggest one, or skip scheduling.\nFor unattended updates using connected sources or Site-hosted tools, follow [Recurring updates](references/recurring-updates.md).\n\n## Execution profile\n\nSelect **managed-linux** only when `SITES_MANAGED_LINUX_CONTAINER=1`, otherwise **portable**. Plain static HTML skips profile configuration. `project-setup.mjs` configures new starters; run `node <plugin-root>/scripts/configure-execution-profile.mjs` only for an existing starter without a known profile for its current checkout and environment.\n\n| Task | Portable | Managed Linux |\n| --- | --- | --- |\n| Project setup | [portable](references/project-setup/portable.md) | [managed-linux](references/project-setup/managed-linux.md) |\n| Preview | [portable](references/preview/portable.md) | [managed-linux](references/preview/managed-linux.md) |\n\nRead the selected **Project setup** reference before setup. Registration uses the shared [Registration](references/registration.md) reference.\n\nThe profile stays in ignored `.sites-runtime/execution-profile.json`. If `changed` is true, restart this Site's preview; keep valid dependencies. If `configured` is false, preserve the project's scripts and configuration.\n\n`<plugin-root>` is the installed plugin directory containing `skills/` and `scripts/`. Run setup and preview helpers with absolute paths and literal arguments in the Site checkout. Use the [Site workflow](../sites-hosting/SKILL.md#site-workflow) for source opening and publishing. Overlap any needed registration, dependency installation, and asset work with authoring; collect each result before the first step that needs it.\n\n## Site lifecycle ownership\n\nThe agent owning the user's Site handles its checkout, Sites tools, publishing, and handoff. Delegate only bounded asset or research work; subagents return results for the owner to integrate. An independently started background task can own a Site.\n\n## 1. Start with the project\n\nFor an existing hosted Site, follow [Open a Site](../sites-hosting/SKILL.md#open-a-site) before editing. Local-only work uses the available checkout and skips registration and source synchronization.\n\n### Choose the execution path\n\nUse the **one-shot fast path** only when all of these are true:\n\n- this is a new site in an empty or projectless workspace;\n- one route can satisfy the request;\n- the request does not require scheduled updates, D1, R2, uploads, app-owned authentication, or external connectors; and\n- the normal deliverable is a private deployed URL.\n\nUse the **capability path** otherwise. This includes existing-site changes, multi-route sites, persistent data, uploads, authentication, and external data. On **managed-linux**, requested browser UI QA also requires the capability path.\n\nWhen access to workspace apps would help fulfill the Site request and the Sites `list_plugin_eligibility` tool is available, you may consider [using workspace app tools in Sites](references/plugin-tools.md). Otherwise, continue without adding access to workspace apps; explain the limitation if it blocks a requested feature.\n\n### Start new projects immediately\n\nStatic assets are an option when the starter would be overkill; consider using or switching to the normal starter when the user asks for more advanced functionality.\n\nWhen switching, prepare the starter separately, port the existing site's content, assets, styling, and behavior, and update the starter's `.openai/hosting.json` with the existing Site's `project_id`, removing `static` for Worker builds. Validate the port, then copy it into the opened checkout, preserving `.git`; remove obsolete files and stale build output.\n\nFor a new Site, follow the selected **Project setup** reference. Infer capabilities from the request; do not ask users to choose technical add-ons.\n\nAfter setup starts, follow **Start image work early** as soon as each required image brief is clear.\n\nOnce a new project's files exist, follow [Open a Site](../sites-hosting/SKILL.md#open-a-site) for hosted work and begin the first product slice while dependencies install.\n\nFollow Development and first preview in the selected **Preview** reference once setup and any required dependency installation finish successfully. Where a user-facing local preview is supported, keep the browser closed until the **First meaningful preview** gate below passes. The starter loading state is a fail-safe only and must never be the intended browser handoff. Keep any development server alive through build and hosting.\n\nA Site-owning agent running in an independently started background, delegated, or invisible task initializes normally but does not start a browser-only preview unless its task otherwise needs the server. A spawned subagent working for that Site-owning agent never initializes a Site checkout.\n\n## 2. Design the experience\n\nKeep this planning lightweight and internal. Make these decisions while project setup continues, and revise them together when implementation reveals a better direction. Do not turn design planning into a mandatory interview or approval gate, generate design options, or pause for visual selection unless the user explicitly asks to compare designs.\n\n### Frame the product and scope\n\nDetermine:\n\n- who the site is for and the primary task they need to complete;\n- the essential content, functionality, and requested capabilities; and\n- the smallest coherent scope that fully satisfies the request without speculative features.\n\nFor a new Site, implement only the requested content and capabilities (unless it falls under the [presentation-site expansion exception](#expand-presentation-led-sites-like-landing-pages-and-marketing-pages)), plus the minimum structure, accessibility, responsive behavior, and basic document metadata needed for that experience to work. “Polished” changes execution quality, not product scope. Do not add sections, calls to action, routes, forms, search, filters, sharing, persistence, authentication, uploads, data, or workflows merely because they are common or easy to add. Add optional capabilities only when requested. For an existing Site, preserve its capabilities unless the requested change requires altering them; do not add new ones without a request.\n\nChoose the dominant presentation mode from the user's intent:\n\n- **Working surface by default:** When the primary goal is to explore, compare, monitor, decide, or act—especially for personal or internal use. The first viewport must expose core controls and at least one useful result when relevant; keep framing brief and secondary.\n- **Narrative surface when intended:** When the primary goal is to publish, persuade, teach, sell, or tell a story.\n- A topic resembling a report, review, or article does not by itself imply narrative intent.\n\nInfer these decisions from the request and existing product when possible. Refer to [Interview the user to clarify intent](#interview-the-user-to-clarify-intent) to determine when it is appropriate to ask discovery questions. When questions are not necessary, proceed immediately with best judgment.\n\n**Build the requested experience itself, not a page advertising it.** Unless the user asks for a landing or marketing page, make the primary activity the visual and functional focus of the first screen. A game should open on the play area or a game-native start screen that leads directly into play; a calculator should show editable inputs and results; an editor or dashboard should open on its workspace or data. Don’t make users scroll past an oversized hero, slogan, feature list, or decorative mockup—or click a generic “Get started” button—just to reach what they asked for. Brief context or necessary setup is fine when it supports the task and stays secondary. Before finishing, check: can the user immediately begin the activity they asked for?\n\n### Interview the user to clarify intent\n\n#### When to ask questions\n\nBefore committing to a direction, consider whether the request supports multiple plausible interpretations that would substantially change the result’s purpose, structure, content, or primary interactions. If so, ask questions that distinguish those directions. Being able to invent a coherent default is not sufficient reason to skip discovery.\n\n#### What to ask\n\nAsk the highest-impact unknowns: purpose, audience, visitor goals, essential pages/content, required features, and look and feel.\n\nUse input fields sparingly and only where multiple choice would truly not be suitable. Each question must ask for exactly one decision or fact. Keep individual questions concise. Prioritize rather than combining independent asks.\n\nDo not ask about technical implementation details unless requested.\n\n#### How many questions to ask\n\nAsk no more than three questions in a single batch; generally use all three entries when there is at least one meaningful question worth asking. Do not ask multiple batches unless prompted.\n\n#### How to ask\n\nIntroduce the batch once in a separate chat message, explaining how the answers will help shape the site and that you will continue with a recommended starting point if unanswered.\n\nAsk questions only when the current conversation supports user replies; otherwise proceed with best judgment.\n\nContinue independent work, but do not announce the site progress or begin implementation until the questions have resolved. If the user skips or does not answer, make coherent assumptions and continue.\n\nAsk one-sentence questions.\n\n### Expand presentation-led sites like landing pages and marketing pages\n\nFor new presentation-led sites primarily intended to introduce, explain, promote, or showcase a subject, such as landing pages, marketing sites, portfolios, event sites, and digital exhibits, read [Presentation-site expansion](references/presentation-site-expansion.md) before choosing content and structure. A visual topic alone does not qualify less presentation-led sites like games, dashboards, or workflows.\n\nFor qualifying requests, that guidance overrides the default requested-only limits for presentation content and structure. Preserve the user's explicit constraints. Use the default scope limits for other site types.\n\n### Shape the experience\n\nMake a lightweight implementation plan:\n\n- Identify the primary flow and what the first viewport must show or enable.\n- Add routes and navigation only when the request requires multiple views.\n- Account for relevant loading, empty, error, and success states.\n- Choose layout, density, and responsive behavior around the primary task; working surfaces must not put a marketing or editorial hero before it.\n\n**Write all visible text for the people who will actually use or read the result**. Think about what they already know and what they need to understand, decide, or do next. Use plain, specific language grounded in the user’s context. Cut filler, hype, unexplained jargon, repeated headings, and copy that states the obvious. Don’t narrate the interface, describe its styling, announce what you built, or address an evaluator. Don’t add a tagline, subtitle, or explanatory block just to fill space. Keep useful labels, brief instructions, and enough detail for the task; use marketing language only when it fits the request. Before finishing, reread the text from the audience’s perspective and remove anything they wouldn’t miss.\n\n### Choose the implementation stack\n\nUse the inline **Reuse installed components** guidance for matching interface primitives; do not read a separate guide merely to select them. Consult [Library selection](references/library-selection.md) only when a requested capability needs a library choice beyond those primitives. Its other library choices are recommendations; preserve the product requirements and existing project.\n\nPreserve existing dependencies and the lockfile unless the requested work requires a change. Reuse suitable declared versions, avoid pruning unused packages as routine cleanup, and update the lockfile for any required dependency changes.\n\nAvoid writing and running unit tests excessively unless the user specifically asks for this.\n\n### Establish the visual direction\n\nBefore the first product-source edit, choose one concise visual thesis from the request's subject, audience, and tone. Let it drive overall page layout, typography, surfaces, spacing rhythm, and imagery, with a coherent palette, borders, corners, icons, and motion. Decide quickly and internally without delaying editing. Different briefs should produce meaningfully different compositions, not the same structure with new copy and colors. For polished or strongly visual work, make at least one memorable, request-appropriate visual decision without inventing content, sections, capabilities, or actions. Carry the direction through routes, responsive and interaction states, and later edits.\n\n**Keep text readable.** Use 16px or larger for main body text. Use 14px as the default minimum for labels and other text people use regularly. Reserve 12–13px for secondary metadata and avoid sizes below 12px. If a due date or status is essential to the task, treat it as regular text. Prefer `rem`, respect browser font settings, and keep content and controls usable at 200% text enlargement. These are Sites defaults, not WCAG-mandated font sizes. Check the actual typeface, weight, line height, contrast, writing system, and viewing conditions together. Ensure characters within text never overlap by using appropriate font sizing, letter spacing, and line height at all supported screen sizes.\n\nEnsure the site renders well across mobile and desktop viewports, with responsive layouts, readable text, and usable controls without clipping or unintended horizontal scrolling.\n\n**Choose tasteful, visually appealing designs.** Never use the generated shadcn default theme as the finished theme of a new site. Choose an intentional theme based on the product. If the user provides no visual direction, infer one. For an existing site, preserve and extend its established brand and theme unless the user requests a redesign. Avoid defaulting to washed-out palettes of warm off-white, beige, sage, dusty coral, or pale lavender. Use them when they fit the user's references, requirements, or existing brand. If the user asks for a new design direction, change more than just the colors. Use status dots, including green dots, sparingly and only to convey meaningful state. Do not use arrows on buttons and links.\n\n**For imagery, do:**\n\n- Use HTML, CSS, and SVG for functional interface styling and geometry, simple non-representational accents, trusted icons, diagrams, and data visualizations.\n- Choose **0–3 discretionary final-site images**: use 1–3 for visually led marketing, brand, editorial, portfolio, consumer, or storytelling Sites; use zero for technical, data-heavy, dashboard, admin, developer, or other utilitarian Sites when typography, layout, icons, or data visualization carry the design. For inherently visual consumer subjects such as pets, food, travel, fashion, and homes, include at least one relevant in-page image unless the user requests an image-free direction.\n- This discretionary budget does not cap suitable user-provided assets, explicitly requested images, or the content of a requested gallery, catalog, portfolio, or similar experience. Social-preview images and deployment thumbnails are separate explicit-request-only workflows.\n- Prefer suitable supplied assets, web image search for real or factually specific subjects, and `imagegen` for original or stylized artwork. Generate clean standalone assets rather than screenshots containing page text or interface chrome.\n- Use asset-only subagents for web image search and `imagegen`; the Site-owning agent selects and integrates results.\n\n**Do not:**\n\n- Build representational images or decorative artwork, including illustrations, objects, or scenes, from styled HTML, CSS shapes, pseudo-elements, or hand-written SVG, except for the simple favicons described below.\n- Add imagery that does not support the site's purpose.\n\n### Start image work early\n\nOnce setup starts and an image brief is clear, dispatch bounded image search or generation while continuing independent Site work. Use web image search for real or factually specific subjects and `imagegen` for original or stylized artwork; never invent URLs, replace requested factual imagery with generated art, or repeat work when a suitable asset already exists.\n\nFor the default 1–3 generated in-page assets, use exactly one image-generation subagent with one request per chosen asset, together as one parallel batch when supported. Do not generate variants or retry in-page generation. Explicit requests for additional generated images take precedence over this default. Have the subagent save outside the Site checkout and return assets to the Site-owning agent for inspection and integration. When delegation is unavailable, the owner makes the same bounded requests using the synchronous fallback below. Explicitly requested social cards follow their separate retry allowance in **Social previews**.\n\nStart asset-only subagents with `fork_turns=\"none\"` and only the subject, factual requirements, placement, dimensions, and visual direction. They return candidate assets and, for search, source-page and image URLs plus available reuse information; they must not edit the Site, call Sites tools, invoke Sites skills, initialize projects, or spawn agents. If concurrency is unavailable, finish the preview slice's independent work first. Request synchronously only the images needed to make that slice coherent, show the preview where supported, then request the remaining required images; omit optional generation that would delay delivery. Never invent asynchronous jobs.\n\nReserve stable image dimensions and continue useful work instead of waiting or polling; optional images must not delay the first product-source edit or a supported preview that already meets the **First meaningful preview** gate. When independent work finishes, collect required results rather than treating pending work as failed. If optional images are not ready and useful when the Site is otherwise ready, omit them and remove their placeholders instead of delaying delivery. Images explicitly requested by the user or required by the visual-consumer rule are not optional: integrate the selected assets or a permitted fallback, or report the Site as incomplete. Verify selected images, their sources, and loading, then integrate required assets and applicable metadata before the final build; never ship unresolved placeholders. Handle requested social-card failures under **Social previews**.\n\n### Keep authoring on the delivery path\n\nAs soon as project files exist, decide the requested scope and visual thesis, then make the earliest coherent product-source edit while any installation continues. Do not draft the full page twice, add a planning-only round, inspect speculative files, or create alternate candidate pages unless requested. Spend polish on execution inside the requested scope. Overlap useful image work with implementation; do not wait on optional imagery or add unrequested features.\n\nThese shortcuts never skip Site registration for hosted work, required dependency installation and build steps, packaging, deployment, or terminal deployment-status verification. Preserve the complete-site publication flow and any supported first meaningful local preview.\n\n## 3. Build, preview, and deliver\n\n### Apply the selected theme\n\nFor the Vinext starter, apply the selected theme through the shared tokens in `app/globals.css` before styling individual components. Update both light and dark theme values when both are present.\n\n### Reuse installed components\n\nThe standard Vinext starter includes the supported Shadcn catalog. For a new Site from that starter, a requested control with a direct catalog match must use the matching primitive on its first implementation. Map side navigation to `sidebar`, tabbed views to `tabs`, modal flows to `dialog`, detail panels to `sheet`, destructive confirmations to `alert-dialog`, searchable pickers to `combobox`, command menus to `command`, boolean choices to `switch` or `checkbox`, constrained choices to `select` or `radio-group`, ranges to `slider`, contextual actions to `dropdown-menu`, hover help to `tooltip`, verification codes to `input-otp`, tables to `table`, progress to `progress`, page navigation to `pagination`, empty/loading states to `empty`/`skeleton`, and transient feedback to `sonner`. Import directly from `@/components/ui/<component>` and compose/restyle at the call site. For existing or template-derived projects, reuse matching primitives only when already present and preserve existing import paths.\n\nSelect by semantic match without catalog inventories, mandatory guide reads, or proactive component scans. If the selected API is unclear for the next edit, open only that implementation; unfamiliarity is not a reason to hand-build a substitute. Use semantic HTML and the project's UI stack for layout, art direction, substantial data visualization beyond the chart wrapper, and uncovered UI. Do not invent features or state to exercise a component or meet a quota.\n\nDo not run the Shadcn CLI, install another component package, change dependency manifests or lockfiles, or edit vendored `components/ui` files merely to obtain, recreate, or restyle an already-installed primitive. Compose and style it at the call site while preserving accessibility and interaction behavior.\n\n### First meaningful preview\n\nWhere the environment supports a user-facing local preview, treat it as an early milestone in both execution paths. Otherwise skip this handoff and continue implementation and any explicitly requested social previews; never deploy an incomplete slice as a substitute. In a visible foreground thread with local preview support, open it as soon as, but not before, all of these are true:\n\n- the route contains the smallest coherent slice that lets a reasonable person recognize the requested site and its intended visual direction;\n- for a new site, any shared theme tokens reflect the selected visual direction rather than the generated defaults;\n- it includes the primary product surface or layout and representative, product-specific content rather than an untouched starter, generic skeleton, blank page, or loading-only state;\n- the primary affordance is visible when the requested experience is interaction-led; and\n- the development server serves the slice successfully, without a blocking runtime error.\n\nThe slice may be static or partially inert. Keep it intentionally bounded and defer secondary routes, complete data models, exhaustive interactions, responsive refinements, animation, polish, and advanced capabilities until after the handoff unless one is required for recognition, security, or a successful render. Work on the slice while installation runs when possible.\n\nFor a new site, replace the starter placeholder content and temporary preview metadata, if present, as part of the slice. Cleanup of unused starter-only files may happen after the handoff, but must finish before publishing.\n\nFor a supported local preview, once the bounded slice is applied, make no further planned product-source edits before the handoff. Fix only compilation or blocking runtime failures, then follow Preview handoff in the selected **Preview** reference to show the first working version without waiting for the complete Site or a deployment. Reuse that preview as the Site's single continuous user-facing view through edits, publishing, and any later fixes.\n\nFor an existing site, use its current coherent experience immediately when it still represents the requested product and serves successfully. If the request changes the primary direction, apply only the smallest representative part first. Preserve the last working content while updates are applied; never replace an existing site with the starter skeleton.\n\n### WebMCP tools for new sites\n\nApply to new sites where the primary journey lets users modify data or meaningful page state, or where a structured tool materially helps an agent complete that journey. Skip static or presentation-only sites whose user journey is limited to reading content or navigating between pages.\n\nAdd [WebMCP tools](references/webmcp.md) after the initial site implementation and before the final build, without delaying any preview required by the selected profile.\n\n### Favicons\n\nGive every new Site a site-specific favicon during its first implementation, even when the user does not ask. Write a small SVG using the Site's colors and a simple recognizable motif that reads at 16 and 32 pixels. Reuse a suitable supplied brand mark. Preserve user-provided favicons in their original format and an existing Site's valid custom icon unless replacement is requested. Use image generation only when the user requests it or the branding requires it.\n\n- **Vinext starter:** replace `public/favicon.svg`; `app/layout.tsx` already references it through `metadata.icons`. If using a supplied icon with another filename or format, update both metadata references to match.\n- **Plain static HTML:** embed the URL-encoded SVG in a `<link rel=\"icon\" type=\"image/svg+xml\" href=\"data:image/svg+xml,...\">` in the HTML `<head>` so single-file Sites stay self-contained.\n- **Other stacks:** use the existing framework metadata or HTML head. For a Worker that serves HTML without static assets, embed a URL-encoded SVG data URL in its favicon link.\n\n### Social previews\n\nGenerate or refresh a social-preview image only when the user explicitly requests a social-preview or social-sharing image. Otherwise preserve any existing preview image and its metadata unchanged. If none exists, omit it; do not start image generation, add an `og.png` asset, or add social-preview image metadata. A missing preview or branding change alone does not authorize generation. Apply this rule in both the **One-shot build** and **Capability path**.\n\n1. **Start early and keep building.** When a new card is explicitly requested, choose its title or primary headline, concise supporting copy, and visual direction early, then follow **Start image work early**. Make one `imagegen` request for a cohesive branded landscape card with that exact title or headline and copy as legible typography, matching the Site's palette, typography, and distinctive motifs while excluding credentials and private data. When delegating, give one `fork_turns=\"none\"` subagent only that brief; have it save the result outside the Site checkout and return the path. Check the card against final copy, branding, and metadata before the final build. Retry or replace at most once total for unusable or stale output; treat any still-invalid card as generation failure.\n2. **Wire the site-wide preview.** When a new card is generated, the Site-owning agent saves it as `public/og.png` (or `og.png` under `static.directory` for buildless sites) and sets site-specific Open Graph and X title, description, and image metadata through the framework's metadata API or HTML `<head>`. Use an absolute URL from a trusted request or deployment origin; never blindly trust forwarded host headers. If generation fails, preserve any existing valid preview; omit `og:image` only when neither an existing nor generated image is available. Never use a generic fallback. Wire the asset before the publishing workflow's build.\n3. **Handle requested item-specific previews.** When the explicit social-preview request covers independently shareable detail pages, use `generateMetadata` or its equivalent to set page title and description and Open Graph/X title, description, and image from the rendered record. Reuse its existing primary image with an absolute trusted-origin URL; otherwise clear both inherited Open Graph and X images. Never reuse the site-wide `og.png` or generate images per record. Validate the root and every detail page when there are at most two; otherwise check at least two representative detail pages. Before final validation, verify that each checked page's title, description, and Open Graph/X fields match its record.\n\n### One-shot build\n\nAfter setup and any necessary clarification, show the first meaningful preview if the environment supports a user-facing local preview, then build the complete site in one focused pass. Continue through `sites-hosting` to publish, following its deployment rules.\n\n1. Read existing instructions and files needed for the next edit, reusing source and setup results already in context. Preserve the package manager and lockfile.\n2. Start required image work under **Start image work early**, then continue the smallest coherent product slice while dispatched work runs. Where a user-facing local preview is supported, complete the **First meaningful preview** handoff above before broadening the implementation. For a genuinely trivial request, the complete implementation may itself be that slice; do not manufacture extra edits merely to demonstrate HMR.\n3. Reuse the project setup and any retained development server or Site tab, then make one complete product patch. Prefer one page and one stylesheet. Include all requested content, interactions, responsive behavior, keyboard and touch behavior when relevant, and accessible labels. Replace the starter placeholder content and metadata with the requested site's own values, remove unused starter-only files, and include the custom favicon described above before publishing unless the user explicitly asked to work on the starter itself. Integrate any explicitly requested **Social previews** result before publishing.\n4. Follow **Preview rules** and **Hosting handoff** below without another polish pass.\n\n### Capability path\n\n#### Project setup\n\n- For a new site, use the setup flow in **Start new projects immediately** and preserve the project's structure.\n- For an existing site, preserve its package manager, lockfile, scripts, architecture, and `.openai/hosting.json`. Install when dependencies are missing or `package.json` or the lockfile changed. Do not replace a working structure merely to use the starter.\n- Keep site code within the selected project surface.\n\n#### Expand the design consistently\n\n- Where a user-facing local preview is supported, apply the bounded slice and complete the **First meaningful preview** handoff above before comprehensive implementation.\n- Start required imagery and explicitly requested social cards under **Start image work early**. Integrate required results before publishing, and omit optional assets that would delay delivery.\n- Build the first viewport around the requested product, not generic dashboard chrome.\n- For a new site, replace the starter placeholder content and metadata and remove unused starter-only files. Set the finished site's title and description through its framework's metadata API or HTML `<head>` before publishing. Preserve starter content only when the user explicitly asked to work on the starter itself.\n- Use concrete, product-specific copy and realistic data.\n- Apply the chosen UX, layout, and visual rules consistently without making every page mechanically identical.\n- Avoid unnecessary client state. Avoid speculative features except for additions permitted by [presentation-site expansion](#expand-presentation-led-sites-like-landing-pages-and-marketing-pages).\n- For server-backed builds, follow [Starter capabilities](references/starter-capabilities.md) and produce Cloudflare Worker-compatible ESM output. Require the Worker entrypoint (`dist/server/index.js` by default) to export a default object with callable `fetch(request, env, ctx)`; if Cloudflare reports no registered event handlers, fix source/build and create a new version instead of redeploying the same archive.\n\nStatic-only builds without runtime bindings, capabilities, or migrations may publish Cloudflare-compatible static output without a Worker. Examples include `dist/index.html`, Next.js exports (`out/`), and vinext exports (`dist/client/`). All static-only builds must set `static.directory` in `.openai/hosting.json` to a supported public output directory (`dist`, `dist/client`, `out`, `build`, or `.output/public`). For Next.js/vinext exports, use `output: 'export'`; select only public assets, excluding any server intermediates.\n\n#### Add only requested capabilities\n\n- For durable state, records, uploads, or other persistence, read [Persistence and storage](references/persistence-and-storage.md).\n- For any SQLite schema or query work, also read [SQLite](references/sqlite.md).\n- For identity-aware or sign-in-gated behavior, read [Authentication](references/authentication.md).\n- For requested Site-hosted MCP tools, read [Sites MCP](../sites-mcp/SKILL.md); browser WebMCP is a separate capability.\n- Hosted Sites do not support raw TCP sockets (`connect()`); use HTTP-based clients or APIs for external databases and services.\n- Use browser storage only for device-local preferences or explicitly local state.\n- Keep logical D1 and R2 declarations in `.openai/hosting.json`; Sites owns the real Cloudflare resources and deployment wiring.\n- Keep local `.env` and `.env.example` keys aligned. Manage hosted runtime values through Sites.\n\n### Preview rules\n\n- In a visible foreground thread with user-facing local preview support, the **First meaningful preview** gate is the only local opening point. If the gate has not passed, keep the browser closed; never open the skeleton as a fallback. If the handoff fails after the gate passes, report it and continue.\n- For an existing site, preserve its normal package and development flow.\n- In a delegated, background, or invisible thread, skip the user-facing browser handoff and say why.\n- Do not scan ports or repeatedly open the browser.\n\n### Hosting handoff\n\nContinue through the [hosting sequence](../sites-hosting/SKILL.md#fast-publish-sequence), passing remaining checks/builds as `commands` and reusing successful results. For local-only work, run only the required local checks/build and hand off the result. Run lint only when requested. Keep any development server running through hosting, then stop it using the environment's preview controls.\n\n## Communicate with the user\n\nAssume the user is a nontechnical knowledge worker. Talk about their site, choices, progress, and results. Keep tools, commands, files, runtimes, browser software, permissions, dependencies, source control, credentials, IDs, builds, and deployment internals out of user-facing messages unless the user asks or must take action.\n\nUnless following [special communication rules](#special-communication-rules-for-initial-site-creation), use no more than one short update for each user-visible phase: preparing the site, building it, and publishing. If a phase takes longer than 60 seconds, give one plain-language update. Keep recoverable technical problems private; say only that you hit a problem and are trying another method.\n\n### Special communication rules for initial site creation\n\n#### 1. Communicate what you're about to build\n\nAfter discovery and design is resolved, but before feature implementation, announce the build plan and time estimate before implementation. Ground the plan in the user’s answers. If proceeding unanswered under the host’s waiting rules, disclose your assumptions here.\n\n1. Explain that you're starting the build and describe the core features and goals requested. If you made meaningful assumptions or substantial additions to the user's request, you must disclose these, framing them warmly as starting points for a complete first version the user can react to.\n\n2. In a new paragraph, give an approximate numeric range for the build and deployment time based on complexity: typically 2–5 minutes for static sites and 4–10 minutes for fullstack sites.\n\n#### 2. Handoff message for a newly created site\n\nGive the user a link to their new site (display in format `Title · domain`). Explain the main features or sections you built. Let them know they can view it, edit it and even share it when they are ready. Offer one or two concrete, optional relevant next steps.\n"}{"goal":{"threadId":"01a118c6-b987-7922-b435-1d2d6fee5f98","objective":"go ahead and make it","status":"active","tokensUsed":2337,"timeUsedSeconds":5,"createdAt":1791418363,"updatedAt":1791418369},"remainingTokens":null,"completionBudgetReport":null}
{"chunk_id":"4a9591","wall_time_seconds":2.640634208,"exit_code":0,"original_token_count":6,"output":"0.186.1\n8.3.3\n1.64.0\n"}
three.js docs (https://threejs.org/docs/)
citeturn15view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://threejs.org/docs/#api/en/renderers/WebGLRenderer","lineno":null}); Total lines: 1932
L0: # cite0†three.js L1:
L2: docs cite1†manual L3:
L4: [Input: ]
L5:
L6: ## Core
L7:
L8: ### Animation
L9:
L10: * cite2†AnimationAction L11: * cite3†AnimationClip L12: * cite4†AnimationMixer L13: * cite5†AnimationObjectGroup L14: * cite6†AnimationUtils L15: * cite7†BooleanKeyframeTrack L16: * cite8†ColorKeyframeTrack L17: * cite9†KeyframeTrack L18: * cite10†NumberKeyframeTrack L19: * cite11†PropertyBinding L20: * cite12†PropertyMixer L21: * cite13†QuaternionKeyframeTrack L22: * cite14†StringKeyframeTrack L23: * cite15†VectorKeyframeTrack L24: ### Audio
L25:
L26: * cite16†Audio L27: * cite17†AudioAnalyser L28: * cite18†AudioContext L29: * cite19†AudioListener L30: * cite20†PositionalAudio L31:
L32: ### Cameras
L33:
L34: * cite21†ArrayCamera L35: * cite22†Camera L36: * cite23†CubeCamera L37: * cite24†OrthographicCamera L38: * cite25†PerspectiveCamera L39: * cite26†StereoCamera L40: ### Core
L41: * cite27†BufferAttribute L42: * cite28†BufferGeometry L43: * cite29†Clock L44: * cite30†EventDispatcher L45: * cite31†Float16BufferAttribute L46: * cite32†Float32BufferAttribute L47: * cite33†GLBufferAttribute L48: * cite34†InstancedBufferAttribute L49: * cite35†InstancedBufferGeometry L50: * cite36†InstancedInterleavedBuffer L51: * cite37†Int16BufferAttribute L52: * cite38†Int32BufferAttribute L53: * cite39†Int8BufferAttribute L54: * cite40†InterleavedBuffer L55: * cite41†InterleavedBufferAttribute L56: * cite42†Layers L57: * cite43†Object3D L58: * cite44†Raycaster L59: * cite45†RenderTarget L60: * cite46†RenderTarget3D L61: * cite47†Timer L62: * cite48†Uint16BufferAttribute L63: * cite49†Uint32BufferAttribute L64: * cite50†Uint8BufferAttribute L65: * cite51†Uint8ClampedBufferAttribute L66: * cite52†Uniform L67: * cite53†UniformsGroup L68: ### Extras
L69:
L70: * cite54†ArcCurve L71: * cite55†CatmullRomCurve3 L72: * cite56†Controls L73: * cite57†CubicBezierCurve L74: * cite58†CubicBezierCurve3 L75: * cite59†Curve L76: * cite60†CurvePath L77: * cite61†DataUtils L78: * cite62†Earcut L79: * cite63†EllipseCurve L80: * cite64†ImageUtils L81: * cite65†LineCurve L82: * cite66†LineCurve3 L83: * cite67†PMREMGenerator L84: * cite68†Path L85: * cite69†QuadraticBezierCurve L86: * cite70†QuadraticBezierCurve3 L87: * cite71†Shape L88: * cite72†ShapePath L89: * cite73†ShapeUtils L90: * cite74†SplineCurve L91: * cite75†TextureUtils L92: * cite76†Interpolations L93: ### Geometries
L94: * cite77†BoxGeometry L95: * cite78†CapsuleGeometry L96: * cite79†CircleGeometry L97: * cite80†ConeGeometry L98: * cite81†CylinderGeometry L99: * cite82†DodecahedronGeometry L100: * cite83†EdgesGeometry L101: * cite84†ExtrudeGeometry L102: * cite85†IcosahedronGeometry L103: * cite86†LatheGeometry L104: * cite87†OctahedronGeometry L105: * cite88†PlaneGeometry L106: * cite89†PolyhedronGeometry L107: * cite90†RingGeometry L108: * cite91†ShapeGeometry L109: * cite92†SphereGeometry L110: * cite93†TetrahedronGeometry L111: * cite94†TorusGeometry L112: * cite95†TorusKnotGeometry L113: * cite96†TubeGeometry L114: * cite97†WireframeGeometry L115: ### Helpers
L116:
L117: * cite98†ArrowHelper L118: * cite99†AxesHelper L119: * cite100†Box3Helper L120: * cite101†BoxHelper L121: * cite102†CameraHelper L122: * cite103†DirectionalLightHelper L123: * cite104†GridHelper L124: * cite105†HemisphereLightHelper L125: * cite106†PlaneHelper L126: * cite107†PointLightHelper L127: * cite108†PolarGridHelper L128: * cite109†SkeletonHelper L129: * cite110†SpotLightHelper L130: ### Lights
L131:
L132: * cite111†AmbientLight L133: * cite112†DirectionalLight L134: * cite113†DirectionalLightShadow L135: * cite114†HemisphereLight L136: * cite115†IESSpotLight L137: * cite116†Light L138: * cite117†LightProbe L139: * cite118†LightShadow L140: * cite119†PointLight L141: * cite120†PointLightShadow L142: * cite121†ProjectorLight L143: * cite122†RectAreaLight L144: * cite123†SpotLight L145: * cite124†SpotLightShadow L146: ### Loaders
L147:
L148: * cite125†AnimationLoader L149: * cite126†AudioLoader L150: * cite127†BufferGeometryLoader L151: * cite128†Cache L152: * cite129†CompressedTextureLoader L153: * cite130†CubeTextureLoader L154: * cite131†DataTextureLoader L155: * cite132†FileLoader L156: * cite133†ImageBitmapLoader L157: * cite134†ImageLoader L158: * cite135†Loader L159: * cite136†LoaderUtils L160: * cite137†LoadingManager L161: * cite138†MaterialLoader L162: * cite139†NodeLoader L163: * cite140†NodeMaterialLoader L164: * cite141†NodeObjectLoader L165: * cite142†ObjectLoader L166: * cite143†TextureLoader L167: ### Materials
L168: * cite144†Line2NodeMaterial L169: * cite145†LineBasicMaterial L170: * cite146†LineBasicNodeMaterial L171: * cite147†LineDashedMaterial L172: * cite148†LineDashedNodeMaterial L173: * cite149†Material L174: * cite150†MeshBasicMaterial L175: * cite151†MeshBasicNodeMaterial L176: * cite152†MeshDepthMaterial L177: * cite153†MeshDistanceMaterial L178: * cite154†MeshLambertMaterial L179: * cite155†MeshLambertNodeMaterial L180: * cite156†MeshMatcapMaterial L181: * cite157†MeshMatcapNodeMaterial L182: * cite158†MeshNormalMaterial L183: * cite159†MeshNormalNodeMaterial L184: * cite160†MeshPhongMaterial L185: * cite161†MeshPhongNodeMaterial L186: * cite162†MeshPhysicalMaterial L187: * cite163†MeshPhysicalNodeMaterial L188: * cite164†MeshSSSNodeMaterial L189: * cite165†MeshStandardMaterial L190: * cite166†MeshStandardNodeMaterial L191: * cite167†MeshToonMaterial L192: * cite168†MeshToonNodeMaterial L193: * cite169†NodeMaterial L194: * cite170†NodeMaterialObserver L195: * cite171†PointsMaterial L196: * cite172†PointsNodeMaterial L197: * cite173†RawShaderMaterial L198: * cite174†SSSLightingModel L199: * cite175†ShaderMaterial L200: * cite176†ShadowMaterial L201: * cite177†ShadowNodeMaterial L202: * cite178†SpriteMaterial L203: * cite179†SpriteNodeMaterial L204: * cite180†VolumeNodeMaterial L205: ### Math
L206: * cite181†BezierInterpolant L207: * cite182†Box2 L208: * cite183†Box3 L209: * cite184†Color L210: * cite185†CubicInterpolant L211: * cite186†Cylindrical L212: * cite187†DiscreteInterpolant L213: * cite188†Euler L214: * cite189†Frustum L215: * cite190†FrustumArray L216: * cite191†Interpolant L217: * cite192†Line3 L218: * cite193†LinearInterpolant L219: * cite194†MathUtils L220: * cite195†Matrix2 L221: * cite196†Matrix3 L222: * cite197†Matrix4 L223: * cite198†Plane L224: * cite199†Quaternion L225: * cite200†QuaternionLinearInterpolant L226: * cite201†Ray L227: * cite202†Sphere L228: * cite203†Spherical L229: * cite204†SphericalHarmonics3 L230: * cite205†Triangle L231: * cite206†Vector2 L232: * cite207†Vector3 L233: * cite208†Vector4 L234: ### Nodes
L235: * cite209†AONode L236: * cite210†AmbientLightNode L237: * cite211†AnalyticLightNode L238: * cite212†ArrayElementNode L239: * cite213†ArrayNode L240: * cite214†AssignNode L241: * cite215†AtomicFunctionNode L242: * cite216†AttributeNode L243: * cite217†BarrierNode L244: * cite218†BasicEnvironmentNode L245: * cite219†BasicLightMapNode L246: * cite220†BasicLightingModel L247: * cite221†BitcastNode L248: * cite222†BitcountNode L249: * cite223†BufferAttributeNode L250: * cite224†BufferNode L251: * cite225†BuiltinNode L252: * cite226†BumpMapNode L253: * cite227†BypassNode L254: * cite228†ClippingNode L255: * cite229†CodeNode L256: * cite230†ColorSpaceNode L257: * cite231†ComputeBuiltinNode L258: * cite232†ComputeNode L259: * cite233†ConditionalNode L260: * cite234†ConstNode L261: * cite235†ContextNode L262: * cite236†ConvertNode L263: * cite237†CubeMapNode L264: * cite238†CubeTextureNode L265: * cite239†DirectionalLightNode L266: * cite240†EnvironmentNode L267: * cite241†EventNode L268: * cite242†ExpressionNode L269: * cite243†FlipNode L270: * cite244†FrontFacingNode L271: * cite245†FunctionCallNode L272: * cite246†FunctionNode L273: * cite247†FunctionOverloadingNode L274: * cite248†GLSLNodeFunction L275: * cite249†GLSLNodeParser L276: * cite250†HemisphereLightNode L277: * cite251†IESSpotLightNode L278: * cite252†IndexNode L279: * cite253†InputNode L280: * cite254†InspectorNode L281: * cite255†IrradianceNode L282: * cite256†IsolateNode L283: * cite257†JoinNode L284: * cite258†LightProbeNode L285: * cite259†LightingContextNode L286: * cite260†LightingModel L287: * cite261†LightingNode L288: * cite262†LightsNode L289: * cite263†LoopNode L290: * cite264†MRTNode L291: * cite265†MaterialNode L292: * cite266†MaterialReferenceNode L293: * cite267†MathNode L294: * cite268†MaxMipLevelNode L295: * cite269†MemberNode L296: * cite270†ModelNode L297: * cite271†Node L298: * cite272†NodeAttribute L299: * cite273†NodeBuilder L300: * cite274†NodeCache L301: * cite275†NodeCode L302: * cite276†NodeError L303: * cite277†NodeFrame L304: * cite278†NodeFunction L305: * cite279†NodeFunctionInput L306: * cite280†NodeParser L307: * cite281†NodeUniform L308: * cite282†NodeVar L309: * cite283†NodeVarying L310: * cite284†NormalMapNode L311: * cite285†Object3DNode L312: * cite286†OperatorNode L313: * cite287†OutputStructNode L314: * cite288†OverrideContextNode L315: * cite289†PMREMNode L316: * cite290†PackFloatNode L317: * cite291†Packed4x8IntegerNode L318: * cite292†ParameterNode L319: * cite293†PassMultipleTextureNode L320: * cite294†PassNode L321: * cite295†PassTextureNode L322: * cite296†PhongLightingModel L323: * cite297†PhysicalLightingModel L324: * cite298†PointLightNode L325: * cite299†PointShadowNode L326: * cite300†PointUVNode L327: * cite301†ProjectorLightNode L328: * cite302†PropertyNode L329: * cite303†RTTNode L330: * cite304†RangeNode L331: * cite305†RectAreaLightNode L332: * cite306†ReferenceBaseNode L333: * cite307†ReferenceElementNode L334: * cite308†ReferenceNode L335: * cite309†ReflectorNode L336: * cite310†RenderOutputNode L337: * cite311†RendererReferenceNode L338: * cite312†RotateNode L339: * cite313†SampleNode L340: * cite314†ScreenNode L341: * cite315†SetNode L342: * cite316†ShadowBaseNode L343: * cite317†ShadowMaskModel --------------------------------------------------------------------------------
Speculative fan-out - TypeSafe AI (https://docs.typesafe.ai/patterns/fan-out)
citeturn15view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/patterns/fan-out","lineno":null}); Total lines: 84>for p in /AGENTS.md /Users/AGENTS.md /Users/sahaj/AGENTS.md /Users/sahaj/Desktop/AGENTS.md /Users/sahaj/Desktop/dev/AGENTS.md /Users/sahaj/Desktop/dev/program/AGENTS.md; do if [ -f "$p" ]; then cat "$p"; fi; done
npm view three version
npm view vite version
npm view @playwright/test version{"goal":{"threadId":"01a118c6-b987-7922-b435-1d2d6fee5f98","objective":"go ahead and make it","status":"active","tokensUsed":2337,"timeUsedSeconds":5,"createdAt":1791418363,"updatedAt":1791418369},"remainingTokens":null,"completionBudgetReport":null}
{"chunk_id":"4a9591","wall_time_seconds":2.640634208,"exit_code":0,"original_token_count":6,"output":"0.186.1\n8.3.3\n1.64.0\n"}
three.js docs (https://threejs.org/docs/)
citeturn15view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://threejs.org/docs/#api/en/renderers/WebGLRenderer","lineno":null}); Total lines: 1932
L0: # cite0†three.js L1:
L2: docs cite1†manual L3:
L4: [Input: ]
L5:
L6: ## Core
L7:
L8: ### Animation
L9:
L10: * cite2†AnimationAction L11: * cite3†AnimationClip L12: * cite4†AnimationMixer L13: * cite5†AnimationObjectGroup L14: * cite6†AnimationUtils L15: * cite7†BooleanKeyframeTrack L16: * cite8†ColorKeyframeTrack L17: * cite9†KeyframeTrack L18: * cite10†NumberKeyframeTrack L19: * cite11†PropertyBinding L20: * cite12†PropertyMixer L21: * cite13†QuaternionKeyframeTrack L22: * cite14†StringKeyframeTrack L23: * cite15†VectorKeyframeTrack L24: ### Audio
L25:
L26: * cite16†Audio L27: * cite17†AudioAnalyser L28: * cite18†AudioContext L29: * cite19†AudioListener L30: * cite20†PositionalAudio L31:
L32: ### Cameras
L33:
L34: * cite21†ArrayCamera L35: * cite22†Camera L36: * cite23†CubeCamera L37: * cite24†OrthographicCamera L38: * cite25†PerspectiveCamera L39: * cite26†StereoCamera L40: ### Core
L41: * cite27†BufferAttribute L42: * cite28†BufferGeometry L43: * cite29†Clock L44: * cite30†EventDispatcher L45: * cite31†Float16BufferAttribute L46: * cite32†Float32BufferAttribute L47: * cite33†GLBufferAttribute L48: * cite34†InstancedBufferAttribute L49: * cite35†InstancedBufferGeometry L50: * cite36†InstancedInterleavedBuffer L51: * cite37†Int16BufferAttribute L52: * cite38†Int32BufferAttribute L53: * cite39†Int8BufferAttribute L54: * cite40†InterleavedBuffer L55: * cite41†InterleavedBufferAttribute L56: * cite42†Layers L57: * cite43†Object3D L58: * cite44†Raycaster L59: * cite45†RenderTarget L60: * cite46†RenderTarget3D L61: * cite47†Timer L62: * cite48†Uint16BufferAttribute L63: * cite49†Uint32BufferAttribute L64: * cite50†Uint8BufferAttribute L65: * cite51†Uint8ClampedBufferAttribute L66: * cite52†Uniform L67: * cite53†UniformsGroup L68: ### Extras
L69:
L70: * cite54†ArcCurve L71: * cite55†CatmullRomCurve3 L72: * cite56†Controls L73: * cite57†CubicBezierCurve L74: * cite58†CubicBezierCurve3 L75: * cite59†Curve L76: * cite60†CurvePath L77: * cite61†DataUtils L78: * cite62†Earcut L79: * cite63†EllipseCurve L80: * cite64†ImageUtils L81: * cite65†LineCurve L82: * cite66†LineCurve3 L83: * cite67†PMREMGenerator L84: * cite68†Path L85: * cite69†QuadraticBezierCurve L86: * cite70†QuadraticBezierCurve3 L87: * cite71†Shape L88: * cite72†ShapePath L89: * cite73†ShapeUtils L90: * cite74†SplineCurve L91: * cite75†TextureUtils L92: * cite76†Interpolations L93: ### Geometries
L94: * cite77†BoxGeometry L95: * cite78†CapsuleGeometry L96: * cite79†CircleGeometry L97: * cite80†ConeGeometry L98: * cite81†CylinderGeometry L99: * cite82†DodecahedronGeometry L100: * cite83†EdgesGeometry L101: * cite84†ExtrudeGeometry L102: * cite85†IcosahedronGeometry L103: * cite86†LatheGeometry L104: * cite87†OctahedronGeometry L105: * cite88†PlaneGeometry L106: * cite89†PolyhedronGeometry L107: * cite90†RingGeometry L108: * cite91†ShapeGeometry L109: * cite92†SphereGeometry L110: * cite93†TetrahedronGeometry L111: * cite94†TorusGeometry L112: * cite95†TorusKnotGeometry L113: * cite96†TubeGeometry L114: * cite97†WireframeGeometry L115: ### Helpers
L116:
L117: * cite98†ArrowHelper L118: * cite99†AxesHelper L119: * cite100†Box3Helper L120: * cite101†BoxHelper L121: * cite102†CameraHelper L122: * cite103†DirectionalLightHelper L123: * cite104†GridHelper L124: * cite105†HemisphereLightHelper L125: * cite106†PlaneHelper L126: * cite107†PointLightHelper L127: * cite108†PolarGridHelper L128: * cite109†SkeletonHelper L129: * cite110†SpotLightHelper L130: ### Lights
L131:
L132: * cite111†AmbientLight L133: * cite112†DirectionalLight L134: * cite113†DirectionalLightShadow L135: * cite114†HemisphereLight L136: * cite115†IESSpotLight L137: * cite116†Light L138: * cite117†LightProbe L139: * cite118†LightShadow L140: * cite119†PointLight L141: * cite120†PointLightShadow L142: * cite121†ProjectorLight L143: * cite122†RectAreaLight L144: * cite123†SpotLight L145: * cite124†SpotLightShadow L146: ### Loaders
L147:
L148: * cite125†AnimationLoader L149: * cite126†AudioLoader L150: * cite127†BufferGeometryLoader L151: * cite128†Cache L152: * cite129†CompressedTextureLoader L153: * cite130†CubeTextureLoader L154: * cite131†DataTextureLoader L155: * cite132†FileLoader L156: * cite133†ImageBitmapLoader L157: * cite134†ImageLoader L158: * cite135†Loader L159: * cite136†LoaderUtils L160: * cite137†LoadingManager L161: * cite138†MaterialLoader L162: * cite139†NodeLoader L163: * cite140†NodeMaterialLoader L164: * cite141†NodeObjectLoader L165: * cite142†ObjectLoader L166: * cite143†TextureLoader L167: ### Materials
L168: * cite144†Line2NodeMaterial L169: * cite145†LineBasicMaterial L170: * cite146†LineBasicNodeMaterial L171: * cite147†LineDashedMaterial L172: * cite148†LineDashedNodeMaterial L173: * cite149†Material L174: * cite150†MeshBasicMaterial L175: * cite151†MeshBasicNodeMaterial L176: * cite152†MeshDepthMaterial L177: * cite153†MeshDistanceMaterial L178: * cite154†MeshLambertMaterial L179: * cite155†MeshLambertNodeMaterial L180: * cite156†MeshMatcapMaterial L181: * cite157†MeshMatcapNodeMaterial L182: * cite158†MeshNormalMaterial L183: * cite159†MeshNormalNodeMaterial L184: * cite160†MeshPhongMaterial L185: * cite161†MeshPhongNodeMaterial L186: * cite162†MeshPhysicalMaterial L187: * cite163†MeshPhysicalNodeMaterial L188: * cite164†MeshSSSNodeMaterial L189: * cite165†MeshStandardMaterial L190: * cite166†MeshStandardNodeMaterial L191: * cite167†MeshToonMaterial L192: * cite168†MeshToonNodeMaterial L193: * cite169†NodeMaterial L194: * cite170†NodeMaterialObserver L195: * cite171†PointsMaterial L196: * cite172†PointsNodeMaterial L197: * cite173†RawShaderMaterial L198: * cite174†SSSLightingModel L199: * cite175†ShaderMaterial L200: * cite176†ShadowMaterial L201: * cite177†ShadowNodeMaterial L202: * cite178†SpriteMaterial L203: * cite179†SpriteNodeMaterial L204: * cite180†VolumeNodeMaterial L205: ### Math
L206: * cite181†BezierInterpolant L207: * cite182†Box2 L208: * cite183†Box3 L209: * cite184†Color L210: * cite185†CubicInterpolant L211: * cite186†Cylindrical L212: * cite187†DiscreteInterpolant L213: * cite188†Euler L214: * cite189†Frustum L215: * cite190†FrustumArray L216: * cite191†Interpolant L217: * cite192†Line3 L218: * cite193†LinearInterpolant L219: * cite194†MathUtils L220: * cite195†Matrix2 L221: * cite196†Matrix3 L222: * cite197†Matrix4 L223: * cite198†Plane L224: * cite199†Quaternion L225: * cite200†QuaternionLinearInterpolant L226: * cite201†Ray L227: * cite202†Sphere L228: * cite203†Spherical L229: * cite204†SphericalHarmonics3 L230: * cite205†Triangle L231: * cite206†Vector2 L232: * cite207†Vector3 L233: * cite208†Vector4 L234: ### Nodes
L235: * cite209†AONode L236: * cite210†AmbientLightNode L237: * cite211†AnalyticLightNode L238: * cite212†ArrayElementNode L239: * cite213†ArrayNode L240: * cite214†AssignNode L241: * cite215†AtomicFunctionNode L242: * cite216†AttributeNode L243: * cite217†BarrierNode L244: * cite218†BasicEnvironmentNode L245: * cite219†BasicLightMapNode L246: * cite220†BasicLightingModel L247: * cite221†BitcastNode L248: * cite222†BitcountNode L249: * cite223†BufferAttributeNode L250: * cite224†BufferNode L251: * cite225†BuiltinNode L252: * cite226†BumpMapNode L253: * cite227†BypassNode L254: * cite228†ClippingNode L255: * cite229†CodeNode L256: * cite230†ColorSpaceNode L257: * cite231†ComputeBuiltinNode L258: * cite232†ComputeNode L259: * cite233†ConditionalNode L260: * cite234†ConstNode L261: * cite235†ContextNode L262: * cite236†ConvertNode L263: * cite237†CubeMapNode L264: * cite238†CubeTextureNode L265: * cite239†DirectionalLightNode L266: * cite240†EnvironmentNode L267: * cite241†EventNode L268: * cite242†ExpressionNode L269: * cite243†FlipNode L270: * cite244†FrontFacingNode L271: * cite245†FunctionCallNode L272: * cite246†FunctionNode L273: * cite247†FunctionOverloadingNode L274: * cite248†GLSLNodeFunction L275: * cite249†GLSLNodeParser L276: * cite250†HemisphereLightNode L277: * cite251†IESSpotLightNode L278: * cite252†IndexNode L279: * cite253†InputNode L280: * cite254†InspectorNode L281: * cite255†IrradianceNode L282: * cite256†IsolateNode L283: * cite257†JoinNode L284: * cite258†LightProbeNode L285: * cite259†LightingContextNode L286: * cite260†LightingModel L287: * cite261†LightingNode L288: * cite262†LightsNode L289: * cite263†LoopNode L290: * cite264†MRTNode L291: * cite265†MaterialNode L292: * cite266†MaterialReferenceNode L293: * cite267†MathNode L294: * cite268†MaxMipLevelNode L295: * cite269†MemberNode L296: * cite270†ModelNode L297: * cite271†Node L298: * cite272†NodeAttribute L299: * cite273†NodeBuilder L300: * cite274†NodeCache L301: * cite275†NodeCode L302: * cite276†NodeError L303: * cite277†NodeFrame L304: * cite278†NodeFunction L305: * cite279†NodeFunctionInput L306: * cite280†NodeParser L307: * cite281†NodeUniform L308: * cite282†NodeVar L309: * cite283†NodeVarying L310: * cite284†NormalMapNode L311: * cite285†Object3DNode L312: * cite286†OperatorNode L313: * cite287†OutputStructNode L314: * cite288†OverrideContextNode L315: * cite289†PMREMNode L316: * cite290†PackFloatNode L317: * cite291†Packed4x8IntegerNode L318: * cite292†ParameterNode L319: * cite293†PassMultipleTextureNode L320: * cite294†PassNode L321: * cite295†PassTextureNode L322: * cite296†PhongLightingModel L323: * cite297†PhysicalLightingModel L324: * cite298†PointLightNode L325: * cite299†PointShadowNode L326: * cite300†PointUVNode L327: * cite301†ProjectorLightNode L328: * cite302†PropertyNode L329: * cite303†RTTNode L330: * cite304†RangeNode L331: * cite305†RectAreaLightNode L332: * cite306†ReferenceBaseNode L333: * cite307†ReferenceElementNode L334: * cite308†ReferenceNode L335: * cite309†ReflectorNode L336: * cite310†RenderOutputNode L337: * cite311†RendererReferenceNode L338: * cite312†RotateNode L339: * cite313†SampleNode L340: * cite314†ScreenNode L341: * cite315†SetNode L342: * cite316†ShadowBaseNode L343: * cite317†ShadowMaskModel --------------------------------------------------------------------------------
Speculative fan-out - TypeSafe AI (https://docs.typesafe.ai/patterns/fan-out)
citeturn15view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/patterns/fan-out","lineno":null}); Total lines: 84{"goal":{"threadId":"01a118c6-b987-7922-b435-1d2d6fee5f98","objective":"go ahead and make it","status":"active","tokensUsed":2337,"timeUsedSeconds":5,"createdAt":1791418363,"updatedAt":1791418369},"remainingTokens":null,"completionBudgetReport":null}
{"chunk_id":"4a9591","wall_time_seconds":2.640634208,"exit_code":0,"original_token_count":6,"output":"0.186.1\n8.3.3\n1.64.0\n"}
three.js docs (https://threejs.org/docs/)
citeturn15view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://threejs.org/docs/#api/en/renderers/WebGLRenderer","lineno":null}); Total lines: 1932
L0: # cite0†three.js L1:
L2: docs cite1†manual L3:
L4: [Input: ]
L5:
L6: ## Core
L7:
L8: ### Animation
L9:
L10: * cite2†AnimationAction L11: * cite3†AnimationClip L12: * cite4†AnimationMixer L13: * cite5†AnimationObjectGroup L14: * cite6†AnimationUtils L15: * cite7†BooleanKeyframeTrack L16: * cite8†ColorKeyframeTrack L17: * cite9†KeyframeTrack L18: * cite10†NumberKeyframeTrack L19: * cite11†PropertyBinding L20: * cite12†PropertyMixer L21: * cite13†QuaternionKeyframeTrack L22: * cite14†StringKeyframeTrack L23: * cite15†VectorKeyframeTrack L24: ### Audio
L25:
L26: * cite16†Audio L27: * cite17†AudioAnalyser L28: * cite18†AudioContext L29: * cite19†AudioListener L30: * cite20†PositionalAudio L31:
L32: ### Cameras
L33:
L34: * cite21†ArrayCamera L35: * cite22†Camera L36: * cite23†CubeCamera L37: * cite24†OrthographicCamera L38: * cite25†PerspectiveCamera L39: * cite26†StereoCamera L40: ### Core
L41: * cite27†BufferAttribute L42: * cite28†BufferGeometry L43: * cite29†Clock L44: * cite30†EventDispatcher L45: * cite31†Float16BufferAttribute L46: * cite32†Float32BufferAttribute L47: * cite33†GLBufferAttribute L48: * cite34†InstancedBufferAttribute L49: * cite35†InstancedBufferGeometry L50: * cite36†InstancedInterleavedBuffer L51: * cite37†Int16BufferAttribute L52: * cite38†Int32BufferAttribute L53: * cite39†Int8BufferAttribute L54: * cite40†InterleavedBuffer L55: * cite41†InterleavedBufferAttribute L56: * cite42†Layers L57: * cite43†Object3D L58: * cite44†Raycaster L59: * cite45†RenderTarget L60: * cite46†RenderTarget3D L61: * cite47†Timer L62: * cite48†Uint16BufferAttribute L63: * cite49†Uint32BufferAttribute L64: * cite50†Uint8BufferAttribute L65: * cite51†Uint8ClampedBufferAttribute L66: * cite52†Uniform L67: * cite53†UniformsGroup L68: ### Extras
L69:
L70: * cite54†ArcCurve L71: * cite55†CatmullRomCurve3 L72: * cite56†Controls L73: * cite57†CubicBezierCurve L74: * cite58†CubicBezierCurve3 L75: * cite59†Curve L76: * cite60†CurvePath L77: * cite61†DataUtils L78: * cite62†Earcut L79: * cite63†EllipseCurve L80: * cite64†ImageUtils L81: * cite65†LineCurve L82: * cite66†LineCurve3 L83: * cite67†PMREMGenerator L84: * cite68†Path L85: * cite69†QuadraticBezierCurve L86: * cite70†QuadraticBezierCurve3 L87: * cite71†Shape L88: * cite72†ShapePath L89: * cite73†ShapeUtils L90: * cite74†SplineCurve L91: * cite75†TextureUtils L92: * cite76†Interpolations L93: ### Geometries
L94: * cite77†BoxGeometry L95: * cite78†CapsuleGeometry L96: * cite79†CircleGeometry L97: * cite80†ConeGeometry L98: * cite81†CylinderGeometry L99: * cite82†DodecahedronGeometry L100: * cite83†EdgesGeometry L101: * cite84†ExtrudeGeometry L102: * cite85†IcosahedronGeometry L103: * cite86†LatheGeometry L104: * cite87†OctahedronGeometry L105: * cite88†PlaneGeometry L106: * cite89†PolyhedronGeometry L107: * cite90†RingGeometry L108: * cite91†ShapeGeometry L109: * cite92†SphereGeometry L110: * cite93†TetrahedronGeometry L111: * cite94†TorusGeometry L112: * cite95†TorusKnotGeometry L113: * cite96†TubeGeometry L114: * cite97†WireframeGeometry L115: ### Helpers
L116:
L117: * cite98†ArrowHelper L118: * cite99†AxesHelper L119: * cite100†Box3Helper L120: * cite101†BoxHelper L121: * cite102†CameraHelper L122: * cite103†DirectionalLightHelper L123: * cite104†GridHelper L124: * cite105†HemisphereLightHelper L125: * cite106†PlaneHelper L126: * cite107†PointLightHelper L127: * cite108†PolarGridHelper L128: * cite109†SkeletonHelper L129: * cite110†SpotLightHelper L130: ### Lights
L131:
L132: * cite111†AmbientLight L133: * cite112†DirectionalLight L134: * cite113†DirectionalLightShadow L135: * cite114†HemisphereLight L136: * cite115†IESSpotLight L137: * cite116†Light L138: * cite117†LightProbe L139: * cite118†LightShadow L140: * cite119†PointLight L141: * cite120†PointLightShadow L142: * cite121†ProjectorLight L143: * cite122†RectAreaLight L144: * cite123†SpotLight L145: * cite124†SpotLightShadow L146: ### Loaders
L147:
L148: * cite125†AnimationLoader L149: * cite126†AudioLoader L150: * cite127†BufferGeometryLoader L151: * cite128†Cache L152: * cite129†CompressedTextureLoader L153: * cite130†CubeTextureLoader L154: * cite131†DataTextureLoader L155: * cite132†FileLoader L156: * cite133†ImageBitmapLoader L157: * cite134†ImageLoader L158: * cite135†Loader L159: * cite136†LoaderUtils L160: * cite137†LoadingManager L161: * cite138†MaterialLoader L162: * cite139†NodeLoader L163: * cite140†NodeMaterialLoader L164: * cite141†NodeObjectLoader L165: * cite142†ObjectLoader L166: * cite143†TextureLoader L167: ### Materials
L168: * cite144†Line2NodeMaterial L169: * cite145†LineBasicMaterial L170: * cite146†LineBasicNodeMaterial L171: * cite147†LineDashedMaterial L172: * cite148†LineDashedNodeMaterial L173: * cite149†Material L174: * cite150†MeshBasicMaterial L175: * cite151†MeshBasicNodeMaterial L176: * cite152†MeshDepthMaterial L177: * cite153†MeshDistanceMaterial L178: * cite154†MeshLambertMaterial L179: * cite155†MeshLambertNodeMaterial L180: * cite156†MeshMatcapMaterial L181: * cite157†MeshMatcapNodeMaterial L182: * cite158†MeshNormalMaterial L183: * cite159†MeshNormalNodeMaterial L184: * cite160†MeshPhongMaterial L185: * cite161†MeshPhongNodeMaterial L186: * cite162†MeshPhysicalMaterial L187: * cite163†MeshPhysicalNodeMaterial L188: * cite164†MeshSSSNodeMaterial L189: * cite165†MeshStandardMaterial L190: * cite166†MeshStandardNodeMaterial L191: * cite167†MeshToonMaterial L192: * cite168†MeshToonNodeMaterial L193: * cite169†NodeMaterial L194: * cite170†NodeMaterialObserver L195: * cite171†PointsMaterial L196: * cite172†PointsNodeMaterial L197: * cite173†RawShaderMaterial L198: * cite174†SSSLightingModel L199: * cite175†ShaderMaterial L200: * cite176†ShadowMaterial L201: * cite177†ShadowNodeMaterial L202: * cite178†SpriteMaterial L203: * cite179†SpriteNodeMaterial L204: * cite180†VolumeNodeMaterial L205: ### Math
L206: * cite181†BezierInterpolant L207: * cite182†Box2 L208: * cite183†Box3 L209: * cite184†Color L210: * cite185†CubicInterpolant L211: * cite186†Cylindrical L212: * cite187†DiscreteInterpolant L213: * cite188†Euler L214: * cite189†Frustum L215: * cite190†FrustumArray L216: * cite191†Interpolant L217: * cite192†Line3 L218: * cite193†LinearInterpolant L219: * cite194†MathUtils L220: * cite195†Matrix2 L221: * cite196†Matrix3 L222: * cite197†Matrix4 L223: * cite198†Plane L224: * cite199†Quaternion L225: * cite200†QuaternionLinearInterpolant L226: * cite201†Ray L227: * cite202†Sphere L228: * cite203†Spherical L229: * cite204†SphericalHarmonics3 L230: * cite205†Triangle L231: * cite206†Vector2 L232: * cite207†Vector3 L233: * cite208†Vector4 L234: ### Nodes
L235: * cite209†AONode L236: * cite210†AmbientLightNode L237: * cite211†AnalyticLightNode L238: * cite212†ArrayElementNode L239: * cite213†ArrayNode L240: * cite214†AssignNode L241: * cite215†AtomicFunctionNode L242: * cite216†AttributeNode L243: * cite217†BarrierNode L244: * cite218†BasicEnvironmentNode L245: * cite219†BasicLightMapNode L246: * cite220†BasicLightingModel L247: * cite221†BitcastNode L248: * cite222†BitcountNode L249: * cite223†BufferAttributeNode L250: * cite224†BufferNode L251: * cite225†BuiltinNode L252: * cite226†BumpMapNode L253: * cite227†BypassNode L254: * cite228†ClippingNode L255: * cite229†CodeNode L256: * cite230†ColorSpaceNode L257: * cite231†ComputeBuiltinNode L258: * cite232†ComputeNode L259: * cite233†ConditionalNode L260: * cite234†ConstNode L261: * cite235†ContextNode L262: * cite236†ConvertNode L263: * cite237†CubeMapNode L264: * cite238†CubeTextureNode L265: * cite239†DirectionalLightNode L266: * cite240†EnvironmentNode L267: * cite241†EventNode L268: * cite242†ExpressionNode L269: * cite243†FlipNode L270: * cite244†FrontFacingNode L271: * cite245†FunctionCallNode L272: * cite246†FunctionNode L273: * cite247†FunctionOverloadingNode L274: * cite248†GLSLNodeFunction L275: * cite249†GLSLNodeParser L276: * cite250†HemisphereLightNode L277: * cite251†IESSpotLightNode L278: * cite252†IndexNode L279: * cite253†InputNode L280: * cite254†InspectorNode L281: * cite255†IrradianceNode L282: * cite256†IsolateNode L283: * cite257†JoinNode L284: * cite258†LightProbeNode L285: * cite259†LightingContextNode L286: * cite260†LightingModel L287: * cite261†LightingNode L288: * cite262†LightsNode L289: * cite263†LoopNode L290: * cite264†MRTNode L291: * cite265†MaterialNode L292: * cite266†MaterialReferenceNode L293: * cite267†MathNode L294: * cite268†MaxMipLevelNode L295: * cite269†MemberNode L296: * cite270†ModelNode L297: * cite271†Node L298: * cite272†NodeAttribute L299: * cite273†NodeBuilder L300: * cite274†NodeCache L301: * cite275†NodeCode L302: * cite276†NodeError L303: * cite277†NodeFrame L304: * cite278†NodeFunction L305: * cite279†NodeFunctionInput L306: * cite280†NodeParser L307: * cite281†NodeUniform L308: * cite282†NodeVar L309: * cite283†NodeVarying L310: * cite284†NormalMapNode L311: * cite285†Object3DNode L312: * cite286†OperatorNode L313: * cite287†OutputStructNode L314: * cite288†OverrideContextNode L315: * cite289†PMREMNode L316: * cite290†PackFloatNode L317: * cite291†Packed4x8IntegerNode L318: * cite292†ParameterNode L319: * cite293†PassMultipleTextureNode L320: * cite294†PassNode L321: * cite295†PassTextureNode L322: * cite296†PhongLightingModel L323: * cite297†PhysicalLightingModel L324: * cite298†PointLightNode L325: * cite299†PointShadowNode L326: * cite300†PointUVNode L327: * cite301†ProjectorLightNode L328: * cite302†PropertyNode L329: * cite303†RTTNode L330: * cite304†RangeNode L331: * cite305†RectAreaLightNode L332: * cite306†ReferenceBaseNode L333: * cite307†ReferenceElementNode L334: * cite308†ReferenceNode L335: * cite309†ReflectorNode L336: * cite310†RenderOutputNode L337: * cite311†RendererReferenceNode L338: * cite312†RotateNode L339: * cite313†SampleNode L340: * cite314†ScreenNode L341: * cite315†SetNode L342: * cite316†ShadowBaseNode L343: * cite317†ShadowMaskModel --------------------------------------------------------------------------------
Speculative fan-out - TypeSafe AI (https://docs.typesafe.ai/patterns/fan-out)
citeturn15view1 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://docs.typesafe.ai/patterns/fan-out","lineno":null}); Total lines: 84<codex_internal_context source="user_goal"> User set goal status: "paused". </codex_internal_context>
No content
ACTUALLY that'll take too long.. i wanna make a bsic fgame like the snake game but the snake is controlled by jev and the user is the apple that spawns in a new location each time the snake eats it. the user can jump one square in any direction and snake has to react and adjust in real time. make it quick!
I’ll make the quick version: you move the apple one square with the arrow keys, Jev steers the snake, and getting eaten respawns you somewhere new. I’ll keep the game lightweight and show whether the snake is using live Jev decisions.
>ls -la
node --version{"chunk_id":"b4cdb9","wall_time_seconds":0.005999083,"exit_code":0,"original_token_count":41,"output":"total 8\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 20:10 .\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:50 ..\n-rw-r--r--@ 1 sahaj staff 120 Oct 7 19:52 .env\nv22.22.3\n"}
{"goal":{"threadId":"01a118c6-b987-7922-b435-1d2d6fee5f98","objective":"go ahead and make it","status":"paused","tokensUsed":11073,"timeUsedSeconds":111,"createdAt":1791418363,"updatedAt":1791418474},"remainingTokens":null,"completionBudgetReport":null}{"chunk_id":"b4cdb9","wall_time_seconds":0.005999083,"exit_code":0,"original_token_count":41,"output":"total 8\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 20:10 .\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:50 ..\n-rw-r--r--@ 1 sahaj staff 120 Oct 7 19:52 .env\nv22.22.3\n"}
{"goal":{"threadId":"01a118c6-b987-7922-b435-1d2d6fee5f98","objective":"go ahead and make it","status":"paused","tokensUsed":11073,"timeUsedSeconds":111,"createdAt":1791418363,"updatedAt":1791418474},"remainingTokens":null,"completionBudgetReport":null}{}The board and game rules are in place. Jev will choose each snake move from the legal directions; the game handles walls, the snake’s body, and apple respawns. I’m wiring up the controls and checking a live round now.
{}
{"chunk_id":"e4c677","wall_time_seconds":0.517562875,"exit_code":0,"original_token_count":325,"output":"\n> apple-vs-jev@1.0.0 test\n> node --test tests/*.test.mjs\n\nTAP version 13\n# Subtest: apple hops one square and cannot enter the snake or leave the board\nok 1 - apple hops one square and cannot enter the snake or leave the board\n ---\n duration_ms: 0.913\n type: 'test'\n ...\n# Subtest: eating grows the snake and respawns the apple on an empty square\nok 2 - eating grows the snake and respawns the apple on an empty square\n ---\n duration_ms: 1.271541\n type: 'test'\n ...\n# Subtest: body and walls prohibit moves but the vacating tail is legal\nok 3 - body and walls prohibit moves but the vacating tail is legal\n ---\n duration_ms: 0.190833\n type: 'test'\n ...\n# Subtest: trapping the head produces no legal moves\nok 4 - trapping the head produces no legal moves\n ---\n duration_ms: 0.12625\n type: 'test'\n ...\n# Subtest: Jev receives precisely the legal directions and no private data\nok 5 - Jev receives precisely the legal directions and no private data\n ---\n duration_ms: 0.872125\n type: 'test'\n ...\n# Subtest: rejects malformed board state and handles a full board\nok 6 - rejects malformed board state and handles a full board\n ---\n duration_ms: 1.324625\n type: 'test'\n ...\n1..6\n# tests 6\n# suites 0\n# pass 6\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 61.034666\n"}
{"chunk_id":"5c2172","wall_time_seconds":1.002253291,"session_id":77428,"original_token_count":26,"output":"\n> apple-vs-jev@1.0.0 start\n> node server.mjs\n\nApple vs. Jev → http://localhost:3000 (Jev connected)\n"}>npm test && node --check server.mjs && node --check public/app.mjs{}
{"chunk_id":"e4c677","wall_time_seconds":0.517562875,"exit_code":0,"original_token_count":325,"output":"\n> apple-vs-jev@1.0.0 test\n> node --test tests/*.test.mjs\n\nTAP version 13\n# Subtest: apple hops one square and cannot enter the snake or leave the board\nok 1 - apple hops one square and cannot enter the snake or leave the board\n ---\n duration_ms: 0.913\n type: 'test'\n ...\n# Subtest: eating grows the snake and respawns the apple on an empty square\nok 2 - eating grows the snake and respawns the apple on an empty square\n ---\n duration_ms: 1.271541\n type: 'test'\n ...\n# Subtest: body and walls prohibit moves but the vacating tail is legal\nok 3 - body and walls prohibit moves but the vacating tail is legal\n ---\n duration_ms: 0.190833\n type: 'test'\n ...\n# Subtest: trapping the head produces no legal moves\nok 4 - trapping the head produces no legal moves\n ---\n duration_ms: 0.12625\n type: 'test'\n ...\n# Subtest: Jev receives precisely the legal directions and no private data\nok 5 - Jev receives precisely the legal directions and no private data\n ---\n duration_ms: 0.872125\n type: 'test'\n ...\n# Subtest: rejects malformed board state and handles a full board\nok 6 - rejects malformed board state and handles a full board\n ---\n duration_ms: 1.324625\n type: 'test'\n ...\n1..6\n# tests 6\n# suites 0\n# pass 6\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 61.034666\n"}
{"chunk_id":"5c2172","wall_time_seconds":1.002253291,"session_id":77428,"original_token_count":26,"output":"\n> apple-vs-jev@1.0.0 start\n> node server.mjs\n\nApple vs. Jev → http://localhost:3000 (Jev connected)\n"}>npm start{}
{"chunk_id":"e4c677","wall_time_seconds":0.517562875,"exit_code":0,"original_token_count":325,"output":"\n> apple-vs-jev@1.0.0 test\n> node --test tests/*.test.mjs\n\nTAP version 13\n# Subtest: apple hops one square and cannot enter the snake or leave the board\nok 1 - apple hops one square and cannot enter the snake or leave the board\n ---\n duration_ms: 0.913\n type: 'test'\n ...\n# Subtest: eating grows the snake and respawns the apple on an empty square\nok 2 - eating grows the snake and respawns the apple on an empty square\n ---\n duration_ms: 1.271541\n type: 'test'\n ...\n# Subtest: body and walls prohibit moves but the vacating tail is legal\nok 3 - body and walls prohibit moves but the vacating tail is legal\n ---\n duration_ms: 0.190833\n type: 'test'\n ...\n# Subtest: trapping the head produces no legal moves\nok 4 - trapping the head produces no legal moves\n ---\n duration_ms: 0.12625\n type: 'test'\n ...\n# Subtest: Jev receives precisely the legal directions and no private data\nok 5 - Jev receives precisely the legal directions and no private data\n ---\n duration_ms: 0.872125\n type: 'test'\n ...\n# Subtest: rejects malformed board state and handles a full board\nok 6 - rejects malformed board state and handles a full board\n ---\n duration_ms: 1.324625\n type: 'test'\n ...\n1..6\n# tests 6\n# suites 0\n# pass 6\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 61.034666\n"}
{"chunk_id":"5c2172","wall_time_seconds":1.002253291,"session_id":77428,"original_token_count":26,"output":"\n> apple-vs-jev@1.0.0 start\n> node server.mjs\n\nApple vs. Jev → http://localhost:3000 (Jev connected)\n"}>mkdir -p artifacts
python3 - <<'PY'
import json
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser=p.chromium.launch(executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',headless=True)
page=browser.new_page(viewport={'width':1440,'height':1000},device_scale_factor=1)
errors=[]
page.on('pageerror',lambda e: errors.append(str(e)))
page.goto('http://localhost:3000',wait_until='networkidle')
page.screenshot(path='artifacts/start.png',full_page=True)
page.get_by_role('button',name='Let’s play').click()
page.wait_for_function('window.gameSnapshot().calls >= 2 || !window.gameSnapshot().running',timeout=20000)
print('Initial live state:',json.dumps(page.evaluate('window.gameSnapshot()')))
before=page.evaluate('window.gameSnapshot().state.apple')
page.keyboard.press('ArrowUp')
page.wait_for_timeout(120)
after=page.evaluate('window.gameSnapshot().state.apple')
print('Apple hop:',before,'->',after)
page.wait_for_function('window.gameSnapshot().catches >= 1 || !window.gameSnapshot().running',timeout=30000)
print('After pursuit:',json.dumps(page.evaluate('window.gameSnapshot()')))
print('Status:',page.locator('#connection').inner_text(),'latency:',page.locator('#latency').inner_text())
print('Overlay:',page.locator('#overlay').is_visible(),page.locator('#overlay-copy').inner_text())
page.screenshot(path='artifacts/playing.png',full_page=True)
page.keyboard.press('p')
frozen=page.evaluate('window.gameSnapshot().elapsed')
page.wait_for_timeout(500)
print('Pause works:',not page.evaluate('window.gameSnapshot().running') and page.evaluate('window.gameSnapshot().elapsed')==frozen)
print('JS errors:',errors)
page.set_viewport_size({'width':390,'height':844})
page.screenshot(path='artifacts/mobile.png',full_page=True)
print('Mobile overflow:',page.evaluate('document.documentElement.scrollWidth > innerWidth'))
browser.close()
PY{"chunk_id":"15618d","wall_time_seconds":1.002790375,"session_id":34160,"original_token_count":0,"output":""}{"chunk_id":"7d6343","wall_time_seconds":0.000206666,"exit_code":1,"original_token_count":416,"output":"Traceback (most recent call last):\n File \"<stdin>\", line 11, in <module>\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/sync_api/_generated.py\", line 11599, in wait_for_function\n self._sync(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_sync_base.py\", line 115, in _sync\n return task.result()\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_page.py\", line 1110, in wait_for_function\n return await self._main_frame.wait_for_function(**locals_to_params(locals()))\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_frame.py\", line 878, in wait_for_function\n await self._channel.send(\"waitForFunction\", self._timeout, params)\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 69, in send\n return await self._connection.wrap_api_call(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 559, in wrap_api_call\n raise rewrite_error(error, f\"{parsed_st['apiName']}: {error}\") from None\nplaywright._impl._errors.Error: Page.wait_for_function: EvalError: Evaluating a string as JavaScript violates the following Content Security Policy directive because 'unsafe-eval' is not an allowed source of script: script-src 'self'\".\n\n at eval (<anonymous>)\n at predicate (eval at evaluate (:290:30), <anonymous>:4:56)\n at next (eval at evaluate (:290:30), <anonymous>:29:29)\n"}
{"chunk_id":"62f059","wall_time_seconds":0.000007917,"exit_code":0,"original_token_count":10,"output":"{\"configured\":true,\"model\":\"jev-1.13.0\"}"}>curl -fsS http://localhost:3000/api/status{"chunk_id":"7d6343","wall_time_seconds":0.000206666,"exit_code":1,"original_token_count":416,"output":"Traceback (most recent call last):\n File \"<stdin>\", line 11, in <module>\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/sync_api/_generated.py\", line 11599, in wait_for_function\n self._sync(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_sync_base.py\", line 115, in _sync\n return task.result()\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_page.py\", line 1110, in wait_for_function\n return await self._main_frame.wait_for_function(**locals_to_params(locals()))\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_frame.py\", line 878, in wait_for_function\n await self._channel.send(\"waitForFunction\", self._timeout, params)\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 69, in send\n return await self._connection.wrap_api_call(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 559, in wrap_api_call\n raise rewrite_error(error, f\"{parsed_st['apiName']}: {error}\") from None\nplaywright._impl._errors.Error: Page.wait_for_function: EvalError: Evaluating a string as JavaScript violates the following Content Security Policy directive because 'unsafe-eval' is not an allowed source of script: script-src 'self'\".\n\n at eval (<anonymous>)\n at predicate (eval at evaluate (:290:30), <anonymous>:4:56)\n at next (eval at evaluate (:290:30), <anonymous>:29:29)\n"}
{"chunk_id":"62f059","wall_time_seconds":0.000007917,"exit_code":0,"original_token_count":10,"output":"{\"configured\":true,\"model\":\"jev-1.13.0\"}"}{"chunk_id":"07f74b","wall_time_seconds":1.001967583,"session_id":12913,"original_token_count":0,"output":""}>python3 -u - <<'PY'
import json
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser=p.chromium.launch(executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',headless=True)
page=browser.new_page(viewport={'width':1440,'height':1000},device_scale_factor=1)
errors=[]
page.on('pageerror',lambda e: errors.append(str(e)))
page.goto('http://localhost:3000',wait_until='networkidle')
page.get_by_role('button',name='Let’s play').click()
page.wait_for_function('() => window.gameSnapshot().calls >= 2 || !window.gameSnapshot().running',timeout=20000)
print('Initial live state:',json.dumps(page.evaluate('window.gameSnapshot()')))
before=page.evaluate('window.gameSnapshot().state.apple')
page.keyboard.press('ArrowUp')
page.wait_for_timeout(120)
after=page.evaluate('window.gameSnapshot().state.apple')
print('Apple hop:',before,'->',after)
page.wait_for_function('() => window.gameSnapshot().catches >= 1 || !window.gameSnapshot().running',timeout=30000)
print('After pursuit:',json.dumps(page.evaluate('window.gameSnapshot()')))
print('Status:',page.locator('#connection').inner_text(),'latency:',page.locator('#latency').inner_text())
print('Overlay:',page.locator('#overlay').is_visible(),page.locator('#overlay-copy').inner_text())
page.screenshot(path='artifacts/playing.png',full_page=True)
page.keyboard.press('p')
frozen=page.evaluate('window.gameSnapshot().elapsed')
page.wait_for_timeout(500)
print('Pause works:',not page.evaluate('window.gameSnapshot().running') and page.evaluate('window.gameSnapshot().elapsed')==frozen)
print('JS errors:',errors)
page.set_viewport_size({'width':390,'height':844})
page.screenshot(path='artifacts/mobile.png',full_page=True)
print('Mobile overflow:',page.evaluate('document.documentElement.scrollWidth > innerWidth'))
browser.close()
PY{"chunk_id":"07f74b","wall_time_seconds":1.001967583,"session_id":12913,"original_token_count":0,"output":""}{"chunk_id":"892f16","wall_time_seconds":0.000298542,"exit_code":0,"original_token_count":186,"output":"Initial live state: {\"state\": {\"snake\": [{\"x\": 6, \"y\": 8}, {\"x\": 5, \"y\": 8}, {\"x\": 4, \"y\": 8}, {\"x\": 3, \"y\": 8}], \"apple\": {\"x\": 12, \"y\": 8}, \"direction\": \"right\"}, \"running\": true, \"elapsed\": 0.5166999999999999, \"catches\": 0, \"calls\": 2, \"tokens\": 1182}\nApple hop: {'x': 12, 'y': 8} -> {'x': 12, 'y': 7}\nAfter pursuit: {\"state\": {\"snake\": [{\"x\": 12, \"y\": 7}, {\"x\": 11, \"y\": 7}, {\"x\": 10, \"y\": 7}, {\"x\": 9, \"y\": 7}, {\"x\": 8, \"y\": 7}], \"apple\": {\"x\": 5, \"y\": 1}, \"direction\": \"right\"}, \"running\": true, \"elapsed\": 0.01669999999999982, \"catches\": 1, \"calls\": 8, \"tokens\": 4747}\nStatus: JEV LIVE latency: 121 ms\nOverlay: False Jump one square at a time.Jev picks every move the snake makes.\nPause works: True\nJS errors: []\nMobile overflow: False\n"}It’s working with live Jev. In the browser test, I moved the apple mid-chase; the snake adjusted, caught it, grew, and triggered a new spawn. The last response took 121 ms. Keyboard controls, pause, and the mobile layout also passed.
>node --input-type=module - <<'JS'
const r = await fetch('http://localhost:3000/api/decide', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({snake:[{x:0,y:0},{x:1,y:0},{x:1,y:1},{x:0,y:1}],apple:{x:5,y:5},direction:'left'})});
const b=await r.json(); console.log(JSON.stringify({status:r.status,...b}));
const env=await fetch('http://localhost:3000/.env');console.log('Secret route status:',env.status);
JS{"chunk_id":"214e4b","wall_time_seconds":0.378543375,"exit_code":0,"original_token_count":39,"output":"{\"status\":200,\"direction\":\"down\",\"confidence\":1,\"probabilities\":{\"down\":1},\"latency\":256,\"inputTokens\":481,\"model\":\"jev-1.13.0\"}\nSecret route status: 404\n"}{"chunk_id":"214e4b","wall_time_seconds":0.378543375,"exit_code":0,"original_token_count":39,"output":"{\"status\":200,\"direction\":\"down\",\"confidence\":1,\"probabilities\":{\"down\":1},\"latency\":256,\"inputTokens\":481,\"model\":\"jev-1.13.0\"}\nSecret route status: 404\n"}{"chunk_id":"214e4b","wall_time_seconds":0.378543375,"exit_code":0,"original_token_count":39,"output":"{\"status\":200,\"direction\":\"down\",\"confidence\":1,\"probabilities\":{\"down\":1},\"latency\":256,\"inputTokens\":481,\"model\":\"jev-1.13.0\"}\nSecret route status: 404\n"}>open http://localhost:3000{"chunk_id":"da704d","wall_time_seconds":0.00000825,"exit_code":0,"original_token_count":0,"output":""}Built and running: Play Apple vs. Jev
Verified live pursuit, respawning, controls, and mobile layout. The sidebar shows actual Jev probabilities and latency.
No content
can u make the design a lot more basic.. look at traces.com and use a similar styling..
I’ll look at traces.com and simplify the game’s layout, typography, and controls to match its style more closely.
Traces (https://traces.com/)
citeturn16view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://traces.com","lineno":null}); Total lines: 793
L0: cite0†NewCreate a Surface on Traces.com L1:
L2: # The Hub for Your
L3: Coding Agents
L4:
L5: Share sessions live & compound your learning. For software developers & teams.
L6:
L7: Download the CLI to get started
L8:
L9: [Button: Homebrew][Button: npm][Button: Shell]
L10:
L11: cite1†View script L12:
L13: `brew install market-dot-dev/tap/traces&&traces`
L14:
L15: OR
L16:
L17: cite2†Sign up for free L18:
L19: Works with your favourite agents
L20:
L21: [Button: For Everyone][Button: For Teams]
L22:
L23: cite3†Image: Public profile preview L24: ## Used by teams like
L25:
L26: * cite4†Image: Worklayer logo L27: * cite5†Image: Hugging Face logo L28: * cite6†Image: Mintlify logo L29: * cite7†Image: 8090 logo L30: * cite8†Image: Documenso logo L31: * cite9†Image: Glide logo L32: * cite10†Image: Influee logo L33: * cite11†Image: Lapel logo L34: * cite12†Image: 11x logo L35: * cite4†Image: Worklayer logo L36: * cite5†Image: Hugging Face logo L37: * cite6†Image: Mintlify logo L38: * cite7†Image: 8090 logo L39: * cite8†Image: Documenso logo L40: * cite9†Image: Glide logo L41: * cite10†Image: Influee logo L42: * cite11†Image: Lapel logo L43: * cite12†Image: 11x logo L44: ## How It Works
L45:
L46: Start sharing traces from any agent, in minutes.
L47: ### Upload from any agent
L48:
L49: Publish traces from 10+ supported agents directly in the CLI.
L50:
L51: [Button: Get the CLI]
L52:
L53: TRACES Q: Quit
L54:
L55: @janedoe Logout
L56:
L57: Time
L58:
L59: Directory
L60:
L61: Agent
L62:
L63: Msgs
L64:
L65: Title
L66:
L67: Today
L68:
L69: 12:45 PM
L70:
L71: frontend
L72:
L73: claude-code
L74:
L75: 13
L76:
L77: HeroVideo.tsx terminal-like preview with trac...
L78:
L79: Publish
L80:
L81: 12:11 PM
L82:
L83: docs
L84:
L85: opencode
L86:
L87: 31
L88:
L89: HeroVideo.tsx terminal view adjustment
L90:
L91: Publish
L92:
L93: 10:00 AM
L94:
L95: frontend
L96:
L97: copilot
L98:
L99: 59
L100:
L101: Schema validation error in parts table
L102:
L103: Publish
L104:
L105: 12:25 PM
L106:
L107: api
L108:
L109: cursor
L110:
L111: 10
L112:
L113: Terminal not working troubleshooting
L114: Publish
L115:
L116: 12:44 PM
L117:
L118: cli
L119:
L120: codex
L121:
L122: 112
L123:
L124: Light chat intro clarifications
L125:
L126: Publish
L127:
L128: 11:28 AM
L129:
L130: traces
L131:
L132: droid
L133:
L134: 386
L135:
L136: Improving app onboarding and hero section
L137:
L138: Publish
L139:
L140: 11:47 AM
L141:
L142: traces
L143:
L144: amp
L145:
L146: 74
L147:
L148: HomeHero background dot fade implementation
L149:
L150: Publish
L151:
L152: 12:02 PM
L153:
L154: packages/shared
L155:
L156: pi
L157:
L158: 18
L159:
L160: Logical commit order strategy
L161:
L162: Publish
L163:
L164: Yesterday
L165:
L166: 01:34 PM
L167:
L168: packages/shared
L169:
L170: antigravity
L171:
L172: 92
L173:
L174: Splitting branch changes by feature area
L175:
L176: •Open Link Copy Link
L177:
L178: 02:53 PM
L179:
L180: docs
L181:
L182: openclaw
L183:
L184: 64
L185:
L186: Data visualization for user activity metrics
L187: •Open Link Copy Link
L188:
L189: 10:19 AM
L190:
L191: traces
L192:
L193: opencode
L194:
L195: 67
L196:
L197: Commit all changes; group in logical order
L198:
L199: •Open Link Copy Link
L200:
L201: 12:22 PM
L202:
L203: frontend
L204:
L205: cursor
L206:
L207: 226
L208:
L209: Terminal command sections - full-card copy but...
L210:
L211: •Open Link Copy Link
L212:
L213: 04:56 PM
L214:
L215: cli
L216:
L217: hermes
L218:
L219: 72
L220:
L221: Fixing WeeklyDensityChart data rendering
L222:
L223: •Open Link Copy Link
L224:
L225: 04:44 PM
L226:
L227: api
L228:
L229: cline
L230:
L231: 515
L232:
L233: Profile Activity Data Visualization Plan
L234:
L235: •Open Link Copy Link
L236:
L237: 01:02 PM
L238:
L239: api
L240:
L241: cline
L242:
L243: 23
L244:
L245: Semantic and logical commit grouping
L246:
L247: •Open Link Copy Link
L248:
L249: 12:38 PM
L250: packages/shared
L251:
L252: codex
L253:
L254: 57
L255:
L256: Rotating link-3 icon.ts -45 degrees
L257:
L258: •Open Link Copy Link
L259:
L260: Feb 10
L261:
L262: 12:31 PM
L263:
L264: traces
L265:
L266: antigravity
L267:
L268: 255
L269:
L270: HomeFeed traces list redesign
L271:
L272: Publish
L273:
L274: 01:18 PM
L275:
L276: traces
L277:
L278: openclaw
L279:
L280: 153
L281:
L282: TraceOverview component border removal
L283:
L284: •Open Link Copy Link Refresh Unpublish
L285:
L286: 03:31 PM
L287:
L288: frontend
L289:
L290: copilot
L291:
L292: 14
L293:
L294: Next.js OpenGraph image route configuration
L295:
L296: •Open Link Copy Link
L297:
L298: 03:23 PM
L299:
L300: cli
L301:
L302: hermes
L303:
L304: 26
L305:
L306: Permanent caching for static Open Graph images
L307:
L308: •Open Link Copy Link
L309:
L310: 03:46 PM
L311:
L312: frontend
L313:
L314: droid
L315:
L316: 39
L317: Aligning TRACES logo in OpenGraph images
L318:
L319: •Open Link Copy Link
L320:
L321: 02:51 PM
L322:
L323: docs
L324:
L325: cline
L326:
L327: 45
L328:
L329: OpenGraph image layout from s/[id]/opengraph-...
L330:
L331: •Open Link Copy Link
L332:
L333: 04:17 PM
L334:
L335: packages/shared
L336:
L337: amp
L338:
L339: 27
L340:
L341: Fixing message cutoff in MessageAccordion.tsx
L342:
L343: •Open Link Copy Link
L344:
L345: 08:38 PM
L346:
L347: docs
L348:
L349: pi
L350:
L351: 23
L352:
L353: Sticky avatar and logo implementation
L354:
L355: •Open Link Copy Link
L356: ### Share your traces
L357:
L358: Copy the link & share your trace with your team or the world.
L359:
L360: 1. cite13†Image: Maya Chen L361:
L362: look up how to make this animation smoother. right now, it looks a little jittery. the animation isn't butter smooth which is what I want.
L363:
L364: 2. I'll identify which animation in this codebase is currently jittery, then look up current best practices for making it feel “butter smooth,” and apply targeted fixes in the relevant file. I'm starting by scanning recent frontend animation code.
L365: 3. I found a few custom animations; the most likely jitter source is the sliding tab indicator in `UserMenu` because it uses imperative WAAPI and can re-measure on state changes. I'm reading that implementation next and then I'll verify smoothing techniques from current guidance.
L366:
L367: traces.com/s/jlkj44k
L368: ### Download & continue sessions
L369:
L370: Download a full trace or continue working on someone else's.
L371:
L372: Download a trace, or continue it in Claude Code. The open agent menu lists Claude Code, Codex, Cline, Pi, Cursor, OpenCode, Oh My Pi, Amp, OpenClaw, GitHub Copilot, Hermes, Droid, Grok, Kimi Code, Antigravity, Prime Agent, fx, DeepSeek Harness, with Claude Code selected.
L373:
L374: Download Continue in…
L375:
L376: Local
L377:
L378: Remote
L379:
L380: Claude Code
L381:
L382: Codex
L383:
L384: Cline
L385:
L386: Pi
L387:
L388: Cursor
L389:
L390: OpenCode
L391:
L392: Oh My Pi
L393:
L394: Amp
L395:
L396: OpenClaw
L397:
L398: GitHub Copilot
L399:
L400: Hermes
L401:
L402: Droid
L403: Grok
L404:
L405: Kimi Code
L406:
L407: Antigravity
L408:
L409: Prime Agent
L410:
L411: fx
L412:
L413: DeepSeek Harness
L414:
L415: Traces for Teams
L416: ## See How Your Team Is Using Agents
L417:
L418: Traces gives teams one place to see work in progress, share context on finished work, and see which agents people are using.
L419:
L420: cite2†Sign up for free L421:
L422: Set up your team with one prompt
L423:
L424: cite14†Image: Team profile preview L425:
L426: > “Github increasingly doesn't feel like the best place to understand the work done on a codebase. Agent traces provide a much more human-readable overview. Just started using traces.com. Feels quite nice.”
L427: Millin Gabani, CEO of cite15†Worklayer†www.myworklayer.com L428:
L429: cite16†See original post†x.com L430: ## Privacy & Trust
L431:
L432: Share agent conversations without worrying about sensitive data.
L433:
L434: ### Flexible Visibility
L435:
L436: Share your traces privately, directly, or publicly, so only the right people see them.
L437:
L438: maujim · 102 messages
L439:
L440: Private
L441:
L442: Diagnose and Enhance Voltage Error Reporting
L443:
L444: maujim · 102 messages
L445:
L446: Direct
L447:
L448: Diagnose and Enhance Voltage Error Reporting
L449:
L450: maujim · 102 messages
L451:
L452: Public
L453:
L454: Diagnose and Enhance Voltage Error Reporting
L455: ### Team-Level Protections
L456:
L457: Set team-level policies to control how your team can share traces.
L458:
L459: Traces can be published as:
L460:
L461: Allowed trace visibility for this team
L462:
L463: Private
L464:
L465: Only team members can view
L466:
L467: [Input]
L468:
L469: Direct
L470:
L471: Anyone with the link can view
L472:
L473: [Input]
L474:
L475: Public
L476:
L477: Visible on public team pages & feeds
L478:
L479: [Input]
L480: ### Scrub Sensitive Data
L481:
L482: We automatically strip sensitive data like API keys, emails & database credentials from traces on publish.
L483:
L484: Shared the rollout trace after scrubbing [REDACTED], [REDACTED], and [REDACTED] from the assistant reply before sending the link to the team.
L485:
L486: The published run keeps the reasoning intact while replacing keys, customer emails, and database URLs with clear [REDACTED] markers anyone can spot immediately.
L487: Reviewers still understand what happened, but the sensitive values stay hidden behind [REDACTED] in every shared view.
L488: ## Share From Anywhere
L489:
L490: Start simple & integrate more as you go.
L491:
L492: ### CLI
L493:
L494: Publish & manage traces directly from your terminal.
L495:
L496: [Button: Get the CLI]
L497:
L498: ### Coding Agents
L499:
L500: Let your agent share traces as you work.
L501:
L502: cite17†Get the skill L503:
L504: ### API
L505:
L506: Publish traces via API with your own tools, schedulers & workflows.
L507:
L508: cite18†Learn more L509:
L510: ### Git hooks
L511:
L512: Automatically share traces on every commit from your CI/CD pipelines.
L513:
L514: cite19†Learn more L515:
L516: ## Pricing
L517:
L518: Free for individuals & small teams, flexible at scale.
L519:
L520: Core
L521:
L522: Free
L523: ### For individuals & small teams
L524:
L525: * Unlimited Traces
L526: * Unlimited Teams
L527: * Up to 50 Seats
L528:
L529: cite2†Sign up L530:
L531: Custom
L532:
L533: Get in touch
L534:
L535: ### For larger teams & enterprises
L536:
L537: * Everything in Core
L538: * Self hosting / On-prem
L539: * Priority support
L540: * Team onboarding & training
L541:
L542: cite20†Contact us L543:
L544: ## A New Way to Work With Agents
L545:
L546: See what ships, loop in the right agents, and share traces with git hooks & custom skills.
L547: ### Team Analytics
L548:
L549: Team analytics preview showing Claude Code, Codex, Cursor, Droid, and Amp as the top agents, with an average session length of 47 minutes and 82.0 percent AI output.
L550:
L551: ### Top Agents
L552:
L553: Claude Code 486
L554:
{"chunk_id":"5a9920","wall_time_seconds":0.000024875,"exit_code":0,"original_token_count":3316,"output":"total 56\ndrwxr-xr-x 11 sahaj staff 352 Oct 7 20:20 .\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:50 ..\n-rw-r--r--@ 1 sahaj staff 120 Oct 7 19:52 .env\n-rw-r--r--@ 1 sahaj staff 40 Oct 7 20:17 .env.example\n-rw-r--r--@ 1 sahaj staff 51 Oct 7 20:17 .gitignore\n-rw-r--r--@ 1 sahaj staff 1782 Oct 7 20:19 README.md\ndrwxr-xr-x@ 5 sahaj staff 160 Oct 7 20:20 artifacts\n-rw-r--r--@ 1 sahaj staff 256 Oct 7 20:17 package.json\ndrwxr-xr-x@ 7 sahaj staff 224 Oct 7 20:19 public\n-rw-r--r--@ 1 sahaj staff 4820 Oct 7 20:19 server.mjs\ndrwxr-xr-x@ 3 sahaj staff 96 Oct 7 20:19 tests\n<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta name=\"theme-color\" content=\"#111610\"><meta name=\"description\" content=\"You are the apple. Jev is the snake. How long can you keep it guessing?\">\n <title>Apple vs. Jev</title><link rel=\"icon\" href=\"/favicon.svg\"><link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n <header><a class=\"wordmark\" href=\"/\" aria-label=\"Apple versus Jev home\"><span class=\"mark\">a<span>j</span></span> APPLE VS. JEV</a><div class=\"live-badge\" id=\"connection\"><span></span> CONNECTING</div></header>\n <main>\n <section class=\"intro\"><div class=\"eyebrow\">A LITTLE ROLE REVERSAL</div><h1>Be the <em>bait.</em></h1><p>You’re the apple. The snake is AI.<br>Keep it guessing. Try not to get eaten.</p></section>\n <section class=\"game-layout\">\n <div class=\"board-column\">\n <div class=\"board-top\"><span><i class=\"apple-dot\"></i> YOU</span><span>17 × 17 <span class=\"dim\">/</span> NO PLACE TO HIDE</span><span><i class=\"snake-dot\"></i> JEV</span></div>\n <div class=\"board-wrap\" id=\"board-wrap\">\n <canvas id=\"board\" width=\"680\" height=\"680\" tabindex=\"0\" aria-label=\"Snake game. You control the apple with arrow keys or W A S D.\"></canvas>\n <div class=\"overlay\" id=\"overlay\"><div class=\"overlay-inner\"><span class=\"overline\" id=\"overlay-tag\">YOU ARE THE APPLE</span><h2 id=\"overlay-title\">Don’t make it easy.</h2><p id=\"overlay-copy\">Jump one square at a time.<br>Jev picks every move the snake makes.</p><button id=\"start\" class=\"primary\">Let’s play <span>↗</span></button><small id=\"setup-hint\">Checking Jev connection…</small></div></div>\n <div class=\"catch-pop\" id=\"catch-pop\" aria-live=\"polite\">CAUGHT. NEW SPOT.</div>\n </div>\n <div class=\"board-bottom\"><span><span class=\"key\">↑</span><span class=\"key\">←</span><span class=\"key\">↓</span><span class=\"key\">→</span> or WASD to hop</span><button id=\"pause\" disabled>Pause <span class=\"key\">P</span></button><button id=\"restart\" aria-label=\"Restart game\">Restart ↻</button></div>\n <div class=\"touch-controls\" aria-label=\"Movement controls\"><button data-direction=\"left\" aria-label=\"Move left\">←</button><div><button data-direction=\"up\" aria-label=\"Move up\">↑</button><button data-direction=\"down\" aria-label=\"Move down\">↓</button></div><button data-direction=\"right\" aria-label=\"Move right\">→</button></div>\n </div>\n <aside>\n <div class=\"score-card\"><div class=\"eyebrow\">CURRENT ESCAPE</div><div class=\"timer\"><span id=\"time\">00</span><small>. <span id=\"tenths\">0</span><span class=\"unit\">s</span></small></div><div class=\"best-row\">PERSONAL BEST <strong id=\"best\">0.0s</strong></div></div>\n <div class=\"numbers\"><div><strong id=\"catches\">0</strong><span>TIMES EATEN</span></div><div><strong id=\"length\">4</strong><span>SNAKE LENGTH</span></div></div>\n <div class=\"mind-card\"><div class=\"mind-heading\"><span class=\"eyebrow\">INSIDE JEV’S HEAD</span><span class=\"brain-mark\">✳</span></div><div class=\"decision\" id=\"decision\">Waiting for you.</div><p id=\"decision-note\">A real model. A very hungry snake.</p><div class=\"probabilities\" id=\"probabilities\"></div><div class=\"telemetry\"><span>LAST RESPONSE <strong id=\"latency\">—</strong></span><span>DECISIONS <strong id=\"calls\">0</strong></span></div></div>\n <div class=\"rules\"><span class=\"rule-number\">01</span><p>Arrow keys or WASD.<br>One press, one square.</p><span class=\"rule-number\">02</span><p>Get eaten? You respawn.<br>The snake gets longer.</p><span class=\"rule-number\">03</span><p>Trap the snake in its own tail.<br>That’s your way out.</p></div>\n <div class=\"cost\">SESSION API COST <span id=\"cost\">$0.0000</span></div>\n </aside>\n </section>\n </main>\n <footer><span>HUMAN INSTINCT <span class=\"dim\">×</span> MACHINE APPETITE</span><span>Powered by Jev <span class=\"dim\">/</span> TypeSafe</span></footer>\n <script type=\"module\" src=\"/app.mjs\"></script>\n</body>\n</html>\n:root{font-family:Arial,Helvetica,sans-serif;color:#e8eddf;background:#111610;font-synthesis:none;color-scheme:dark;--lime:#c5f778;--muted:#86947d;--border:#2a3425;--apple:#ff7c66}*{box-sizing:border-box}body{margin:0;background:radial-gradient(ellipse at 35% 35%,#1c261640,transparent 60%);min-height:100vh}button,a{-webkit-tap-highlight-color:transparent}button{font:inherit;cursor:pointer}button:focus-visible,a:focus-visible,canvas:focus-visible{outline:2px solid var(--lime);outline-offset:5px}header{height:87px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;padding:0 6vw}.wordmark{color:#e8eddf;text-decoration:none;font-size:12px;font-weight:700;letter-spacing:2px;display:flex;align-items:center;gap:14px}.mark{font-size:32px;letter-spacing:-6px;color:var(--apple);padding-right:6px;line-height:1}.mark span{color:var(--lime)}.live-badge{display:flex;align-items:center;gap:8px;border:1px solid var(--border);border-radius:30px;padding:10px 13px;font-size:10px;letter-spacing:1.3px;color:var(--muted)}.live-badge>span{width:6px;height:6px;background:#697561;border-radius:50%}.live-badge.ready{color:var(--lime)}.live-badge.ready>span{background:var(--lime);box-shadow:0 0 9px #c5f77850}.live-badge.error{color:var(--apple)}.live-badge.error>span{background:var(--apple)}main{max-width:1060px;padding:40px 30px 20px;margin:auto}.intro{margin-bottom:30px}.eyebrow{font-size:10px;letter-spacing:2px;font-weight:700;color:var(--muted)}h1{font-size:clamp(44px,6vw,72px);letter-spacing:-4px;line-height:1;margin:15px 0 13px;font-weight:600}h1 em{font-family:Georgia,serif;font-weight:400;color:var(--lime)}.intro p{font-size:14px;line-height:1.7;color:var(--muted);margin:0}.game-layout{display:grid;grid-template-columns:minmax(0,620px) minmax(235px,1fr);gap:38px;align-items:start}.board-top{display:flex;justify-content:space-between;font-size:10px;letter-spacing:1px;align-items:center;margin-bottom:12px}.board-top>span{display:flex;align-items:center;gap:7px}.board-top>span:nth-child(2){color:#839076;font-size:9px}.apple-dot,.snake-dot{width:7px;height:7px;display:inline-block;background:var(--apple);border-radius:2px}.snake-dot{background:var(--lime)}.dim{color:#4d5b45}.board-wrap{position:relative;aspect-ratio:1;background:#1a2317;border:1px solid #35442d;border-radius:10px;overflow:hidden;box-shadow:0 20px 80px #0003}canvas{display:block;width:100%;height:100%;touch-action:none}.overlay{position:absolute;inset:0;display:grid;place-items:center;background:#101a12bc;backdrop-filter:blur(5px);text-align:center;padding:25px}.overlay[hidden]{display:none}.overlay-inner{max-width:330px}.overline{font-size:10px;font-weight:700;letter-spacing:2px;color:var(--lime)}h2{font-size:clamp(26px,4vw,36px);letter-spacing:-1.3px;margin:18px 0 13px;font-weight:500}.overlay p{font-size:14px;color:#b0baa5;line-height:1.75;margin:0 0 25px}.primary{border:0;background:var(--lime);color:#1a2810;padding:16px 22px;border-radius:5px;min-width:185px;font-size:14px;font-weight:700;display:inline-flex;justify-content:space-between;gap:28px}.primary:hover{background:#d7ff9d}.primary:disabled{opacity:.5;cursor:wait}.overlay small{display:block;font-size:11px;line-height:1.5;color:#8f9b84;margin:16px auto 0;max-width:300px}.board-bottom{display:flex;align-items:center;gap:17px;padding-top:17px;color:var(--muted);font-size:11px;flex-wrap:wrap}.board-bottom>span{margin-right:auto;display:flex;gap:3px;align-items:center}.key{font-family:monospace;font-size:10px;display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:20px;border:1px solid #35432d;border-bottom-width:2px;border-radius:3px;margin-right:3px;color:#adb99f}.board-bottom button{border:0;background:transparent;color:#a9b69c;padding:0;font-size:11px}.board-bottom button:disabled{opacity:.4}.catch-pop{position:absolute;left:50%;top:42%;transform:translate(-50%,15px);padding:12px 18px;background:var(--apple);border-radius:5px;color:#381c15;font-weight:800;font-size:11px;letter-spacing:1px;opacity:0;pointer-events:none;transition:opacity .15s,transform .15s;white-space:nowrap}.catch-pop.show{opacity:1;transform:translate(-50%,0)}aside{padding-top:23px}.score-card{padding-bottom:20px;border-bottom:1px solid var(--border)}.timer{font-size:65px;letter-spacing:-3px;font-variant-numeric:tabular-nums;line-height:1.1;margin:14px 0 17px}.timer>small{font-size:31px;color:#809071;letter-spacing:-2px}.timer .unit{font-size:16px;letter-spacing:0;margin-left:7px}.best-row{display:flex;justify-content:space-between;align-items:center;font-size:9px;letter-spacing:1px;color:var(--muted)}.best-row strong{color:var(--lime);font-size:12px;font-weight:400;letter-spacing:0}.numbers{display:flex;padding:22px 0;border-bottom:1px solid var(--border)}.numbers>div{width:50%;display:flex;flex-direction:column;gap:8px}.numbers>div+div{padding-left:22px;border-left:1px solid var(--border)}.numbers strong{font-size:29px;font-weight:400}.numbers span{font-size:9px;letter-spacing:1px;color:var(--muted)}.mind-card{margin-top:23px;border:1px solid #35442a;background:#1d28187d;border-radius:7px;padding:18px}.mind-heading{display:flex;justify-content:space-between;align-items:center}.mind-heading .eyebrow{font-size:9px;letter-spacing:1.3px}.brain-mark{color:var(--lime);font-size:22px}.decision{font-size:19px;letter-spacing:-.5px;margin-top:18px}.mind-card p{color:var(--muted);font-size:11px;line-height:1.6;margin:8px 0 20px}.probabilities{display:grid;gap:8px}.prob-row{display:grid;grid-template-columns:37px 1fr 28px;gap:8px;align-items:center;font-size:10px;color:var(--muted)}.track{height:3px;background:#34442a;overflow:hidden;border-radius:4px}.fill{height:100%;background:var(--lime);transition:width .18s}.prob-row.picked{color:var(--lime)}.telemetry{border-top:1px solid var(--border);margin-top:18px;padding-top:13px;display:flex;justify-content:space-between;gap:12px}.telemetry>span{display:flex;flex-direction:column;gap:7px;font-size:8px;letter-spacing:.6px;color:var(--muted)}.telemetry strong{font-size:12px;letter-spacing:0;color:#dbe6ce;font-weight:400}.rules{display:grid;grid-template-columns:24px 1fr;gap:14px 6px;margin:24px 0}.rule-number{font-size:10px;color:#57664d;line-height:1.7}.rules p{margin:0;font-size:11px;line-height:1.7;color:var(--muted)}.cost{border-top:1px solid var(--border);padding-top:15px;font-size:9px;letter-spacing:.7px;color:#65755b;display:flex;justify-content:space-between}.cost span{font-family:monospace;letter-spacing:0}footer{max-width:1000px;margin:20px auto;padding:22px 0;border-top:1px solid var(--border);display:flex;justify-content:space-between;font-size:9px;letter-spacing:1.3px;color:#6b7a60}.touch-controls{display:none;align-items:center;justify-content:center;gap:8px;margin-top:20px}.touch-controls>div{display:grid;gap:8px}.touch-controls button{background:#24301d;border:1px solid #415631;color:var(--lime);width:54px;height:45px;border-radius:7px;font-size:22px;touch-action:none}.touch-controls button:active{background:#435d2d}@media(min-width:1100px) and (max-height:950px){header{height:65px}main{padding-top:25px;max-width:940px}.intro{margin-bottom:22px;display:grid;grid-template-columns:1fr 1fr}.intro .eyebrow{grid-column:1/-1}h1{font-size:59px;margin-top:12px}.intro p{align-self:center;justify-self:end}.game-layout{grid-template-columns:minmax(0,510px) 1fr;gap:35px}footer{max-width:880px}.rules{gap:8px;margin:18px 0}.score-card{padding-bottom:16px}.numbers{padding:16px 0}.mind-card{margin-top:18px}.timer{font-size:54px;margin:10px 0}.mind-card p{margin-bottom:12px}}@media(max-width:700px){header{height:65px;padding:0 20px}.wordmark{font-size:10px;gap:10px;letter-spacing:1px}.live-badge{font-size:8px;padding:8px 10px}main{padding:27px 18px 10px}.intro{margin-bottom:24px}.intro p{font-size:13px}h1{letter-spacing:-2px}.game-layout{grid-template-columns:1fr;gap:15px}aside{display:grid;grid-template-columns:1fr 1fr;gap:15px;padding:10px 0}.score-card{border-bottom:0}.numbers{border:0;padding:0;align-self:center}.numbers>div+div{padding-left:12px}.numbers span{font-size:8px}.timer{font-size:46px}.timer>small{font-size:25px}.mind-card{grid-column:1/-1;margin:0}.rules{display:none}.cost{grid-column:1/-1}.touch-controls{display:flex}.board-top>span:nth-child(2){font-size:8px;letter-spacing:.5px}.board-bottom{gap:12px;font-size:10px}footer{margin:20px 18px;padding-top:18px;gap:15px;font-size:8px;letter-spacing:.5px}.probabilities{grid-template-columns:1fr 1fr;column-gap:20px}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"}>ls -la
cat public/index.html
cat public/style.cssTraces (https://traces.com/)
citeturn16view0 [wordlim: 200] Crawled: today; Content type: text/html; Source: open({"ref_id":"https://traces.com","lineno":null}); Total lines: 793
L0: cite0†NewCreate a Surface on Traces.com L1:
L2: # The Hub for Your
L3: Coding Agents
L4:
L5: Share sessions live & compound your learning. For software developers & teams.
L6:
L7: Download the CLI to get started
L8:
L9: [Button: Homebrew][Button: npm][Button: Shell]
L10:
L11: cite1†View script L12:
L13: `brew install market-dot-dev/tap/traces&&traces`
L14:
L15: OR
L16:
L17: cite2†Sign up for free L18:
L19: Works with your favourite agents
L20:
L21: [Button: For Everyone][Button: For Teams]
L22:
L23: cite3†Image: Public profile preview L24: ## Used by teams like
L25:
L26: * cite4†Image: Worklayer logo L27: * cite5†Image: Hugging Face logo L28: * cite6†Image: Mintlify logo L29: * cite7†Image: 8090 logo L30: * cite8†Image: Documenso logo L31: * cite9†Image: Glide logo L32: * cite10†Image: Influee logo L33: * cite11†Image: Lapel logo L34: * cite12†Image: 11x logo L35: * cite4†Image: Worklayer logo L36: * cite5†Image: Hugging Face logo L37: * cite6†Image: Mintlify logo L38: * cite7†Image: 8090 logo L39: * cite8†Image: Documenso logo L40: * cite9†Image: Glide logo L41: * cite10†Image: Influee logo L42: * cite11†Image: Lapel logo L43: * cite12†Image: 11x logo L44: ## How It Works
L45:
L46: Start sharing traces from any agent, in minutes.
L47: ### Upload from any agent
L48:
L49: Publish traces from 10+ supported agents directly in the CLI.
L50:
L51: [Button: Get the CLI]
L52:
L53: TRACES Q: Quit
L54:
L55: @janedoe Logout
L56:
L57: Time
L58:
L59: Directory
L60:
L61: Agent
L62:
L63: Msgs
L64:
L65: Title
L66:
L67: Today
L68:
L69: 12:45 PM
L70:
L71: frontend
L72:
L73: claude-code
L74:
L75: 13
L76:
L77: HeroVideo.tsx terminal-like preview with trac...
L78:
L79: Publish
L80:
L81: 12:11 PM
L82:
L83: docs
L84:
L85: opencode
L86:
L87: 31
L88:
L89: HeroVideo.tsx terminal view adjustment
L90:
L91: Publish
L92:
L93: 10:00 AM
L94:
L95: frontend
L96:
L97: copilot
L98:
L99: 59
L100:
L101: Schema validation error in parts table
L102:
L103: Publish
L104:
L105: 12:25 PM
L106:
L107: api
L108:
L109: cursor
L110:
L111: 10
L112:
L113: Terminal not working troubleshooting
L114: Publish
L115:
L116: 12:44 PM
L117:
L118: cli
L119:
L120: codex
L121:
L122: 112
L123:
L124: Light chat intro clarifications
L125:
L126: Publish
L127:
L128: 11:28 AM
L129:
L130: traces
L131:
L132: droid
L133:
L134: 386
L135:
L136: Improving app onboarding and hero section
L137:
L138: Publish
L139:
L140: 11:47 AM
L141:
L142: traces
L143:
L144: amp
L145:
L146: 74
L147:
L148: HomeHero background dot fade implementation
L149:
L150: Publish
L151:
L152: 12:02 PM
L153:
L154: packages/shared
L155:
L156: pi
L157:
L158: 18
L159:
L160: Logical commit order strategy
L161:
L162: Publish
L163:
L164: Yesterday
L165:
L166: 01:34 PM
L167:
L168: packages/shared
L169:
L170: antigravity
L171:
L172: 92
L173:
L174: Splitting branch changes by feature area
L175:
L176: •Open Link Copy Link
L177:
L178: 02:53 PM
L179:
L180: docs
L181:
L182: openclaw
L183:
L184: 64
L185:
L186: Data visualization for user activity metrics
L187: •Open Link Copy Link
L188:
L189: 10:19 AM
L190:
L191: traces
L192:
L193: opencode
L194:
L195: 67
L196:
L197: Commit all changes; group in logical order
L198:
L199: •Open Link Copy Link
L200:
L201: 12:22 PM
L202:
L203: frontend
L204:
L205: cursor
L206:
L207: 226
L208:
L209: Terminal command sections - full-card copy but...
L210:
L211: •Open Link Copy Link
L212:
L213: 04:56 PM
L214:
L215: cli
L216:
L217: hermes
L218:
L219: 72
L220:
L221: Fixing WeeklyDensityChart data rendering
L222:
L223: •Open Link Copy Link
L224:
L225: 04:44 PM
L226:
L227: api
L228:
L229: cline
L230:
L231: 515
L232:
L233: Profile Activity Data Visualization Plan
L234:
L235: •Open Link Copy Link
L236:
L237: 01:02 PM
L238:
L239: api
L240:
L241: cline
L242:
L243: 23
L244:
L245: Semantic and logical commit grouping
L246:
L247: •Open Link Copy Link
L248:
L249: 12:38 PM
L250: packages/shared
L251:
L252: codex
L253:
L254: 57
L255:
L256: Rotating link-3 icon.ts -45 degrees
L257:
L258: •Open Link Copy Link
L259:
L260: Feb 10
L261:
L262: 12:31 PM
L263:
L264: traces
L265:
L266: antigravity
L267:
L268: 255
L269:
L270: HomeFeed traces list redesign
L271:
L272: Publish
L273:
L274: 01:18 PM
L275:
L276: traces
L277:
L278: openclaw
L279:
L280: 153
L281:
L282: TraceOverview component border removal
L283:
L284: •Open Link Copy Link Refresh Unpublish
L285:
L286: 03:31 PM
L287:
L288: frontend
L289:
L290: copilot
L291:
L292: 14
L293:
L294: Next.js OpenGraph image route configuration
L295:
L296: •Open Link Copy Link
L297:
L298: 03:23 PM
L299:
L300: cli
L301:
L302: hermes
L303:
L304: 26
L305:
L306: Permanent caching for static Open Graph images
L307:
L308: •Open Link Copy Link
L309:
L310: 03:46 PM
L311:
L312: frontend
L313:
L314: droid
L315:
L316: 39
L317: Aligning TRACES logo in OpenGraph images
L318:
L319: •Open Link Copy Link
L320:
L321: 02:51 PM
L322:
L323: docs
L324:
L325: cline
L326:
L327: 45
L328:
L329: OpenGraph image layout from s/[id]/opengraph-...
L330:
L331: •Open Link Copy Link
L332:
L333: 04:17 PM
L334:
L335: packages/shared
L336:
L337: amp
L338:
L339: 27
L340:
L341: Fixing message cutoff in MessageAccordion.tsx
L342:
L343: •Open Link Copy Link
L344:
L345: 08:38 PM
L346:
L347: docs
L348:
L349: pi
L350:
L351: 23
L352:
L353: Sticky avatar and logo implementation
L354:
L355: •Open Link Copy Link
L356: ### Share your traces
L357:
L358: Copy the link & share your trace with your team or the world.
L359:
L360: 1. cite13†Image: Maya Chen L361:
L362: look up how to make this animation smoother. right now, it looks a little jittery. the animation isn't butter smooth which is what I want.
L363:
L364: 2. I'll identify which animation in this codebase is currently jittery, then look up current best practices for making it feel “butter smooth,” and apply targeted fixes in the relevant file. I'm starting by scanning recent frontend animation code.
L365: 3. I found a few custom animations; the most likely jitter source is the sliding tab indicator in `UserMenu` because it uses imperative WAAPI and can re-measure on state changes. I'm reading that implementation next and then I'll verify smoothing techniques from current guidance.
L366:
L367: traces.com/s/jlkj44k
L368: ### Download & continue sessions
L369:
L370: Download a full trace or continue working on someone else's.
L371:
L372: Download a trace, or continue it in Claude Code. The open agent menu lists Claude Code, Codex, Cline, Pi, Cursor, OpenCode, Oh My Pi, Amp, OpenClaw, GitHub Copilot, Hermes, Droid, Grok, Kimi Code, Antigravity, Prime Agent, fx, DeepSeek Harness, with Claude Code selected.
L373:
L374: Download Continue in…
L375:
L376: Local
L377:
L378: Remote
L379:
L380: Claude Code
L381:
L382: Codex
L383:
L384: Cline
L385:
L386: Pi
L387:
L388: Cursor
L389:
L390: OpenCode
L391:
L392: Oh My Pi
L393:
L394: Amp
L395:
L396: OpenClaw
L397:
L398: GitHub Copilot
L399:
L400: Hermes
L401:
L402: Droid
L403: Grok
L404:
L405: Kimi Code
L406:
L407: Antigravity
L408:
L409: Prime Agent
L410:
L411: fx
L412:
L413: DeepSeek Harness
L414:
L415: Traces for Teams
L416: ## See How Your Team Is Using Agents
L417:
L418: Traces gives teams one place to see work in progress, share context on finished work, and see which agents people are using.
L419:
L420: cite2†Sign up for free L421:
L422: Set up your team with one prompt
L423:
L424: cite14†Image: Team profile preview L425:
L426: > “Github increasingly doesn't feel like the best place to understand the work done on a codebase. Agent traces provide a much more human-readable overview. Just started using traces.com. Feels quite nice.”
L427: Millin Gabani, CEO of cite15†Worklayer†www.myworklayer.com L428:
L429: cite16†See original post†x.com L430: ## Privacy & Trust
L431:
L432: Share agent conversations without worrying about sensitive data.
L433:
L434: ### Flexible Visibility
L435:
L436: Share your traces privately, directly, or publicly, so only the right people see them.
L437:
L438: maujim · 102 messages
L439:
L440: Private
L441:
L442: Diagnose and Enhance Voltage Error Reporting
L443:
L444: maujim · 102 messages
L445:
L446: Direct
L447:
L448: Diagnose and Enhance Voltage Error Reporting
L449:
L450: maujim · 102 messages
L451:
L452: Public
L453:
L454: Diagnose and Enhance Voltage Error Reporting
L455: ### Team-Level Protections
L456:
L457: Set team-level policies to control how your team can share traces.
L458:
L459: Traces can be published as:
L460:
L461: Allowed trace visibility for this team
L462:
L463: Private
L464:
L465: Only team members can view
L466:
L467: [Input]
L468:
L469: Direct
L470:
L471: Anyone with the link can view
L472:
L473: [Input]
L474:
L475: Public
L476:
L477: Visible on public team pages & feeds
L478:
L479: [Input]
L480: ### Scrub Sensitive Data
L481:
L482: We automatically strip sensitive data like API keys, emails & database credentials from traces on publish.
L483:
L484: Shared the rollout trace after scrubbing [REDACTED], [REDACTED], and [REDACTED] from the assistant reply before sending the link to the team.
L485:
L486: The published run keeps the reasoning intact while replacing keys, customer emails, and database URLs with clear [REDACTED] markers anyone can spot immediately.
L487: Reviewers still understand what happened, but the sensitive values stay hidden behind [REDACTED] in every shared view.
L488: ## Share From Anywhere
L489:
L490: Start simple & integrate more as you go.
L491:
L492: ### CLI
L493:
L494: Publish & manage traces directly from your terminal.
L495:
L496: [Button: Get the CLI]
L497:
L498: ### Coding Agents
L499:
L500: Let your agent share traces as you work.
L501:
L502: cite17†Get the skill L503:
L504: ### API
L505:
L506: Publish traces via API with your own tools, schedulers & workflows.
L507:
L508: cite18†Learn more L509:
L510: ### Git hooks
L511:
L512: Automatically share traces on every commit from your CI/CD pipelines.
L513:
L514: cite19†Learn more L515:
L516: ## Pricing
L517:
L518: Free for individuals & small teams, flexible at scale.
L519:
L520: Core
L521:
L522: Free
L523: ### For individuals & small teams
L524:
L525: * Unlimited Traces
L526: * Unlimited Teams
L527: * Up to 50 Seats
L528:
L529: cite2†Sign up L530:
L531: Custom
L532:
L533: Get in touch
L534:
L535: ### For larger teams & enterprises
L536:
L537: * Everything in Core
L538: * Self hosting / On-prem
L539: * Priority support
L540: * Team onboarding & training
L541:
L542: cite20†Contact us L543:
L544: ## A New Way to Work With Agents
L545:
L546: See what ships, loop in the right agents, and share traces with git hooks & custom skills.
L547: ### Team Analytics
L548:
L549: Team analytics preview showing Claude Code, Codex, Cursor, Droid, and Amp as the top agents, with an average session length of 47 minutes and 82.0 percent AI output.
L550:
L551: ### Top Agents
L552:
L553: Claude Code 486
L554:
{"chunk_id":"5a9920","wall_time_seconds":0.000024875,"exit_code":0,"original_token_count":3316,"output":"total 56\ndrwxr-xr-x 11 sahaj staff 352 Oct 7 20:20 .\ndrwxr-xr-x 3 sahaj staff 96 Oct 7 19:50 ..\n-rw-r--r--@ 1 sahaj staff 120 Oct 7 19:52 .env\n-rw-r--r--@ 1 sahaj staff 40 Oct 7 20:17 .env.example\n-rw-r--r--@ 1 sahaj staff 51 Oct 7 20:17 .gitignore\n-rw-r--r--@ 1 sahaj staff 1782 Oct 7 20:19 README.md\ndrwxr-xr-x@ 5 sahaj staff 160 Oct 7 20:20 artifacts\n-rw-r--r--@ 1 sahaj staff 256 Oct 7 20:17 package.json\ndrwxr-xr-x@ 7 sahaj staff 224 Oct 7 20:19 public\n-rw-r--r--@ 1 sahaj staff 4820 Oct 7 20:19 server.mjs\ndrwxr-xr-x@ 3 sahaj staff 96 Oct 7 20:19 tests\n<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta name=\"theme-color\" content=\"#111610\"><meta name=\"description\" content=\"You are the apple. Jev is the snake. How long can you keep it guessing?\">\n <title>Apple vs. Jev</title><link rel=\"icon\" href=\"/favicon.svg\"><link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n <header><a class=\"wordmark\" href=\"/\" aria-label=\"Apple versus Jev home\"><span class=\"mark\">a<span>j</span></span> APPLE VS. JEV</a><div class=\"live-badge\" id=\"connection\"><span></span> CONNECTING</div></header>\n <main>\n <section class=\"intro\"><div class=\"eyebrow\">A LITTLE ROLE REVERSAL</div><h1>Be the <em>bait.</em></h1><p>You’re the apple. The snake is AI.<br>Keep it guessing. Try not to get eaten.</p></section>\n <section class=\"game-layout\">\n <div class=\"board-column\">\n <div class=\"board-top\"><span><i class=\"apple-dot\"></i> YOU</span><span>17 × 17 <span class=\"dim\">/</span> NO PLACE TO HIDE</span><span><i class=\"snake-dot\"></i> JEV</span></div>\n <div class=\"board-wrap\" id=\"board-wrap\">\n <canvas id=\"board\" width=\"680\" height=\"680\" tabindex=\"0\" aria-label=\"Snake game. You control the apple with arrow keys or W A S D.\"></canvas>\n <div class=\"overlay\" id=\"overlay\"><div class=\"overlay-inner\"><span class=\"overline\" id=\"overlay-tag\">YOU ARE THE APPLE</span><h2 id=\"overlay-title\">Don’t make it easy.</h2><p id=\"overlay-copy\">Jump one square at a time.<br>Jev picks every move the snake makes.</p><button id=\"start\" class=\"primary\">Let’s play <span>↗</span></button><small id=\"setup-hint\">Checking Jev connection…</small></div></div>\n <div class=\"catch-pop\" id=\"catch-pop\" aria-live=\"polite\">CAUGHT. NEW SPOT.</div>\n </div>\n <div class=\"board-bottom\"><span><span class=\"key\">↑</span><span class=\"key\">←</span><span class=\"key\">↓</span><span class=\"key\">→</span> or WASD to hop</span><button id=\"pause\" disabled>Pause <span class=\"key\">P</span></button><button id=\"restart\" aria-label=\"Restart game\">Restart ↻</button></div>\n <div class=\"touch-controls\" aria-label=\"Movement controls\"><button data-direction=\"left\" aria-label=\"Move left\">←</button><div><button data-direction=\"up\" aria-label=\"Move up\">↑</button><button data-direction=\"down\" aria-label=\"Move down\">↓</button></div><button data-direction=\"right\" aria-label=\"Move right\">→</button></div>\n </div>\n <aside>\n <div class=\"score-card\"><div class=\"eyebrow\">CURRENT ESCAPE</div><div class=\"timer\"><span id=\"time\">00</span><small>. <span id=\"tenths\">0</span><span class=\"unit\">s</span></small></div><div class=\"best-row\">PERSONAL BEST <strong id=\"best\">0.0s</strong></div></div>\n <div class=\"numbers\"><div><strong id=\"catches\">0</strong><span>TIMES EATEN</span></div><div><strong id=\"length\">4</strong><span>SNAKE LENGTH</span></div></div>\n <div class=\"mind-card\"><div class=\"mind-heading\"><span class=\"eyebrow\">INSIDE JEV’S HEAD</span><span class=\"brain-mark\">✳</span></div><div class=\"decision\" id=\"decision\">Waiting for you.</div><p id=\"decision-note\">A real model. A very hungry snake.</p><div class=\"probabilities\" id=\"probabilities\"></div><div class=\"telemetry\"><span>LAST RESPONSE <strong id=\"latency\">—</strong></span><span>DECISIONS <strong id=\"calls\">0</strong></span></div></div>\n <div class=\"rules\"><span class=\"rule-number\">01</span><p>Arrow keys or WASD.<br>One press, one square.</p><span class=\"rule-number\">02</span><p>Get eaten? You respawn.<br>The snake gets longer.</p><span class=\"rule-number\">03</span><p>Trap the snake in its own tail.<br>That’s your way out.</p></div>\n <div class=\"cost\">SESSION API COST <span id=\"cost\">$0.0000</span></div>\n </aside>\n </section>\n </main>\n <footer><span>HUMAN INSTINCT <span class=\"dim\">×</span> MACHINE APPETITE</span><span>Powered by Jev <span class=\"dim\">/</span> TypeSafe</span></footer>\n <script type=\"module\" src=\"/app.mjs\"></script>\n</body>\n</html>\n:root{font-family:Arial,Helvetica,sans-serif;color:#e8eddf;background:#111610;font-synthesis:none;color-scheme:dark;--lime:#c5f778;--muted:#86947d;--border:#2a3425;--apple:#ff7c66}*{box-sizing:border-box}body{margin:0;background:radial-gradient(ellipse at 35% 35%,#1c261640,transparent 60%);min-height:100vh}button,a{-webkit-tap-highlight-color:transparent}button{font:inherit;cursor:pointer}button:focus-visible,a:focus-visible,canvas:focus-visible{outline:2px solid var(--lime);outline-offset:5px}header{height:87px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;padding:0 6vw}.wordmark{color:#e8eddf;text-decoration:none;font-size:12px;font-weight:700;letter-spacing:2px;display:flex;align-items:center;gap:14px}.mark{font-size:32px;letter-spacing:-6px;color:var(--apple);padding-right:6px;line-height:1}.mark span{color:var(--lime)}.live-badge{display:flex;align-items:center;gap:8px;border:1px solid var(--border);border-radius:30px;padding:10px 13px;font-size:10px;letter-spacing:1.3px;color:var(--muted)}.live-badge>span{width:6px;height:6px;background:#697561;border-radius:50%}.live-badge.ready{color:var(--lime)}.live-badge.ready>span{background:var(--lime);box-shadow:0 0 9px #c5f77850}.live-badge.error{color:var(--apple)}.live-badge.error>span{background:var(--apple)}main{max-width:1060px;padding:40px 30px 20px;margin:auto}.intro{margin-bottom:30px}.eyebrow{font-size:10px;letter-spacing:2px;font-weight:700;color:var(--muted)}h1{font-size:clamp(44px,6vw,72px);letter-spacing:-4px;line-height:1;margin:15px 0 13px;font-weight:600}h1 em{font-family:Georgia,serif;font-weight:400;color:var(--lime)}.intro p{font-size:14px;line-height:1.7;color:var(--muted);margin:0}.game-layout{display:grid;grid-template-columns:minmax(0,620px) minmax(235px,1fr);gap:38px;align-items:start}.board-top{display:flex;justify-content:space-between;font-size:10px;letter-spacing:1px;align-items:center;margin-bottom:12px}.board-top>span{display:flex;align-items:center;gap:7px}.board-top>span:nth-child(2){color:#839076;font-size:9px}.apple-dot,.snake-dot{width:7px;height:7px;display:inline-block;background:var(--apple);border-radius:2px}.snake-dot{background:var(--lime)}.dim{color:#4d5b45}.board-wrap{position:relative;aspect-ratio:1;background:#1a2317;border:1px solid #35442d;border-radius:10px;overflow:hidden;box-shadow:0 20px 80px #0003}canvas{display:block;width:100%;height:100%;touch-action:none}.overlay{position:absolute;inset:0;display:grid;place-items:center;background:#101a12bc;backdrop-filter:blur(5px);text-align:center;padding:25px}.overlay[hidden]{display:none}.overlay-inner{max-width:330px}.overline{font-size:10px;font-weight:700;letter-spacing:2px;color:var(--lime)}h2{font-size:clamp(26px,4vw,36px);letter-spacing:-1.3px;margin:18px 0 13px;font-weight:500}.overlay p{font-size:14px;color:#b0baa5;line-height:1.75;margin:0 0 25px}.primary{border:0;background:var(--lime);color:#1a2810;padding:16px 22px;border-radius:5px;min-width:185px;font-size:14px;font-weight:700;display:inline-flex;justify-content:space-between;gap:28px}.primary:hover{background:#d7ff9d}.primary:disabled{opacity:.5;cursor:wait}.overlay small{display:block;font-size:11px;line-height:1.5;color:#8f9b84;margin:16px auto 0;max-width:300px}.board-bottom{display:flex;align-items:center;gap:17px;padding-top:17px;color:var(--muted);font-size:11px;flex-wrap:wrap}.board-bottom>span{margin-right:auto;display:flex;gap:3px;align-items:center}.key{font-family:monospace;font-size:10px;display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:20px;border:1px solid #35432d;border-bottom-width:2px;border-radius:3px;margin-right:3px;color:#adb99f}.board-bottom button{border:0;background:transparent;color:#a9b69c;padding:0;font-size:11px}.board-bottom button:disabled{opacity:.4}.catch-pop{position:absolute;left:50%;top:42%;transform:translate(-50%,15px);padding:12px 18px;background:var(--apple);border-radius:5px;color:#381c15;font-weight:800;font-size:11px;letter-spacing:1px;opacity:0;pointer-events:none;transition:opacity .15s,transform .15s;white-space:nowrap}.catch-pop.show{opacity:1;transform:translate(-50%,0)}aside{padding-top:23px}.score-card{padding-bottom:20px;border-bottom:1px solid var(--border)}.timer{font-size:65px;letter-spacing:-3px;font-variant-numeric:tabular-nums;line-height:1.1;margin:14px 0 17px}.timer>small{font-size:31px;color:#809071;letter-spacing:-2px}.timer .unit{font-size:16px;letter-spacing:0;margin-left:7px}.best-row{display:flex;justify-content:space-between;align-items:center;font-size:9px;letter-spacing:1px;color:var(--muted)}.best-row strong{color:var(--lime);font-size:12px;font-weight:400;letter-spacing:0}.numbers{display:flex;padding:22px 0;border-bottom:1px solid var(--border)}.numbers>div{width:50%;display:flex;flex-direction:column;gap:8px}.numbers>div+div{padding-left:22px;border-left:1px solid var(--border)}.numbers strong{font-size:29px;font-weight:400}.numbers span{font-size:9px;letter-spacing:1px;color:var(--muted)}.mind-card{margin-top:23px;border:1px solid #35442a;background:#1d28187d;border-radius:7px;padding:18px}.mind-heading{display:flex;justify-content:space-between;align-items:center}.mind-heading .eyebrow{font-size:9px;letter-spacing:1.3px}.brain-mark{color:var(--lime);font-size:22px}.decision{font-size:19px;letter-spacing:-.5px;margin-top:18px}.mind-card p{color:var(--muted);font-size:11px;line-height:1.6;margin:8px 0 20px}.probabilities{display:grid;gap:8px}.prob-row{display:grid;grid-template-columns:37px 1fr 28px;gap:8px;align-items:center;font-size:10px;color:var(--muted)}.track{height:3px;background:#34442a;overflow:hidden;border-radius:4px}.fill{height:100%;background:var(--lime);transition:width .18s}.prob-row.picked{color:var(--lime)}.telemetry{border-top:1px solid var(--border);margin-top:18px;padding-top:13px;display:flex;justify-content:space-between;gap:12px}.telemetry>span{display:flex;flex-direction:column;gap:7px;font-size:8px;letter-spacing:.6px;color:var(--muted)}.telemetry strong{font-size:12px;letter-spacing:0;color:#dbe6ce;font-weight:400}.rules{display:grid;grid-template-columns:24px 1fr;gap:14px 6px;margin:24px 0}.rule-number{font-size:10px;color:#57664d;line-height:1.7}.rules p{margin:0;font-size:11px;line-height:1.7;color:var(--muted)}.cost{border-top:1px solid var(--border);padding-top:15px;font-size:9px;letter-spacing:.7px;color:#65755b;display:flex;justify-content:space-between}.cost span{font-family:monospace;letter-spacing:0}footer{max-width:1000px;margin:20px auto;padding:22px 0;border-top:1px solid var(--border);display:flex;justify-content:space-between;font-size:9px;letter-spacing:1.3px;color:#6b7a60}.touch-controls{display:none;align-items:center;justify-content:center;gap:8px;margin-top:20px}.touch-controls>div{display:grid;gap:8px}.touch-controls button{background:#24301d;border:1px solid #415631;color:var(--lime);width:54px;height:45px;border-radius:7px;font-size:22px;touch-action:none}.touch-controls button:active{background:#435d2d}@media(min-width:1100px) and (max-height:950px){header{height:65px}main{padding-top:25px;max-width:940px}.intro{margin-bottom:22px;display:grid;grid-template-columns:1fr 1fr}.intro .eyebrow{grid-column:1/-1}h1{font-size:59px;margin-top:12px}.intro p{align-self:center;justify-self:end}.game-layout{grid-template-columns:minmax(0,510px) 1fr;gap:35px}footer{max-width:880px}.rules{gap:8px;margin:18px 0}.score-card{padding-bottom:16px}.numbers{padding:16px 0}.mind-card{margin-top:18px}.timer{font-size:54px;margin:10px 0}.mind-card p{margin-bottom:12px}}@media(max-width:700px){header{height:65px;padding:0 20px}.wordmark{font-size:10px;gap:10px;letter-spacing:1px}.live-badge{font-size:8px;padding:8px 10px}main{padding:27px 18px 10px}.intro{margin-bottom:24px}.intro p{font-size:13px}h1{letter-spacing:-2px}.game-layout{grid-template-columns:1fr;gap:15px}aside{display:grid;grid-template-columns:1fr 1fr;gap:15px;padding:10px 0}.score-card{border-bottom:0}.numbers{border:0;padding:0;align-self:center}.numbers>div+div{padding-left:12px}.numbers span{font-size:8px}.timer{font-size:46px}.timer>small{font-size:25px}.mind-card{grid-column:1/-1;margin:0}.rules{display:none}.cost{grid-column:1/-1}.touch-controls{display:flex}.board-top>span:nth-child(2){font-size:8px;letter-spacing:.5px}.board-bottom{gap:12px;font-size:10px}footer{margin:20px 18px;padding-top:18px;gap:15px;font-size:8px;letter-spacing:.5px}.probabilities{grid-template-columns:1fr 1fr;column-gap:20px}}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"}>python3 -u - <<'PY'
from playwright.sync_api import sync_playwright
import json
with sync_playwright() as p:
browser=p.chromium.launch(executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',headless=True)
page=browser.new_page(viewport={'width':1440,'height':1000},device_scale_factor=1)
page.goto('https://traces.com',wait_until='domcontentloaded',timeout=30000)
page.wait_for_timeout(2500)
page.screenshot(path='artifacts/traces-reference.png')
print(json.dumps(page.evaluate('''() => ['body','h1','h2','p','button','header','nav'].map(s=>{let e=document.querySelector(s); if(!e)return {s};let c=getComputedStyle(e);return {s,color:c.color,background:c.backgroundColor,font:c.fontFamily,size:c.fontSize,weight:c.fontWeight,border:c.border,radius:c.borderRadius,spacing:c.letterSpacing,text:e.textContent.slice(0,100)};})'''),indent=2))
browser.close()
PY{"chunk_id":"c19aba","wall_time_seconds":1.00256,"session_id":69394,"original_token_count":0,"output":""}>sed -n '1,145p' public/app.mjs
curl -fsS http://localhost:3000/api/status{"chunk_id":"68f6ce","wall_time_seconds":0.000012416,"exit_code":0,"original_token_count":2041,"output":"import { SIZE, DIRECTIONS, newGame, legalMoves, moveApple, stepSnake } from './game.mjs';\n\nconst $ = id => document.getElementById(id);\nconst canvas = $('board'), ctx = canvas.getContext('2d');\nlet state = newGame(), previousSnake = state.snake.map(p => ({ ...p })), previousApple = { ...state.apple };\nlet snakeMovedAt = 0, appleMovedAt = 0, running = false, started = false, finished = false, ready = false;\nlet epoch = 0, elapsed = 0, catches = 0, calls = 0, tokens = 0, lastFrame = performance.now(), lastHop = 0;\nlet appleHistory = [], particles = [], flash = 0, best = 0, popupTimer;\ntry { best = Number(localStorage.getItem('apple-vs-jev-best')) || 0; } catch {}\n$('best').textContent = `${best.toFixed(1)}s`;\nconst arrows = { up: '↑', right: '→', down: '↓', left: '←' };\nfor (const direction of Object.keys(DIRECTIONS)) {\n const row = document.createElement('div'); row.className = 'prob-row'; row.id = `prob-${direction}`;\n const label = document.createElement('span'); label.textContent = `${arrows[direction]} ${direction}`;\n const track = document.createElement('div'); track.className = 'track';\n const fill = document.createElement('div'); fill.className = 'fill'; fill.style.width = '0%'; track.append(fill);\n const value = document.createElement('span'); value.textContent = '—'; row.append(label, track, value);\n $('probabilities').append(row);\n}\nfunction badge(label, kind) {\n const el = $('connection'); el.className = `live-badge ${kind}`;\n el.replaceChildren(document.createElement('span'), document.createTextNode(label));\n}\nasync function checkConnection() {\n $('start').disabled = true;\n try {\n const response = await fetch('/api/status');\n if (!response.ok) throw new Error('Server unavailable.');\n const result = await response.json(); ready = result.configured;\n badge(ready ? 'JEV READY' : 'KEY NEEDED', ready ? 'ready' : 'error');\n $('setup-hint').textContent = ready ? 'Arrow keys / WASD · No lives. Just another chance.' : 'Add JEV_API_KEY to .env and restart the server.';\n $('start').disabled = !ready;\n } catch {\n badge('SERVER OFFLINE', 'error');\n $('setup-hint').textContent = 'Start the local server with npm start, then reload.';\n }\n}\nfunction overlay(tag, title, copy, button, hint = '') {\n $('overlay-tag').textContent = tag; $('overlay-title').textContent = title;\n $('overlay-copy').textContent = copy;\n $('start').replaceChildren(document.createTextNode(button), Object.assign(document.createElement('span'), { textContent: '↗' }));\n $('setup-hint').textContent = hint; $('overlay').hidden = false;\n}\nfunction saveBest() {\n if (elapsed > best) {\n best = elapsed; $('best').textContent = `${best.toFixed(1)}s`;\n try { localStorage.setItem('apple-vs-jev-best', String(best)); } catch {}\n }\n}\nfunction reset() {\n epoch++; running = false; started = false; finished = false;\n state = newGame(); previousSnake = state.snake.map(p => ({ ...p })); previousApple = { ...state.apple };\n elapsed = 0; catches = 0; appleHistory = []; particles = []; flash = 0;\n $('catches').textContent = '0'; $('length').textContent = '4';\n $('decision').textContent = 'Waiting for you.';\n $('decision-note').textContent = 'A real model. A very hungry snake.';\n for (const direction of Object.keys(DIRECTIONS)) {\n const row = $(`prob-${direction}`); row.classList.remove('picked'); row.children[1].firstChild.style.width = '0%'; row.lastChild.textContent = '—';\n }\n clearTimeout(popupTimer); $('catch-pop').classList.remove('show');\n}\nfunction start() {\n if (!ready || running) return;\n if (finished) reset();\n running = true; started = true; epoch++;\n $('overlay').hidden = true; $('pause').disabled = false;\n $('pause').replaceChildren(document.createTextNode('Pause '), Object.assign(document.createElement('span'), { className: 'key', textContent: 'P' }));\n canvas.focus({ preventScroll: true });\n badge('JEV LIVE', 'ready');\n runSnake(epoch);\n}\nfunction pause() {\n if (!started || finished) return;\n if (!running) { start(); return; }\n running = false; epoch++;\n badge('PAUSED', '');\n overlay('TAKE A BREATHER', 'A fair pause.', 'The snake is waiting. Your escape timer is stopped.', 'Keep running');\n $('pause').textContent = 'Resume P';\n}\nfunction win() {\n saveBest(); running = false; finished = true; epoch++;\n $('pause').disabled = true; badge('YOU WIN', 'ready');\n overlay('HUMAN INSTINCT WINS', 'Outsmarted.', `Jev ran out of legal moves. Your best escape: ${best.toFixed(1)} seconds.`, 'Play again');\n}\nfunction recordDecision(result) {\n calls++; tokens += result.inputTokens || 0;\n $('calls').textContent = String(calls); $('latency').textContent = `${result.latency} ms`;\n $('cost').textContent = `$${(tokens / 1000000 * .042).toFixed(4)}`;\n}\nconst delay = ms => new Promise(resolve => setTimeout(resolve, ms));\nasync function runSnake(runEpoch) {\n while (running && epoch === runEpoch) {\n if (!legalMoves(state).length) { win(); return; }\n const startTime = performance.now();\n const snapshot = { ...state, snake: state.snake.map(p => ({ ...p })), apple: { ...state.apple }, appleHistory: [...appleHistory] };\n try {\n const response = await fetch('/api/decide', {\n method: 'POST', headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(snapshot), signal: AbortSignal.timeout(6500),\n });\n const result = await response.json();\n if (result.direction) recordDecision(result);\n if (!running || epoch !== runEpoch) return;\n if (!response.ok) throw new Error(result.error || 'Jev could not choose a move.');\n if (result.trapped) { win(); return; }\n await delay(Math.max(0, 210 - (performance.now() - startTime)));\n if (!running || epoch !== runEpoch) return;\n // Apple movement never changes the snake head; revalidate occupancy before execution.\n previousSnake = state.snake.map(p => ({ ...p }));\n const oldApple = { ...state.apple };\n const move = stepSnake(state, result.direction);\n if (!move.valid) continue;\n snakeMovedAt = performance.now();\n $('decision').textContent = `${arrows[result.direction]} Heading ${result.direction}.`;\n $('decision-note').textContent = `Jev chose ${result.direction} · ${Math.round(result.confidence * 100)}% confidence`;\n for (const direction of Object.keys(DIRECTIONS)) {\n const row = $(`prob-${direction}`), probability = result.probabilities?.[direction];\n row.classList.toggle('picked', direction === result.direction);\n row.children[1].firstChild.style.width = `${(probability || 0) * 100}%`;\n row.lastChild.textContent = probability === undefined ? '—' : `${Math.round(probability * 100)}%`;\n }\n if (move.ate) {\n saveBest(); elapsed = 0; catches++; appleHistory = [];\n $('catches').textContent = String(catches); $('length').textContent = String(state.snake.length);\n flash = 1;\n for (let i = 0; i < 22; i++) particles.push({ x: oldApple.x + .5, y: oldApple.y + .5, vx: (Math.random() - .5) * 9, vy: (Math.random() - .5) * 9, life: 1 });\n $('catch-pop').classList.add('show'); clearTimeout(popupTimer);\n popupTimer = setTimeout(() => $('catch-pop').classList.remove('show'), 650);\n if (move.filled) {\n running = false; finished = true; epoch++; $('pause').disabled = true;\n overlay('WELL FED', 'Jev ate the board.', 'Every square is snake. Time for a fresh round.', 'Play again'); return;\n }\n previousApple = { ...state.apple }; appleMovedAt = performance.now();\n }\n } catch (error) {\n if (!running || epoch !== runEpoch) return;\n running = false; epoch++; badge('JEV DISCONNECTED', 'error');\n overlay('SNAKE ON HOLD', 'Connection hiccup.', error.name === 'TimeoutError' ? 'Jev took too long to respond. Your timer is paused.' : error.message, 'Retry');\n $('decision').textContent = 'Waiting for connection.';\n $('decision-note').textContent = 'No simulated AI: the snake waits for Jev.';\n $('pause').textContent = 'Resume P';\n }\n }\n}\nfunction hop(direction) {\n{\"configured\":true,\"model\":\"jev-1.13.0\"}"}
{"chunk_id":"212f8a","wall_time_seconds":1.854565542,"exit_code":0,"original_token_count":545,"output":"[\n {\n \"s\": \"body\",\n \"color\": \"lab(6.32376 0 0)\",\n \"background\": \"lab(96.5432 -0.0000596046 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"14px\",\n \"weight\": \"400\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"normal\",\n \"text\": \"((a, b, c, d, e, f, g, h) => {\\n let i = document.documentElement, j = [\\\"light\\\", \\\"dark\\\"];\\n \"\n },\n {\n \"s\": \"h1\",\n \"color\": \"rgba(0, 0, 0, 0)\",\n \"background\": \"lab(96.5432 -0.0000596046 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"48px\",\n \"weight\": \"400\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"-3.12px\",\n \"text\": \"The Hub for YourCoding Agents\"\n },\n {\n \"s\": \"h2\",\n \"color\": \"lab(45.2248 0 0)\",\n \"background\": \"rgba(0, 0, 0, 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"11px\",\n \"weight\": \"600\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"1.76px\",\n \"text\": \"Used by teams like\"\n },\n {\n \"s\": \"p\",\n \"color\": \"lab(45.2248 0 0)\",\n \"background\": \"rgba(0, 0, 0, 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"16px\",\n \"weight\": \"400\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"normal\",\n \"text\": \"Share sessions live & compound your learning. For software developers & teams.\"\n },\n {\n \"s\": \"button\",\n \"color\": \"lab(6.32376 0 0)\",\n \"background\": \"rgb(255, 255, 255)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"14px\",\n \"weight\": \"500\",\n \"border\": \"1px solid rgb(255, 255, 255)\",\n \"radius\": \"5px\",\n \"spacing\": \"normal\",\n \"text\": \"Setup promptCopy setup prompt\"\n },\n {\n \"s\": \"header\"\n },\n {\n \"s\": \"nav\",\n \"color\": \"lab(6.32376 0 0)\",\n \"background\": \"lab(96.5432 -0.0000596046 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"14px\",\n \"weight\": \"400\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"normal\",\n \"text\": \"TracesTeamsDiscoverBlogDocsHelpSetup promptCopy setup promptSign in\"\n }\n]\n"}{"chunk_id":"68f6ce","wall_time_seconds":0.000012416,"exit_code":0,"original_token_count":2041,"output":"import { SIZE, DIRECTIONS, newGame, legalMoves, moveApple, stepSnake } from './game.mjs';\n\nconst $ = id => document.getElementById(id);\nconst canvas = $('board'), ctx = canvas.getContext('2d');\nlet state = newGame(), previousSnake = state.snake.map(p => ({ ...p })), previousApple = { ...state.apple };\nlet snakeMovedAt = 0, appleMovedAt = 0, running = false, started = false, finished = false, ready = false;\nlet epoch = 0, elapsed = 0, catches = 0, calls = 0, tokens = 0, lastFrame = performance.now(), lastHop = 0;\nlet appleHistory = [], particles = [], flash = 0, best = 0, popupTimer;\ntry { best = Number(localStorage.getItem('apple-vs-jev-best')) || 0; } catch {}\n$('best').textContent = `${best.toFixed(1)}s`;\nconst arrows = { up: '↑', right: '→', down: '↓', left: '←' };\nfor (const direction of Object.keys(DIRECTIONS)) {\n const row = document.createElement('div'); row.className = 'prob-row'; row.id = `prob-${direction}`;\n const label = document.createElement('span'); label.textContent = `${arrows[direction]} ${direction}`;\n const track = document.createElement('div'); track.className = 'track';\n const fill = document.createElement('div'); fill.className = 'fill'; fill.style.width = '0%'; track.append(fill);\n const value = document.createElement('span'); value.textContent = '—'; row.append(label, track, value);\n $('probabilities').append(row);\n}\nfunction badge(label, kind) {\n const el = $('connection'); el.className = `live-badge ${kind}`;\n el.replaceChildren(document.createElement('span'), document.createTextNode(label));\n}\nasync function checkConnection() {\n $('start').disabled = true;\n try {\n const response = await fetch('/api/status');\n if (!response.ok) throw new Error('Server unavailable.');\n const result = await response.json(); ready = result.configured;\n badge(ready ? 'JEV READY' : 'KEY NEEDED', ready ? 'ready' : 'error');\n $('setup-hint').textContent = ready ? 'Arrow keys / WASD · No lives. Just another chance.' : 'Add JEV_API_KEY to .env and restart the server.';\n $('start').disabled = !ready;\n } catch {\n badge('SERVER OFFLINE', 'error');\n $('setup-hint').textContent = 'Start the local server with npm start, then reload.';\n }\n}\nfunction overlay(tag, title, copy, button, hint = '') {\n $('overlay-tag').textContent = tag; $('overlay-title').textContent = title;\n $('overlay-copy').textContent = copy;\n $('start').replaceChildren(document.createTextNode(button), Object.assign(document.createElement('span'), { textContent: '↗' }));\n $('setup-hint').textContent = hint; $('overlay').hidden = false;\n}\nfunction saveBest() {\n if (elapsed > best) {\n best = elapsed; $('best').textContent = `${best.toFixed(1)}s`;\n try { localStorage.setItem('apple-vs-jev-best', String(best)); } catch {}\n }\n}\nfunction reset() {\n epoch++; running = false; started = false; finished = false;\n state = newGame(); previousSnake = state.snake.map(p => ({ ...p })); previousApple = { ...state.apple };\n elapsed = 0; catches = 0; appleHistory = []; particles = []; flash = 0;\n $('catches').textContent = '0'; $('length').textContent = '4';\n $('decision').textContent = 'Waiting for you.';\n $('decision-note').textContent = 'A real model. A very hungry snake.';\n for (const direction of Object.keys(DIRECTIONS)) {\n const row = $(`prob-${direction}`); row.classList.remove('picked'); row.children[1].firstChild.style.width = '0%'; row.lastChild.textContent = '—';\n }\n clearTimeout(popupTimer); $('catch-pop').classList.remove('show');\n}\nfunction start() {\n if (!ready || running) return;\n if (finished) reset();\n running = true; started = true; epoch++;\n $('overlay').hidden = true; $('pause').disabled = false;\n $('pause').replaceChildren(document.createTextNode('Pause '), Object.assign(document.createElement('span'), { className: 'key', textContent: 'P' }));\n canvas.focus({ preventScroll: true });\n badge('JEV LIVE', 'ready');\n runSnake(epoch);\n}\nfunction pause() {\n if (!started || finished) return;\n if (!running) { start(); return; }\n running = false; epoch++;\n badge('PAUSED', '');\n overlay('TAKE A BREATHER', 'A fair pause.', 'The snake is waiting. Your escape timer is stopped.', 'Keep running');\n $('pause').textContent = 'Resume P';\n}\nfunction win() {\n saveBest(); running = false; finished = true; epoch++;\n $('pause').disabled = true; badge('YOU WIN', 'ready');\n overlay('HUMAN INSTINCT WINS', 'Outsmarted.', `Jev ran out of legal moves. Your best escape: ${best.toFixed(1)} seconds.`, 'Play again');\n}\nfunction recordDecision(result) {\n calls++; tokens += result.inputTokens || 0;\n $('calls').textContent = String(calls); $('latency').textContent = `${result.latency} ms`;\n $('cost').textContent = `$${(tokens / 1000000 * .042).toFixed(4)}`;\n}\nconst delay = ms => new Promise(resolve => setTimeout(resolve, ms));\nasync function runSnake(runEpoch) {\n while (running && epoch === runEpoch) {\n if (!legalMoves(state).length) { win(); return; }\n const startTime = performance.now();\n const snapshot = { ...state, snake: state.snake.map(p => ({ ...p })), apple: { ...state.apple }, appleHistory: [...appleHistory] };\n try {\n const response = await fetch('/api/decide', {\n method: 'POST', headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(snapshot), signal: AbortSignal.timeout(6500),\n });\n const result = await response.json();\n if (result.direction) recordDecision(result);\n if (!running || epoch !== runEpoch) return;\n if (!response.ok) throw new Error(result.error || 'Jev could not choose a move.');\n if (result.trapped) { win(); return; }\n await delay(Math.max(0, 210 - (performance.now() - startTime)));\n if (!running || epoch !== runEpoch) return;\n // Apple movement never changes the snake head; revalidate occupancy before execution.\n previousSnake = state.snake.map(p => ({ ...p }));\n const oldApple = { ...state.apple };\n const move = stepSnake(state, result.direction);\n if (!move.valid) continue;\n snakeMovedAt = performance.now();\n $('decision').textContent = `${arrows[result.direction]} Heading ${result.direction}.`;\n $('decision-note').textContent = `Jev chose ${result.direction} · ${Math.round(result.confidence * 100)}% confidence`;\n for (const direction of Object.keys(DIRECTIONS)) {\n const row = $(`prob-${direction}`), probability = result.probabilities?.[direction];\n row.classList.toggle('picked', direction === result.direction);\n row.children[1].firstChild.style.width = `${(probability || 0) * 100}%`;\n row.lastChild.textContent = probability === undefined ? '—' : `${Math.round(probability * 100)}%`;\n }\n if (move.ate) {\n saveBest(); elapsed = 0; catches++; appleHistory = [];\n $('catches').textContent = String(catches); $('length').textContent = String(state.snake.length);\n flash = 1;\n for (let i = 0; i < 22; i++) particles.push({ x: oldApple.x + .5, y: oldApple.y + .5, vx: (Math.random() - .5) * 9, vy: (Math.random() - .5) * 9, life: 1 });\n $('catch-pop').classList.add('show'); clearTimeout(popupTimer);\n popupTimer = setTimeout(() => $('catch-pop').classList.remove('show'), 650);\n if (move.filled) {\n running = false; finished = true; epoch++; $('pause').disabled = true;\n overlay('WELL FED', 'Jev ate the board.', 'Every square is snake. Time for a fresh round.', 'Play again'); return;\n }\n previousApple = { ...state.apple }; appleMovedAt = performance.now();\n }\n } catch (error) {\n if (!running || epoch !== runEpoch) return;\n running = false; epoch++; badge('JEV DISCONNECTED', 'error');\n overlay('SNAKE ON HOLD', 'Connection hiccup.', error.name === 'TimeoutError' ? 'Jev took too long to respond. Your timer is paused.' : error.message, 'Retry');\n $('decision').textContent = 'Waiting for connection.';\n $('decision-note').textContent = 'No simulated AI: the snake waits for Jev.';\n $('pause').textContent = 'Resume P';\n }\n }\n}\nfunction hop(direction) {\n{\"configured\":true,\"model\":\"jev-1.13.0\"}"}
{"chunk_id":"212f8a","wall_time_seconds":1.854565542,"exit_code":0,"original_token_count":545,"output":"[\n {\n \"s\": \"body\",\n \"color\": \"lab(6.32376 0 0)\",\n \"background\": \"lab(96.5432 -0.0000596046 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"14px\",\n \"weight\": \"400\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"normal\",\n \"text\": \"((a, b, c, d, e, f, g, h) => {\\n let i = document.documentElement, j = [\\\"light\\\", \\\"dark\\\"];\\n \"\n },\n {\n \"s\": \"h1\",\n \"color\": \"rgba(0, 0, 0, 0)\",\n \"background\": \"lab(96.5432 -0.0000596046 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"48px\",\n \"weight\": \"400\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"-3.12px\",\n \"text\": \"The Hub for YourCoding Agents\"\n },\n {\n \"s\": \"h2\",\n \"color\": \"lab(45.2248 0 0)\",\n \"background\": \"rgba(0, 0, 0, 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"11px\",\n \"weight\": \"600\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"1.76px\",\n \"text\": \"Used by teams like\"\n },\n {\n \"s\": \"p\",\n \"color\": \"lab(45.2248 0 0)\",\n \"background\": \"rgba(0, 0, 0, 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"16px\",\n \"weight\": \"400\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"normal\",\n \"text\": \"Share sessions live & compound your learning. For software developers & teams.\"\n },\n {\n \"s\": \"button\",\n \"color\": \"lab(6.32376 0 0)\",\n \"background\": \"rgb(255, 255, 255)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"14px\",\n \"weight\": \"500\",\n \"border\": \"1px solid rgb(255, 255, 255)\",\n \"radius\": \"5px\",\n \"spacing\": \"normal\",\n \"text\": \"Setup promptCopy setup prompt\"\n },\n {\n \"s\": \"header\"\n },\n {\n \"s\": \"nav\",\n \"color\": \"lab(6.32376 0 0)\",\n \"background\": \"lab(96.5432 -0.0000596046 0)\",\n \"font\": \"Inter, \\\"Inter Fallback\\\", sans-serif\",\n \"size\": \"14px\",\n \"weight\": \"400\",\n \"border\": \"0px solid rgb(227, 227, 227)\",\n \"radius\": \"0px\",\n \"spacing\": \"normal\",\n \"text\": \"TracesTeamsDiscoverBlogDocsHelpSetup promptCopy setup promptSign in\"\n }\n]\n"}(empty result)Traces uses a light gray background, thin borders, plain sans-serif text, and simple black buttons. I’ll use that direction: a centered board, a compact score row, and Jev’s details tucked into an expandable section.
Script error:
apply_patch verification failed: invalid patch: multiple operations target /Users/sahaj/Desktop/dev/program/jev/public/index.html>node --check public/app.mjsScript error:
apply_patch verification failed: invalid patch: multiple operations target /Users/sahaj/Desktop/dev/program/jev/public/index.html>cat public/index.html{"chunk_id":"ff724f","wall_time_seconds":0.000014292,"exit_code":0,"original_token_count":1015,"output":"<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta name=\"theme-color\" content=\"#111610\"><meta name=\"description\" content=\"You are the apple. Jev is the snake. How long can you keep it guessing?\">\n <title>Apple vs. Jev</title><link rel=\"icon\" href=\"/favicon.svg\"><link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n <header><a class=\"wordmark\" href=\"/\" aria-label=\"Apple versus Jev home\"><span class=\"mark\">a<span>j</span></span> APPLE VS. JEV</a><div class=\"live-badge\" id=\"connection\"><span></span> CONNECTING</div></header>\n <main>\n <section class=\"intro\"><div class=\"eyebrow\">A LITTLE ROLE REVERSAL</div><h1>Be the <em>bait.</em></h1><p>You’re the apple. The snake is AI.<br>Keep it guessing. Try not to get eaten.</p></section>\n <section class=\"game-layout\">\n <div class=\"board-column\">\n <div class=\"board-top\"><span><i class=\"apple-dot\"></i> YOU</span><span>17 × 17 <span class=\"dim\">/</span> NO PLACE TO HIDE</span><span><i class=\"snake-dot\"></i> JEV</span></div>\n <div class=\"board-wrap\" id=\"board-wrap\">\n <canvas id=\"board\" width=\"680\" height=\"680\" tabindex=\"0\" aria-label=\"Snake game. You control the apple with arrow keys or W A S D.\"></canvas>\n <div class=\"overlay\" id=\"overlay\"><div class=\"overlay-inner\"><span class=\"overline\" id=\"overlay-tag\">YOU ARE THE APPLE</span><h2 id=\"overlay-title\">Don’t make it easy.</h2><p id=\"overlay-copy\">Jump one square at a time.<br>Jev picks every move the snake makes.</p><button id=\"start\" class=\"primary\">Let’s play <span>↗</span></button><small id=\"setup-hint\">Checking Jev connection…</small></div></div>\n <div class=\"catch-pop\" id=\"catch-pop\" aria-live=\"polite\">CAUGHT. NEW SPOT.</div>\n </div>\n <div class=\"board-bottom\"><span><span class=\"key\">↑</span><span class=\"key\">←</span><span class=\"key\">↓</span><span class=\"key\">→</span> or WASD to hop</span><button id=\"pause\" disabled>Pause <span class=\"key\">P</span></button><button id=\"restart\" aria-label=\"Restart game\">Restart ↻</button></div>\n <div class=\"touch-controls\" aria-label=\"Movement controls\"><button data-direction=\"left\" aria-label=\"Move left\">←</button><div><button data-direction=\"up\" aria-label=\"Move up\">↑</button><button data-direction=\"down\" aria-label=\"Move down\">↓</button></div><button data-direction=\"right\" aria-label=\"Move right\">→</button></div>\n </div>\n <aside>\n <div class=\"score-card\"><div class=\"eyebrow\">CURRENT ESCAPE</div><div class=\"timer\"><span id=\"time\">00</span><small>. <span id=\"tenths\">0</span><span class=\"unit\">s</span></small></div><div class=\"best-row\">PERSONAL BEST <strong id=\"best\">0.0s</strong></div></div>\n <div class=\"numbers\"><div><strong id=\"catches\">0</strong><span>TIMES EATEN</span></div><div><strong id=\"length\">4</strong><span>SNAKE LENGTH</span></div></div>\n <div class=\"mind-card\"><div class=\"mind-heading\"><span class=\"eyebrow\">INSIDE JEV’S HEAD</span><span class=\"brain-mark\">✳</span></div><div class=\"decision\" id=\"decision\">Waiting for you.</div><p id=\"decision-note\">A real model. A very hungry snake.</p><div class=\"probabilities\" id=\"probabilities\"></div><div class=\"telemetry\"><span>LAST RESPONSE <strong id=\"latency\">—</strong></span><span>DECISIONS <strong id=\"calls\">0</strong></span></div></div>\n <div class=\"rules\"><span class=\"rule-number\">01</span><p>Arrow keys or WASD.<br>One press, one square.</p><span class=\"rule-number\">02</span><p>Get eaten? You respawn.<br>The snake gets longer.</p><span class=\"rule-number\">03</span><p>Trap the snake in its own tail.<br>That’s your way out.</p></div>\n <div class=\"cost\">SESSION API COST <span id=\"cost\">$0.0000</span></div>\n </aside>\n </section>\n </main>\n <footer><span>HUMAN INSTINCT <span class=\"dim\">×</span> MACHINE APPETITE</span><span>Powered by Jev <span class=\"dim\">/</span> TypeSafe</span></footer>\n <script type=\"module\" src=\"/app.mjs\"></script>\n</body>\n</html>\n"}
{"chunk_id":"3d3912","wall_time_seconds":0.00000825,"exit_code":0,"original_token_count":3421,"output":"import { SIZE, DIRECTIONS, newGame, legalMoves, moveApple, stepSnake } from './game.mjs';\n\nconst $ = id => document.getElementById(id);\nconst canvas = $('board'), ctx = canvas.getContext('2d');\nlet state = newGame(), previousSnake = state.snake.map(p => ({ ...p })), previousApple = { ...state.apple };\nlet snakeMovedAt = 0, appleMovedAt = 0, running = false, started = false, finished = false, ready = false;\nlet epoch = 0, elapsed = 0, catches = 0, calls = 0, tokens = 0, lastFrame = performance.now(), lastHop = 0;\nlet appleHistory = [], particles = [], flash = 0, best = 0, popupTimer;\ntry { best = Number(localStorage.getItem('apple-vs-jev-best')) || 0; } catch {}\n$('best').textContent = `${best.toFixed(1)}s`;\nconst arrows = { up: '↑', right: '→', down: '↓', left: '←' };\nfor (const direction of Object.keys(DIRECTIONS)) {\n const row = document.createElement('div'); row.className = 'prob-row'; row.id = `prob-${direction}`;\n const label = document.createElement('span'); label.textContent = `${arrows[direction]} ${direction}`;\n const track = document.createElement('div'); track.className = 'track';\n const fill = document.createElement('div'); fill.className = 'fill'; fill.style.width = '0%'; track.append(fill);\n const value = document.createElement('span'); value.textContent = '—'; row.append(label, track, value);\n $('probabilities').append(row);\n}\nfunction badge(label, kind) {\n const el = $('connection'); el.className = `live-badge ${kind}`;\n el.replaceChildren(document.createElement('span'), document.createTextNode(label));\n}\nasync function checkConnection() {\n $('start').disabled = true;\n try {\n const response = await fetch('/api/status');\n if (!response.ok) throw new Error('Server unavailable.');\n const result = await response.json(); ready = result.configured;\n badge(ready ? 'JEV READY' : 'KEY NEEDED', ready ? 'ready' : 'error');\n $('setup-hint').textContent = ready ? 'Arrow keys / WASD · No lives. Just another chance.' : 'Add JEV_API_KEY to .env and restart the server.';\n $('start').disabled = !ready;\n } catch {\n badge('SERVER OFFLINE', 'error');\n $('setup-hint').textContent = 'Start the local server with npm start, then reload.';\n }\n}\nfunction overlay(tag, title, copy, button, hint = '') {\n $('overlay-tag').textContent = tag; $('overlay-title').textContent = title;\n $('overlay-copy').textContent = copy;\n $('start').replaceChildren(document.createTextNode(button), Object.assign(document.createElement('span'), { textContent: '↗' }));\n $('setup-hint').textContent = hint; $('overlay').hidden = false;\n}\nfunction saveBest() {\n if (elapsed > best) {\n best = elapsed; $('best').textContent = `${best.toFixed(1)}s`;\n try { localStorage.setItem('apple-vs-jev-best', String(best)); } catch {}\n }\n}\nfunction reset() {\n epoch++; running = false; started = false; finished = false;\n state = newGame(); previousSnake = state.snake.map(p => ({ ...p })); previousApple = { ...state.apple };\n elapsed = 0; catches = 0; appleHistory = []; particles = []; flash = 0;\n $('catches').textContent = '0'; $('length').textContent = '4';\n $('decision').textContent = 'Waiting for you.';\n $('decision-note').textContent = 'A real model. A very hungry snake.';\n for (const direction of Object.keys(DIRECTIONS)) {\n const row = $(`prob-${direction}`); row.classList.remove('picked'); row.children[1].firstChild.style.width = '0%'; row.lastChild.textContent = '—';\n }\n clearTimeout(popupTimer); $('catch-pop').classList.remove('show');\n}\nfunction start() {\n if (!ready || running) return;\n if (finished) reset();\n running = true; started = true; epoch++;\n $('overlay').hidden = true; $('pause').disabled = false;\n $('pause').replaceChildren(document.createTextNode('Pause '), Object.assign(document.createElement('span'), { className: 'key', textContent: 'P' }));\n canvas.focus({ preventScroll: true });\n badge('JEV LIVE', 'ready');\n runSnake(epoch);\n}\nfunction pause() {\n if (!started || finished) return;\n if (!running) { start(); return; }\n running = false; epoch++;\n badge('PAUSED', '');\n overlay('TAKE A BREATHER', 'A fair pause.', 'The snake is waiting. Your escape timer is stopped.', 'Keep running');\n $('pause').textContent = 'Resume P';\n}\nfunction win() {\n saveBest(); running = false; finished = true; epoch++;\n $('pause').disabled = true; badge('YOU WIN', 'ready');\n overlay('HUMAN INSTINCT WINS', 'Outsmarted.', `Jev ran out of legal moves. Your best escape: ${best.toFixed(1)} seconds.`, 'Play again');\n}\nfunction recordDecision(result) {\n calls++; tokens += result.inputTokens || 0;\n $('calls').textContent = String(calls); $('latency').textContent = `${result.latency} ms`;\n $('cost').textContent = `$${(tokens / 1000000 * .042).toFixed(4)}`;\n}\nconst delay = ms => new Promise(resolve => setTimeout(resolve, ms));\nasync function runSnake(runEpoch) {\n while (running && epoch === runEpoch) {\n if (!legalMoves(state).length) { win(); return; }\n const startTime = performance.now();\n const snapshot = { ...state, snake: state.snake.map(p => ({ ...p })), apple: { ...state.apple }, appleHistory: [...appleHistory] };\n try {\n const response = await fetch('/api/decide', {\n method: 'POST', headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(snapshot), signal: AbortSignal.timeout(6500),\n });\n const result = await response.json();\n if (result.direction) recordDecision(result);\n if (!running || epoch !== runEpoch) return;\n if (!response.ok) throw new Error(result.error || 'Jev could not choose a move.');\n if (result.trapped) { win(); return; }\n await delay(Math.max(0, 210 - (performance.now() - startTime)));\n if (!running || epoch !== runEpoch) return;\n // Apple movement never changes the snake head; revalidate occupancy before execution.\n previousSnake = state.snake.map(p => ({ ...p }));\n const oldApple = { ...state.apple };\n const move = stepSnake(state, result.direction);\n if (!move.valid) continue;\n snakeMovedAt = performance.now();\n $('decision').textContent = `${arrows[result.direction]} Heading ${result.direction}.`;\n $('decision-note').textContent = `Jev chose ${result.direction} · ${Math.round(result.confidence * 100)}% confidence`;\n for (const direction of Object.keys(DIRECTIONS)) {\n const row = $(`prob-${direction}`), probability = result.probabilities?.[direction];\n row.classList.toggle('picked', direction === result.direction);\n row.children[1].firstChild.style.width = `${(probability || 0) * 100}%`;\n row.lastChild.textContent = probability === undefined ? '—' : `${Math.round(probability * 100)}%`;\n }\n if (move.ate) {\n saveBest(); elapsed = 0; catches++; appleHistory = [];\n $('catches').textContent = String(catches); $('length').textContent = String(state.snake.length);\n flash = 1;\n for (let i = 0; i < 22; i++) particles.push({ x: oldApple.x + .5, y: oldApple.y + .5, vx: (Math.random() - .5) * 9, vy: (Math.random() - .5) * 9, life: 1 });\n $('catch-pop').classList.add('show'); clearTimeout(popupTimer);\n popupTimer = setTimeout(() => $('catch-pop').classList.remove('show'), 650);\n if (move.filled) {\n running = false; finished = true; epoch++; $('pause').disabled = true;\n overlay('WELL FED', 'Jev ate the board.', 'Every square is snake. Time for a fresh round.', 'Play again'); return;\n }\n previousApple = { ...state.apple }; appleMovedAt = performance.now();\n }\n } catch (error) {\n if (!running || epoch !== runEpoch) return;\n running = false; epoch++; badge('JEV DISCONNECTED', 'error');\n overlay('SNAKE ON HOLD', 'Connection hiccup.', error.name === 'TimeoutError' ? 'Jev took too long to respond. Your timer is paused.' : error.message, 'Retry');\n $('decision').textContent = 'Waiting for connection.';\n $('decision-note').textContent = 'No simulated AI: the snake waits for Jev.';\n $('pause').textContent = 'Resume P';\n }\n }\n}\nfunction hop(direction) {\n if (!running || performance.now() - lastHop < 85) return;\n const prev = { ...state.apple };\n if (moveApple(state, direction)) {\n previousApple = prev; appleMovedAt = performance.now(); lastHop = appleMovedAt;\n appleHistory.push(direction); appleHistory = appleHistory.slice(-4);\n }\n}\nconst keyMap = { ArrowUp: 'up', ArrowDown: 'down', ArrowLeft: 'left', ArrowRight: 'right', w: 'up', a: 'left', s: 'down', d: 'right' };\ndocument.addEventListener('keydown', e => {\n const key = e.key.length === 1 ? e.key.toLowerCase() : e.key;\n if (keyMap[key]) { e.preventDefault(); if (!e.repeat) hop(keyMap[key]); }\n if (key === 'p' || (e.code === 'Space' && e.target === canvas)) { e.preventDefault(); if (!e.repeat) pause(); }\n});\n$('start').addEventListener('click', start); $('pause').addEventListener('click', pause);\n$('restart').addEventListener('click', () => { if (started) saveBest(); reset(); if (ready) start(); });\ndocument.querySelectorAll('[data-direction]').forEach(button => button.addEventListener('pointerdown', e => { e.preventDefault(); hop(button.dataset.direction); }));\nlet touchStart;\ncanvas.addEventListener('pointerdown', e => { touchStart = { x: e.clientX, y: e.clientY }; canvas.setPointerCapture(e.pointerId); });\ncanvas.addEventListener('pointerup', e => {\n if (!touchStart) return;\n const dx = e.clientX - touchStart.x, dy = e.clientY - touchStart.y; touchStart = null;\n if (Math.max(Math.abs(dx), Math.abs(dy)) < 12) return;\n hop(Math.abs(dx) > Math.abs(dy) ? dx > 0 ? 'right' : 'left' : dy > 0 ? 'down' : 'up');\n});\ndocument.addEventListener('visibilitychange', () => { if (document.hidden && running) pause(); });\nwindow.addEventListener('blur', () => { if (running) pause(); });\nfunction roundedRect(x, y, w, h, r, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.roundRect(x, y, w, h, r); ctx.fill(); }\nfunction draw(now) {\n const dt = Math.min((now - lastFrame) / 1000, .1); lastFrame = now;\n if (running) elapsed += dt;\n $('time').textContent = String(Math.floor(elapsed)).padStart(2, '0');\n $('tenths').textContent = String(Math.floor(elapsed * 10) % 10);\n const W = 680, cell = W / SIZE;\n ctx.clearRect(0, 0, W, W); ctx.fillStyle = '#1b2518'; ctx.fillRect(0, 0, W, W);\n for (let y = 0; y < SIZE; y++) for (let x = 0; x < SIZE; x++) {\n if ((x + y) % 2 === 0) { ctx.fillStyle = '#1e281a'; ctx.fillRect(x * cell, y * cell, cell, cell); }\n ctx.fillStyle = '#34412b'; ctx.fillRect(x * cell - .5, y * cell - .5, 1, 1);\n }\n // Interpolate the snake's movement without changing its discrete collision grid.\n const t = Math.min(1, Math.max(0, (now - snakeMovedAt) / 120));\n const points = state.snake.map((p, i) => {\n const old = previousSnake[Math.min(i, previousSnake.length - 1)] || p;\n return { x: (old.x + (p.x - old.x) * t + .5) * cell, y: (old.y + (p.y - old.y) * t + .5) * cell };\n });\n ctx.save(); ctx.shadowColor = '#a7df4930'; ctx.shadowBlur = 22;\n ctx.strokeStyle = '#bce978'; ctx.lineWidth = cell * .7; ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n ctx.beginPath(); points.forEach((p, i) => i ? ctx.lineTo(p.x, p.y) : ctx.moveTo(p.x, p.y)); ctx.stroke(); ctx.restore();\n points.forEach((p, i) => {\n if (i === 0) return;\n ctx.fillStyle = '#1627101c'; ctx.beginPath(); ctx.arc(p.x, p.y, 2.5, 0, Math.PI * 2); ctx.fill();\n });\n const head = points[0], dir = DIRECTIONS[state.direction], side = { x: -dir.y, y: dir.x };\n roundedRect(head.x - 15, head.y - 15, 30, 30, 10, '#cffd89');\n for (const sign of [-1, 1]) {\n const x = head.x + dir.x * 7 + side.x * sign * 7, y = head.y + dir.y * 7 + side.y * sign * 7;\n ctx.fillStyle = '#17230f'; ctx.beginPath(); ctx.arc(x, y, 3, 0, Math.PI * 2); ctx.fill();\n }\n if (state.apple) {\n const a = Math.min(1, (now - appleMovedAt) / 90);\n const ax = (previousApple.x + (state.apple.x - previousApple.x) * a + .5) * cell;\n const ay = (previousApple.y + (state.apple.y - previousApple.y) * a + .5) * cell;\n const pulse = 1 + Math.sin(now / 230) * .05;\n ctx.save(); ctx.translate(ax, ay); ctx.scale(pulse, pulse);\n ctx.fillStyle = '#ff7c6610'; ctx.beginPath(); ctx.arc(0, 0, 23, 0, Math.PI * 2); ctx.fill();\n ctx.shadowBlur = 18; ctx.shadowColor = '#ff7c6640';\n ctx.fillStyle = '#ff7c66'; ctx.beginPath();\n ctx.moveTo(0, -10); ctx.bezierCurveTo(-19, -21, -22, 7, -8, 15); ctx.quadraticCurveTo(-3, 18, 0, 14); ctx.quadraticCurveTo(6, 18, 12, 11); ctx.bezierCurveTo(24, -8, 12, -20, 0, -10); ctx.fill();\n ctx.shadowBlur = 0; ctx.strokeStyle = '#8aae62'; ctx.lineWidth = 3; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(0, -12); ctx.quadraticCurveTo(-2, -18, 2, -22); ctx.stroke();\n ctx.fillStyle = '#c5f778'; ctx.beginPath(); ctx.ellipse(7, -18, 6, 3, -.5, 0, Math.PI * 2); ctx.fill();\n ctx.fillStyle = '#ffffff60'; ctx.beginPath(); ctx.ellipse(-8, -5, 2.5, 5, .4, 0, Math.PI * 2); ctx.fill(); ctx.restore();\n }\n particles = particles.filter(p => p.life > 0);\n for (const p of particles) {\n p.life -= dt * 2; p.x += p.vx * dt; p.y += p.vy * dt;\n ctx.globalAlpha = Math.max(0, p.life); roundedRect(p.x * cell, p.y * cell, 5, 5, 2, '#ff7c66');\n }\n ctx.globalAlpha = 1;\n if (flash > 0) { ctx.fillStyle = `rgba(255,124,102,${flash * .13})`; ctx.fillRect(0, 0, W, W); flash = Math.max(0, flash - dt * 3); }\n requestAnimationFrame(draw);\n}\nrequestAnimationFrame(draw);\ncheckConnection();\n// Read-only inspection for local QA; credentials are never available in this context.\nwindow.gameSnapshot = () => ({ state: structuredClone(state), running, elapsed, catches, calls, tokens });\n"}>cat public/app.mjs{"chunk_id":"ff724f","wall_time_seconds":0.000014292,"exit_code":0,"original_token_count":1015,"output":"<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta name=\"theme-color\" content=\"#111610\"><meta name=\"description\" content=\"You are the apple. Jev is the snake. How long can you keep it guessing?\">\n <title>Apple vs. Jev</title><link rel=\"icon\" href=\"/favicon.svg\"><link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n <header><a class=\"wordmark\" href=\"/\" aria-label=\"Apple versus Jev home\"><span class=\"mark\">a<span>j</span></span> APPLE VS. JEV</a><div class=\"live-badge\" id=\"connection\"><span></span> CONNECTING</div></header>\n <main>\n <section class=\"intro\"><div class=\"eyebrow\">A LITTLE ROLE REVERSAL</div><h1>Be the <em>bait.</em></h1><p>You’re the apple. The snake is AI.<br>Keep it guessing. Try not to get eaten.</p></section>\n <section class=\"game-layout\">\n <div class=\"board-column\">\n <div class=\"board-top\"><span><i class=\"apple-dot\"></i> YOU</span><span>17 × 17 <span class=\"dim\">/</span> NO PLACE TO HIDE</span><span><i class=\"snake-dot\"></i> JEV</span></div>\n <div class=\"board-wrap\" id=\"board-wrap\">\n <canvas id=\"board\" width=\"680\" height=\"680\" tabindex=\"0\" aria-label=\"Snake game. You control the apple with arrow keys or W A S D.\"></canvas>\n <div class=\"overlay\" id=\"overlay\"><div class=\"overlay-inner\"><span class=\"overline\" id=\"overlay-tag\">YOU ARE THE APPLE</span><h2 id=\"overlay-title\">Don’t make it easy.</h2><p id=\"overlay-copy\">Jump one square at a time.<br>Jev picks every move the snake makes.</p><button id=\"start\" class=\"primary\">Let’s play <span>↗</span></button><small id=\"setup-hint\">Checking Jev connection…</small></div></div>\n <div class=\"catch-pop\" id=\"catch-pop\" aria-live=\"polite\">CAUGHT. NEW SPOT.</div>\n </div>\n <div class=\"board-bottom\"><span><span class=\"key\">↑</span><span class=\"key\">←</span><span class=\"key\">↓</span><span class=\"key\">→</span> or WASD to hop</span><button id=\"pause\" disabled>Pause <span class=\"key\">P</span></button><button id=\"restart\" aria-label=\"Restart game\">Restart ↻</button></div>\n <div class=\"touch-controls\" aria-label=\"Movement controls\"><button data-direction=\"left\" aria-label=\"Move left\">←</button><div><button data-direction=\"up\" aria-label=\"Move up\">↑</button><button data-direction=\"down\" aria-label=\"Move down\">↓</button></div><button data-direction=\"right\" aria-label=\"Move right\">→</button></div>\n </div>\n <aside>\n <div class=\"score-card\"><div class=\"eyebrow\">CURRENT ESCAPE</div><div class=\"timer\"><span id=\"time\">00</span><small>. <span id=\"tenths\">0</span><span class=\"unit\">s</span></small></div><div class=\"best-row\">PERSONAL BEST <strong id=\"best\">0.0s</strong></div></div>\n <div class=\"numbers\"><div><strong id=\"catches\">0</strong><span>TIMES EATEN</span></div><div><strong id=\"length\">4</strong><span>SNAKE LENGTH</span></div></div>\n <div class=\"mind-card\"><div class=\"mind-heading\"><span class=\"eyebrow\">INSIDE JEV’S HEAD</span><span class=\"brain-mark\">✳</span></div><div class=\"decision\" id=\"decision\">Waiting for you.</div><p id=\"decision-note\">A real model. A very hungry snake.</p><div class=\"probabilities\" id=\"probabilities\"></div><div class=\"telemetry\"><span>LAST RESPONSE <strong id=\"latency\">—</strong></span><span>DECISIONS <strong id=\"calls\">0</strong></span></div></div>\n <div class=\"rules\"><span class=\"rule-number\">01</span><p>Arrow keys or WASD.<br>One press, one square.</p><span class=\"rule-number\">02</span><p>Get eaten? You respawn.<br>The snake gets longer.</p><span class=\"rule-number\">03</span><p>Trap the snake in its own tail.<br>That’s your way out.</p></div>\n <div class=\"cost\">SESSION API COST <span id=\"cost\">$0.0000</span></div>\n </aside>\n </section>\n </main>\n <footer><span>HUMAN INSTINCT <span class=\"dim\">×</span> MACHINE APPETITE</span><span>Powered by Jev <span class=\"dim\">/</span> TypeSafe</span></footer>\n <script type=\"module\" src=\"/app.mjs\"></script>\n</body>\n</html>\n"}
{"chunk_id":"3d3912","wall_time_seconds":0.00000825,"exit_code":0,"original_token_count":3421,"output":"import { SIZE, DIRECTIONS, newGame, legalMoves, moveApple, stepSnake } from './game.mjs';\n\nconst $ = id => document.getElementById(id);\nconst canvas = $('board'), ctx = canvas.getContext('2d');\nlet state = newGame(), previousSnake = state.snake.map(p => ({ ...p })), previousApple = { ...state.apple };\nlet snakeMovedAt = 0, appleMovedAt = 0, running = false, started = false, finished = false, ready = false;\nlet epoch = 0, elapsed = 0, catches = 0, calls = 0, tokens = 0, lastFrame = performance.now(), lastHop = 0;\nlet appleHistory = [], particles = [], flash = 0, best = 0, popupTimer;\ntry { best = Number(localStorage.getItem('apple-vs-jev-best')) || 0; } catch {}\n$('best').textContent = `${best.toFixed(1)}s`;\nconst arrows = { up: '↑', right: '→', down: '↓', left: '←' };\nfor (const direction of Object.keys(DIRECTIONS)) {\n const row = document.createElement('div'); row.className = 'prob-row'; row.id = `prob-${direction}`;\n const label = document.createElement('span'); label.textContent = `${arrows[direction]} ${direction}`;\n const track = document.createElement('div'); track.className = 'track';\n const fill = document.createElement('div'); fill.className = 'fill'; fill.style.width = '0%'; track.append(fill);\n const value = document.createElement('span'); value.textContent = '—'; row.append(label, track, value);\n $('probabilities').append(row);\n}\nfunction badge(label, kind) {\n const el = $('connection'); el.className = `live-badge ${kind}`;\n el.replaceChildren(document.createElement('span'), document.createTextNode(label));\n}\nasync function checkConnection() {\n $('start').disabled = true;\n try {\n const response = await fetch('/api/status');\n if (!response.ok) throw new Error('Server unavailable.');\n const result = await response.json(); ready = result.configured;\n badge(ready ? 'JEV READY' : 'KEY NEEDED', ready ? 'ready' : 'error');\n $('setup-hint').textContent = ready ? 'Arrow keys / WASD · No lives. Just another chance.' : 'Add JEV_API_KEY to .env and restart the server.';\n $('start').disabled = !ready;\n } catch {\n badge('SERVER OFFLINE', 'error');\n $('setup-hint').textContent = 'Start the local server with npm start, then reload.';\n }\n}\nfunction overlay(tag, title, copy, button, hint = '') {\n $('overlay-tag').textContent = tag; $('overlay-title').textContent = title;\n $('overlay-copy').textContent = copy;\n $('start').replaceChildren(document.createTextNode(button), Object.assign(document.createElement('span'), { textContent: '↗' }));\n $('setup-hint').textContent = hint; $('overlay').hidden = false;\n}\nfunction saveBest() {\n if (elapsed > best) {\n best = elapsed; $('best').textContent = `${best.toFixed(1)}s`;\n try { localStorage.setItem('apple-vs-jev-best', String(best)); } catch {}\n }\n}\nfunction reset() {\n epoch++; running = false; started = false; finished = false;\n state = newGame(); previousSnake = state.snake.map(p => ({ ...p })); previousApple = { ...state.apple };\n elapsed = 0; catches = 0; appleHistory = []; particles = []; flash = 0;\n $('catches').textContent = '0'; $('length').textContent = '4';\n $('decision').textContent = 'Waiting for you.';\n $('decision-note').textContent = 'A real model. A very hungry snake.';\n for (const direction of Object.keys(DIRECTIONS)) {\n const row = $(`prob-${direction}`); row.classList.remove('picked'); row.children[1].firstChild.style.width = '0%'; row.lastChild.textContent = '—';\n }\n clearTimeout(popupTimer); $('catch-pop').classList.remove('show');\n}\nfunction start() {\n if (!ready || running) return;\n if (finished) reset();\n running = true; started = true; epoch++;\n $('overlay').hidden = true; $('pause').disabled = false;\n $('pause').replaceChildren(document.createTextNode('Pause '), Object.assign(document.createElement('span'), { className: 'key', textContent: 'P' }));\n canvas.focus({ preventScroll: true });\n badge('JEV LIVE', 'ready');\n runSnake(epoch);\n}\nfunction pause() {\n if (!started || finished) return;\n if (!running) { start(); return; }\n running = false; epoch++;\n badge('PAUSED', '');\n overlay('TAKE A BREATHER', 'A fair pause.', 'The snake is waiting. Your escape timer is stopped.', 'Keep running');\n $('pause').textContent = 'Resume P';\n}\nfunction win() {\n saveBest(); running = false; finished = true; epoch++;\n $('pause').disabled = true; badge('YOU WIN', 'ready');\n overlay('HUMAN INSTINCT WINS', 'Outsmarted.', `Jev ran out of legal moves. Your best escape: ${best.toFixed(1)} seconds.`, 'Play again');\n}\nfunction recordDecision(result) {\n calls++; tokens += result.inputTokens || 0;\n $('calls').textContent = String(calls); $('latency').textContent = `${result.latency} ms`;\n $('cost').textContent = `$${(tokens / 1000000 * .042).toFixed(4)}`;\n}\nconst delay = ms => new Promise(resolve => setTimeout(resolve, ms));\nasync function runSnake(runEpoch) {\n while (running && epoch === runEpoch) {\n if (!legalMoves(state).length) { win(); return; }\n const startTime = performance.now();\n const snapshot = { ...state, snake: state.snake.map(p => ({ ...p })), apple: { ...state.apple }, appleHistory: [...appleHistory] };\n try {\n const response = await fetch('/api/decide', {\n method: 'POST', headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(snapshot), signal: AbortSignal.timeout(6500),\n });\n const result = await response.json();\n if (result.direction) recordDecision(result);\n if (!running || epoch !== runEpoch) return;\n if (!response.ok) throw new Error(result.error || 'Jev could not choose a move.');\n if (result.trapped) { win(); return; }\n await delay(Math.max(0, 210 - (performance.now() - startTime)));\n if (!running || epoch !== runEpoch) return;\n // Apple movement never changes the snake head; revalidate occupancy before execution.\n previousSnake = state.snake.map(p => ({ ...p }));\n const oldApple = { ...state.apple };\n const move = stepSnake(state, result.direction);\n if (!move.valid) continue;\n snakeMovedAt = performance.now();\n $('decision').textContent = `${arrows[result.direction]} Heading ${result.direction}.`;\n $('decision-note').textContent = `Jev chose ${result.direction} · ${Math.round(result.confidence * 100)}% confidence`;\n for (const direction of Object.keys(DIRECTIONS)) {\n const row = $(`prob-${direction}`), probability = result.probabilities?.[direction];\n row.classList.toggle('picked', direction === result.direction);\n row.children[1].firstChild.style.width = `${(probability || 0) * 100}%`;\n row.lastChild.textContent = probability === undefined ? '—' : `${Math.round(probability * 100)}%`;\n }\n if (move.ate) {\n saveBest(); elapsed = 0; catches++; appleHistory = [];\n $('catches').textContent = String(catches); $('length').textContent = String(state.snake.length);\n flash = 1;\n for (let i = 0; i < 22; i++) particles.push({ x: oldApple.x + .5, y: oldApple.y + .5, vx: (Math.random() - .5) * 9, vy: (Math.random() - .5) * 9, life: 1 });\n $('catch-pop').classList.add('show'); clearTimeout(popupTimer);\n popupTimer = setTimeout(() => $('catch-pop').classList.remove('show'), 650);\n if (move.filled) {\n running = false; finished = true; epoch++; $('pause').disabled = true;\n overlay('WELL FED', 'Jev ate the board.', 'Every square is snake. Time for a fresh round.', 'Play again'); return;\n }\n previousApple = { ...state.apple }; appleMovedAt = performance.now();\n }\n } catch (error) {\n if (!running || epoch !== runEpoch) return;\n running = false; epoch++; badge('JEV DISCONNECTED', 'error');\n overlay('SNAKE ON HOLD', 'Connection hiccup.', error.name === 'TimeoutError' ? 'Jev took too long to respond. Your timer is paused.' : error.message, 'Retry');\n $('decision').textContent = 'Waiting for connection.';\n $('decision-note').textContent = 'No simulated AI: the snake waits for Jev.';\n $('pause').textContent = 'Resume P';\n }\n }\n}\nfunction hop(direction) {\n if (!running || performance.now() - lastHop < 85) return;\n const prev = { ...state.apple };\n if (moveApple(state, direction)) {\n previousApple = prev; appleMovedAt = performance.now(); lastHop = appleMovedAt;\n appleHistory.push(direction); appleHistory = appleHistory.slice(-4);\n }\n}\nconst keyMap = { ArrowUp: 'up', ArrowDown: 'down', ArrowLeft: 'left', ArrowRight: 'right', w: 'up', a: 'left', s: 'down', d: 'right' };\ndocument.addEventListener('keydown', e => {\n const key = e.key.length === 1 ? e.key.toLowerCase() : e.key;\n if (keyMap[key]) { e.preventDefault(); if (!e.repeat) hop(keyMap[key]); }\n if (key === 'p' || (e.code === 'Space' && e.target === canvas)) { e.preventDefault(); if (!e.repeat) pause(); }\n});\n$('start').addEventListener('click', start); $('pause').addEventListener('click', pause);\n$('restart').addEventListener('click', () => { if (started) saveBest(); reset(); if (ready) start(); });\ndocument.querySelectorAll('[data-direction]').forEach(button => button.addEventListener('pointerdown', e => { e.preventDefault(); hop(button.dataset.direction); }));\nlet touchStart;\ncanvas.addEventListener('pointerdown', e => { touchStart = { x: e.clientX, y: e.clientY }; canvas.setPointerCapture(e.pointerId); });\ncanvas.addEventListener('pointerup', e => {\n if (!touchStart) return;\n const dx = e.clientX - touchStart.x, dy = e.clientY - touchStart.y; touchStart = null;\n if (Math.max(Math.abs(dx), Math.abs(dy)) < 12) return;\n hop(Math.abs(dx) > Math.abs(dy) ? dx > 0 ? 'right' : 'left' : dy > 0 ? 'down' : 'up');\n});\ndocument.addEventListener('visibilitychange', () => { if (document.hidden && running) pause(); });\nwindow.addEventListener('blur', () => { if (running) pause(); });\nfunction roundedRect(x, y, w, h, r, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.roundRect(x, y, w, h, r); ctx.fill(); }\nfunction draw(now) {\n const dt = Math.min((now - lastFrame) / 1000, .1); lastFrame = now;\n if (running) elapsed += dt;\n $('time').textContent = String(Math.floor(elapsed)).padStart(2, '0');\n $('tenths').textContent = String(Math.floor(elapsed * 10) % 10);\n const W = 680, cell = W / SIZE;\n ctx.clearRect(0, 0, W, W); ctx.fillStyle = '#1b2518'; ctx.fillRect(0, 0, W, W);\n for (let y = 0; y < SIZE; y++) for (let x = 0; x < SIZE; x++) {\n if ((x + y) % 2 === 0) { ctx.fillStyle = '#1e281a'; ctx.fillRect(x * cell, y * cell, cell, cell); }\n ctx.fillStyle = '#34412b'; ctx.fillRect(x * cell - .5, y * cell - .5, 1, 1);\n }\n // Interpolate the snake's movement without changing its discrete collision grid.\n const t = Math.min(1, Math.max(0, (now - snakeMovedAt) / 120));\n const points = state.snake.map((p, i) => {\n const old = previousSnake[Math.min(i, previousSnake.length - 1)] || p;\n return { x: (old.x + (p.x - old.x) * t + .5) * cell, y: (old.y + (p.y - old.y) * t + .5) * cell };\n });\n ctx.save(); ctx.shadowColor = '#a7df4930'; ctx.shadowBlur = 22;\n ctx.strokeStyle = '#bce978'; ctx.lineWidth = cell * .7; ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n ctx.beginPath(); points.forEach((p, i) => i ? ctx.lineTo(p.x, p.y) : ctx.moveTo(p.x, p.y)); ctx.stroke(); ctx.restore();\n points.forEach((p, i) => {\n if (i === 0) return;\n ctx.fillStyle = '#1627101c'; ctx.beginPath(); ctx.arc(p.x, p.y, 2.5, 0, Math.PI * 2); ctx.fill();\n });\n const head = points[0], dir = DIRECTIONS[state.direction], side = { x: -dir.y, y: dir.x };\n roundedRect(head.x - 15, head.y - 15, 30, 30, 10, '#cffd89');\n for (const sign of [-1, 1]) {\n const x = head.x + dir.x * 7 + side.x * sign * 7, y = head.y + dir.y * 7 + side.y * sign * 7;\n ctx.fillStyle = '#17230f'; ctx.beginPath(); ctx.arc(x, y, 3, 0, Math.PI * 2); ctx.fill();\n }\n if (state.apple) {\n const a = Math.min(1, (now - appleMovedAt) / 90);\n const ax = (previousApple.x + (state.apple.x - previousApple.x) * a + .5) * cell;\n const ay = (previousApple.y + (state.apple.y - previousApple.y) * a + .5) * cell;\n const pulse = 1 + Math.sin(now / 230) * .05;\n ctx.save(); ctx.translate(ax, ay); ctx.scale(pulse, pulse);\n ctx.fillStyle = '#ff7c6610'; ctx.beginPath(); ctx.arc(0, 0, 23, 0, Math.PI * 2); ctx.fill();\n ctx.shadowBlur = 18; ctx.shadowColor = '#ff7c6640';\n ctx.fillStyle = '#ff7c66'; ctx.beginPath();\n ctx.moveTo(0, -10); ctx.bezierCurveTo(-19, -21, -22, 7, -8, 15); ctx.quadraticCurveTo(-3, 18, 0, 14); ctx.quadraticCurveTo(6, 18, 12, 11); ctx.bezierCurveTo(24, -8, 12, -20, 0, -10); ctx.fill();\n ctx.shadowBlur = 0; ctx.strokeStyle = '#8aae62'; ctx.lineWidth = 3; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(0, -12); ctx.quadraticCurveTo(-2, -18, 2, -22); ctx.stroke();\n ctx.fillStyle = '#c5f778'; ctx.beginPath(); ctx.ellipse(7, -18, 6, 3, -.5, 0, Math.PI * 2); ctx.fill();\n ctx.fillStyle = '#ffffff60'; ctx.beginPath(); ctx.ellipse(-8, -5, 2.5, 5, .4, 0, Math.PI * 2); ctx.fill(); ctx.restore();\n }\n particles = particles.filter(p => p.life > 0);\n for (const p of particles) {\n p.life -= dt * 2; p.x += p.vx * dt; p.y += p.vy * dt;\n ctx.globalAlpha = Math.max(0, p.life); roundedRect(p.x * cell, p.y * cell, 5, 5, 2, '#ff7c66');\n }\n ctx.globalAlpha = 1;\n if (flash > 0) { ctx.fillStyle = `rgba(255,124,102,${flash * .13})`; ctx.fillRect(0, 0, W, W); flash = Math.max(0, flash - dt * 3); }\n requestAnimationFrame(draw);\n}\nrequestAnimationFrame(draw);\ncheckConnection();\n// Read-only inspection for local QA; credentials are never available in this context.\nwindow.gameSnapshot = () => ({ state: structuredClone(state), running, elapsed, catches, calls, tokens });\n"}>cat > public/index.html <<'EOF'
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#f5f5f5"><meta name="description" content="You control the apple. Jev controls the snake.">
<title>Apple vs. Jev</title><link rel="icon" href="/favicon.svg"><link rel="stylesheet" href="/style.css">
</head>
<body>
<header><a class="wordmark" href="/" aria-label="Apple versus Jev home"><span class="mark" aria-hidden="true"></span> APPLE / JEV</a><div class="live-badge" id="connection"><span></span> Connecting</div></header>
<main>
<section class="intro"><h1>You’re the apple.<br>Jev is the snake.</h1><p>Move with arrow keys or WASD. See how long you last.</p></section>
<section class="game" aria-label="Apple versus Jev game">
<div class="scores">
<div>Time <strong><span id="time">00</span>.<span id="tenths">0</span>s</strong></div>
<div>Best <strong id="best">0.0s</strong></div>
<div>Eaten <strong id="catches">0</strong></div>
<div>Length <strong id="length">4</strong></div>
</div>
<div class="board-wrap" id="board-wrap">
<canvas id="board" width="680" height="680" tabindex="0" aria-label="Snake game. You control the apple with arrow keys or W A S D."></canvas>
<div class="overlay" id="overlay"><div class="overlay-inner"><span class="overline" id="overlay-tag">Your move</span><h2 id="overlay-title">Stay out of reach.</h2><p id="overlay-copy">You hop one square at a time.<br>Get eaten and you’ll respawn.</p><button id="start" class="primary">Play</button><small id="setup-hint">Checking Jev connection…</small></div></div>
<div class="catch-pop" id="catch-pop" aria-live="polite">Eaten. New spot.</div>
</div>
<div class="board-bottom"><div class="legend"><span><i class="apple-dot"></i> You</span><span><i class="snake-dot"></i> Jev</span></div><div class="actions"><button id="pause" disabled title="Pause or resume with P">Pause <kbd>P</kbd></button><button id="restart" aria-label="Restart game">Restart</button></div></div>
</section>
<div class="touch-controls" aria-label="Movement controls"><button data-direction="left" aria-label="Move left">←</button><div><button data-direction="up" aria-label="Move up">↑</button><button data-direction="down" aria-label="Move down">↓</button></div><button data-direction="right" aria-label="Move right">→</button></div>
<details class="model-details">
<summary><span>Jev’s decisions</span><span class="summary-hint">Live probabilities & timing</span></summary>
<div class="details-content"><div class="decision" id="decision">Waiting to start.</div><p id="decision-note">Every snake move is chosen by Jev.</p><div class="probabilities" id="probabilities"></div><div class="telemetry"><span>Response <strong id="latency">—</strong></span><span>Decisions <strong id="calls">0</strong></span><span>Session cost <strong id="cost">$0.0000</strong></span></div></div>
</details>
<p class="game-note">The snake grows each time it catches you. Trap it to win.</p>
</main>
<footer>Made with <a href="https://typesafe.ai" target="_blank" rel="noreferrer">Jev by TypeSafe</a></footer>
<script type="module" src="/app.mjs"></script>
</body>
</html>
EOF
cat > public/style.css <<'EOF'
:root {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
color: #222; background: #f5f5f5; color-scheme: light; font-synthesis: none;
--border: #ddd; --muted: #737373;
}
* { box-sizing: border-box; }
body { margin: 0; min-height: 100vh; }
button, a { -webkit-tap-highlight-color: transparent; }
button { font: inherit; cursor: pointer; }
button:focus-visible, a:focus-visible, canvas:focus-visible, summary:focus-visible { outline: 2px solid #555; outline-offset: 4px; }
header { height: 48px; padding: 0 22px; border-bottom: 1px solid #e3e3e3; display: flex; align-items: center; justify-content: space-between; }
.wordmark { display: flex; align-items: center; gap: 10px; font-size: 12px; font-weight: 600; letter-spacing: 2px; text-decoration: none; color: inherit; }
.mark { width: 15px; height: 15px; border: 1.5px solid #222; border-radius: 3px; position: relative; }
.mark::after { content: ""; position: absolute; inset: 3px; border: 1.5px solid #222; border-radius: 1px; }
.live-badge { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--muted); }
.live-badge > span { width: 5px; height: 5px; border-radius: 50%; background: #999; }
.live-badge.ready > span { background: #628768; }
.live-badge.error { color: #ad4034; }
.live-badge.error > span { background: #ad4034; }
main { width: min(100% - 36px, 510px); margin: 0 auto; }
.intro { padding: 30px 0 24px; text-align: center; }
h1 { font-size: 34px; font-weight: 400; line-height: 1.08; letter-spacing: -1.6px; margin: 0 0 14px; }
.intro p { font-size: 14px; color: var(--muted); line-height: 1.6; margin: 0; }
.game { border: 1px solid #d2d2d2; border-radius: 7px; background: white; overflow: hidden; }
.scores { display: grid; grid-template-columns: repeat(4, 1fr); border-bottom: 1px solid var(--border); padding: 13px 17px; }
.scores > div { display: flex; align-items: center; gap: 9px; font-size: 12px; color: var(--muted); }
.scores > div:not(:first-child) { justify-content: flex-end; }
.scores strong { color: #262626; font-size: 13px; font-weight: 500; font-variant-numeric: tabular-nums; }
.board-wrap { position: relative; aspect-ratio: 1; background: #fafafa; overflow: hidden; }
canvas { display: block; width: 100%; height: 100%; touch-action: none; }
.overlay { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; background: #fafafaeb; padding: 22px; }
.overlay[hidden] { display: none; }
.overlay-inner { width: 100%; max-width: 300px; }
.overline { color: var(--muted); font-size: 12px; }
h2 { font-size: 25px; font-weight: 400; letter-spacing: -.8px; margin: 13px 0 12px; }
.overlay p { font-size: 14px; line-height: 1.65; color: #737373; margin: 0 0 23px; }
.primary { background: #202020; color: #fff; border: 1px solid #202020; border-radius: 5px; font-size: 14px; padding: 10px 26px; min-width: 134px; }
.primary:hover { background: #363636; }
.primary:disabled { opacity: .45; cursor: wait; }
.overlay small { display: block; font-size: 12px; line-height: 1.6; color: #888; margin: 15px auto 0; }
.board-bottom { min-height: 49px; display: flex; align-items: center; justify-content: space-between; padding: 9px 14px; border-top: 1px solid var(--border); }
.legend, .legend > span, .actions { display: flex; align-items: center; }
.legend { gap: 15px; font-size: 12px; color: var(--muted); }
.legend > span { gap: 6px; }
.apple-dot, .snake-dot { display: inline-block; width: 7px; height: 7px; border-radius: 1px; background: #ed715d; }
.snake-dot { background: #292929; }
.actions { gap: 7px; }
.actions button { font-size: 12px; background: #fff; color: #444; border: 1px solid #ddd; padding: 5px 9px; border-radius: 4px; }
.actions button:hover { background: #f6f6f6; }
.actions button:disabled { opacity: .4; cursor: default; }
kbd, .key { font: inherit; color: #888; font-size: 10px; margin-left: 5px; }
.catch-pop { position: absolute; left: 50%; top: 40%; transform: translateX(-50%); border: 1px solid #ddd; background: #fff; padding: 10px 16px; border-radius: 5px; font-size: 13px; color: #444; opacity: 0; pointer-events: none; transition: opacity .12s; white-space: nowrap; }
.catch-pop.show { opacity: 1; }
.model-details { margin-top: 13px; border: 1px solid var(--border); border-radius: 5px; background: #fff; font-size: 12px; }
summary { padding: 12px 14px; cursor: pointer; color: #555; }
summary::marker { font-size: 10px; color: #888; }
summary > span:first-child { margin-left: 4px; }
.summary-hint { float: right; color: #969696; }
.details-content { padding: 3px 16px 16px; }
.decision { font-size: 14px; color: #222; }
.details-content > p { font-size: 12px; line-height: 1.5; color: #777; margin: 6px 0 15px; }
.probabilities { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 24px; }
.prob-row { display: grid; grid-template-columns: 47px 1fr 30px; gap: 8px; align-items: center; color: #888; font-size: 11px; }
.prob-row.picked { color: #222; }
.track { height: 3px; background: #eee; border-radius: 2px; overflow: hidden; }
.fill { height: 100%; background: #333; transition: width .15s; }
.telemetry { margin-top: 17px; padding-top: 12px; border-top: 1px solid #eee; display: flex; justify-content: space-between; gap: 10px; color: #888; font-size: 11px; }
.telemetry strong { color: #444; font-weight: 400; margin-left: 4px; font-variant-numeric: tabular-nums; }
.game-note { text-align: center; color: #999; font-size: 12px; line-height: 1.6; margin: 15px 0 0; }
footer { text-align: center; padding: 22px 16px; font-size: 12px; color: #999; }
footer a { color: #777; text-decoration: none; }
footer a:hover { text-decoration: underline; }
.touch-controls { display: none; align-items: center; justify-content: center; gap: 8px; margin-top: 16px; }
.touch-controls > div { display: grid; gap: 8px; }
.touch-controls button { background: #fff; border: 1px solid #d5d5d5; color: #333; width: 48px; height: 42px; border-radius: 5px; font-size: 20px; touch-action: none; }
.touch-controls button:active { background: #e8e8e8; }
@media (max-width: 600px) {
header { padding: 0 16px; height: 44px; }
.wordmark { font-size: 11px; letter-spacing: 1.6px; }
.live-badge { font-size: 11px; }
main { width: min(100% - 28px, 510px); }
.intro { padding: 25px 0 21px; }
h1 { font-size: 30px; }
.intro p { max-width: 290px; margin: auto; font-size: 13px; }
.scores { padding: 12px; }
.scores > div { gap: 5px; font-size: 11px; }
.scores strong { font-size: 12px; }
.touch-controls { display: flex; }
.summary-hint { font-size: 11px; }
.telemetry { flex-wrap: wrap; }
.probabilities { column-gap: 14px; }
.prob-row { grid-template-columns: 40px 1fr 26px; gap: 5px; }
}
@media (min-width: 601px) and (max-height: 850px) {
main { max-width: 440px; }
.intro { padding: 22px 0 18px; }
h1 { font-size: 30px; margin-bottom: 10px; }
footer { padding: 16px; }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
EOF{"chunk_id":"cfc7b2","wall_time_seconds":0.000012708,"exit_code":0,"original_token_count":0,"output":""}>python3 - <<'PY'
from pathlib import Path
p = Path('public/app.mjs')
s = p.read_text()
replacements = {
"'JEV READY' : 'KEY NEEDED'": "'Jev ready' : 'Key needed'",
"Arrow keys / WASD · No lives. Just another chance.": "Arrow keys / WASD",
"'SERVER OFFLINE'": "'Server offline'",
"$('start').replaceChildren(document.createTextNode(button), Object.assign(document.createElement('span'), { textContent: '↗' }));": "$('start').textContent = button;",
"Waiting for you.": "Waiting to start.",
"A real model. A very hungry snake.": "Every snake move is chosen by Jev.",
"'JEV LIVE'": "'Jev live'",
"'PAUSED'": "'Paused'",
"overlay('TAKE A BREATHER', 'A fair pause.', 'The snake is waiting. Your escape timer is stopped.', 'Keep running');": "overlay('Paused', 'Take your time.', 'The snake and your timer are paused.', 'Resume');",
"'YOU WIN'": "'You win'",
"'HUMAN INSTINCT WINS', 'Outsmarted.'": "'You win', 'Snake trapped.'",
"i < 22": "i < 6",
"(Math.random() - .5) * 9": "(Math.random() - .5) * 5",
"'JEV DISCONNECTED'": "'Jev disconnected'",
"'SNAKE ON HOLD', 'Connection hiccup.'": "'Connection lost', 'Snake paused.'",
"'#1b2518'": "'#fafafa'",
"'#1e281a'": "'#f5f5f5'",
"'#34412b'": "'#d9d9d9'",
"ctx.save(); ctx.shadowColor = '#a7df4930'; ctx.shadowBlur = 22;": "ctx.save();",
"ctx.strokeStyle = '#bce978'; ctx.lineWidth = cell * .7; ctx.lineCap = 'round'; ctx.lineJoin = 'round';": "ctx.strokeStyle = '#303030'; ctx.lineWidth = cell * .66; ctx.lineCap = 'square'; ctx.lineJoin = 'miter';",
"ctx.fillStyle = '#1627101c'; ctx.beginPath(); ctx.arc(p.x, p.y, 2.5, 0, Math.PI * 2); ctx.fill();": "ctx.fillStyle = '#ffffff20'; ctx.fillRect(p.x - 1.5, p.y - 1.5, 3, 3);",
"roundedRect(head.x - 15, head.y - 15, 30, 30, 10, '#cffd89');": "roundedRect(head.x - 14, head.y - 14, 28, 28, 3, '#202020');",
"ctx.fillStyle = '#17230f'; ctx.beginPath(); ctx.arc(x, y, 3, 0, Math.PI * 2); ctx.fill();": "ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(x, y, 2.5, 0, Math.PI * 2); ctx.fill();",
"roundedRect(p.x * cell, p.y * cell, 5, 5, 2, '#ff7c66');": "roundedRect(p.x * cell, p.y * cell, 4, 4, 1, '#ed715d');",
"if (flash > 0) { ctx.fillStyle = `rgba(255,124,102,${flash * .13})`; ctx.fillRect(0, 0, W, W); flash = Math.max(0, flash - dt * 3); }": "if (flash > 0) { flash = Math.max(0, flash - dt * 3); }",
}
for old, new in replacements.items():
assert old in s, old
s = s.replace(old, new)
start = s.index(' const pulse =')
end = s.index('\n }\n particles', start)
s = s[:start] + ''' ctx.save(); ctx.translate(ax, ay);
roundedRect(-13, -10, 26, 25, 5, '#ed715d');
roundedRect(-1, -17, 3, 9, 1, '#5b6853');
roundedRect(2, -18, 8, 4, 1, '#879a77');
ctx.restore();''' + s[end:]
p.write_text(s)
Path('public/favicon.svg').write_text('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#f5f5f5"/><path d="M20 40V24h16v16h10" fill="none" stroke="#292929" stroke-width="10" stroke-linecap="square" stroke-linejoin="miter"/><rect x="41" y="12" width="12" height="12" rx="2" fill="#ed715d"/></svg>\n')
PY
node --check public/app.mjs
npm test{"chunk_id":"3fb368","wall_time_seconds":0.507633208,"exit_code":0,"original_token_count":325,"output":"\n> apple-vs-jev@1.0.0 test\n> node --test tests/*.test.mjs\n\nTAP version 13\n# Subtest: apple hops one square and cannot enter the snake or leave the board\nok 1 - apple hops one square and cannot enter the snake or leave the board\n ---\n duration_ms: 1.334125\n type: 'test'\n ...\n# Subtest: eating grows the snake and respawns the apple on an empty square\nok 2 - eating grows the snake and respawns the apple on an empty square\n ---\n duration_ms: 1.220667\n type: 'test'\n ...\n# Subtest: body and walls prohibit moves but the vacating tail is legal\nok 3 - body and walls prohibit moves but the vacating tail is legal\n ---\n duration_ms: 0.150875\n type: 'test'\n ...\n# Subtest: trapping the head produces no legal moves\nok 4 - trapping the head produces no legal moves\n ---\n duration_ms: 0.111\n type: 'test'\n ...\n# Subtest: Jev receives precisely the legal directions and no private data\nok 5 - Jev receives precisely the legal directions and no private data\n ---\n duration_ms: 0.590542\n type: 'test'\n ...\n# Subtest: rejects malformed board state and handles a full board\nok 6 - rejects malformed board state and handles a full board\n ---\n duration_ms: 1.484583\n type: 'test'\n ...\n1..6\n# tests 6\n# suites 0\n# pass 6\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 56.637792\n"}The simpler design is in place. I’m checking the desktop and phone layouts, plus movement and pause controls, before wrapping up.
>python3 - <<'PY'
from playwright.sync_api import sync_playwright
import json
with sync_playwright() as p:
browser = p.chromium.launch(executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', headless=True)
page = browser.new_page(viewport={'width':1440,'height':1000})
errors=[]
page.on('pageerror', lambda e: errors.append(str(e)))
page.goto('http://localhost:3000',wait_until='networkidle')
page.screenshot(path='artifacts/simple-desktop-start.png',full_page=True)
assert not page.locator('details').evaluate('(e) => e.open')
page.click('#start')
before=page.evaluate('window.gameSnapshot().state.apple')
page.keyboard.press('ArrowUp')
after=page.evaluate('window.gameSnapshot().state.apple')
assert after['y']==before['y']-1
page.wait_for_function('() => window.gameSnapshot().calls >= 2 || !window.gameSnapshot().running',timeout=20000)
result=page.evaluate('window.gameSnapshot()')
assert result['running'] and result['calls']>=2, result
page.screenshot(path='artifacts/simple-desktop-playing.png',full_page=True)
page.keyboard.press('p')
assert not page.evaluate('window.gameSnapshot().running')
page.click('summary')
assert page.locator('details').evaluate('(e) => e.open')
assert page.locator('#latency').inner_text() != '—'
page.click('#start')
assert page.evaluate('window.gameSnapshot().running')
page.keyboard.press('p')
mobile=browser.new_page(viewport={'width':390,'height':844},is_mobile=True,has_touch=True,device_scale_factor=2)
mobile.on('pageerror',lambda e: errors.append(str(e)))
mobile.goto('http://localhost:3000',wait_until='networkidle')
assert mobile.evaluate('document.documentElement.scrollWidth <= innerWidth')
mobile.screenshot(path='artifacts/simple-mobile.png',full_page=True)
mobile.click('#start')
before=mobile.evaluate('window.gameSnapshot().state.apple')
mobile.locator('[data-direction="up"]').tap()
after=mobile.evaluate('window.gameSnapshot().state.apple')
assert after['y']==before['y']-1
mobile.click('#pause')
assert not errors, errors
print(json.dumps({'desktop':'passed','mobile':'passed','liveDecisions':result['calls'],'keyboardAndTouch':'passed','pauseResume':'passed','errors':errors}))
browser.close()
PY{"chunk_id":"37c7fe","wall_time_seconds":1.00209275,"session_id":9435,"original_token_count":0,"output":""}{"chunk_id":"5a1528","wall_time_seconds":0.000011042,"exit_code":1,"original_token_count":340,"output":"Traceback (most recent call last):\n File \"<stdin>\", line 8, in <module>\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/sync_api/_generated.py\", line 9054, in goto\n self._sync(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_sync_base.py\", line 115, in _sync\n return task.result()\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_page.py\", line 552, in goto\n return await self._main_frame.goto(**locals_to_params(locals()))\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_frame.py\", line 153, in goto\n await self._channel.send(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 69, in send\n return await self._connection.wrap_api_call(\n File \"/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/playwright/_impl/_connection.py\", line 559, in wrap_api_call\n raise rewrite_error(error, f\"{parsed_st['apiName']}: {error}\") from None\nplaywright._impl._errors.Error: Page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/\nCall log:\n - navigating to \"http://localhost:3000/\", waiting until \"networkidle\"\n\n"}>npm start{"chunk_id":"e6ec11","wall_time_seconds":1.001869959,"session_id":21439,"original_token_count":26,"output":"\n> apple-vs-jev@1.0.0 start\n> node server.mjs\n\nApple vs. Jev → http://localhost:3000 (Jev connected)\n"}>python3 - <<'PY'
from playwright.sync_api import sync_playwright
import json
with sync_playwright() as p:
browser = p.chromium.launch(executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', headless=True)
page = browser.new_page(viewport={'width':1440,'height':1000})
errors=[]
page.on('pageerror', lambda e: errors.append(str(e)))
page.goto('http://localhost:3000',wait_until='networkidle')
page.screenshot(path='artifacts/simple-desktop-start.png',full_page=True)
assert not page.locator('details').evaluate('(e) => e.open')
page.click('#start')
before=page.evaluate('window.gameSnapshot().state.apple')
page.keyboard.press('ArrowUp')
after=page.evaluate('window.gameSnapshot().state.apple')
assert after['y']==before['y']-1
page.wait_for_function('() => window.gameSnapshot().calls >= 2 || !window.gameSnapshot().running',timeout=20000)
result=page.evaluate('window.gameSnapshot()')
assert result['running'] and result['calls']>=2, result
page.screenshot(path='artifacts/simple-desktop-playing.png',full_page=True)
page.keyboard.press('p')
assert not page.evaluate('window.gameSnapshot().running')
page.click('summary')
assert page.locator('details').evaluate('(e) => e.open')
assert page.locator('#latency').inner_text() != '—'
page.click('#start')
assert page.evaluate('window.gameSnapshot().running')
page.keyboard.press('p')
mobile=browser.new_page(viewport={'width':390,'height':844},is_mobile=True,has_touch=True,device_scale_factor=2)
mobile.on('pageerror',lambda e: errors.append(str(e)))
mobile.goto('http://localhost:3000',wait_until='networkidle')
assert mobile.evaluate('document.documentElement.scrollWidth <= innerWidth')
mobile.screenshot(path='artifacts/simple-mobile.png',full_page=True)
mobile.click('#start')
before=mobile.evaluate('window.gameSnapshot().state.apple')
mobile.locator('[data-direction="up"]').tap()
after=mobile.evaluate('window.gameSnapshot().state.apple')
assert after['y']==before['y']-1
mobile.click('#pause')
assert not errors, errors
print(json.dumps({'desktop':'passed','mobile':'passed','liveDecisions':result['calls'],'keyboardAndTouch':'passed','pauseResume':'passed','errors':errors}))
browser.close()
PY{"chunk_id":"75b961","wall_time_seconds":1.001905,"session_id":4762,"original_token_count":0,"output":""}{"chunk_id":"8c8d23","wall_time_seconds":0.000017833,"exit_code":1,"original_token_count":23,"output":"Traceback (most recent call last):\n File \"<stdin>\", line 15, in <module>\nAssertionError\n"}{"chunk_id":"a0beda","wall_time_seconds":1.002710875,"session_id":29880,"original_token_count":0,"output":""}>python3 - <<'PY'
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
b=p.chromium.launch(executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',headless=True)
page=b.new_page(viewport={'width':1440,'height':1000})
page.goto('http://localhost:3000',wait_until='networkidle')
page.click('#start')
print('before',page.evaluate('window.gameSnapshot()'))
page.keyboard.press('ArrowUp')
print('after',page.evaluate('window.gameSnapshot()'))
print('overlay',page.locator('#overlay-copy').inner_text())
b.close()
PY{"chunk_id":"a0beda","wall_time_seconds":1.002710875,"session_id":29880,"original_token_count":0,"output":""}{"chunk_id":"2e2b04","wall_time_seconds":0.000007334,"exit_code":0,"original_token_count":133,"output":"before {'state': {'snake': [{'x': 5, 'y': 8}, {'x': 4, 'y': 8}, {'x': 3, 'y': 8}, {'x': 2, 'y': 8}], 'apple': {'x': 12, 'y': 8}, 'direction': 'right'}, 'running': True, 'elapsed': 0, 'catches': 0, 'calls': 0, 'tokens': 0}\nafter {'state': {'snake': [{'x': 5, 'y': 8}, {'x': 4, 'y': 8}, {'x': 3, 'y': 8}, {'x': 2, 'y': 8}], 'apple': {'x': 12, 'y': 7}, 'direction': 'right'}, 'running': True, 'elapsed': 0.033299999999999955, 'catches': 0, 'calls': 0, 'tokens': 0}\noverlay You hop one square at a time.Get eaten and you’ll respawn.\n"}>python3 - <<'PY'
from playwright.sync_api import sync_playwright
import json
with sync_playwright() as p:
browser = p.chromium.launch(executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', headless=True)
page = browser.new_page(viewport={'width':1440,'height':1000})
errors=[]
page.on('pageerror', lambda e: errors.append(str(e)))
page.goto('http://localhost:3000',wait_until='networkidle')
assert not page.locator('details').evaluate('(e) => e.open')
page.click('#start')
before=page.evaluate('window.gameSnapshot().state.apple')
page.keyboard.press('ArrowUp')
after=page.evaluate('window.gameSnapshot().state.apple')
assert after['y']==before['y']-1, {'before':before,'after':after,'state':page.evaluate('window.gameSnapshot()')}
page.wait_for_function('() => window.gameSnapshot().calls >= 2 || !window.gameSnapshot().running',timeout=20000)
result=page.evaluate('window.gameSnapshot()')
assert result['running'] and result['calls']>=2, result
page.screenshot(path='artifacts/simple-desktop-playing.png',full_page=True)
page.keyboard.press('p')
assert not page.evaluate('window.gameSnapshot().running')
page.click('summary')
assert page.locator('details').evaluate('(e) => e.open')
assert page.locator('#latency').inner_text() != '—'
page.click('#start')
assert page.evaluate('window.gameSnapshot().running')
page.keyboard.press('p')
mobile=browser.new_page(viewport={'width':390,'height':844},is_mobile=True,has_touch=True,device_scale_factor=2)
mobile.on('pageerror',lambda e: errors.append(str(e)))
mobile.goto('http://localhost:3000',wait_until='networkidle')
assert mobile.evaluate('document.documentElement.scrollWidth <= innerWidth')
mobile.screenshot(path='artifacts/simple-mobile.png',full_page=True)
mobile.click('#start')
before=mobile.evaluate('window.gameSnapshot().state.apple')
mobile.locator('[data-direction="up"]').tap()
after=mobile.evaluate('window.gameSnapshot().state.apple')
assert after['y']==before['y']-1
mobile.click('#pause')
assert not errors, errors
print(json.dumps({'desktop':'passed','mobile':'passed','liveDecisions':result['calls'],'keyboardAndTouch':'passed','pauseResume':'passed','errors':errors}))
browser.close()
PY{"chunk_id":"f54d1d","wall_time_seconds":1.002268417,"session_id":70390,"original_token_count":0,"output":""}{
"session_id": 70390,
"chars": "",
"yield_time_ms": 1000,
"max_output_tokens": 1500
}