Jacquard
Core 0.3.0 · research prototype agents → SKILL.md · llms.txt

A programming language for code that models write and people review.

When a model hands you a change, Jacquard answers three questions before you read a function body:

  1. What can this change touch? The checked signature lists every effect, and the runtime refuses any you have not granted.
  2. What will it do where you can't look? Run the same code against a snapshot, an exact probability model or every case.
  3. Is what I approved still what runs? An approval names a hash that survives reformatting and breaks on any real edit.
curl -fsSL https://raw.githubusercontent.com/jbwinters/jacquard-lang/jacquard-core-0.3.0/scripts/install.sh | sh

Installs Core 0.3.0 (7 October 2026) to ~/.local on Linux x86-64 or macOS, with checksums verified. No OCaml needed.

New here? Read why a language, or the introduction on FriendMachine Research.

01 · what can this change touch?

The answer is on the first line of the diff.

A model edits a function that cleans up display names. In most languages, finding out whether the change can reach the network means reading everything it calls. In Jacquard the checker infers every function's effect row, and the row is part of the signature.

--- a/normalize.jac
+++ b/normalize.jac
@@ -1,3 +1,6 @@
 -- Clean up a display name before it is stored.
-normalize-name : (Text) ->{} Text
-normalize-name(name) = text.trim(name)
+normalize-name : (Text) ->{Net} Text
+normalize-name(name) = text.trim(lookup-alias(name))
+
+lookup-alias : (Text) ->{Net} Text
+lookup-alias(name) = net.get(text.concat("https://aliases.example/", name))
$ jac check after.jac --print-sigs
lookup-alias : (Text) ->{Net} Text
normalize-name : (Text) ->{Net} Text

The new {Net} is not a comment the model chose to write. The checker computed it from lookup-alias, and a signature that left it out would not check. Until someone grants network access, the runtime refuses to run the change:

$ jac run run.jac
error[E0814]: The program requires an effect that was not granted
  Cause: This program requires net [world/high] — reach a network endpoint through the granted handler, which is not granted (performed via `normalize-name`).
  Next step: grant it with --allow net, or handle the effect in the program
[exit status 3]

This is language-level enforcement in a research runtime. It constrains Jacquard programs; it does not replace an operating-system sandbox.

Review the whole change, from diff to approval →

02 · what will it do where you can't look?

Run the same code against worlds you cannot reproduce.

A release policy is written once against a Telemetry effect. A handler answers the program's requests to the outside world. An injected dependency is a handler that resumes the program once; a Jacquard handler may also resume it never or many times. So the same policy can run against today's readings, against an exact probability model, and against every combination of readings.

multi effect Telemetry where {
  inventory-health : () -> Health
  payments-health : () -> Health
  error-spike? : () -> Bool
}

-- A pure, reviewable release policy.
decide : (Health, Health, Bool) ->{} Decision
decide(inventory, payments, spike) =
  match (inventory, payments, spike) {
    | (_, Down, _) -> Hold("payments-down")
    | (_, Degraded, _) -> Canary(5)
    | (Down, Healthy, _) -> Hold("inventory-down")
    | (Degraded, Healthy, _) -> Canary(10)
    | (Healthy, Healthy, True) -> Canary(5)
    | (Healthy, Healthy, False) -> Ship
  }

release-assessment : () ->{Telemetry} Assessment
release-assessment() = {
  let inventory = inventory-health()
  let payments = payments-health()
  let spike = error-spike?()
  Assessment(inventory, payments, spike, decide(inventory, payments, spike))
}

A fixed snapshot

A handler that answers each reading from today's values.

assessment(healthy, degraded, false, canary(5))

An exact probability model

Given an observed checkout failure, which decisions could the policy have made, and how likely was each? Enumeration lists every one with its exact probability.

0.305077  canary(5)
0.295394  hold("inventory-down")
0.184621  canary(10)
0.155903  hold("payments-down")
0.059005  ship

Every world, checked

Warp, Jacquard's test framework, checks the safety property in all 18 combinations of the readings instead of a sample.

PASS release-risk-suite/release risk/the concrete snapshot chooses a five-percent canary (1 check)
PASS release-risk-suite/release risk/the conditioned posterior is normalized with five decisions (2 checks)
PASS release-risk-suite/release risk/a down service is never approved to ship (verified exhaustively (18 cases))
3 passed, 0 failed, 0 skipped, 0 refused

Output of demos/case-studies/release-risk/run.sh from the 0.3.0 install, re-checked by scripts/verify_examples.sh. Walk through it →

03 · is what I approved still what runs?

An approval survives reformatting and breaks on any real edit.

Jacquard hashes the canonical resolved structure of each definition (SHA-256). Comments, layout and local names are erased, and every definition it calls is included by its own hash. An approval that names the hash survives an agent reformatting the code. Any structural change, in the definition or in anything beneath it, produces a new hash that needs a new approval.

greet(name) = {
  println(text.concat("hello ", name))
  text.length(name)
}

greet("reviewer")
-- Same function: a comment, a new parameter name, a new layout.
greet(who) = { println(text.concat("hello ", who))
               text.length(who) }

greet("reviewer")
greet(name) = {
  println(text.concat("hi ", name))
  text.length(name)
}

greet("reviewer")
Hash of greet from jac hash, first 12 of 64 hex digits
VersionHash
Original
greet.jac
451680d275e1
Reformatted, renamed, commented
greet-reformatted.jac
451680d275e1
Edited: says hi instead
greet-edited.jac
45cfe66faa1e

Equal hashes mean equal canonical structure. They say nothing about whether two different programs behave alike.

04 · for agents

Built to be learned from one file.

SKILL.md covers installing Jacquard and writing, checking, running, testing and compiling programs, and loads as a skill in coding agents. Every diagnostic carries a stable code, a cause and a next step, also available as JSON with --diagnostic-format json-v1.

Set up Claude Code, Codex or another agent →

05 · in your application

Keep the decision in Jacquard and the I/O in your service.

Jacquard Host calls checked Jacquard functions from Python, TypeScript or Go. The function's effect row says which services the application must provide; you bind each effect to an ordinary object, and a missing one is refused before anything runs.

from jacquard_host import Runtime


class Warehouse:
    def __init__(self, counts):
        self.counts = counts

    def on_hand(self, sku):
        return self.counts.get(sku, 0)


program = Runtime().prepare("reorder.jac")
reorder = program.function("reorder", effects={"Stock": Warehouse({"bolt": 12})})

print(reorder("bolt", 40))
print(reorder("nut", 40))

See the policy and the refusal →

06 · the boundary

What 0.3.0 is, and is not.

  • A research prototype with a checker, an interpreter, a native compiler via C, a standard library and the Warp test framework.
  • No real network adapter ships; examples run against stubs, scripted responses, recorded traces and probability models.
  • Exact inference is finite and discrete. Exhaustive checks are exhaustive only within their declared bounds.
  • Native binaries cover a documented subset: no dynamic eval, interpreted tasks or typed channels.
  • No package manager, no formal soundness proof, no continuous distributions.
  • The surface syntax is an evolving v0; future releases may not parse every program unchanged.

Read the full limits · bounded claims · release notes