Slip — the micro-LISP
Slip is Caravan's embedded symbolic engine: a tiny, total (step-capped,
always terminates), sandboxed (no IO, no clock, no randomness) LISP
over the JSON universe. Models use it through the lisp tool to do exact
arithmetic, counting, filtering, and data reshaping instead of
approximating in prose; humans poke it with /lisp.
❯ /lisp (mean (map (lambda (r) (get "t" r)) data))
Why
Long agentic runs die on small arithmetic and bookkeeping mistakes.
Handing a model — 2B or 200B — an exact calculator with its full manual
in the tool description removes a whole failure class. Homoiconicity
(code = lists) plays to model strengths: programs are easy to generate,
inspect, and even transform with read / show / eval.
The language on one page
; forms
(if cond then else) (let ((x 1) (y 2)) body) (define name expr)
(lambda (x) body) (do e1 e2) (quote x) or 'x
; math / compare (+ - * / mod abs min max round sum mean)
(+ 1 2 3) ; 6 (= != < > <= >= not and or)
(sum (range 1 101)) ; 5050
; lists
(list 1 2) (len xs) (first xs) (last xs) (nth 0 xs) (rest xs)
(append a b) (reverse xs) (sort xs) (range 0 10)
(map f xs) (filter f xs) (reduce f init xs)
(map upper (list "a" "b")) ; builtins are first-class
; records & tables (JSON objects / arrays of objects)
(get "name" row) (keys row) (put "k" v row)
(select "name" "age" rows) (where "role" "admin" rows) (sort-by "age" rows)
; strings
(str "n=" 3) (upper s) (lower s) (contains s sub)
(split "a,b" ",") (join xs ", ")
; types & JSON
(number? x) (string? x) (list? x) (record? x) (null? x)
(parse-json "[1,2]") (to-json x)
; code as data
(read "(+ 1 2)") ; → the list (+ 1 2)
(show '(+ 1 2)) ; → "(+ 1 2)"
(eval '(+ 1 2)) ; → 3
Recursion works and is safe — the evaluator burns a step budget (default 100 000) and returns a clean error instead of hanging:
(define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))
(fact 10) ; 3628800
The lisp tool
Input: {"program": "...", "data": <any JSON>} — data is bound to the
symbol data inside the program. Native data operations (sum, sort,
where, …) cost one step regardless of size, so million-element folds
are fine; only interpreted steps (lambda applications) burn budget.
From OCaml: Caravan.Lisp.run ?max_steps ?data src →
(Value.t, string) result.