Release: 0.34 - Toolsmith
0.34.1
Released 2026-04-21 · GitHub release
phel format --dry-run + PHAR ships test dirs + phel doc PHAR warnings fixed + CLI memory_limit bump.
🎉 Added
CLI
phel format --dry-runlists files that would be reformatted; exits non-zero when any file would change (#1533)
🐛 Fixed
Build
- PHAR ships first-party
src/**/Test/directories sophel testruns from the distributed archive (#1533)
CLI
bin/phelsetsmemory_limit=-1for large-project tokenizationphel docno longer emitsrmdir(...): No such file or directorywarnings when run from the PHAR
Docs
docs/performance.md: CLI opcache setup and cache reset
👥 Contributors
Full Changelog: v0.34.0...v0.34.1
0.34.0 - Toolsmith
Released 2026-04-20 · GitHub release
Reader literals (#inst/#regex/#php) + nREPL/LSP/lint/watch tooling + new modules (match, schema, async, ai) + generative test shrinking.
🎉 Added
Reader & Compiler
#inst "..."reads as\DateTimeImmutableand#regex "..."reads as a delimited PCRE string; user tags via(register-tag "name" f)in the newphel\readernamespace;data-readers.phelat any source root is auto-loaded (#1523)#phpreader literal:#php [1 2 3]expands to(php-indexed-array 1 2 3);#php {"a" 1}to(php-associative-array "a" 1)(non-recursive) (#1472)- PHP interop shorthands:
(.method obj args),(.-field obj),(ClassName/method args),\Ns\Class/MEMBER,(new ClassName args)(#1467, #1471, #1477) defreturns a printable var ref (e.g.#'user/my-var) (#1468)
REPL
- History vars
*1,*2,*3, and*efor last exception (#1474) - Prompt shows current namespace and tracks
(ns ...)switches (#1474)
CLI
phel eval -reads the expression from stdin (#1494)phel agent-install [<platform>|--all]writes skill files for Claude Code, Cursor, Codex, Gemini, Copilot, Aider;--with-docs,--dry-run,--force(#1495)phel nrepl --port=N --host=addrbencode-over-TCP nREPL server witheval,clone,close,describe,load-file,interrupt,completions,lookup,info,eldoc(#1507)phel analyze <file>prints JSON diagnostics;phel index <dir>... [--out=file.json]builds a symbol table;phel api-daemonserves the Api facade as JSON-RPC on stdio (#1508)ApiFacade::analyzeSource,indexProject,resolveSymbol,findReferences,completeAtPoint(#1508, #1518, #1525)phel lint [paths]... [--format=human|json|github] [--config=path] [--no-cache]with rules: unresolved-symbol, arity-mismatch, unused-binding, unused-require, unused-import, shadowed-binding, redundant-do, duplicate-key, invalid-destructuring, discouraged-var; configurable viaphel-lint.phel(#1509)phel watch [paths]... [-b backend] [--poll=500] [--debounce=100]reloads changed namespaces in dependency order (inotify, fswatch, polling);(watch! ["src/"])viaphel\watch(#1512)phel lspLSP v3.17 server over stdio with hover, definition, references, completion, document/workspace symbols, rename, formatting, debounced publishDiagnostics (#1513)
Agent docs
.agents/ships task recipes, per-platform adapters, and example projects (todo-app,http-json-api,cli-wordcount) (#1495)composer test-agentsvalidates every example; runs in CI (#1500)
Formatter
- Aligns key/value pairs in
cond,case,condp, and bindings oflet/loop/binding/for/foreach/dofor/if-let/when-let(#1452)
Testing
phel\test/reportis a multimethod dispatching on event:type(#1516)- Reporters:
default,testdox,dot,tap,junit-xml; select viaphel test --reporter=<name>(repeatable);--output=pathfor junit-xml (#1516) phel testselectors:--include=<tag>,--exclude=<tag>,--ns=<glob>,--filter=<regex>(repeatable); tag via^:integrationor^{:tags [:integration :slow]}; skipped tests emit:skipped(#1517)defspecshrinks counterexamples via rose-treephel\test\shrink; emits:defspec-failedwith:shrunk-args,:original-args,:shrink-steps,:seed;^:no-shrinkor:shrink? falseopts out (#1519)
Modules
phel\test\gen: generators,sample,quick-check,defspecwith seedable PRNG (#1451)phel\ai:chat-with-toolsOpenAI tool use,tool-calls,tool-result; exponential backoff on 429/5xx; per-callopts(:provider,:timeout,:base-url,:api-key,:max-retries);*http-post*seam;docs/ai-guide.md(#1456)phel\core:uuid=,uuid-nil?,uuid-version,uuid-variant(#1476)phel\core:defmultiaccepts optional docstring(defmulti name "doc" dispatch-fn)(#1515)phel\repl:find-ns,create-ns,remove-ns,intern,ns-interns(#1488)phel\cli: spec-map wrapper oversymfony/consolewith prompts, tables, progress, coercion, hooks, signals, test helpers;docs/cli-guide.md(#1498)phel\match:matchmacro with literal, vector, map, wildcard,:as,:guard,:or, rest-binding patterns (#1511)phel\schema:validate,explain,conform,coerce,generate,instrument!; kinds:vector,:set,:map,:map-of,:tuple,:enum,:and,:or,:maybe,:re,:fn,:ref,[:=> args ret]; named-schema registry (#1520)phel\async: fiber-backedpromise,deliver,future-call,future-fiber,future?; 3-argdereftimeouts;docs/async-guide.md(#1521, #1522)phel docand REPL completion coverphel\async,phel\cli,phel\match,phel\pprint,phel\router,phel\walk,phel\test\gen(#1518)
🐛 Fixed
REPL & Compiler
eval()runtime errors map to userstring:Nvia source map (#1475)- Non-callable literal calls (
('foo),(42),(nil),("x")) raisePHEL011at analysis time with source location (#1473) - REPL multi-line buffer counts
#(...),|(...),#?(...),#?@(...),[],{},#{...}toward balance (#1493)
Build
phel buildsuppresses compiled-program stdout during compilation (#1455)- Windows cache: drive-letter and UNC paths preserved verbatim (#1465)
build/release.shbumps.agents/VERSIONalongsideVersionFinder.phpandCHANGELOG.md
Modules
phel\ai/check-responseraisesRuntimeExceptionwith provider message when body lacks:error :message(#1456)phel\aitext extraction picks firsttextblock, skipping precedingtool_use(#1456)phel\http/request-from-globalserror points torequest-from-mapfor tests (#1524)(:key nil)returns default (#1504)(get v nil)and(get l nil)return default on vectors/lists (#1504)- Vector/list with nil index raise
InvalidArgumentException(#1504) - Stack-trace arg rendering truncates each Phel argument at 200 chars (#1504)
phel test --reporter=junit-xmlpreserves namespace and testcase order in output (#1528)
⚖️ Changed
docs/php-interop.md: namespaced PHP functions (php/Amp\trapSignal) and(def alias php/\Ns\fn)capture (#1469)phel buildprints summary with fresh/cached counts and output directory (#1455)phel\ai/chat-with-toolsreturns{:text :tool-calls :stop-reason :raw}(#1456)
🗑️ Removed
Public API
phel\http/create-response-from-map,phel\http/create-response-from-string(useresponse-from-map/response-from-string) (#1491)Keyword::createForNamespace()(useKeyword::create($name, $namespace)) (#1485)PhelConfig::setOut()(usePhelConfig::setBuildConfig()) (#1485)PhelBuildConfig::setMainPhpFilename()(usePhelBuildConfig::setMainPhpPath()) (#1485)PhelFunctionaccessorsname(),doc(),fnSignatures(),signature(),description(),groupKey(),githubUrl(),docUrl(),file(),line(),namespace()(use readonly properties) (#1485)
Internals
GlobalEnvironmentNotInitializedException,PhelFileFinder,PhelFileFinderInterface(#1482, #1490)FileException::canNotCreateTempFile(),ExtractorException::duplicateNamespace(),EmitterResult::getSource(),TokenStream::getReadTokens(),LoadClasspath::resetCache()(#1482, #1490)
Changed (breaking)
phel initdefaults to Flat layout (src/,tests/); pass--nestedto keep the legacysrc/phel/<name>/layout. Existing projects keep working since scaffolding only runs on new projects (#1453).ProjectLayout::Conventionalrenamed toProjectLayout::Nested;PhelConfig::useConventionalLayout()renamed touseNestedLayout()(#1453).
👥 Contributors
@Chemaclass @CosmeValera @JesusValeraDev
Full Changelog: v0.33.0...v0.34.0
Downloads
v0.34.1
- phel.phar (1.83 MB)
v0.34.0
- phel.phar (1.85 MB)