Probably – a programming language for LLM workflows, powered by Jev TypeSafe.ai released Probably 0.1, a small programming language for LLM workflows that is executed by a TypeScript interpreter and powered by Jev for judgments and probabilities. The language uses `feels` for confidence-thresholded yes/no judgments, `match` to choose among 2-8 descriptions, `llm` to call a text-generation model through Cloudflare AI Gateway, and `while`/`repeat` loops capped at five iterations. Probably 0.1 has no confidence gate on `match`, uses a default 50% threshold for `feels`, and lets users replay the last completed run without calling a model. probably∿ https://probably-lang.southpolesteve.workers.dev/ A small language for uncertain times. A programming language for LLM workflows, powered by Jev https://typesafe.ai/blog/introducing-system-one-models-and-jev . Determinism is overrated. Replay repeats the last completed run without calling a model. Download run JSON saves its source, input and decisions. Your output will appear here. Each judgment shows its probabilities and the exact value it saw. The language, in a few minutes. Probably 0.1 Probably is its own small language. A TypeScript interpreter executes the code; Jev https://typesafe.ai/blog/introducing-system-one-models-and-jev supplies judgments and probabilities. A separate text model generates prose. feels asks a question, match picks a description, and llm generates text. Run is a playground button, not a language keyword. Try the inbox department: Jev checks urgency and routes the email. Each branch gives the LLM a different reply strategy. A loop edits the tone, a confidence check flags uncertainty, and a final LLM call writes a subject from the finished reply. The last output is your draft. When running locally, change the input to a sales pitch or meeting request to see the route change. This example drafts replies; it does not send email. 1. Values, input and output let declares a variable. Assign again to update it. Values are strings, nonnegative numbers or booleans; comments start with // . input reads the input box and print adds a line to output. js let message = input let attempts = 3 let optimistic = true message = "Everything is probably fine." print message Variables belong to their block. Assignment can update a variable in an outer block. Strings use double quotes and escapes such as \n . Semicolons are optional. 2. Call a language model with llm llm sends an instruction to a text-generation LLM through Cloudflare AI Gateway and returns its response as a string. using passes the value to work on. Only that value is passed as context; the model does not see all your variables. js let draft = llm "Explain this in one sentence." using input print draft You can omit using when the instruction needs no context. print only displays a value; it never calls a model. Older programs can still use write as an alias for llm . 3. Make a judgment with if … feels feels compares a value with a quoted description. Normally the higher-probability yes/no answer wins. Add a confidence threshold to handle ambiguity explicitly. if message feels "genuinely urgent" with confidence 80% { print "Drop everything." } otherwise maybe { print "Ask a follow-up question." } else { print "It can wait." } At 80%, a 90% yes takes the first branch, a 90% no takes else , and a 60/40 split takes otherwise maybe . The threshold uses the winning answer’s probability. It is a model estimate, not a guarantee of truth. Thresholds range from 50–100%; the default is 50%. If you omit the maybe block, an uncertain result runs neither branch. 4. Choose a branch with match match asks Jev to choose among 2–8 distinct descriptions. The highest-probability label wins, even when no label is a great fit. Include an “other” label when useful. js match message { "a bug report" = { print "Investigate." } "a feature request" = { print "Add to the wishlist." } "something else" = { print "Ask a human." } } There is no confidence gate on match in 0.1. Ties use the first label; yes wins a tied if . 5. Keep trying with while and repeat while … feels asks Jev before every iteration, including after the last rewrite. repeat runs a fixed number of times without asking a model. while draft feels "full of corporate jargon" { draft = llm "Rewrite plainly." using draft } print draft repeat 3 { print "This is definitely helping." } While loops allow at most five iterations and report an error if the condition is still true. repeat accepts a literal integer from 1 to 5. The complete run also has a 12-model-call budget, so elaborate programs can hit that limit first. 6. Embrace chaos, then replay it Inside chaos , judgments sample from their probabilities. A 20% answer has a 20% chance of being chosen. Any confidence gate is checked before sampling. chaos { if input feels "a sensible business idea" { print "Fund it." } else { print "Fund it, but ironically." } } Hosted examples stream the same cached results on each run. Locally, Run again makes fresh calls and may produce the same result. Replay uses the last completed run’s original source, input, model results and random draws. It makes no model calls. Download run JSON saves that recording; replay a saved file locally with bun run run --replay recording.json . Recordings contain your input and generated text. What 0.1 supports—and where it stops This is an experimental language for playful workflows. It has no arithmetic, arrays, objects, functions, imports, network tools or JavaScript execution. feels is a condition inside if or while , not a standalone expression. The .prob extension simply identifies a Probably source file; filenames do not affect execution. Runs stop at 12 model calls, 200 statements or 90 seconds. Source is limited to 12,000 characters, input to 6,000 and nesting to 12 blocks. Errors stop the program; earlier output remains visible. Stop cancels interpretation, although an already-dispatched model request may still finish remotely. The hosted Worker streams previously recorded Jev judgments and generated text for the exact bundled examples. Custom code or inputs have no cached result and are rejected without calling a model. Run locally to execute your own programs with live providers. Run it yourself. Download source ↓ https://probably-lang.southpolesteve.workers.dev/probably-source.zip Run the live interpreter locally, or deploy the cached playground to Cloudflare Workers https://developers.cloudflare.com/workers/ . Local model calls use AI Gateway https://developers.cloudflare.com/ai-gateway/get-started/ . 1. Get the code and connect Cloudflare.Install Bun https://bun.sh/ , download and unzip the source, then open its folder in your terminal. In your Cloudflare account, create an AI Gateway called default . Add Gateway credits or a Jev provider key https://developers.cloudflare.com/ai-gateway/configuration/bring-your-own-keys/ with alias default so Jev can run. cd probably bun install 2. Run locally.Copy the example settings, then open .env and fill in your Cloudflare account ID and API token. Use the permissions in the Gateway setup guide https://developers.cloudflare.com/ai-gateway/get-started/ . Keep GATEWAY ID=default . cp .env.example .env bun run dev Open the localhost URL printed in your terminal. The interpreter runs on your machine; the models run remotely. 3. Deploy to Cloudflare.Choose a unique Worker name in wrangler.jsonc , then run: bunx wrangler login bun run deploy This deploys the cached playground. The Worker streams bundled recordings and requires no model bindings or provider credentials. Use the local server or CLI for live model execution. The source includes the interpreter, playground, examples, tests and a full README. Model calls use your Cloudflare or provider account’s quota and billing.