Commite0b17ab4Recorded21 Feb 2026Repositorysigil-web-demo

feat: Add live-coding support via nREPL and SSE reload

Message

Add the infrastructure for live-coding Sigil web applications. An AI agent or editor connects to a running app's nREPL, redefines handlers or views, and triggers a browser refresh — no page reload needed.

New modules: - (sigil web dev): Dev broadcast channel, dev-reload!, dev-morph!, dev-error!, dev-sse-handler for SSE-based browser refresh - (sigil nrepl client): Reusable nREPL client for connecting to running Sigil apps over TCP - (sigil mcp dev-tools): MCP tools (dev-connect, dev-eval, dev-reload, dev-status, dev-disconnect) that proxy to nREPL

Changes: - (sigil web ui): Add sse-reload event for page re-fetch + Idiomorph morph - sigil-web-ui.js: Handle sigil:reload event with fetch + morph cycle - Vinyl Vault demo: Wire up nREPL server (port 7888) and dev SSE endpoint

Changed
 package.sgl                  |  1 +
 src/sigil/web/demo.sgl       | 17 +++++++++++++++--
 src/sigil/web/demo/views.sgl |  3 ++-
 3 files changed, 18 insertions(+), 3 deletions(-)
Diff
package.sglmodified
@@ -16,6 +16,7 @@
16
(from-workspace name: "sigil-stdlib")
17
(from-workspace name: "sigil-http")
18
(from-workspace name: "sigil-web")
+19
(from-workspace name: "sigil-nrepl")
20
(from-workspace name: "sigil-sqlite")
21
(from-workspace name: "sigil-sxml")
22
(from-workspace name: "sigil-css")))
src/sigil/web/demo.sglmodified
@@ -15,6 +15,8 @@
15
(sigil http request)
16
(sigil web)
17
(sigil web ui)
+18
(sigil web dev)
+19
(sigil nrepl)
20
(sigil sqlite)
21
(sigil web demo db)
22
(sigil web demo views))
@@ -222,7 +224,8 @@
224
(route method: POST pattern: "/records" handler: create-record-handler)
225
(route method: POST pattern: "/records/:id" handler: update-record-handler)
226
(route method: DELETE pattern: "/records/:id" handler: delete-record-handler)
225
(route method: GET pattern: "/js/sigil-web-ui.js" handler: (sigil-web-ui-handler))))
+227
(route method: GET pattern: "/js/sigil-web-ui.js" handler: (sigil-web-ui-handler))
+228
(route method: GET pattern: "/__dev/events" handler: (dev-sse-handler))))
229
(with-db _ db)
230
(with-logging)
231
(with-content-type default: "text/html; charset=utf-8")
@@ -230,10 +233,20 @@
233
234
;;; Start the demo server.
235
(define (start-demo)
233
(let ((db (sqlite-open "vinyl-vault.db")))
+236
(let ((db (sqlite-open "vinyl-vault.db"))
+237
(dev (make-dev-broadcast)))
238
(init-db db)
239
(display "Vinyl Vault running at http://localhost:8080\n")
+240
(display "nREPL at port 7888\n")
241
(with-async
+242
;; nREPL goroutine
+243
(let ((nrepl (nrepl-start 7888)))
+244
(when nrepl
+245
(go (let loop ()
+246
(nrepl-process-pending nrepl)
+247
(sleep 0.05)
+248
(loop)))))
+249
;; HTTP server
250
(http-serve (make-app db) port: 8080))))
251
252
))
src/sigil/web/demo/views.sglmodified
@@ -393,7 +393,8 @@
393
(li (a (@ (href "/records/new")) "Add Record")))))
394
(div (@ (id "sg-flash-container")))
395
(main (@ (class "container"))
396
,body-content))))
+396
,body-content)
+397
(div (@ (data-sg-sse "/__dev/events") (style "display:none"))))))
398
399
;; ============================================================
400
;; Pages