A Go library and CLI for decision models: ask typed questions, get answers with probabilities.
- Go library:
go get github.com/deepnoodle-ai/decide, then ask typed questions from your program. Jump to the Go guide. - CLI:
brew install deepnoodle-ai/tap/decide, then ask questions about files, folders, JSON records, diffs, and text from your shell or CI. Jump to the CLI.
Docs: decide.deepnoodle.ai, with a quickstart, tutorials, and the reference. Agents can start with the agent guide.
brew install deepnoodle-ai/tap/decideOr go install github.com/deepnoodle-ai/decide/cmd/decide@latest, or
download a binary from the releases.
A decision model answers typed questions instead of generating text.
Decide asks yes-or-no (noul), multiple-choice (choice), and scale
(score) questions, and each answer comes back typed, with a
probability, so a script or a program can act on it directly. There is
no prose to parse.
Decide works with Jev on the TypeSafe API, Clef on Cloudflare Workers AI, GPT-6 Luna on OpenAI's Decisions API, and any other service that speaks the Jev API, with the same commands and the same Go code. Switch between them without changing anything else:
| Jev by TypeSafe | Clef by Cloudflare | GPT-6 Luna by OpenAI | |
|---|---|---|---|
| Models | jev-latest |
clef, and clef-flash for lower latency |
gpt-6-luna |
| Runs on | the TypeSafe API | Cloudflare Workers AI | the Decisions API, in beta |
Clef's weights are open on Hugging Face under Apache 2.0.
With Jev, the default, set your TypeSafe API key:
export TYPESAFE_API_KEY=...
echo "The new release fixed everything I cared about" | decide run sentimentWith Clef, set a Workers AI API token and your account ID, and choose the Cloudflare provider:
export CLOUDFLARE_AUTH_TOKEN=...
export CLOUDFLARE_ACCOUNT_ID=...
export DECIDE_PROVIDER=cloudflare # or pass --provider cloudflare
echo "The new release fixed everything I cared about" | decide run sentimentWith GPT-6 Luna, set your OpenAI API key and choose the OpenAI provider:
export OPENAI_API_KEY=...
export DECIDE_PROVIDER=openai # or pass --provider openai
echo "The new release fixed everything I cared about" | decide run sentimentWith another Jev-compatible service, such as one you host yourself, set its address and a model name:
export TYPESAFE_API_KEY=...
export TYPESAFE_BASE_URL=https://decisions.example.com
echo "The new release fixed everything I cared about" | decide run sentiment --model my-modelYou get a typed answer with its probability. With Jev, the output looks like this; the first line names whichever provider and model you chose:
Running sentiment on 1 line · typesafe jev-latest
stdin:1 The new release fixed everything I cared about
sentiment positive 94%
✓ 1 answered nothing flagged 1.2s
See these results again with: decide runs view 20261002-153012-a1b2
Building from source requires Go 1.27 or later. Run decide on its own for
a tour.
Decide comes with eleven templates. A template is a named set of questions.
| Template | Asks about each item |
|---|---|
sentiment |
Is it positive, negative, or neutral? |
triage |
Is this support request urgent, and how severe is its impact? |
ticket-routing |
Does this support ticket belong to billing, engineering, or other? |
relevance |
Is it relevant to a question you choose? |
code-risk |
Could it cause security or data problems, and how maintainable is it? |
security |
Can untrusted input reach a SQL query, a command, a fetched URL, or a page, and is any cryptography weak? |
prompt-injection |
Does it try to take over an AI agent that reads it? |
task-readiness |
Is this issue ready to hand to a coding agent, and how large is it? |
pr-description |
Do this pull request's title and description meet your guidelines? |
command-risk |
Could this shell command destroy work, expose secrets, deploy or publish, or cause severe harm? |
receipt-quality |
Does this image show a readable receipt? Runs on Clef. |
decide run code-risk src --include '*.go'
decide run security src # injection, SSRF, XSS, weak crypto
decide run relevance docs --each section -p question="pricing"
decide runs view --format csv > results.csv
decide runs view --top 20 # the 20 items nearest their flags, flagged first
decide run code-risk src --fail-on flagged # exit code 2 if anything is flagged
git diff main | decide run code-risk --each function # judge each changed function
git diff main | decide run prompt-injection # hidden instructions for AI agents
gh issue list --json number,title,body | decide run task-readiness
gh pr view 42 --json number,title,body | decide run pr-description --fail-on flagged
echo 'git reset --hard HEAD~3' | decide run command-risk # before an agent runs itDecide reads JSONL, JSON, CSV, text, Markdown, source code, diffs, and images,
flags answers that need attention, and resumes stopped runs. It keeps
every answer, by the model name you ask for, so a second run asks only
about what changed, and asks again when a live answer shows the model
behind the name changed. It prints
text, JSON, CSV, a Markdown report, or GitHub Actions annotations on a pull
request. To try the templates on planted problems, see
demo. You can write your own template in a few lines of
JSON with decide templates new. The reference
covers it all. The tutorials
and recipes show it in GitHub Actions, other CI
systems, and git hooks.
go get github.com/deepnoodle-ai/decideCreate a client for Jev:
client, err := decide.NewClient() // reads TYPESAFE_API_KEY and TYPESAFE_BASE_URLFor another Jev-compatible service, pass decide.WithBaseURL and
decide.WithModel. Or create a client for Clef:
client, err := backend.NewClient(backend.Config{
Provider: backend.Cloudflare,
APIKey: os.Getenv("CLOUDFLARE_AUTH_TOKEN"),
AccountID: os.Getenv("CLOUDFLARE_ACCOUNT_ID"),
Model: "clef", // or "clef-flash"
})Or for GPT-6 Luna, with Provider: backend.OpenAI and
APIKey: os.Getenv("OPENAI_API_KEY"). Then ask a question the same way
with any of them:
e, err := decide.Eval(ctx, client, ticket, decide.Noul("Is this about billing?"))
if err != nil {
return err
}
fmt.Println(e.Answer.Noul) // the probability of yes, such as 0.97To ask a built-in template's questions, use the
templates package. You get its tuned wording and flags, and
they change when you upgrade decide:
req := decide.NewRequest(command)
severe := decide.Ask(req, "severe", templates.CommandRisk.Noul("severe"))
resp, err := client.SystemOne(ctx, req)
if err != nil {
return err
}
a, err := severe.From(resp)
if err != nil || templates.CommandRisk.Flagged("severe", a) { // yes >= 80%, as in decide run
// stop the command
}Every answer is validated against its question, and transient failures
are retried. The package documentation
covers asking several questions at once, Pick, and test fakes in
decidetest. Packages under patterns/, such as gate,
rank, and funnel, build common decisions from answers. The
examples show each one in a short program.
The decide plugin gives Claude a second opinion. It checks content from outside before Claude acts on it and, in bypass mode, each shell command before it runs, and it gives Claude a judge tool for its own typed questions. In Claude Code:
/plugin marketplace add deepnoodle-ai/decide
/plugin install decide@decide
The Claude Code guide shows how to set it
up and use /decide:audit and /decide:hunt. See plugin/README.md
for what each check does and what it sends.
Decide is young. Before v1, the library API and the CLI may change in any release.
Issues and pull requests are welcome. Please read CONTRIBUTING.md first, and report security issues as described in SECURITY.md.
