Lisp for PHP, macros, persistent data structures, REPL.
PHP 8.5 or newer. Linux and macOS are supported: the full compiler, core and PHAR suites run on both in CI, and a failure on either blocks a release. Windows is best effort, running a reduced suite. What a version number promises, and for how long, is in the stability policy.
composer require phel-lang/phel-lang1. Open a REPL
./vendor/bin/phel replphel:1:> (->> [1 2 3 4 5] (filter odd?) (map #(* % %)) (reduce +))
35
phel:2:> (defn greet [name] (str "Hello, " name "!"))
| user/greet
phel:3:> (greet "Phel")
| "Hello, Phel!"2. Scaffold a project
./vendor/bin/phel init # add `--minimal` for a single-file layoutCreates phel-config.php, src/main.phel, tests/main_test.phel. With
--minimal the two sources sit at the project root instead. Then:
./vendor/bin/phel run src/main.phel # run
./vendor/bin/phel test # tests
./vendor/bin/phel build # compile to PHP
./vendor/bin/phel config # inspect the merged config3. Eval inline or via stdin
./vendor/bin/phel eval '(+ 1 2)' # prints 3
echo '(println "hi")' | ./vendor/bin/phel eval -
./vendor/bin/phel eval - < script.phel4. Enable shell completion (optional)
./vendor/bin/phel completion dumps a tab-completion script for bash, zsh, or fish. It completes commands, their options, and dynamic values (function names for doc, project namespaces for run/test).
# bash — restart your shell afterwards
./vendor/bin/phel completion bash | sudo tee /etc/bash_completion.d/phel
# zsh — write into a directory on your $fpath
./vendor/bin/phel completion zsh > "${fpath[1]}/_phel"
# fish
./vendor/bin/phel completion fish > ~/.config/fish/completions/phel.fishThe zsh script starts with #compdef phel, so completion only triggers for a binary named phel on your $PATH. If you call ./vendor/bin/phel (or ./bin/phel in a dev checkout), symlink a global phel first, e.g. on macOS + Homebrew:
phel completion zsh > "$(brew --prefix)/share/zsh/site-functions/_phel"
ln -sf "$PWD/bin/phel" "$(brew --prefix)/bin/phel" # global `phel` so #compdef matches
rm -f ~/.zcompdump* # force compinit to rebuild
# then open a new shellPrefer a project template?
web-skeletonorcli-skeleton: click Use this template for a one-click start.
More examples →
|
Data pipeline (def users
[{:name "Ada" :age 36}
{:name "Bob" :age 17}
{:name "Cam" :age 41}])
(->> users
(filter #(>= (:age %) 18))
(map :name)
sort)
;; => ["Ada" "Cam"] |
HTTP response (ns app (:require phel.http :as h))
(def req (h/request-from-globals))
(h/emit-response
(h/response-from-map
{:status 200
:headers {"Content-Type" "text/plain"}
:body (str "Hello " (:uri req))})) |
|
Macros (defmacro unless [pred & body]
`(if (not ~pred)
(do ~@body)))
(unless (zero? 1)
(println "not zero"))
;; => not zero
(unless false (println "ok"))
;; => ok |
PHP interop (ns app)
(def now (new DateTime))
(.format now "Y-m-d")
;; => "2026-04-20"
(def epoch (new DateTime "1970-01-01"))
(.-days (.diff now epoch))
;; => 20564 |
- Getting Started: install, REPL, first script (5 min)
- CLI Reference & DX Guide: every command, the dev loop, compile vs eval vs run vs build
- phel-lang.org: full documentation, tutorials, exercises, blog
- Contributor docs: repository internals, agent tooling, project layout
- Architecture decisions: why the repository is shaped the way it is
- Packagist
- CONTRIBUTING.md: setup and workflow
- AGENTS.md: architecture and review expectations
Skill files for Claude Code, Cursor, Codex, Gemini, Copilot, Aider: resources/agents/
./vendor/bin/phel agent-install [platform] # install skill file for one agent (claude, cursor, ...)
./vendor/bin/phel agent-install --auto # only agents detected in this project
./vendor/bin/phel agent-install --all # every supported platformClaude Code (.claude/) and Codex (.codex/, .agents/, AGENTS.md) configs generate from a single source tree under .agnostic-ai/ via agnostic-ai. Those directories are gitignored; run sync after cloning to materialize them. Add more targets (Gemini, Cursor, ...) by appending to targets: in agnostic-ai.yaml.
brew install Chemaclass/tap/agnostic-ai # or: go install github.com/chemaclass/agnostic-ai/cmd/agnostic-ai@latest
agnostic-ai sync # regenerate per-tool configsEdit specs under .agnostic-ai/{rules,agents,skills,hooks,scripts,overlays}/, then agnostic-ai sync again. A CI gate runs sync --check on every PR to block drift between the source and the (gitignored) emitted files.