fulcro

tony.kay 2026-02-18T00:04:05.829699Z

Recent Fulcro releases have added everything you need to get headless CLJC stuff working (e.g. run your app in your JVM WITH your server). This leads to VERY fast e2e testing abilities, fast LLM interaction (LLM runs the app and server together, and is able to see a hiccup UI instead of using playwright et al). Should be MUCH faster to dev with LLMs. On that front I’ve also added async chart support to statecharts and am working on a new composable “routing” system that treats the statechart as a projection of the URL (e.g. URL shows app state. period, and editing URL is a request to move to a state in the statechart). The goal is a system-as-a-statechart where UI and URL are external concerns (as Fulcro always tries to make them be), but on a new level. Routing systems have to invent a bunch of “features” to deal with the I/O story of the app (componentDidMount, hooks, and other “great ideas” that pepper your logic into poorly chosen spots). With a statechart, which has all of your concerns covered (on-entry, on-exit, raising events, etc etc) you no longer need a “routing” system. What you need is some node types that also happen to help you change what’s on screen. Instead of your app “using a routing system” your app is simply structured the way that “makes sense” and the features of the chart give you all of the data manipulation logic. Entering a state causes the data structures underneath to morph so that the “right thing” also happens to be on screen. See https://github.com/fulcrologic/fulcro/blob/main/src/test/com/fulcrologic/fulcro/headless_spec.clj for some details (this is mostly rendering to the server dom data tree…but there’s also a transformer to hiccup as well) More to come…

2
👀 2
3
michaelwhitford 2026-02-21T17:00:42.258839Z

Wow thank you for these updates to statecharts, my system is fully using all of it to VERY good effect. The git backed persistence is allowing my agents to recover across sessions beautifully.

tony.kay 2026-02-22T00:13:28.534449Z

Nice! glad to hear you’re seeing similar benefits

michaelwhitford 2026-02-19T15:12:09.674569Z

I incorporated these changes into my current project and they are awesome! Thank you very much for these changes. I did notice a few things. The digest function is awesome for letting the LLM see the "flow" of the app. The only problem is it shows too much data by default. I have a web based chat ui for AI agents, and just a short conversation with tool calls was enough data to fill 200k context from the AI calling rt/digest. I had the AI create a ui_digest tool that offers progressive communications, showing the top level, and truncating long strings and values, with the option to dig deeper as needed and that is working well. I wrote my entire AI agent framework in statecharts, and am using them from within fulcro by starting a simple env with event loop. I have mutations setup that allow fulcro and the statecharts to communicate. The new headless setup is much better for this, but is still not perfect. I would like to be able to have this coupled better, but I am not sure how to make it work. I would love to have statecharts that run in clojure with full access to fulcro, without having to run 2 different environments with mutations bridging them. I feel there is a ton of fulcro and fulcro-rad functionality that I could use from my statecharts if this was more tightly integrated. I'm not a programmer by trade, just a hobbyist so I am not sure how to make this work better. I really like statecharts for full control and introspection, and have been using them for a couple years now for most of my projects. They are especially useful to AI because the AI can see everything easily with almost no special tooling required once you create a good concise prompt on the tools available in statecharts, like the simple and runtime namespaces. I like the direction you are going and look forward to seeing the statecharts changes you are hinting at here.

tony.kay 2026-02-19T16:02:47.696639Z

We’re launching a new project and are in the midst of writing a statecharts-integrated version of the RAD primitives…not sure if/when we’ll release that. Not sure what you mean with the digest bit polluting your window. I’m not using that directly in my AI flows much. In terms of comms I’m also not sure 2 diff envs? The RAD stuff is already able to be used from statecharts…you just make a new state type that starts the UISM. I’m working on ui_routes stuff in statecharts right now (about to release a big bump in that) and when done the whole ecosystem will be aimed at composable systems as statecharts.

tony.kay 2026-02-19T16:03:17.493419Z

Our results with headless testing dev with LLMs is spectacular…Super fast. One-shot getting things completely right.

michaelwhitford 2026-02-19T16:17:44.223759Z

Fulcro can start a statechart as part of the client db env in clojurescript, but I want my agent loop to run whether the browser is running or not, the web ui is just a way to see what is happening with the agents. Currently i could not figure out a way to get fulcro to start these statecharts integrated, so I have a bootstrap that runs from server.clj that starts a simple env and event loop. Then I created mutations, for example the web ui chat uses a mutation to send the conversation to the agent statechart, which processes it, and sends it back using a server push over the websocket remote so the response shows up in the chat ui.

