[Caml-list] Attn: Development Editor, Latest OCaml Weekly News

Alan Schmitt
2025-12-09T15:05:06Z

[-- Attachment #1: Type: text/plain, Size: 17984 bytes --]

Hello

Here is the latest OCaml Weekly News, for the week of December 02 to 09,
2025.

Table of Contents
─────────────────

editors dev-meeting: 15th of December about the `ocaml.nvim' plugin
Mosaic - A Modern Terminal User Interface Framework for OCaml (Early Preview)
Making html_of_jsx ~10x faster
Tyre - type-safe regular expressions 1.0
Porting an OxCaml Project to Dune Package Management
Other OCaml News
Old CWN

editors dev-meeting: 15th of December about the `ocaml.nvim' plugin
═══════════════════════════════════════════════════════════════════

Archive:
<https://discuss.ocaml.org/t/ann-editors-dev-meeting-15th-of-december-about-the-ocaml-nvim-plugin/17559/1>

Charlène_Gros announced
───────────────────────

Hi!

We are organizing the next public dev meeting about editors for OCaml!

It will take place on December 15th at 5 pm.

The focus will be on the new NeoVim plugin for OCaml, which adds extra
features to the classical `lspconfig' for standard LSP support, to
provide all of the Merlin features in Neovim.

We will explore why having this type of plugin is beneficial for
maintaining OCaml editor tools, and we will dive into the codebase to
understand how it works and see what happens in Neovim.

For the agenda:

• A tour-de-table to allow the participants who wish to do so to
present themselves and mention issues / PRs they are interested in.

• Talk and Q&A

• Discuss issues and pull requests that were tagged in advance or
mentioned during the tour-de-table.

Feel free to join!

Meeting link: <https://meet.google.com/qxr-zxge-fvg>

Mosaic - A Modern Terminal User Interface Framework for OCaml (Early Preview)
═════════════════════════════════════════════════════════════════════════════

Archive:
<https://discuss.ocaml.org/t/ann-mosaic-a-modern-terminal-user-interface-framework-for-ocaml-early-preview/17572/1>

Thibaut Mattio announced
────────────────────────

I'm excited to share an early preview of [Mosaic], a modern terminal
user interface framework for OCaml.

[Mosaic] <https://github.com/tmattio/mosaic>

What is Mosaic?
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

Mosaic is a high-level framework for building terminal user interfaces
in OCaml. It provides a TEA (The Elm Architecture) runtime with a
CSS-compatible flexbox layout engine and a rich set of composable
components. It handles text shaping (styling, wrapping, selection),
focus and event bubbling, z-ordering, and responsive layout.

Under the hood, it builds on two libraries that can also be used
independently:

• *Matrix*: a terminal runtime focused on performance and modern
protocols. Highlights: near-zero-allocation diffed rendering,
immediate- mode API, Kitty keyboard, SGR/URXVT/X10 mouse, bracketed
paste, focus tracking, inline/alt/split display modes, and built-in
debug overlay/frame dumps. It also provides a virtual terminal
emulator (VTE) and pseudo-terminal (PTY) management subsystems.
• *Toffee*: a CSS-compatible layout engine. It's a port of Rust’s
[Taffy] with Flexbox, CSS Grid, and Block layout;
gap/padding/borders/titles; and layout caching for efficiency.

[Taffy] <https://github.com/DioxusLabs/taffy>

Why Mosaic?
╌╌╌╌╌╌╌╌╌╌╌

Terminal UIs are seeing a renaissance. Tools like Claude Code and
OpenCode have gotten people excited about what can be built in the
terminal and the TUI community is gaining momentum in other
ecosystems.

OCaml has had LambdaTerm and Notty for terminal graphics for years,
but there's been a gap when it comes to performance and high-level
abstractions for building complex UIs.

Mosaic aims to fill that gap by providing Matrix as a solid terminal
foundation, and building a high-level TEA framework with layout and
components on top.

On a personal side, I'm building Mosaic to power the two projects I'm
currently working on:

• It will be the basis for a TUI dashboard for monitoring model
training in [Raven]. We're starting an [Outreachy] internship to
build this out this Monday.
• It powers Spice, the upcoming OCaml coding agent I announced at
[FunOCaml 2025].

[Raven] <https://github.com/raven-ml/raven>

[Outreachy] <https://www.outreachy.org/>

[FunOCaml 2025] <https://www.youtube.com/watch?v=BAvXqd0QeVM>

Try It Now
╌╌╌╌╌╌╌╌╌╌

The libraries aren't on opam yet, but you can try them today:

*Option 1: Pin from GitHub*

┌────
│ opam pin add https://github.com/tmattio/mosaic.git
└────

*Option 2: Build from source*

┌────
│ git clone https://github.com/tmattio/mosaic
│ cd mosaic
│ opam install . --deps-only
│ dune build
└────

Then run some examples:

┌────
│ # Interactive Game of Life (ported from Notty examples)
│ dune exec ./matrix/examples/02-life/main.exe
│
│ # Particles simulation with multiple display modes
│ dune exec ./matrix/examples/14-particles/main.exe
│
│ # High-level TEA counter
│ dune exec ./mosaic/examples/01-counter/main.exe
└────

Have a look at the examples directories ([Matrix] and [Mosaic]) for
more demos to explore!

As a bonus, we also have more complete demos for both projects:

• A graphical terminal emulator built with Matrix:
<https://github.com/tmattio/mosaic/tree/main/matrix/examples/x-emulator>
• A dashboard app built with Mosaic:
<https://github.com/tmattio/mosaic/tree/main/mosaic/examples/x-dashboard>

[Matrix] <https://github.com/tmattio/mosaic/tree/main/matrix/examples>

[Mosaic] <https://github.com/tmattio/mosaic/tree/main/mosaic/examples>

Quick Examples
╌╌╌╌╌╌╌╌╌╌╌╌╌╌

◊ Mosaic: The Elm Architecture

Mosaic follows TEA for building declarative UIs:

┌────
│ open Mosaic_tea
│
│ type msg = Increment | Decrement | Quit
│
│ let init () = (0, Cmd.none)
│
│ let update msg model =
│ match msg with
│ | Increment -> (model + 1, Cmd.none)
│ | Decrement -> (model - 1, Cmd.none)
│ | Quit -> (model, Cmd.quit)
│
│ let view model =
│ box ~align_items:Center ~justify_content:Center
│ ~size:{ width = pct 100; height = pct 100 }
│ [
│ box ~flex_direction:Column ~align_items:Center ~gap:(gap 1)
│ ~border:true ~padding:(padding 2) ~title:"Counter"
│ [
│ text ~content:(Printf.sprintf "Count: %d" model) ();
│ text ~content:"Press + or - to change, q to quit" ();
│ ];
│ ]
│
│ let subscriptions _model =
│ Sub.on_key (fun ev ->
│ match (Mosaic_ui.Event.Key.data ev).key with
│ | Char c when Uchar.equal c (Uchar.of_char '+') -> Some Increment
│ | Char c when Uchar.equal c (Uchar.of_char '-') -> Some Decrement
│ | Char c when Uchar.equal c (Uchar.of_char 'q') -> Some Quit
│ | Escape -> Some Quit
│ | _ -> None)
│
│ let () = run { init; update; view; subscriptions }
└────

◊ Matrix: Low-Level Power

For direct terminal control, Matrix provides an immediate-mode API:

┌────
│ open Matrix
│
│ let () =
│ run
│ ~on_render:(fun _ctx ->
│ Image.(
│ string "Hello from Matrix!" |> bg Color.blue |> pad ~l:2 ~t:1))
│ ~on_input:(fun ctx -> function
│ | Key { key = Escape; _ } -> quit ctx
│ | _ -> ())
│ ()
└────

Coming Soon: TUI for ML Training
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

We're starting an [Outreachy] internship to build a TUI for monitoring
model training with [Raven], the scientific computing ecosystem for
OCaml. It will provide a [TensorBoard] experience in the terminal,
built entirely with Mosaic.

A good example of what we're aiming to build is Wandb's newly released
TUI:

<https://us1.discourse-cdn.com/flex020/uploads/ocaml/optimized/2X/1/1a0303418fba64bb4a168e4ae1488592d3cb96c0_2_1380x814.jpeg>

[Outreachy] <https://www.outreachy.org/>

[Raven] <https://github.com/raven-ml/raven>

[TensorBoard] <https://www.tensorflow.org/tensorboard>

Mosaic vs Notty
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

Notty is the current go-to terminal UI library for OCaml, with a
well-designed declarative image API. Mosaic sits a level above: it’s a
TEA runtime with flexbox layout, rich components, focus/event
bubbling, and diffed rendering via Matrix. In scope, Notty is closer
to Matrix (the terminal infrastructure under Mosaic) than to Mosaic
itself.

Matrix covers the low-level rendering, modern terminal protocols, and
immediate-mode API that Notty doesn’t. For a detailed Matrix vs Notty
comparison, see our [comparison table].

[comparison table]
<https://github.com/tmattio/mosaic/tree/main/matrix#matrix-vs-notty>

Acknowledgements
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

Mosaic stands on the shoulders of great work:

• [Bubble Tea] - inspiration for the high-level TEA runtime and app
structure.
• [Notty] - Matrix's declarative Image API is directly copied from
Notty's to provide a familiar interface for OCaml users.
• [OpenTUI] - the biggest influence on Mosaic UI internals (render
tree, text buffer, events, selection). Mosaic's UI internals have
been rewritten to mirror OpenTUI's following its release, if you're
working in TypeScript, I can't recommend it enough, it's a fantastic
piece of engineering.
• [Rich] and [Textual] - for ideas on rich text, diagnostics, and
polished terminal UX.

[Bubble Tea] <https://github.com/charmbracelet/bubbletea>

[Notty] <https://github.com/pqwy/notty/>

[OpenTUI] <https://github.com/sst/opentui/>

[Rich] <https://github.com/Textualize/rich/>

[Textual] <https://github.com/Textualize/textual>

Feedback Welcome
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌

This is an early preview. APIs are stabilizing but may change. I'd
love your feedback on:

• API ergonomics
• Missing components or features you need
• Performance on your terminal
• Bugs (please open issues!)

Give it a try and let me know what you think!

Making html_of_jsx ~10x faster
══════════════════════════════

Archive:
<https://discuss.ocaml.org/t/making-html-of-jsx-10x-faster/17579/1>

David Sancho announced
──────────────────────

Hello ocamlers,

I wrote a blog post about some optimizations I made in [html_of_jsx]

<https://sancho.dev/blog/making-html-of-jsx-10x-faster>

I wanted to share it since those tricks are only possible at the
preprocess stage, and a library would fall short. html_of_jsx is a
small library that is used in a few places, but also a playground for
server-reason-react (a bigger project).

Anyway, I'm still getting used to share some of the long forms of
content, so feel free to give me some feedback/corrections or ask any
question.

[html_of_jsx] <https://github.com/davesnx/html_of_jsx/>

Tyre - type-safe regular expressions 1.0
════════════════════════════════════════

Archive:
<https://discuss.ocaml.org/t/ann-tyre-type-safe-regular-expressions-1-0/17584/1>

Emile Trotignon announced
─────────────────────────

I am happy to announce the release of [Tyre] 1.0.

This release makes big changes to the typing: there is a whole host of
far more practical combinators allowing you to write code like in a
parser combinator library :

┌────
│ let url =
│ let+ scheme = opt (const Http (str "http") <|> const Https (str "http") <* str "://")
│ and+ host = rep_any
│ and+ port = opt (str ":" *> pos_int)
│ and+ path = list (str "/" *> rep_any)
│ in
│ (scheme, host, port, path)
└────
(this is not a correct url parser by any means, its just to give an
idea of how you can use this lib)

This does not allow you to use `eval', because only one direction of
the conversion is given (there is no code to convert from a url
tuple). However in the cases where you don't need `eval' this is far
easier to write. The difference is typed, you can't get runtime error
by calling eval on the wrong regex.

There are also convencience changes such as charset and the
`matched_string' function, that reduce the need to insert `Re' bits in
your regexp.

Here is the full changelog:

• Introduce charsets: contrary to `Re', they have a different type
from regex.
• Type the difference between regexps that can be evaluated reversed
and the ones that cannot: `(evaluable, 'a) Tyre.t' and
`(non_evaluable, 'a) Tyre.t'.
• Introduce alias `type pattern' for `(non_evaluable, 'a) Tyre.t'.
• Introduce `val lift : ('a -> string) -> 'a pattern -> ('e, 'a) t' to
transform a pattern into an expression by giving an explicit
conversion function. Also `liftpp' that does the same with better
performance by using `Format'.
• Introduce `val unlift : (evaluable, 'a) t -> 'a pattern'.
• Introduce `val either: ('e, 'a) Tyre.t -> ('e, 'b) Tyre.t -> ('e,
('a, 'b) Either.t) Tyre.t'.
• Change the type of `alt' to `(_, 'a) t -> (_, 'a) t -> 'a
pattern'. Previous users of `alt' should switch to `either'.
• Introduce `~val alt_eval: ('a -> [~Left | ~Right]) -> ('e, 'a) t ->
('e, 'a) t -> ('e, 'a) t~' This has flat typing but is compatible
with `eval'.
• Operators: `<|>' is `alt', `<||>' is `either'.
• Introduce `val map : ('a -> 'b) -> (_, 'a) t -> 'b pattern' and its
corresponding operators: `let+' and `<$>'.
• Introduce `(and+)' which is an alias of `seq'.
• Introduce `val app: ('e, 'a -> 'b) t -> ('e, 'a) t -> 'b pattern'
and its corresponding operator `<*>'
• Introduce `val matched_string : (_, 'a) t -> (_, string) t' that
discards the computed value and just return the string that was
matched.
• Drop dependency on `Result' library. Stdlib is now used.
• Introduce `val rep_charset: Charset.t -> (_, string) t', and
shortcut `val rep_any: (_, string) t'.

[Tyre] <https://github.com/Drup/tyre/>

Porting an OxCaml Project to Dune Package Management
════════════════════════════════════════════════════

Archive:
<https://discuss.ocaml.org/t/blog-porting-an-oxcaml-project-to-dune-package-management/17582/1>

Sudha Parimala announced
────────────────────────

I recently worked on porting the [OxCaml tutorial] to build with Dune
Package Management. What was initially anticipated as a
straightforward change ended up uncovering a few issues and requiring
several patches. I wrote about the experience here:
<https://tensors.ink/posts/oxcaml-dune-pkg>. Any questions or feedback
welcome!

[OxCaml tutorial] <https://github.com/oxcaml/tutorial-icfp25>

Other OCaml News
════════════════

From the ocaml.org blog
───────────────────────

Here are links from many OCaml blogs aggregated at [the ocaml.org
blog].

• [ICFP 2025: Looking Back at the Biggest Functional Programming
Conference of the Year]
• [Foundational AI for Ecosystem Resilience workshop]
• [Tile Server]
• [A Vision for OCaml in the AI Era - Thibaut Mattio - FUN OCaml 2025]

[the ocaml.org blog] <https://ocaml.org/blog/>

[ICFP 2025: Looking Back at the Biggest Functional Programming
Conference of the Year]
<https://tarides.com/blog/2025-12-04-icfp-2025-looking-back-at-the-biggest-functional-programming-conference-of-the-year>

[Foundational AI for Ecosystem Resilience workshop]
<https://anil.recoil.org/notes/foundational-ecosystem-workshop>

[Tile Server] <https://www.tunbury.org/2025/12/02/tessera-stac/>

[A Vision for OCaml in the AI Era - Thibaut Mattio - FUN OCaml 2025]
<https://watch.ocaml.org/videos/watch/b959eeaf-e8c1-48e4-9d16-f8084a7bdda9>

Old CWN
═══════

If you happen to miss a CWN, you can [send me a message] and I'll mail
it to you, or go take a look at [the archive] or the [RSS feed of the
archives].

If you also wish to receive it every week by mail, you may subscribe
to the [caml-list].

[Alan Schmitt]

[send me a message] <mailto:alan.schmitt@polytechnique.org>

[the archive] <https://alan.petitepomme.net/cwn/>

[RSS feed of the archives] <https://alan.petitepomme.net/cwn/cwn.rss>

[caml-list] <https://sympa.inria.fr/sympa/info/caml-list>

[Alan Schmitt] <https://alan.petitepomme.net/>

[-- Attachment #2: Type: text/html, Size: 35078 bytes --]