Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The first ten minutes

Ten minutes, from an empty machine to a reflex that learned a phrase of yours. Every output line below is what the terminal shows.

1. Say something

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

Two things happened. evoke wrote your home project: the file ~/.config/evoke/evoke.toml, with one line, adapter = "jev". And it told you the one thing it needs. [3] is the exit code. It means needs a human. Export the key and try again:

$ evoke "lock the screen"
  no reflexes are installed  →  evoke add evoke-build/reflexes
[3]

2. Install the collection

evoke-build/reflexes is the first-party collection: fifteen reflexes for what a Mac does at a word. Installing a repository installs every reflex in it.

$ evoke add evoke-build/reflexes
+ awake       evoke-build/reflexes/awake 0.1.0       write        runs awake.mts
              needs runs caffeinate
+ download    evoke-build/reflexes/download 0.1.0    write        runs download.mts
              needs writes {to} ~/Downloads · hosts *
+ lock        evoke-build/reflexes/lock 0.1.0        write        runs lock.mts
              needs runs open
+ mail        evoke-build/reflexes/mail 0.1.0        write        runs mail.mts
              needs runs open
+ note        evoke-build/reflexes/note 0.1.0        write        runs note.mts
              needs writes {file}
+ open        evoke-build/reflexes/open 0.1.0        read         runs open
              needs reads {place}
+ power       evoke-build/reflexes/power 0.1.0       destructive  runs power.mts
              needs runs osascript
+ screenshot  evoke-build/reflexes/screenshot 0.1.0  write        runs screenshot.mts
              needs writes ~/Desktop · runs screencapture
+ sleep       evoke-build/reflexes/sleep 0.1.0       write        runs sleep.mts
              needs runs pmset
+ sound       evoke-build/reflexes/sound 0.1.0       write        runs sound.mts
              needs runs osascript
+ timer       evoke-build/reflexes/timer 0.1.0       write        runs timer.mts
              needs runs osascript
+ trash       evoke-build/reflexes/trash 0.1.0       destructive  runs osascript
+ visit       evoke-build/reflexes/visit 0.1.0       read         runs visit.mts
              needs reads ~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist · runs open plutil
+ volume      evoke-build/reflexes/volume 0.1.0      write        runs volume.mts
              needs runs osascript
+ wifi        evoke-build/reflexes/wifi 0.1.0        write        runs wifi.mts
              needs runs networksetup
  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>"

One row per reflex: its local name, where it came from, its tag, its effect, and what it runs. Under it, what it touches: the paths, the network as hosts *, the programs; a row without that line declares nothing, and its body touches nothing but its own folder. The kernel holds each body to that line: Security. Then the inactive lines. A reflex that needs your words or a setting stays out of every decision until it has them. Each line ends with the command that gives it what it lacks. Nothing is guessed for you.

3. Use it

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

The indented line is evoke's own, on stderr. It shows the call it chose and its confidence. The last line is the reflex's result, on stdout. The confidence was over the bar for a write reflex, so it ran without asking.

A less certain decision confirms first. [t]each records what you meant, then runs:

$ evoke "kill the wifi"
  wifi state="off" · write · weakest: state 0.86
    a write runs at 0.90 or more
  Turn Wi-Fi off?  [y]es [n]o [t]each > t
+ overlays/wifi.toml  [examples] "kill the wifi" = { state = "off" }
wi-fi off

That one line in overlays/wifi.toml is yours. It is an example the classifier now sees, in a file no update will touch.

A destructive one always confirms, however sure:

$ evoke "restart the computer"
  power action="restart" · destructive · weakest: route 0.98
    it cannot be undone, so it always waits for a yes
  Make the laptop restart now?  [y]es [n]o [t]each > n
[2]

[2] means declined: you said no, or nothing fit. When what you said fits nothing, evoke abstains and shows you the ranking, and reminds you of what is not yet in play:

$ evoke "what time is it"
  none of them 0.85 · timer 0.10 · awake 0.03 · lock 0.02
  note, open and visit are inactive  →  evoke show
[2]

4. Give it your words

Some reflexes need words only you can supply: your folders, your sites. A vocabulary is that list. It is one file you own, and every reflex that names it reads it.

$ evoke vocab places add desktop "The desktop." --value "~/Desktop"
+ vocab/places.toml  desktop = { what = "The desktop.", value = "~/Desktop" }
$ evoke "open my desktop folder"
  open place="desktop"  0.95

The meaning is what the classifier reads. The value is what the reflex receives: open opened that folder. A setting works the same way:

$ evoke config note file "~/notes.txt"
+ evoke.toml  [config.note] file = "~/notes.txt"

The notes file must exist, since the reflex declares it: touch ~/notes.txt first. A secret is only ever named, never stored: evoke config <reflex> <key> --env <VAR> writes the variable's name, and the value is read from your environment when the reflex runs.

5. Teach it

Teaching works from the command line too, and you can teach what something is not:

$ evoke teach "go dark" wifi state=off
+ overlays/wifi.toml  [examples] "go dark" = { state = "off" }
$ evoke teach "what time is it" not timer
+ overlays/timer.toml  [examples] "what time is it" = false

6. Look inside

try decides without running and shows every judgment. why explains the last sentence. show prints what is installed, or one reflex as it is used, with + next to every line that is yours.

$ 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

  replay answered 25 questions in 2 rounds

Which reflex, then each value with what it stands on, then what would happen and why. The weakest answer is the confidence. It sits under the write bar, so this one would wait for a yes.

Where things are

WhatWhere
Your project: evoke.toml, evoke.lock, overlays/, vocab/~/.config/evoke/
Installed code, keyed by content hash~/.cache/evoke/store/
The decision log, the REPL's history~/.local/state/evoke/

Your project holds only what you wrote, the lock, and generated types. Put it in your dotfiles. Everything else is a cache, and evoke sync rebuilds it on a new machine.

Next: Concepts, or straight to Typing a request.

FAQPrivacyGitHub