tony.kay 2026-02-19T16:24:31.311919Z

Are you using headless CLJC stuff? Sounds like “no”…for websockets your setup would be a little more involved, but I think still possible. The latest Fulcro even has a CLJ implementation of a lot of React Hooks (though I prefer not to use those for real logic/data needs). I’ve built a “headless” skill for AI, and a CLJ stubs skill (which explains how to write a “working but minimal” CLJ version of things). For example I tell it for UI components (like js dropdowns) just make a wrapper that converts it to a dom select with the proper callbacks made available. For things like pretty graphs just emit a div and convert all attributes to have :data- prefixes so the tests can see the inputs sent to the component

michaelwhitford 2026-02-19T16:31:47.285609Z

I converted it to use the headless stuff from 3.9.3 last night. It seems to work well, but I still am using cljs for the web ui with statechart routing. I don't want a fully headless setup, more of a hybrid one. The web ui is great the way it is, I just hate how I have to bridge to the statecharts that are running outside fulcro using mutations. To me headless implies no browser, but I use the browser for a chat interface, and various rad reports that pull data from the agent statecharts using mutations.

michaelwhitford 2026-02-19T16:33:58.954889Z

The agent statecharts run contantly, so I don't want that to stop if I close the browser. I originally was using statecharts started in cljs but when I'd close the browser it would all stop working. That lead to this hybrid setup where I have a statecharts simple env started from server.clj and the mutations for communication.

michaelwhitford 2026-02-19T16:46:12.247319Z

Here is a link to an older app where i started playing with this setup, in this app I kept it all to 1 component. https://gitlab.com/michaelwhitford/gailish/-/blob/main/src/main/us/whitford/gailish/components/mattermost_bot.clj?ref_type=heads#L633

michaelwhitford 2026-02-19T16:48:17.111419Z

In my newest app that is unreleased yet I am starting an nrepl server, and the statecharts simple env from server.clj so that the AI can access the entire system from the nrepl. For dev I have it start the shadow-cljs repl, and with my clojure-mcp-light tools it can access both nrepls as needed.

tony.kay 2026-02-19T17:19:57.977549Z

I’m using the term “headless” to mean you can run the UI and server in the server during LLM and tests…you still have the web ui as what users would use. The point is to have fast LLM interaction/turnarounds without needing a browser in that loop. On your statecharts issue: You’re saying that you want persistent statecharts in the browser…well, you could just make them fully server-side and just bridge it with what looks like an event queue (e.g. you send events to the server as statechart events, and it returns the new config). I’ve toyed with more advanced ideas (full-stack statechart where the chart runs in both, but that gets kinda crazy). You could also run the statechart with a new implementation of the statechart working memory store using browser local storage…lots of options.

tony.kay 2026-02-19T17:22:46.042939Z

I’m about to release statecharts 1.3.1 (1.3.1-SNAPSHOT is available now). I’ve been calling the ui routing “alpha”…the new version has a few minor breaking changes. Be interested in your feedback. The Guide.adoc was ai-updated on the routing-rewrite branch in github.

michaelwhitford 2026-02-19T17:24:41.102179Z

That bridging part is where I use mutations currently. I click send on a chat in the browser, it fires a mutation that sends the data to the statechart as an event with a data payload. The statechart processes it through an LLM api, then when the response comes back it uses a push from fulcro to send that response back to the webui over a websockets remote.

✅ 1
tony.kay 2026-02-19T17:26:20.117339Z

The new routing stuff allows for full composition (e.g. an invocation state can have subroutes, and even be dynamically loaded module). The URL integration is better…and I think the params stuff…I’m still testing it before I actually release it to see how well it works headless and in UI under various scenarios…there is a demo in https://github.com/fulcrologic/statecharts/tree/routing-rewrite/src/routing-demo2/com/fulcrologic/statecharts/routing_demo2

tony.kay 2026-02-19T17:26:44.281069Z

Main API change is :route/path changed to :route/segment…the params are no longer part of the path ever…and even that isn’t required…defaults to just using the component’s name. If you see holes, let me know

michaelwhitford 2026-02-19T17:28:39.606889Z

I will have time tomorrow to explore these new changes, thank you.

tony.kay 2026-02-19T17:31:13.255969Z

sure….I’m trying them now and there is some breakage…had AI do some of the URL sync work, and it appears flaky at best…oh, looks like it was the demo that was the problem, not the code of the lib.

