🦎 In Which The Lizard Speaks Truth
It was 1:47 AM. The developer sat surrounded by nine glowing screens (not a laptop, a command center), staring at the signal inspector. The signals were there. Beautiful, reactive, perfectly namespaced. Except they weren’t. They were at the root level. Again.
A small lizard appeared on screen 7.
“You’re fighting windmills,” the Lizard said.
“But the signals! The reactivity! The components!” the developer protested.
“Reactive signals are wonderful,” the Lizard replied, crawling across to screen 4. “But you’re using a sports car to plow a field.”
The Architecture Mismatch
Let the record show: Reactive signal frameworks are genuinely excellent.
They combine the best ideas from modern frontend development into elegant packages. Signal systems are reactive and intuitive. Real-time integration is first-class. The syntax is clean. The bundle sizes are tiny.
What signal-based MPA frameworks excel at:
- Enhancing server-rendered pages with sprinkles of reactivity
- Real-time dashboards where client state matters
- Interactive widgets that need local state management
- Applications where the page IS the application
What we tried to build:
- A SPA-like sidebar that navigates between domains
- Forms where server-side state is the source of truth
- SSE-patched content that needed signal namespacing
- 100 forms that all work the same boring way
🐿️ The Squirrel, caffeinated and twitchy, pointed at the screen: “Look! The component template processes signals at render time! But we’re SSE-patching content AFTER render! The signals never get namespaced!”
The Windmill Revelation
The framework authors were right all along: “This is not for SPA.”
We tried to make an MPA framework do SPA things:
- Navigate without page reload ❌
- Maintain signal state across navigations ❌
- Namespace SSE-patched content ❌
- Garbage collect signals on navigation ❌
We fought:
- Form content types vs signals
- Signal prefix locality
- Form parsing vs signal reading timing
- Template render-time vs SSE patch-time
The core issue: Component systems rewrite signal bindings when the template renders. But SSE-patched content arrives AFTER render. The train has left the station. The signals are orphans at the root level.
🦎 “You can’t retrofit namespacing onto content that missed the rewrite pass,” the Lizard said, now on screen 2. “It’s like trying to stamp a passport after they’ve left the country.”
What We Learned (The Treasure)
The V3 experiment was not a failure. It was an education.
Technical learnings:
- Signals prefixed with
_are typically local-only (never sent to server) - SSE helpers often consume the request body - read form/signals BEFORE
- Component namespacing happens at template render time, not patch time
- Form submission doesn’t need reactive signals - just
nameattributes - Server-authoritative forms don’t benefit from client-side reactivity
Philosophical learnings:
- Don’t use a reactive framework for server-authoritative forms
- The DOM is truth - when the element dies, the behavior dies
- Boring technology is beautiful technology
- If you’re fighting the framework, you’re using the framework wrongly
- 🦎 “The best abstraction is the one you don’t have to think about”
Architectural learnings (we keep these!):
- Nav chrome pattern (header, content, footer)
- FooterMode state machine (List, View, Edit, Create, Pick)
- Picker pattern with putURL
- Domain registry pattern
- GitStore for server-side drafts
- The gorgeous V3 UI design
🐿️ The v2 Homecoming
The Squirrel’s ears perked up. “Remember V2? Remember hx-swap-oob? Remember when things just… worked?”
“We lived two years without loading states,” the developer nodded.
“Because your server responds in 50ms!” the Squirrel chittered. “You don’t NEED loading states!”
The realization hit like a mass of caffeinated rodent:
We already had the answer. We’d been using it for two years.
<!-- This is the way -->
<div hx-ext="sse" sse-connect="/sse" sse-swap="message">
<!-- Server sends HTML, it just appears -->
</div>
No signals to manage. No namespacing to debug. No content-type gymnastics.
Server says “here’s some HTML.” Client says “okay” and puts it in the DOM.
The V4 Stack:
- HTMX 2.x (the boring workhorse)
hx-ext="sse"(streaming we know and love)hx-swap-oob="true"(server controls what updates)- Hyperscript (local UI sugar, when needed)
- Templ (HTML templating, unchanged)
- Go + Cobra (backend, unchanged)
Announcing V4: Codename “Solid”
The Lizard climbed to the top of screen 9 and cleared its throat.
“Let it be known throughout the land:
V3 served its purpose - to teach us what NOT to do.
V4 rises from these learnings. Clean. Boring. Solid.
One repo. One binary. Cobra subcommands.
solid mon # monitoring
solid reason # AI chat/reasoning
solid log # lifelog
The Solid family inherits:
- The V3 UI (gorgeous)
- The V3 architecture (sound)
- The V2 patterns (proven)
- The Lizard’s wisdom (eternal)
The Solid family discards:
- Signal gymnastics
- Component namespacing battles
- Framework fighting
- 1:47 AM debugging sessions
🐿️☕ The Squirrel raised a tiny coffee cup: “To boring technology!”
🦎 The Lizard nodded solemnly: “To knowing when to change course.”
The Final Commit Message
feat(v3): Complete the reactive signals experiment
What we built:
- Signal-based forms with reactive UI
- Component namespacing for isolation
- Blur auto-save with optimistic concurrency
- A lot of documentation
What we learned:
- Reactive MPA frameworks are excellent (for what they're designed for)
- We were building a SPA in an MPA framework
- HTMX + SSE does everything we need
- The DOM is truth
What comes next:
- V4 "Solid" with HTMX
- One form, thought through completely
- 100 forms, all the same boring way
🦎 "Is it fun to fight windmills?" - No. No it is not.
Co-Authored-By: The Lizard <wisdom@localhost>
Co-Authored-By: The Squirrel <coffee@localhost>
And so V3 was archived, its lessons preserved in markdown, its spirit living on in V4.
The Lizard returned to guarding the codebase.
The Squirrel went to find more coffee.
The developer, finally, went to sleep.
Tomorrow, they would build something solid.
🦎🐿️☕
THE END
(of V3)
See also:
The Saga (in which endings become beginnings):
- The Solid Convergence - V4 rises from V3’s ashes
- The Signal Safari - The deep dive into signals that led here
- The Lizard Brain vs The Caffeinated Squirrel - The philosophy that knew when to stop
The References (knowing when to change course):
- [HTMX](https://htmx.org/) - The boring workhorse that was right all along
- [Choose Boring Technology](https://mcfunley.com/choose-boring-technology) - Dan McKinley’s wisdom, validated again
