evoke

Install evoke and run your first command.

Natural-language commands for small programs you install. A reflex is a small program you install and ask for in your words. Pick a route below: the evoke CLI on macOS or Linux, or the SDK in a Node app. Each ends when a sentence you type runs a reflex.

Each button switches every step below.

Change the example →

  1. What you need before you start

    • macOS or Linuxevoke runs on both. The collection, fifteen ready-made reflexes this route adds, is for a Mac. On Linux, install evoke in step 2, skip the collection, and start with a command you already run. Wrapping it takes one short file, with no code and no Node.
    • Node 24 or newerThirteen of the fifteen run a JavaScript file, so install Node before you add them. The other two run a command the Mac already has, and need no Node. Neither does a reflex you write around a command.
    • gitevoke add fetches reflexes from a git repository. Your own git settings and credentials apply.
    • Node 24.5 or newerYour project also needs ES modules: "type": "module" in package.json, or .mts files.
    • git, for reflexes from a repositoryOnly when you install reflexes from a git repository into your app's folder. The file in step 2 defines its reflex in code, so it needs no git.
    • A classifier keyA classifier reads each sentence you type: Jev, TypeSafe AI's model. It answers which reflex you mean and which value fills each input, with a probability for each. It needs an API key from TypeSafe AI, set as TYPESAFE_API_KEY. TypeSafe AI says Jev is most accurate in English.

    Get a key from TypeSafe AI, at typesafe.ai. A TypeSafe AI key you already hold works here. Copy it: the next step puts it in your shell.

    evoke is free and open source. Each time evoke decides what a sentence asks for, it sends one request to the classifier. The classifier's provider bills that request to the account your key belongs to. In the terminal, a sentence you repeat is answered from a local cache, with no request. evoke never contacts evoke.build, and there is no evoke account. What a decision costs →

  2. Set your key and install evoke

    Set the key. Put your key in place of <value>. evoke reads it only when it sends a sentence to the classifier, and never writes it to a file. The line lasts until you close this terminal. To keep it, add it to your shell's startup file, such as ~/.zshrc.

    export TYPESAFE_API_KEY=<value>

    Install the CLI. The script fetches the release built for your machine, checks it against the release's checksums, and puts evoke in ~/.local/bin. If that folder is not on your PATH, the script's last lines print the command that adds it.

    curl -fsSL https://evoke.build/install.sh | sh

    Add the collection. This line fetches fifteen reflexes for a Mac from git, and pins each one to its version. Install Node first, because evoke add records where it is.

    evoke add evoke-build/reflexes

    It prints one row per reflex. note, open and visit stay inactive until you give them a notes file, a folder and a site. Until then, no sentence reaches them. A line under the rows names the command that gives each one what it needs. The other ten work at once. A reflex runs as you, held by the kernel to what its manifest declares, so read what you add: every file of the collection is public.

    On Linux, skip this line. The collection is for a Mac. Wrap a command you already run instead, then use steps 3 and 4 with a sentence that asks for it. A reflex around a command, in the manual →

    Set the key. Put your key in place of <value>. The SDK reads it from the environment only when it sends a sentence to the classifier. The line lasts until you close this terminal.

    export TYPESAFE_API_KEY=<value>

    Install the SDK. It carries evoke's core as WebAssembly, so it has no build step and no dependencies.

    npm install @evoke-build/evoke

    Write one file. It defines a reflex in code, so no reflex files are needed. One call then decides, asks, confirms and runs.

    app.ts
    import { load, reflex } from "@evoke-build/evoke"
    import { jev } from "@evoke-build/evoke/jev"
    
    const timer = reflex({
      description: "Start a countdown timer.",
      effect: "write",
      confirm: "Start a {duration} timer?",
      args: { duration: { ask: "How long?", pick: "duration" } },
      examples: { "timer for 10 minutes": { duration: "10 minutes" } },
    }, async ({ duration }) => {                       // duration: number, in seconds
      setTimeout(() => console.log("ring"), duration * 1000)
      return `ringing in ${duration} s`
    })
    
    const project = await load({ reflexes: { timer }, adapter: jev() })
    const handled = await project.handle(process.argv[2] ?? "", {
      confirm: async d => { console.log(d.prompt.template); return true },
      ask: async d => ({ duration: "10 minutes" }),
    })
    console.log(handled.outcome === "ran" ? handled.result.text : handled.outcome)

    To stay short, this file answers evoke's questions itself. Your app would ask the person using it.

  3. See the decision before anything runs

    evoke try decides and runs nothing. It prints the classifier's answers: which reflex, each input, and what would happen.

    evoke try "kill the wifi"
    evoke try
      which reflex            wifi 0.95   (none of them 0.03 · power 0.01)
      state                   off 0.86   (on 0.10 · not said 0.04)
      → waits for a yes: wifi state="off" · write · weakest: state 0.86
        a write runs at 0.90 or more

    Turning Wi-Fi off changes something, so wifi is a write reflex. A write runs without a question only when evoke is at least 0.9 sure of every answer. That is its bar. Here the least sure answer is 0.86, so this sentence would ask you first. Try a sentence of your own the same way. Nothing runs.

    evoke printed these lines in one of its own tests, from answers written for it, after note and open were set up. The numbers the classifier gives you will differ.

    decide() makes a decision and runs nothing. It is the first thing handle() does. To see one on its own, add these lines to app.ts after load(). The result is a typed union: narrow it by outcome, then by reflex. When the decision is to run, these lines print the call and how sure evoke is.

    decide only
    const d = await project.decide("timer for 10 minutes")
    if (d.outcome === "run") console.log(d.call, d.confidence)
  4. Run your first command

    Type what you want, in quotes after evoke. It prints the call it chose and how sure it is. Then the reflex prints what it did.

    evoke "set the volume to 40 percent"
    evoke
      volume level="40 percent"  0.96
    volume 40%

    In this test run, 0.96 cleared the bar of 0.9, so it ran without asking. The last line, volume 40%, is your first result. Your number may differ. Under 0.9, evoke asks first, with [y]es [n]o [t]each. Typing t saves your sentence as an example in your own file, then runs it.

    Run the file with a sentence. handle() decides, asks for anything missing, confirms, and runs. The file prints what the timer returned, and the timer rings ten minutes later. The program stays open until then, so press Ctrl-C to end it sooner.

    node app.ts "timer for 10 minutes"
  5. Set up your example