tony.kay 2026-02-19T22:44:59.875139Z

I decided to revert the original ns and put the new stuff in a new pkg…so I won’t break your code with the update…it was marked alpha, but I still think now that I’ve got more files it just makes it ok to deprecate the old thing instead.

michaelwhitford 2026-02-19T22:47:57.714579Z

I think I can live with that, I just incorporated 1.3.0 into my new app, and the old app can stay pointed to the earlier versions if you just want to go for it.

michaelwhitford 2026-02-19T22:48:33.132499Z

Turns out about 80% of what I had you eliminated with the async statechart support.

tony.kay 2026-02-19T22:56:54.692079Z

Yeah, that was a mind-blowingly good idea…honestly, my “laziness”/“lack of time” had kind of blocked it from my mind by not having time to write it…then I realized I could have AI give it a shot. Last friday I was literally starting a convo with AI and was about to type “help me figure out how to eliminate this cruft in js because of the stupid async nature of js…” and it hit me that all I wanted was blocking, which could be implemented as parking…it was a very meticulous and messy thing to do, but I knew AI was good at that kind of thing when it had a good ref implementation. It made a few mistakes, and there may still be bugs, but so far it looks pretty solid, and cost me very little time to do as a result.

tony.kay 2026-02-19T23:00:18.292459Z

I heard a comment the other day (a compliment to the clj-statecharts lib) that was “and you didn’t over-engineer it”, which I suspect was a “dig” at my version…but my version supports invocations in an completely arbitrary and composable way, deep history nodes (part of the spec), is pluggable in ways that allowed this easy evolution in many different ways (all of which I’ve used)…I can use it for everything I need…e.g. I use it for long-running CLJ charts with a transaction aware CLJ memory store/event queue (implemented in SQL)…Personally, I’m quite happy with the exact level of engineering I did. 😄 My teams even use it for things like server side job tracking of SQS submitting background jobs with UI progress tracking. We have a cluster running 50k+ persisted long-running (some for years) statecharts in parallel right this minute. I use it to as a scheduling system for nightly infra tasks within the cluster where one and only one node should run a job (my event queue guarantees exactly once delivery semantics on a chart, cluster wide…though the chart logic internally does have to be idempotent 😄).

michaelwhitford 2026-02-19T23:08:25.285649Z

I have written a fulcro-rad-git adapter to use git repos as memory, and feed forward communication mechanism for AI. I also wrote a git-embed rust util that turns a git repo of text files into a vector database with similarity search. git as history graph, knowledge graph, agent memory and communication, and similarity search in one. I feel I am doing very well with Opus and Sonnet, and a bit of local qwen3 thrown in.

tony.kay 2026-02-19T23:09:18.613339Z

nice

michaelwhitford 2026-02-19T23:22:49.514609Z

Your description of some of your charts, could you maybe ask your AI to extract the patterns into example statecharts in the repo? Those sound like great use cases for an agent swarm, but I'd want to use git as the backing...

tony.kay 2026-02-19T23:36:36.479349Z

The charts themselves are less interesting that the plugins: SQLDurableEventQueue, SQLMemoryStore, the thread pool/infra setup for running thread pools for event delivery across the cluster, etc. I’m guessing an LLM could roughly reproduce them from the ideas + the statecharts repo source. I don’t really have the time to do an extraction/verification/etc…even driving an LLM…too many things to proofread already,

michaelwhitford 2026-02-19T23:37:29.613859Z

I pasted your last comment and Opus is starting to design a git backed persistant statechart. hah.

tony.kay 2026-02-19T23:37:39.948369Z

exactly

tony.kay 2026-02-19T23:40:08.406499Z

it’s all an idea and a bit of nudging away

tony.kay 2026-02-20T02:58:45.035249Z

statecharts 1.4.0-RC1 released

tony.kay 2026-02-23T17:50:15.129949Z

FYI, I just realized I have a poor choice of signatures onthe routing busy hook,..I’m doing tons of review. The 1.4 API should be considered slightly unstable until I’ve worked on it a bit more. The problem with busy was that it was giving the ROUTE statechart info, and you more care about the local component. So, the signature will change to accept [app ui-props] which is much easier to use.

michaelwhitford 2026-02-23T17:53:33.116819Z

It's no problem for me, I have a full set of documentation and an agent that I can spawn to update it when you change it upstream, and then schedule more agents to integrate. git-backed persistence is pretty amazing.

💯 1