nav-etc.sx had its own plans-nav-items (35 entries) that loaded after
nav-data.sx (36 entries) and silently overwrote it, hiding sx-host.
All nav items are now solely defined in nav-data.sx.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace WebTransport-only design with three-transport model:
- Browser↔server: WebSocket (works today, no infrastructure changes)
- Browser↔browser: WebRTC data channels (true P2P, NAT traversal)
- Server↔server: HTTP federation (existing sx-pub)
Home nodes relay WebRTC signaling. Reliable channels for chat/components,
unreliable channels for game state/cursor positions. Transport-agnostic
protocol layer — upgrade to WebTransport later with zero SX changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Debugging & analysis section to tool catalogue (sx_trace, sx_deps,
sx_build_manifest)
- Update harness entry to mention multi-file and setup support
- Update tool count from 35+ to 40+
- Add tool table to CLAUDE.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 2d: shared-signal primitive — local signal writes propagate to
peers via WebTransport rooms. Same deref/reset!/swap! API, networking
invisible to the reactive layer. LWW default, CRDT opt-in.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two new demo pages with live interactive islands:
Cyst (/geography/reactive/examples/cyst):
Parent island with a cyst inside. Parent + button increments parent
count, cyst + button increments cyst count. Cyst state survives
parent re-renders. Shows the isolation boundary in action.
Reactive Expressions (/geography/reactive/examples/reactive-expressions):
Temperature signal with 5 expression types all updating live:
bare deref, str+deref, arithmetic+deref, full conversion string,
conditional. Demonstrates that any expression containing deref
auto-tracks signal dependencies.
Both verified reactive with Playwright clicks on the live server.
Nav entries added to reactive-examples-nav-items.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New defisland ~sx-tools/tool-playground: paste SX source, click a tool
button, see the output. 7 tools run client-side in the browser:
summarise, read-tree, find-all, validate, get-context, serialize,
hypersx.
Each uses the same SX functions the MCP server uses: sx-parse for
parsing, tree walking for annotation/summarise/find, sx-serialize for
round-trip, sx->hypersx for alternative syntax.
Pre-loaded with a sample defcomp. Users can paste any SX and explore
all the comprehension tools interactively.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added 7 new documentation sections with code examples:
- Cyst: isolated reactive subtrees that survive parent re-renders
- Reactive expressions: auto-wrapping deref-containing exprs in computed
- Live island preview: paste defisland, get working reactive preview
- HyperSX: indentation-based alternative syntax viewer
- Inline test runner: browser-embedded test execution with pass/fail
- Test harness: three-layer test infrastructure (core/reactive/web)
- Core signals: spec-level reactive primitives, zero platform deps
Each section has code examples. The test runner section links to the
live temperature converter demo with 5/5 inline tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New language feature: (cyst [:key id] body...) creates a DOM container
with its own island scope that persists across parent reactive re-renders.
On first render, the body is evaluated in a fresh with-island-scope and
the resulting DOM is cached. On subsequent renders, the cached DOM node
is returned if still connected to the document.
This solves the fundamental problem of nesting reactive islands inside
other islands' render trees — the child island's DOM (with its event
handlers and signal subscriptions) survives when the parent re-renders.
Implementation: *memo-cache* dict keyed by cyst id. render-dom checks
isConnected before returning cached node. Each cyst gets its own
disposer list via with-island-scope.
Usage in sx-tools: defisland render preview now wrapped in (cyst :key
full-name ...). Real mouse clicks work — counter increments, temperature
converts, computed signals update. Verified on both local and live site.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Removed auto-parse on source change (the (reset! parsed ...) at top
of letrec body). Only Parse button triggers parsing now.
- Split defcomp/defisland render: defcomp uses parameter substitution
with bindings signal, defisland uses live component call.
- Removed stopPropagation wrapper (didn't help).
Island previews are reactive — signals, computed, swap! all work.
Known: Playwright's click (which triggers focus change from textarea)
resets the island. Direct JS clicks and PointerEvent dispatches work
correctly. Real islands on demo pages work perfectly with mouse clicks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The island preview refactoring replaced both defcomp and defisland
handling with sx-load-components + component call. This broke parameter
substitution for defcomp (which uses bindings signal for live preview).
Split the cond: defcomp uses the original subst approach (extract params,
read bindings, substitute symbols in body). defisland uses the live
preview via sx-load-components + native render-dom-island.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- render-html-island wraps body SSR in cek-try (graceful fallback to
empty container when island body has DOM/signal code)
- defcomp placeholder pattern: server renders safe placeholder div
with data-sx-island, browser hydrates the actual island
- cek-try primitive added to both server and browser OCaml kernels
- assert/assert= added to spec/harness.sx for standalone use
- Test source stored in <script type="text/sx-test" data-for="...">
with HTML entity decoding via host-call replaceAll
Temperature converter: 5 tests embedded in demo page. Test runner
hydrates and finds tests but body render is empty — needs debugging
of the specific construct that silently fails in render-to-dom.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Temperature converter tests (6 tests): initial value, computed
fahrenheit derivation, +5/-5 click handlers, reactive propagation,
multiple click accumulation.
New components:
- sx/sx/reactive-islands/test-runner.sx — reusable defisland that
parses test source, runs defsuite/deftest forms via cek-eval, and
displays pass/fail results with re-run button
- sx/sx/reactive-islands/test-temperature.sx — standalone test file
Added cek-try primitive to both browser (sx_browser.ml) and server
(sx_server.ml) for safe test execution with error catching.
Browser bundle now includes harness files (harness.sx,
harness-reactive.sx, harness-web.sx) for inline test execution.
Known: SSR renders test runner body instead of placeholder, causing
arity error on complex str expressions. Needs island SSR handling fix.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
defisland expressions are now rendered as fully reactive live previews.
The component is registered via sx-load-components, then called through
the native render-dom-island adapter path — same code path as real
islands on the page.
Bare (deref sig) expressions are fully reactive — clicking buttons
updates signal values and DOM updates in real time. Compound expressions
like (str (deref c) "°C") render statically (cek-reactive-text only
tracks bare deref). Next: auto-wrap deref-containing expressions in
computed signals for full reactive expression support.
Also cleaned up stale effect and preview-el signal from earlier attempts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
defisland expressions in the render tab are now evaluated through
render-to-dom inside with-island-scope, producing real DOM with signal
bindings. The rendered output persists in a stable container managed by
an effect, outside the reactive render tree.
Known limitation: signal subscriptions don't fire on button clicks yet —
the reactive wiring needs investigation into how deferred (setTimeout)
execution contexts interact with CEK signal tracking. Static rendering
(initial values) works correctly.
Also: removed stale effect that attempted hydrate-island approach.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- sx_changed: list .sx files changed since a ref with structural summaries
- sx_diff_branch: structural diff of all .sx changes vs base ref
- sx_blame: git blame for .sx files, optionally focused on a tree path
- sx_doc_gen: generate component docs from defcomp/defisland signatures
- sx_playwright: run Playwright browser tests with structured results
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New comprehension tools:
- sx_find_across: search pattern across all .sx files in a directory
- sx_comp_list: list all definitions (defcomp/defisland/defmacro/defpage/define)
- sx_comp_usage: find all uses of a component across files
- sx_diff: structural diff between two .sx files (ADDED/REMOVED/CHANGED)
- sx_eval: REPL — evaluate SX expressions in the MCP server env
Smart read_tree enhancements:
- Auto-summarise large files (>200 lines)
- focus param: expand only matching subtrees, collapse rest
- max_depth/max_lines/offset for depth limiting and pagination
Smart editing tools:
- sx_rename_symbol: rename all occurrences of a symbol in a file
- sx_replace_by_pattern: find+replace first/all pattern matches
- sx_insert_near: insert before/after a pattern match (top-level)
- sx_rename_across: rename symbol across all .sx files (with dry_run)
- sx_write_file: create .sx files with parse validation
Development tools:
- sx_pretty_print: reformat .sx files with indentation (also used by all edit tools)
- sx_build: build JS bundle or OCaml binary
- sx_test: run test suites with structured pass/fail results
- sx_format_check: lint for empty bindings, missing bodies, duplicate params
- sx_macroexpand: evaluate expressions with a file's macro definitions loaded
Also: updated hook to block Write on .sx files, added custom explore agent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sx->hypersx transform converts parsed SX to a readable indentation-based
format: CSS selector shorthand (div.card#main), signal sugar (@count,
signal(), :=, <-), string interpolation ("Count: {@count}"), and
structural keywords (when, if, let, map, for).
Implemented as pure SX in web/lib/hypersx.sx, loaded in browser via
js_of_ocaml platform. Added as "hypersx" tab in the tree editor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Register cond-scheme? as OCaml primitive — was defined in spec/evaluator.sx
but never exposed to the browser runtime, causing render.sx to crash with
"Undefined symbol: cond-scheme?" on every SX response. This broke URL
updates on navigation (handle-history never ran after the rendering error).
Tree editor render tab now extracts &key params from defcomp/defisland
definitions and shows input fields. Values substitute into the rendered
preview live as you type. Inputs live outside the reactive cond branch
so signal updates don't steal focus.
sx-tools page function accepts &key params (title, etc.) forwarded to
the overview component.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The render tab now correctly renders HTML tag expressions as live DOM
(div, h2, p, ul, etc. with Tailwind classes). Non-HTML expressions
(defcomp, define, etc.) are shown as serialized SX text.
Previous version tried eval-expr which errored silently in the browser.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tree editor island now has 4 tabs: tree, context, validate, render.
The render tab evaluates SX source as live HTML — type a (div (h2 "Hello"))
and see it rendered immediately.
MCP server paths changed from JSON arrays [0,2,1] to SX strings "(0 2 1)".
Fixes serialization issues and is more natural for an SX tool. The
json_to_path function now parses SX via sx-parse.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 4: defisland ~sx-tools/tree-editor — interactive tree viewer
embedded in the SX Tools page. Features:
- Textarea with :bind for SX source input
- Parse button to re-parse on demand
- Tree view: annotated tree with path labels, clickable nodes
- Context view: enclosing chain from root to selected node
- Validate view: structural integrity checks (catches missing body etc.)
MCP server fixes: added ident-start?, ident-char?, make-keyword,
escape-string, sx-expr-source — needed by parser.sx when loaded
into the MCP evaluator.
Also: .mcp.json for Claude Code MCP server config, CLAUDE.md protocol
for structural .sx file editing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two bugs caused code blocks to render empty across the site:
1. ~docs/code component had parameter named `code` which collided with
the HTML <code> tag name. Renamed to `src` and updated all 57
callers. Added font-mono class for explicit monospace.
2. Batched IO dispatch in ocaml_bridge.py only skipped one leading
number (batch ID) but the format has two (epoch + ID):
(io-request EPOCH ID "name" args...). Changed to skip all leading
numbers so the string name is correctly found. This fixes highlight
and other batchable helpers returning empty results.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two paren bugs in home-stepper.sx caused the home page to render blank:
1. Line 222 had one extra ) that prematurely closed the letrec bindings
list — rebuild-preview and do-back became body expressions instead
of bindings, making them undefined in scope.
2. Lines 241-308 were outside the let/letrec scope entirely — the outer
let closed at line 240, so freeze-scope, cookie restore, source
parsing, and the entire div rendering tree had no access to signals
or letrec functions.
Also hardens defisland to wrap multi-expression bodies in (begin ...),
matching the Python-side fix from 9f0c541. Both spec/evaluator.sx and
the OCaml transpiled sx_ref.ml are updated.
Adds SX Tools essay under Applications — the revised plan for structural
tree reading/editing tools for .sx files, motivated by this exact bug.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Brings in sx-pub federated publishing protocol (Phases 1-4):
- DB models, IPFS publishing, federation, anchoring
- Live dashboard UI on the plan page
- Dev infrastructure (docker-compose, dev-pub.sh)
Conflicts: sx-browser.js (kept ocaml-vm rebuild), sx-pub.sx (kept sx-pub version with dashboard)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- do-back: uses steps-to-preview + render-to-dom (O(1) render)
instead of replaying every do-step from 0 (O(n) DOM ops + cssx)
- Hydration effect: same rebuild-preview instead of step replay
- Cookie save moved to button on-click only (not per-step)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Promotes reactive-runtime from a plan page to a full applications section
with 7 nav items (ref, foreign FFI, state machines, commands, render loop,
keyed lists, app shell) and its own page function.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the VM called a JIT-compiled lambda, it passed vm.globals
(the caller's global env) instead of cl.vm_env_ref (the closure's
captured env that was merged at compile time). Closure-captured
variables like code-tokens from island let/letrec scopes were
invisible at runtime, causing "Undefined symbol" errors that
cascaded to disable render-to-html globally.
Fix: call_closure uses cl.vm_env_ref at both call sites (cached
bytecode and fresh compilation).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
rebuild-preview had one extra close paren that closed the outer
(when container) prematurely, pushing do-back and build-code-dom
out of the letrec scope. Result: "Undefined symbol: build-code-dom".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Platform:
- sx-platform.js: extract ?v= query from script tag URL, append to
all .sx file XHR requests. Prevents stale cached .sx files.
Stepper performance:
- do-back: use rebuild-preview (pure SX→DOM render) instead of
replaying every do-step from 0. O(1) instead of O(n).
- Hydration effect: same rebuild-preview instead of step replay.
- Cookie save moved from do-step to button on-click handlers only.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Server-rendered dashboard showing live data from sx-pub API:
- Server status (DB, IPFS, actor, domain)
- Actor identity card with public key
- Collections grid with paths
- Published documents with CIDs and sizes
- Recent outbox activity feed
- Followers list
- API endpoint links for direct access
All phases marked as complete.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New endpoints:
- POST /pub/anchor — batch unanchored Publish activities into Merkle tree,
pin tree to IPFS, submit root to OpenTimestamps, store OTS proof on IPFS
- GET /pub/verify/<cid> — verify a CID's Merkle proof against anchored tree
Uses existing shared/utils/anchoring.py infrastructure:
- build_merkle_tree (SHA256, deterministic sort)
- get_merkle_proof / verify_merkle_proof (inclusion proofs)
- submit_to_opentimestamps (3 calendar servers with fallback)
Tested: anchored 1 activity, Merkle tree + OTS proof pinned to IPFS,
verification returns :verified true with full proof chain.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New endpoints:
- GET /pub/outbox — paginated activity feed
- POST /pub/inbox — receive Follow/Accept/Publish from remote servers
- POST /pub/follow — follow a remote sx-pub server
- GET /pub/followers — list accepted followers
- GET /pub/following — list who we follow
Federation mechanics:
- HTTP Signature generation (RSA-SHA256) for signed outgoing requests
- HTTP Signature verification for incoming requests
- Auto-accept Follow → store follower → send Accept back
- Accept handling → update following state
- Publish mirroring → pin remote CID to local IPFS
- deliver_to_followers → fan out signed activities to all follower inboxes
- Publish now records activity in outbox for federation delivery
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New endpoints:
- POST /pub/publish — pin SX content to IPFS, store path→CID in DB
- GET /pub/browse/<collection> — list published documents
- GET /pub/doc/<collection>/<slug> — resolve path to CID, fetch from IPFS
- GET /pub/cid/<cid> — direct CID fetch (immutable, cache forever)
New helpers: pub-publish, pub-collection-items, pub-resolve-document, pub-fetch-cid
Tested: published stdlib.sx (6.9KB) → QmQQyR3Ltqi5sFiwZh5dutPbAM4QsEBnw419RyNnTj4fFM
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The opam base image has dune in the switch but not on PATH.
RUN eval $(opam env) doesn't persist across layers. Install dune
explicitly and set PATH so dune is available in build steps.
Also fix run-tests.sh to respect QUICK env var from caller
(was being overwritten to false).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three issues in the stepper island's client-side rendering:
1. do-step used eval-expr with empty env for ~cssx/tw spreads — component
not found, result leaked as [object Object]. Fixed: call ~cssx/tw
directly (in scope from island env) with trampoline.
2. steps-to-preview excluded spreads — SSR preview had no styling.
Fixed: include spreads in the tree so both SSR and client render
with CSSX classes.
3. build-children used named let (let loop ...) which produces
unresolved Thunks in render mode due to the named-let compiler
desugaring interacting with the render/eval boundary. Fixed:
rewrote as plain recursive function bc-loop avoiding named let.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add sx-pub plan page under Applications with full protocol spec:
wire format, endpoints, storage, flows, AP critique, phases
- Add nav entry and page function for /sx/(applications.(sx-pub))
- Add docker-compose.dev-pub.yml (sx_docs image + DB + IPFS + Redis)
- Add dev-pub.sh launch script (pub.sx-web.org via Caddy)
- Rebuild sx-browser.js with var fixes for SES compatibility
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>