ESAC · A DECISION ENDPOINT

Every program has a moment
where it has to decide.

Which team gets this ticket. Which tool to call next. Is this urgent, yes or no. esac is one endpoint for that moment: hand it what you know and the branches you are choosing between. It hands back the branch, and how sure it is.

A name, an idea, and one live endpoint · ask.esac.sh, best effort

The joke in the name

case "$ticket" in
  billing)  route billing ;;
  sales)    route sales   ;;
  retail)   route retail  ;;
esac   # where the case resolves
In the shell, case opens the block and esac closes it. Somewhere in between, the program commits to a branch.

The same decision, as a call

state:  "Help! My payouts have been
         failing for 3 days!"
ask:    which team? billing, sales, retail

-> billing   0.844
   retail    0.091
   sales     0.064
Real output, 2026-10-01, from Amazon's open-source Strands Decider running on a four-core box with no GPU. About two seconds once the model is loaded.

Ask it yourself

curl -s -X POST https://ask.esac.sh/v1/systemone \
  -H 'Content-Type: application/json' \
  -d '{
    "state": "...",
    "questions": {
      "team": {
        "type": "choice",
        "instructions": "...",
        "criteria": {
          "a": "...",
          "b": "..."
        }
      }
    }
  }'
Fill the three slots. state is what you know. instructions is the question. criteria is one line per branch, keyed by the name you want back. No key, no sign-up.

What comes back

// the payouts ticket above, asked this way
{
  "answers": {
    "team": {
      "type": "choice",
      "choice": "billing",
      "probabilities": {
        "billing": 0.9822,
        "sales":   0.0120,
        "retail":  0.0058
      },
      "confidence": 0.9733
    }
  },
  "latency_ms": 5419
}
Real response, 2026-10-05. The model runs warm on a four-core box with no GPU, one request at a time, best effort. Count on about six seconds, and keep the body under 64KB.

Pick a branch

Give it the options. Get a probability on every one of them, not a paragraph you have to parse. Bounded choices, one call.

Yes, no, or how much

A yes/no that comes back as a number between 0 and 1. A score against a rubric you wrote. Answers shaped like a type, so your code can act on them without a second model to read the first one.

Know when to ask a human

Every answer carries a confidence. High, act. Low, hand it to a person. That one number is the whole reason this class of model exists.

Under the hood

A new class of model appeared this fall: decision models. They cannot write a sentence. They take a state and a set of declared questions and return calibrated probabilities over the answers, in a single forward pass. TypeSafe shipped the first one, Jev. Amazon's Strands Labs open-sourced a two-billion-parameter one you can run yourself. OpenAI announced its own.

esac would be the thin layer in front of whichever you pick: three primitives, choice, score and a yes/no, over HTTP, with the backend swappable. Hosted when you want speed and scale. Local when the data cannot leave the building.

What it is not

It is not a product. There is no API key to ask for and no waitlist. What runs behind ask.esac.sh is one open model on one small box, serving one request at a time, with no promise it stays up. This page is the idea, written down before the rest of the code, so the name means something when the code arrives.

And the honest limit of the models themselves, measured rather than assumed: they answer a fully specified question well, and they are poor at finding a comparison you did not spell out. Treat a low confidence as a request for a human, not as an answer.