Examples · 01 of 06
Run everyday Mac tasks from the terminal, in plain words.
Type "set the volume to 40 percent" in your terminal, and evoke sets it. A reflex is a small program you install and ask for in your words. Fifteen reflexes for everyday Mac tasks install with one line. This example runs today on a Mac, and every file is on GitHub.
The request and the result
01Three sentences, three outcomes.
A volume change runs at once. A less certain request asks first, and can keep your phrase as an example. A restart asks every time.
- 1Sure enough, so it ran. «40 percent» is a number read from your sentence and checked against the range 0 to 100. The least sure answer was 0.96, and a change runs without a question at 0.9 or above.
- 2«kill» meant off, but only at 0.86. Under 0.9, so evoke asked first. Typing
t, for teach, saved your phrase as an example in a file of yours, then ran. - 3Sure at 0.98, and it still asked. Its author marked
powerdestructive, so it asks every time. No number and no flag skips that question.[2]means you answered no.
Every line is from a session in evoke's tests, which run on every change. The classifier's numbers in it come from a file written for the test, so yours will differ. How sure evoke must be to run →
The collection
02What each of the fifteen reflexes does.
Together they are evoke's collection, and one command installs them all. Each prints one short line about what it did.
| Reflex | What it does | Effect |
|---|---|---|
awake | Keeps the laptop awake for a while, or until you stop it. | write |
download | Saves a file from a URL to your Downloads folder, or to one of your folders. | write |
lock | Locks the screen. | write |
mail | Starts an email in your mail app. Nothing is sent until you press send. | write |
note | Adds a dated line to your notes file. | write |
open | Opens one of your folders. | read |
power | Restarts the laptop or shuts it down. | destructive |
screenshot | Captures the screen, a window or a selection. | write |
sleep | Puts the laptop to sleep. | write |
sound | Mutes or unmutes, or turns the volume up or down. | write |
timer | Counts down, then rings. | write |
trash | Empties the trash. | destructive |
visit | Opens one of your sites, in a private window if you ask for one. | read |
volume | Sets the output volume. | write |
wifi | Turns Wi-Fi on or off. | write |
- 1The effect sets the bar. A reflex that only reads runs without a question at 0.8 or above, one that writes at 0.9, and a destructive one always asks.
- 2Three start inactive.
openneeds your folders,visityour sites andnoteyour notes file. Step 5 below gives them what they need. - 3Twelve run a JavaScript file, so they need Node 24 or newer.
openandtrashrun a program the Mac already has.
Inside one reflex
03A reflex is a manifest, and usually a short program.
This is volume. The manifest says what it does and what to ask you. The program runs one
AppleScript command. Ten others are built the same way. open and trash are a
manifest alone, which names a program the Mac already has.
reflex = 1 description = """ Set the output volume to a percentage. From 0, silent, to 100, for everything the laptop plays.""" not_for = [ "muting or unmuting", "turning it up or down by an amount", "one app's volume", "changing the screen brightness", "asking what the volume is", ] tags = ["sound"] effect = "write" confirm = "Set the volume to {level}?" run = "volume.mts" platforms = ["macos"] [needs] runs = ["osascript"] [args.level] ask = "How loud, in percent?" pick = "number" range = [0, 100] [examples] "set the volume to 35 percent" = { level = "35 percent" } "volume 60%" = { level = "60%" } "bring the sound up to seventy" = { level = "seventy" } "drop the volume to 20 percent" = { level = "20 percent" } "set the volume to 40" = { level = "40" } "turn the sound down to 10" = { level = "10" } "mute the sound" = false [tests] "put the volume at 100 percent" = { level = "100 percent" } "make the speakers twenty five percent" = { level = "twenty five percent" } "lower the volume a little" = false "set the volume for me" = { level = false } "unmute my speakers" = false "turn the brightness up to 70" = false "how loud is it right now" = false
// Set the output volume through AppleScript: `set volume output volume <0–100>`. import { execFile } from "node:child_process" import { promisify } from "node:util" import type { Reflex } from "./reflex.d.ts" const exec = promisify(execFile) export default (async ({ level }, { signal }) => { const percent = Math.round(level) // The one value written into AppleScript source: an integer, so it can only ever be digits. if (!Number.isInteger(percent)) throw new Error(`level ${level} is not a number`) if (process.platform !== "darwin") throw new Error("runs on macOS only") try { await exec("osascript", ["-e", `set volume output volume ${percent}`], { signal }) } catch (error) { if (signal.aborted) throw signal.reason throw new Error(said(error) ?? "the volume did not change") } return `volume ${percent}%` }) satisfies Reflex /** What a failed command said on stderr, when it said anything; else nothing, and the caller's own words stand. */ function said(error: unknown): string | undefined { const text = typeof error === "object" && error !== null && "stderr" in error ? error.stderr : undefined return typeof text === "string" && text.trim() !== "" ? text.trim() : undefined }
- 1The manifest is how you ask for it. A description, what it is not for, one input read as a number from 0 to 100, and example sentences.
- 2The program checks the platform first. On another system it stops at once and
says it runs on macOS only. On a Mac it runs
osascriptand returns one line. - 3Every file is on GitHub. The collection is MIT-licensed, so you can copy a script into a reflex of your own.
One boundary
04A value outside its range never reaches the program.
The manifest gives the volume a range of 0 to 100. Your sentence chooses the value. evoke checks it against the range before the program sees it.
$ evoke "set the volume to 150 percent" How loud, in percent? 150 percent is outside 0–100 > 40 volume level="40" 0.96
evoke asked the input's own question, with the reason on the same line. Your answer was checked
the same way, then volume ran with 40. evoke guarantees that every value is one the reflex allows.
It cannot guarantee that it read you right, which is why a bar decides what runs without a question.
When evoke asks for a value, in the manual →
What can run, and what cannot →
Set it up
05Set it up on your Mac, from nothing to your first sentence.
Seven steps in your terminal. Every output line below comes from a session in evoke's tests. If a step stops, the line it prints ends with the command that fixes it. Each stop and its fix, on Get started →
- macOSThe collection's programs are for a Mac. evoke itself also runs on Linux.
- Node 24 or newerThirteen of the fifteen reflexes run a JavaScript file.
- git
evoke addfetches the collection from GitHub, at its newest version. - A key from TypeSafe AIFor Jev, the classifier that reads your sentences. TypeSafe AI bills each request to your key.
- Your words, for three reflexesA folder, a site and a notes file. Optional, and one line each.
-
Install evoke
The script downloads the release built for your Mac, checks it against the release's checksums, and puts evoke in
~/.local/bin. If it prints a line that begins «add it to your PATH», run the command on that line first.curl -fsSL https://evoke.build/install.sh | sh -
Give evoke a key
The classifier that reads each sentence is Jev, TypeSafe AI's model. Without a key, your first sentence stops and names the one it needs.
[3]means evoke needs something from you.evoke$ evoke "lock the screen" jev needs TYPESAFE_API_KEY, a key from typesafe.ai → export TYPESAFE_API_KEY=<value> [3]
Get a key from TypeSafe AI, then export it. evoke reads it from your shell when it decides, and never writes it to a file. Each decision is one request, billed to your key, and a sentence you repeat is answered from a local cache.
export TYPESAFE_API_KEY=<value> -
Have Node 24 or newer
Twelve reflexes run a JavaScript file, so
evoke addlooks fornodeon yourPATHand records where it is. Install Node 24 or newer from nodejs.org first. If you install it later,evoke syncrecords it. -
Install the collection
Each row names a reflex, where it came from and at which version, its effect, and what it runs. Your rows show the collection's newest version. No code runs while it installs.
evoke$ evoke add evoke-build/reflexes + awake evoke-build/reflexes/awake 0.1.0 write runs awake.mts + download evoke-build/reflexes/download 0.1.0 write runs download.mts + lock evoke-build/reflexes/lock 0.1.0 write runs lock.mts + mail evoke-build/reflexes/mail 0.1.0 write runs mail.mts + note evoke-build/reflexes/note 0.1.0 write runs note.mts + open evoke-build/reflexes/open 0.1.0 read runs open + power evoke-build/reflexes/power 0.1.0 destructive runs power.mts + screenshot evoke-build/reflexes/screenshot 0.1.0 write runs screenshot.mts + sleep evoke-build/reflexes/sleep 0.1.0 write runs sleep.mts + sound evoke-build/reflexes/sound 0.1.0 write runs sound.mts + timer evoke-build/reflexes/timer 0.1.0 write runs timer.mts + trash evoke-build/reflexes/trash 0.1.0 destructive runs osascript + visit evoke-build/reflexes/visit 0.1.0 read runs visit.mts + volume evoke-build/reflexes/volume 0.1.0 write runs volume.mts + wifi evoke-build/reflexes/wifi 0.1.0 write runs wifi.mts inactive note: config "file" is not set → evoke config note file <value> inactive open: vocabulary "places" is empty → evoke vocab places add <word> "<meaning>" inactive visit: vocabulary "sites" is empty → evoke vocab sites add <word> "<meaning>"
A reflex runs as you, held by the kernel to what its manifest declares, the line under each row. Read what you install: every file is on GitHub.
-
Give three reflexes your words
The inactive lines above each end with the command that fixes them. In the first line,
desktopis your word and «The desktop.» its meaning, which the classifier reads. The path goes only to the reflex. The notes file is a path under your home.evoke$ evoke vocab places add desktop "The desktop." --value "~/Desktop" + vocab/places.toml desktop = { what = "The desktop.", value = "~/Desktop" } $ evoke config note file "~/notes.txt" + evoke.toml [config.note] file = "~/notes.txt"
For
visit, add a site the same way:evoke vocab sites add github "GitHub." --value https://github.com -
Look at a decision before it runs
evoke trydecides and runs nothing. It shows which reflex, each value with what it stands on, and what would happen: here, 0.86 is under 0.9, so it would ask first.evoke try$ evoke try "kill the wifi" "kill the wifi" which reflex wifi 0.95 (none of them 0.03 · power 0.01) Turn Wi-Fi on or off. state off 0.86 (on 0.10 · not said 0.04) asked a second way: off 0.86; the less sure of the two counts is it off? yes 0.95 → waits for a yes: wifi state="off" · write · weakest: state 0.86 a write runs at 0.90 or more
-
Type your first sentence
The indented line is evoke's own: the call it chose, and how sure it was. The last line is the reflex's result.
evoke$ evoke "set the volume to 40 percent" volume level="40 percent" 0.96 volume 40%
Next, teach evoke a phrase of yours, or wrap a script of your own. The manual's first ten minutes carry on from here.