
Write HTML. Render video. Built for agents.
Sema is a Lisp where LLM calls, agents, prompts, and tool dispatch are language primitives. You can write agent workflows in Sema, run them through a Rust bytecode VM, and expose them to LLM clients through the built-in MCP server.
Builders who want reusable language and runtime pieces for agent-led coding, review, and LLM workflows.
You can build agent scripts and ship them as a single binary instead of stitching together prompts, SDKs, and glue code.
Defines prompts, chats, conversations, completions, extraction, streaming, batching, embeddings, and vision as language features.
Supports `defagent`, `deftool`, budgets, caching, fallback chains, and tool calls inside normal S-expression code.
Works with Anthropic, OpenAI, Gemini, Ollama, Groq, xAI, Mistral, Moonshot, and OpenAI-compatible endpoints.
Includes `sema mcp` so LLM clients can compile, format, evaluate, and build Sema code, and call your own Lisp tools.
Ships a formatter, language server, debugger, notebook UI, and standalone builder in the same repo.
`sema build` compiles scripts into self-contained executables with bundled assets.
# macOS / Linux curl -fsSL https://sema-lang.com/install.sh | sh # Windows (PowerShell) powershell -ExecutionPolicy ByPass -c "irm https://github.com/sema-lisp/sema/releases/latest/download/sema-lang-installer.ps1 | iex" # Homebrew (macOS / Linux) brew install helgesverre/tap/sema-lang
cargo install sema-lang
git clone https://github.com/sema-lisp/sema cd sema && cargo build --release # Binary at target/release/sema
sema # REPL (with tab completion) sema script.sema # Run a file sema -e '(+ 1 2)' # Evaluate expression sema --no-llm script.sema # Run without LLM (faster startup) sema build app.sema -o myapp # Build standalone executable ./myapp # Run without sema installed
sema notebook new my-notebook.sema-nb # Create a notebook sema notebook serve my-notebook.sema-nb # Open in browser (localhost:8888) sema notebook run my-notebook.sema-nb # Run all cells headlessly sema notebook export my-notebook.sema-nb # Export to Markdown
sema fmt script.sema # Canonical code formatter sema lsp # Language Server (completions, hover, go-to-def, rename) sema dap # Debug Adapter (breakpoints, stepping, variable inspection) sema mcp # Model Context Protocol server for LLM clients
A Lisp where LLM agents are language primitives, not an SDK — compiled to a fast bytecode VM, shipped as a single binary.
Docs · Playground · For Agents · Examples · Issues
Stop rewriting the agent loop. Every LLM script grows the same scaffolding — retries, caching, cost caps, rate limits, tool dispatch, conversation state. Sema makes that scaffolding the runtime: your script stays the size of its idea, ships as a single binary, and your coding agent already speaks the language.
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 — with Clojure-style keywords (:foo), map literals ({:key val}), and vector literals ([1 2 3]).
A coding agent with file tools, safety checks, and budget tracking — in ~40 lines:
;; Define tools the LLM can call
(deftool read-file
"Read a file's contents"
{:path {:type :string :description "File path"}}
(lambda (path)
(if (file/exists? path) (file/read path) "File not found")))
(deftool edit-file
"Replace text in a file"
{:path {:type :string} :old {:type :string} :new {:type :string}}
(lambda (path old new)
(file/write path (string/replace (file/read path) old new))
"Done"))
(deftool run-command
"Run a shell command"
{:command {:type :string :description "Shell command to run"}}
(lambda (command) (:stdout (shell "sh" "-c" command))))
;; Create an agent with tools, system prompt, and spending limit
(defagent coder
{:system (format "You are a coding assistant. Working directory: ~a" (sys/cwd))
:tools [read-file edit-file run-command]
:max-turns 20}) ; no :model → uses the configured default provider
;; Run it — budget is scoped, automatically restored after the block
(llm/with-budget {:max-cost-usd 0.50} (lambda ()
(define result (agent/run coder "Add error handling to src/main.rs"))
(println (:response result))
(println (format "Cost: $~a" (:spent (llm/budget-remaining))))))
;; Simple completion
(llm/complete "Explain monads in one sentence")
;; Structured data extraction — returns a map, not a string
(llm/extract
{:vendor {:type :string} :amount {:type :number} :date {:type :string}}
"Bought coffee for $4.50 at Blue Bottle on Jan 15")
;; => {:amount 4.5 :date "2025-01-15" :vendor "Blue Bottle"}
;; Classification
(llm/classify (list :positive :negative :neutral) "This product is amazing!")
;; => :positive
;; Multi-turn conversations as immutable data
(define conv (conversation/new {:model "claude-haiku-4-5-20251001"}))
(define conv (conversation/say conv "The secret number is 7"))
(define conv (conversation/say conv "What's the secret number?"))
(conversation/last-reply conv) ;; => "The secret number is 7."
;; Streaming
(llm/stream "Tell me a story" {:max-tokens 500})
;; Batch — all prompts sent concurrently
(llm/batch (list "Translate 'hello' to French"
"Translate 'hello' to Spanish"
"Translate 'hello' to German"))
;; Vision — extract structured data from images
(llm/extract-from-image
{:text :string :background_color :string}
"assets/logo.png")
;; => {:background_color "white" :text "Sema"}
;; Multi-modal chat — send images in messages
(define img (file/read-bytes "photo.jpg"))
(llm/chat (list (message/with-image :user "Describe this image." img)))
;; Cost tracking
(llm/set-budget 1.00)
(llm/budget-remaining) ;; => {:limit 1.0 :spent 0.05 :remaining 0.95}
;; Response caching — avoid duplicate API calls during development
(llm/with-cache (lambda ()
(llm/complete "Explain monads")))
;; Cassettes — record real responses once, replay them in CI (no keys, no network)
(llm/with-cassette "fixtures/run.jsonl" {:mode :auto} (lambda ()
(llm/complete "Explain monads")))
;; Fallback chains — automatic provider failover
(llm/with-fallback [:anthropic :openai :groq]
(lambda () (llm/complete "Hello")))
;; In-memory vector store for semantic search (RAG)
(vector-store/create "docs")
(vector-store/add "docs" "id" (llm/embed "text") {:source "file.txt"})
(vector-store/search "docs" (llm/embed "query") 5)
;; Cross-encoder reranking — the retrieve-many → rerank-to-a-few RAG move
(llm/rerank "how do I read a file?"
["file/read returns a string" "http/get fetches a URL"]
{:top-k 3})
;; => ({:index 0 :score 0.98 :document "file/read returns a string"} ...)
;; Text chunking for LLM pipelines
(text/chunk long-document {:size 500 :overlap 100})
;; Prompt templates
(prompt/render "Hello {{name}}" {:name "Alice"})
; => "Hello Alice"
;; Persistent key-value store
(kv/open "cache" "cache.json")
(kv/set "cache" "key" {:data "value"})
(kv/get "cache" "key")
All providers are auto-configured from environment variables — just set the API key and go.
| Provider | Chat | Stream | Tools | Embeddings | Vision |
|---|---|---|---|---|---|
| Anthropic | ✅ | ✅ | ✅ | — | ✅ |
| OpenAI | ✅ | ✅ | ✅ | ✅ | ✅ |
| Google Gemini | ✅ | ✅ | ✅ | — | ✅ |
| Ollama | ✅ | ✅ | ✅ | — | ✅ |
| Groq | ✅ | ✅ | ✅ | — | — |
| xAI | ✅ | ✅ | ✅ | — | — |
| Mistral | ✅ | ✅ | ✅ | — | — |
| Moonshot | ✅ | ✅ | ✅ | — | — |
| Jina | — | — | — | ✅ | — |
| Voyage | — | — | — | ✅ | — |
| Cohere | — | — | — | ✅ | — |
| Any OpenAI-compat | ✅ | ✅ | ✅ | — | ✅ |
| Custom (Lisp) | ✅ | — | ✅ | — | — |
Hundreds of built-in functions, tail-call optimization, macros, modules, error handling — not a toy.
;; Closures, higher-order functions, TCO
(define (fibonacci n)
(let loop ((i 0) (a 0) (b 1))
(if (= i n) a (loop (+ i 1) b (+ a b)))))
(fibonacci 50) ;; => 12586269025
;; Full R7RS numeric tower — bignums, exact rationals, complex numbers
(expt 2 100) ;; => 1267650600228229401496703205376
(+ 1/2 1/3) ;; => 5/6
(sqrt -1) ;; => 0+1i
;; Maps, keywords-as-functions, f-strings
(define person {:name "Ada" :age 36 :langs ["Lisp" "Rust"]})
(:name person) ;; => "Ada"
(println f"${(:name person)} knows ${(length (:langs person))} languages")
;; Destructuring
(let (({:keys [name age]} person))
(println f"${name} is ${age}"))
;; Pattern matching with guards
(define (classify n)
(match n
(x when (> x 100) "big")
(x when (> x 0) "small")
(_ "non-positive")))
;; Functional pipelines
(->> (range 1 100)
(filter even?)
(map #(* % %))
(take 5))
;; => (4 16 36 64 100)
;; Nested data access
(define config {:db {:host "localhost" :port 5432}})
(get-in config [:db :host]) ;; => "localhost"
;; Macros
(defmacro unless (test . body)
`(if ,test nil (begin ,@body)))
;; Modules
(module utils (export square)
(define (square x) (* x x)))
;; HTTP, JSON, regex, file I/O, crypto, CSV, datetime...
(define data (json/decode (http/get "https://api.example.com/data")))
📖 Full language reference, stdlib docs, and more examples at sema-lang.com/docs
sema.run — Browser-based playground with 20+ example programs. No install required. Runs entirely in WebAssembly.
Sema is new, so your agent hasn't seen it. Fix that in one command — append the
agent crib sheet to your repo's AGENTS.md (and point CLAUDE.md at it):
curl -fsSL https://sema-lang.com/docs/for-agents.md >> AGENTS.md
ln -s AGENTS.md CLAUDE.md # Claude Code, Cursor, etc. read this
for-agents.md is a compact working guide for
an LLM that already knows a Lisp. It covers the rules most likely to cause incorrect
generated code and links to /llms.txt, a machine index
of every doc page. The agent can fetch only the page it needs (for example,
/docs/llm/tools-agents.md) instead of loading the whole manual. Every doc URL also
serves raw Markdown: append .md to a sema-lang.com/docs/... link to get the source.
Install pre-built binaries (no Rust required):
# macOS / Linux
curl -fsSL https://sema-lang.com/install.sh | sh
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://github.com/sema-lisp/sema/releases/latest/download/sema-lang-installer.ps1 | iex"
# Homebrew (macOS / Linux)
brew install helgesverre/tap/sema-lang
Or install from crates.io:
cargo install sema-lang
Or build from source:
git clone https://github.com/sema-lisp/sema
cd sema && cargo build --release
# Binary at target/release/sema
For local development that needs an optimized binary, use jake release-fast
or cargo build --profile release-fast. The binary is at
target/release-fast/sema. This profile uses incremental compilation and
parallel codegen, with no cross-crate LTO. Use --release for performance
measurements and distribution builds. See the
build profile measurements for build times
and runtime tradeoffs.
sema # REPL (with tab completion)
sema script.sema # Run a file
sema -e '(+ 1 2)' # Evaluate expression
sema --no-llm script.sema # Run without LLM (faster startup)
sema build app.sema -o myapp # Build standalone executable
./myapp # Run without sema installed
Generate tab-completion scripts for your shell:
# Zsh (macOS / Linux)
mkdir -p ~/.zsh/completions
sema completions zsh > ~/.zsh/completions/_sema
# Bash
mkdir -p ~/.local/share/bash-completion/completions
sema completions bash > ~/.local/share/bash-completion/completions/sema
# Fish
sema completions fish > ~/.config/fish/completions/sema.fish
📖 Full setup instructions for all shells: sema-lang.com/docs/shell-completions
📖 Full CLI reference, flags, and REPL commands: sema-lang.com/docs/cli
Each editor plugin lives in its own repo under the sema-lisp org:
| Editor | Repository | Install |
|---|---|---|
| VS Code | vscode-sema | ext install sema-lang.sema-lang |
| Zed | zed-sema | Extensions → search Sema |
| IntelliJ | intellij-sema | JetBrains Marketplace → Sema |
| Neovim | sema.nvim | { "sema-lisp/sema.nvim" } |
| Vim | sema.vim | Plug 'sema-lisp/sema.vim' |
| Emacs | emacs-sema | MELPA → sema-mode |
| Helix | helix-sema | clone + ./install.sh |
| Sublime Text | sublime-sema | Package Control → Sema |
All plugins provide syntax highlighting; VS Code, Zed, IntelliJ, Neovim, Emacs, Helix, and Sublime also wire up the built-in language server (sema lsp), and several (VS Code, Zed, IntelliJ, Neovim, Helix) add debugging (sema dap) — some also register the MCP server (sema mcp). Zed, Helix, and Neovim highlight via the shared tree-sitter-sema grammar; the others ship their own.
📖 Full installation instructions and per-editor feature lists: sema-lang.com/docs/editors
Sema includes a Jupyter-inspired notebook interface with a browser UI:
sema notebook new my-notebook.sema-nb # Create a notebook
sema notebook serve my-notebook.sema-nb # Open in browser (localhost:8888)
sema notebook run my-notebook.sema-nb # Run all cells headlessly
sema notebook export my-notebook.sema-nb # Export to Markdown
Cells share a persistent environment — definitions in earlier cells are visible in later ones. Notebooks are saved as .sema-nb JSON files.
📖 Full notebook documentation: sema-lang.com/docs/notebook
A full toolchain ships in the box — no plugins to assemble:
sema fmt script.sema # Canonical code formatter
sema lsp # Language Server (completions, hover, go-to-def, rename)
sema dap # Debug Adapter (breakpoints, stepping, variable inspection)
sema mcp # Model Context Protocol server for LLM clients
The MCP server lets LLM clients (Claude Desktop, Cursor, Claude Code) compile, format, evaluate, and build Sema code — and call your own deftool Lisp tools — directly in your environment.
The examples/ directory has 50+ programs:
| Example | What it does |
|---|---|
coding-agent.sema | Full coding agent with file editing, search, and shell tools |
review.sema | AI code reviewer for git diffs |
commit-msg.sema | Generate conventional commit messages from staged changes |
summarize.sema | Summarize files or piped input |
game-of-life.sema | Conway's Game of Life |
brainfuck.sema | Brainfuck interpreter |
mandelbrot.sema | ASCII Mandelbrot set |
json-api.sema | Fetch and process JSON APIs |
test-vision.sema | Vision extraction and multi-modal chat tests |
test-extract.sema | Structured extraction and classification |
test-batch.sema | Batch/parallel LLM completions |
test-pipeline.sema | Caching, budgets, rate limiting, retry, fallback chains |
test-text-tools.sema | Text chunking, prompt templates, document abstraction |
test-vector-store.sema | In-memory vector store with similarity search |
test-kv-store.sema | Persistent JSON-backed key-value store |
expr-evaluator.sema | Mini calculator using match on tagged vectors |
shape-geometry.sema | Shape areas/perimeters with map pattern matching |
http-router.sema | HTTP router with match on nested maps and guards |
destructuring.sema | Comprehensive destructuring showcase (vector, map, lambda) |
demo.sema-nb | Interactive notebook demo (run with sema notebook serve) |
The pitch in one line: no LangChain, no provider SDK, no agent framework, no glue
script — the agent loop, retries, caching, budgets, tracing, and tool dispatch are the
language runtime, and the whole thing is one binary you can scp to a box.
invoke_agent → chat → execute_tool tree, exportable to Jaeger, Grafana, Datadog, Langfuse, Arize Phoenix, and more — zero manual instrumentation, off by defaultsema build compiles programs into self-contained binaries with auto-traced imports and bundled assets@sema-lang/sema to run Sema client-side in JS via WebAssemblysema pkg pulls dependencies from git or the live registry at pkg.sema-lang.com, pinned by a sema.lock for reproducible installscall/cc) or fully hygienic macros (syntax-rules) — has auto-gensym (foo#) for preventing variable captureRc-based, no cross-thread sharing of valuescrates/
sema-core/ NaN-boxed Value type, errors, environment
sema-reader/ Lexer and s-expression parser
sema-vm/ Bytecode compiler and virtual machine
sema-eval/ Trampoline-based evaluator, special forms, modules
sema-stdlib/ Built-in functions across many modules
sema-io/ Process-wide async I/O pool (tokio) behind the core seam
sema-llm/ LLM provider trait + multi-provider clients
sema-workflow/ Dynamic-workflow runtime — journaled runs, bounded fan-out, --resume
sema-otel/ OpenTelemetry tracing (GenAI semantic conventions)
sema-docs/ Canonical builtin docs (powers LSP hover + REPL apropos)
sema-lsp/ Language Server Protocol implementation
sema-dap/ Debug Adapter Protocol server
sema-fmt/ Source code formatter
sema-mcp/ Model Context Protocol server
sema-notebook/ Jupyter-inspired notebook interface with browser UI
sema-wasm/ WebAssembly build for sema.run playground
sema/ CLI binary: REPL + file runner + standalone builder
🔬 Deep-dive into the internals: Architecture · Evaluator · Lisp Comparison
MIT — see LICENSE.
Sign in to join the discussion.
No comments yet. Be the first to say what this is good for.

Write HTML. Render video. Built for agents.
Ultra-lightweight, open-source, self-hosted personal AI agent framework in Python with WebUI, tools, memory, MCP, multi-agent workflows, automation, and chat apps
SkillOpt is a text-space optimizer that trains reusable natural-language skills for frozen LLM agents through trajectory-driven edits, validation-gated updates, and deployable best_skill.md artifacts.

Omnigent is an open-source AI agent framework and meta-harness: orchestrate Claude Code, Codex, Cursor, Pi, and custom agents — swap harnesses without rewriting, enforce policies and sandboxing, and collaborate in real time from any device.
A theoretical reconstruction of the Claude Mythos architecture, built from first principles using the available research literature.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!