fractal-engine is a recursive language-model compute engine for long-context,
long-horizon work. A root model drives a persistent Clojure REPL, writes fenced
Clojure, receives compact host observations, and continues until it calls
(FINAL value).
The engine is built as a Clojure SDK plus an agent-operable CLI/control plane. It is not a consumer chat app and not a repository-analysis product. It is a small runtime substrate for durable model-driven work:
lm and map-lm;rlm and map-rlm;attach-rlm;flowchart LR
A["Caller or agent"] --> B["fractal.engine.api"]
A --> C["fractal CLI"]
C --> B
B --> D["Session loop"]
D --> E["Persistent Clojure REPL"]
D --> F["Provider adapter"]
E --> G["FINAL / lm / rlm calls"]
D --> H["SQLite event store"]
D --> I["BlobStore payloads"]
H --> J["Views, heads, lineage"]
I --> J
The public Clojure facade is fractal.engine.api. The CLI facade is
fractal.engine.cli, exposed by clojure -M:cli and by the bin/fractal
wrapper.
| Capability | What it gives you |
|---|---|
| Persistent sessions | A model works inside a durable Clojure session whose vars can survive turns and process restarts. |
| Exact host work | Model-written fenced Clojure runs in a capability-clamped SCI context and returns compact observations. |
| Provider adapter seam | Offline fake runs and live provider runs share the same runtime path. |
| Recursive harness | lm, map-lm, rlm, map-rlm, and attach-rlm let the model choose bounded leaf judgment, child sessions, fan-out, or derived continuation. |
| Durable storage | SQLite stores events and session rows; BlobStore stores content-addressed payload bytes. |
| Immutable heads | Completed turns publish continuation heads used by resume, attach, and lineage inspection. |
| Agent control plane | The CLI drives usage commands and read-only inspection commands with JSON/EDN output and explicit config files. |
Check locally:
java -version
clojure --version
Create a local config file and durable store. This uses the fake adapter, so it does not need provider credentials, network access, or paid calls.
clojure -M:cli init \
--config fractal.edn \
--store-dir .fractal/sessions/demo \
--session demo
Run one turn and inspect the result:
clojure -M:cli run \
--config fractal.edn \
--session demo \
--message "return a small value" \
--pretty
clojure -M:cli report \
--config fractal.edn \
--session demo \
--pretty
Trace the model code and engine observations for the latest turn:
clojure -M:cli trace \
--config fractal.edn \
--session demo \
--pretty
The default CLI output is JSON. Use --edn when exact Clojure-shaped values
matter, especially payload refs:
clojure -M:cli turns --config fractal.edn --session demo --edn
(require '[fractal.engine.api :as fe])
(def cfg
(fe/make-config
{:adapter :fake
:model "fake-model"
:capability :default
:fake/respond
(fe/responder
[[:default "```clojure\n(FINAL {:answer 42})\n```"]])}))
(def session (fe/start-session! cfg))
(def result (fe/run-turn! session "What is 6 times 7?"))
(:status result)
;; => :final
(:turn/final-value result)
;; => {:answer 42}
(fe/stop-session! session)
Use :store :sqlite and a relative :store/dir when a session should survive
process restart:
(def cfg
(fe/make-config
{:adapter :fake
:model "fake-model"
:capability :default
:store :sqlite
:store/dir ".fractal/sessions/sdk-demo"
:fake/respond
(fe/responder
[["define" "```clojure\n(def remembered 7)\n(FINAL :defined)\n```"]
["use" "```clojure\n(FINAL (* remembered 6))\n```"]])}))
(def first-handle (fe/start-session! cfg {:id "sdk-demo"}))
(fe/run-turn! first-handle "define")
(fe/close-session! first-handle)
(def reopened (fe/resume-session! cfg "sdk-demo"))
(:turn/final-value (fe/run-turn! reopened "use"))
;; => 42
Resume restores from the published current head. It does not replay provider calls or old evals.
Set :harness :rlm to expose the recursive model-facing surface inside the
session REPL:
FINAL
lm
map-lm
rlm
map-rlm
attach-rlm
The outer SDK and CLI call shape stays the same. The model decides whether to use ordinary Clojure, a bounded leaf call, or a child session.
Use the smallest sufficient kind:
lm / map-lm for bounded semantic judgments.rlm / map-rlm for subproblems that need their own loop and state.attach-rlm to derive a fresh child from a selected prior head without
advancing the source session.Run:
clojure -M:cli <command> [options] [args]
or build the wrapper target and call:
bin/fractal <command> [options] [args]
Usage commands:
init config start run turn resume stop close compact wait
Inspection commands:
status progress view events heads head edges tree payload messages turns steps evals trace check report
The CLI is designed for agents and scripts first. It is non-interactive by default, uses explicit config files and session ids, emits structured output, and keeps payload hydration explicit.
Full CLI docs: docs/AGENT_CONTROL_PLANE.md.
Provider-backed runs use :adapter :sdk, a provider id, model ids, and provider
configuration supplied by your runtime environment or local secret manager. Keep
credentials out of tracked files.
For live recursion, set explicit leashes:
{:adapter :sdk
:provider :provider-key
:model "root-model-id"
:harness :rlm
:child-model "child-model-id"
:leaf-model "leaf-model-id"
:store :sqlite
:store/dir ".fractal/sessions/live-demo"
:max-steps 8
:max-turns 4
:call-timeout-ms 90000
:max-fanout 4
:fanout-pool 2
:leaf-concurrency 2
:cache-ttl "5m"}
Live validation is opt-in and may spend money. See
docs/LIVE_VALIDATION.md.
Build the thin library jar:
clojure -T:build jar
Build the CLI uberjar:
clojure -T:build uber
java -jar target/fractal.jar help
Install the library jar into the local Maven repository:
clojure -T:build install
Release automation is tag-driven. Pushing a v* tag from a commit that contains
the release workflow will:
CLOJARS_USERNAME and
CLOJARS_PASSWORD repository secrets;target/fractal.jar.The release version is derived from the tag name without the leading v.
After a release is published, depend on the Clojars coordinate:
{:deps {net.clojars.deadmeme5441/fractal-engine {:mvn/version "0.5.0"}}}
Then use the public facade:
(require '[fractal.engine.api :as fe])
Do not depend on internal runtime namespaces unless you are contributing to the engine itself.
Default offline gate:
clojure -M:test
git diff --check
Optional live suite:
clojure -M:live-test
The default test alias excludes ^:live tests and should not make network calls
or require credentials.
src/fractal/engine/api.clj: public SDK facade.src/fractal/engine/cli.clj: agent CLI facade.docs/: public maintainer and user documentation.spec/: architecture record and design rationale.test/fractal/engine/: offline and opt-in live tests.Recommended docs:
docs/README.md: v1 overview.docs/GETTING_STARTED.md: SDK and CLI walkthrough.docs/API.md: public API reference.docs/AGENT_CONTROL_PLANE.md: CLI contract.docs/ARCHITECTURE.md: runtime architecture.docs/STORAGE_AND_HEADS.md: storage and heads.docs/RECURSION.md: recursion semantics.docs/TESTING.md: validation guide.Apache-2.0. See LICENSE.
Can you improve this documentation? These fine people already did:
DeadMeme5441 & DeadMemeEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |