Getting Started
Sema is a Scheme-like Lisp where prompts are s-expressions, conversations are persistent data structures, and LLM calls are just another form of evaluation. It combines a Scheme core with Clojure-style keywords (:foo), map literals ({:key val}), and vector literals ([1 2 3]).
Why Sema?
- LLMs as language primitives — prompts, messages, conversations, tools, and agents are first-class data types, not string templates bolted on
- Multi-provider — Anthropic, OpenAI, Gemini, Groq, xAI, Mistral, Ollama, and more, all auto-configured from environment variables
- Practical Lisp — closures, tail-call optimization, macros, modules, error handling, HTTP, file I/O, regex, JSON — everything you need to build real programs
- Embeddable — clean Rust crate structure, builder API, sync interface (learn more)
Installation
Install pre-built binaries (no Rust required):
bash
# macOS / Linux
curl -fsSL https://sema-lang.com/install.sh | sh
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://github.com/HelgeSverre/sema/releases/latest/download/sema-lang-installer.ps1 | iex"
# Homebrew (macOS / Linux)
brew install helgesverre/tap/sema-langOr install from crates.io:
bash
cargo install sema-langOr build from source:
bash
git clone https://github.com/HelgeSverre/sema
cd sema
cargo build --release
# Binary is at target/release/semaQuick Start
bash
sema # Start the REPL
sema script.sema # Run a file
sema -e '(+ 1 2)' # Evaluate an expression
sema -p '(map sqr (range 5))' # Evaluate and always printscheme
;; In the REPL:
sema> (define (greet name) f"Hello, ${name}!")
sema> (greet "world")
"Hello, world!"
sema> (map #(* % %) (range 1 6))
(1 4 9 16 25)
sema> (define person {:name "Ada" :age 36})
sema> (:name person)
"Ada"Examples
Working with Data
scheme
;; Keywords as accessor functions, short lambdas with #(...)
(define people [{:name "Ada" :age 36}
{:name "Bob" :age 28}
{:name "Cat" :age 42}])
(map #(:name %) people) ; => ("Ada" "Bob" "Cat")
(->> people
(filter #(> (:age %) 30))
(map #(:name %))) ; => ("Ada" "Cat")
;; Destructuring and f-strings
(let (({:keys [name age]} (first people)))
(println f"${name} is ${age} years old"))
;; Pattern matching
(define (describe person)
(match person
({:keys [name age]} when (> age 40)
f"${name} is experienced")
({:keys [name]}
f"${name} is on the team")))LLM Completion
scheme
;; Simple completion (requires an API key env var)
(llm/complete "Explain recursion in one sentence" {:max-tokens 50})
;; Structured chat with message history
(llm/chat
[(message :system "You are a helpful assistant.")
(message :user "What is Lisp? One sentence.")]
{:max-tokens 100})Persistent Conversations
scheme
(define conv (conversation/new {:model "claude-haiku-4-5-20251001"}))
(define conv (conversation/say conv "Remember: the secret number is 7"))
(define conv (conversation/say conv "What is the secret number?"))
(conversation/last-reply conv)
; => "The secret number is 7."What's Next?
- CLI Reference — all flags, subcommands, and environment variables
- Shell Completions — tab completions for bash, zsh, fish, and more
- Editor Support — plugins for VS Code, Vim/Neovim, Emacs, and Helix
- Embedding in Rust — use Sema as a scripting engine in your app
- Data Types — the 20 built-in types
- Special Forms — control flow, bindings, and iteration
- Macros & Modules — metaprogramming and code organization
- LLM Primitives — completions, chat, tools, agents, embeddings, and more