When a step stops, evoke prints the fix.

When evoke stops because it needs something from you, it prints one line. The line ends with the command that fixes it, and evoke exits with code 3. These are the cases a first run meets. In the SDK, the same line is the message of a DiagnosticError.

Your shell cannot find evoke.

The script put evoke in ~/.local/bin, and that folder is not on your PATH yet. The script's last lines print the export PATH=… line that adds it. Run that line, and add it to your shell's startup file to keep it.

evoke prints that it needs TYPESAFE_API_KEY.

evoke
$ evoke "lock the screen"
  jev needs TYPESAFE_API_KEY, a key from typesafe.ai  →  export TYPESAFE_API_KEY=<value>
[3]

The key is not set in this terminal. An exported variable lasts only in the terminal where you set it, so export it again. To keep it, add the line to your shell's startup file. The [3] in the panel is the exit code: evoke needs something from you.

evoke prints that no reflexes are installed.

Nothing is installed yet. Add the collection with evoke add evoke-build/reflexes, the command the line ends with. On Linux, add a reflex of your own instead.

evoke add reports that Node is missing.

Thirteen of the collection's reflexes run JavaScript files, and evoke add records where Node is. Install Node 24 or newer, then run evoke sync. It records Node, and the reflexes can run.

How evoke finds Node, in the manual →

A reflex is listed as inactive.

This line is a notice, not a stop. The add still succeeds. The reflex needs a word or a setting of yours, such as a folder or a notes file. Until it has one, it stays out of every decision. Its line ends with the command that gives it what it lacks.

You have no key yet.

Installing needs no key. evoke run runs a reflex by name, with no classifier, so no key is read: evoke run volume level=40. Typing a sentence needs the key. Meanwhile, every example page shows a session evoke printed, and needs no key.

Run by name, in the manual →

Once your first command runs, the manual goes further.

It takes the same first run further. It adds settings for a reflex, a look inside any decision, and where your files live.

It starts from the same file. Then it adds reflexes from files, what each outcome of a decision means, and tests that run offline after one recording.