Skip to content

Latest commit

 

History

5,588 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Phel logo

Tests Quality PHPStan level 9 Psalm level 1 Psalm Type-coverage Status

Packagist Version Packagist Downloads PHP Version Required License Ask DeepWiki


Lisp for PHP, macros, persistent data structures, REPL.

Requirements

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.

Get Started

composer require phel-lang/phel-lang

1. Open a REPL

./vendor/bin/phel repl
phel: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 layout

Creates 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 config

3. 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.phel

4. 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.fish

The 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 shell

Prefer a project template? web-skeleton or cli-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

Documentation

AI Coding Agents

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 platform

Repo-level AI tooling

Claude 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 configs

Edit 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.

About

A functional, Lisp-inspired language that compiles to PHP. Inspired by Clojure, Phel brings macros, persistent data structures, and expressive functional idioms to the PHP ecosystem.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

526 stars

Watchers

7 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages