My aggregated monorepo of OCaml code, automaintained
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Minor updates

+289 -7
+61
Dockerfile
··· 1 + FROM ocaml/opam:debian-ocaml-5.2 AS build 2 + 3 + # System dependencies 4 + RUN sudo apt-get update && sudo apt-get install -y \ 5 + autoconf \ 6 + pkg-config \ 7 + libgmp-dev \ 8 + libev-dev \ 9 + libffi-dev \ 10 + libssl-dev \ 11 + python3 \ 12 + jq \ 13 + && sudo rm -rf /var/lib/apt/lists/* 14 + 15 + # Set up oxcaml switch with the ox opam repo 16 + RUN opam update --all \ 17 + && opam switch create 5.2.0+ox \ 18 + --repos ox=git+https://github.com/oxcaml/opam-repository.git,alpha=git+https://github.com/kit-ty-kate/opam-alpha-repository.git,default \ 19 + && eval $(opam env --switch 5.2.0+ox) 20 + 21 + # Copy opam file first for dependency caching 22 + WORKDIR /home/opam/mono 23 + COPY --chown=opam:opam root.opam . 24 + RUN opam install --switch 5.2.0+ox --deps-only -y ./root.opam 25 + 26 + # Copy the full monorepo source 27 + COPY --chown=opam:opam . . 28 + 29 + # Build and install plugins, then build the site (without universes) 30 + RUN eval $(opam env --switch 5.2.0+ox) \ 31 + && dune build @install \ 32 + && dune install 2>/dev/null \ 33 + && dune build @site \ 34 + && dune build @doc 35 + 36 + # Assemble the site into _site/ 37 + RUN mkdir -p _site \ 38 + && cp -rf _build/default/site/_html/* _site/ \ 39 + && cp -rf _build/default/_doc/_html/reference/* _site/reference/ \ 40 + && mkdir -p _site/odoc.support/ \ 41 + && cp -rf _build/default/_doc/_html/odoc.support/* _site/odoc.support/ 42 + 43 + # Universe building (jtw is built from source in js_top_worker/) 44 + RUN eval $(opam env --switch 5.2.0+ox) \ 45 + && jtw opam astring base brr note mime_printer fpath rresult \ 46 + opam-format bos odoc.model tyxml yojson uri jsonm \ 47 + js_top_worker-widget-leaflet \ 48 + tessera-geotessera-jsoo tessera-viz-jsoo \ 49 + onnxrt -o _site/_opam 50 + 51 + # Deploy onnxrt assets 52 + RUN if [ -f onnxrt/example/sentiment/model_quantized.onnx ]; then \ 53 + cp onnxrt/example/sentiment/vocab.txt _site/_opam/vocab.txt \ 54 + && cp onnxrt/example/sentiment/model_quantized.onnx _site/_opam/model_quantized.onnx; \ 55 + fi \ 56 + && cp onnxrt/example/add.onnx _site/_opam/add.onnx 57 + 58 + # Lightweight final image with just the built site 59 + FROM nginx:alpine 60 + COPY --from=build /home/opam/mono/_site /usr/share/nginx/html 61 + EXPOSE 80
+148
build-site.sh
··· 1 + #!/bin/bash 2 + # Build the full jon.recoil.org site into _site/. 3 + # 4 + # Dune outputs go into _build/ (which dune controls and may wipe). 5 + # We assemble the final site into _site/ so that expensive artifacts 6 + # like universes persist across rebuilds. 7 + # 8 + # Usage: 9 + # ./build-site.sh # build everything 10 + # ./build-site.sh --fresh # rebuild universes from scratch 11 + # ./build-site.sh --serve # build and serve on port 8080 12 + 13 + set -euo pipefail 14 + 15 + MONO=$(cd "$(dirname "$0")" && pwd) 16 + SITE="$MONO/_site" 17 + DUNE_SITE="$MONO/_build/default/site/_html" 18 + DUNE_DOC="$MONO/_build/default/_doc/_html" 19 + SERVE=false 20 + FRESH=false 21 + 22 + for arg in "$@"; do 23 + case "$arg" in 24 + --serve) SERVE=true ;; 25 + --fresh) FRESH=true ;; 26 + esac 27 + done 28 + 29 + if $FRESH; then 30 + echo "=== --fresh: removing _site ===" 31 + rm -rf "$SITE" 32 + fi 33 + 34 + mkdir -p "$SITE" 35 + 36 + # Ensure we're on the right switch. 37 + export OPAMSWITCH=5.2.0+ox 38 + eval "$(opam env)" 39 + 40 + echo "=== Step 1: Build and register plugins ===" 41 + cd "$MONO" 42 + dune build @install 43 + dune install 2>/dev/null 44 + echo " plugins registered" 45 + 46 + echo "" 47 + echo "=== Step 2: Build site content ===" 48 + dune build @site 2>&1 | grep -v '^Warning\|^File\|^$' | tail -5 || true 49 + echo " dune @site done" 50 + 51 + echo "" 52 + echo "=== Step 3: Build reference docs ===" 53 + dune build @doc 2>&1 | tail -5 || true 54 + echo " dune @doc done" 55 + 56 + echo "" 57 + echo "=== Step 4: Assemble site ===" 58 + cp -rf "$DUNE_SITE/"* "$SITE/" 59 + cp -rf "$DUNE_DOC/reference/"* "$SITE/reference/" 60 + mkdir -p "$SITE/odoc.support/" 61 + cp -rf "$DUNE_DOC/odoc.support/"* "$SITE/odoc.support/" 62 + echo " assembled into $SITE/" 63 + 64 + echo "" 65 + echo "=== Step 5: Build site universe (notebooks) ===" 66 + if [ -f "$SITE/_opam/worker.js" ]; then 67 + echo " universe already exists, skipping (use --fresh to rebuild)" 68 + else 69 + jtw opam astring base brr note mime_printer fpath rresult \ 70 + opam-format bos odoc.model tyxml yojson uri jsonm \ 71 + js_top_worker-widget-leaflet \ 72 + tessera-geotessera-jsoo tessera-viz-jsoo \ 73 + onnxrt -o "$SITE/_opam" 74 + echo " universe built → $SITE/_opam/" 75 + fi 76 + 77 + echo "" 78 + echo "=== Step 6: Deploy onnxrt example assets ===" 79 + SENTIMENT_SRC="$MONO/onnxrt/example/sentiment" 80 + if [ ! -f "$SENTIMENT_SRC/model_quantized.onnx" ]; then 81 + echo " downloading DistilBERT model..." 82 + bash "$SENTIMENT_SRC/download_model.sh" 83 + fi 84 + cp "$SENTIMENT_SRC/vocab.txt" "$SITE/_opam/vocab.txt" 85 + cp "$SENTIMENT_SRC/model_quantized.onnx" "$SITE/_opam/model_quantized.onnx" 86 + cp "$MONO/onnxrt/example/add.onnx" "$SITE/_opam/add.onnx" 87 + echo " deployed vocab.txt + model_quantized.onnx + add.onnx → $SITE/_opam/" 88 + 89 + echo "" 90 + echo "=== Step 7: Build demo universes ===" 91 + DEMO_DIR="$SITE/reference/odoc-interactive-extension" 92 + 93 + if [ -f "$DEMO_DIR/universe/worker.js" ]; then 94 + echo " demo universes already exist, skipping (use --fresh to rebuild)" 95 + else 96 + UNIVERSES=$(mktemp -d) 97 + trap 'rm -rf "$UNIVERSES"' EXIT 98 + 99 + echo " building default universe (cmdliner, 5.2.0+ox switch)..." 100 + jtw opam --switch=5.2.0+ox -o "$UNIVERSES/default" cmdliner 101 + 102 + echo " building v3 universe (cmdliner, 5.2.0+ox switch)..." 103 + jtw opam --switch=5.2.0+ox -o "$UNIVERSES/v3" cmdliner 104 + 105 + echo " building oxcaml universe (5.2.0+ox switch)..." 106 + jtw opam --switch=5.2.0+ox -o "$UNIVERSES/oxcaml" 107 + 108 + for d in universe universe-v2 universe-v3 universe-oxcaml; do 109 + rm -rf "$DEMO_DIR/$d" 110 + done 111 + 112 + cp -r "$UNIVERSES/default" "$DEMO_DIR/universe" 113 + echo " deployed universe/" 114 + 115 + cp -r "$UNIVERSES/default" "$DEMO_DIR/universe-v2" 116 + echo " deployed universe-v2/" 117 + 118 + cp -r "$UNIVERSES/v3" "$DEMO_DIR/universe-v3" 119 + echo " deployed universe-v3/" 120 + 121 + cp -r "$UNIVERSES/oxcaml" "$DEMO_DIR/universe-oxcaml" 122 + echo " deployed universe-oxcaml/" 123 + 124 + for d in universe universe-v2 universe-v3 universe-oxcaml; do 125 + cp "$SITE/_x-ocaml/x-ocaml.js" "$DEMO_DIR/$d/x-ocaml.js" 126 + done 127 + fi 128 + 129 + echo "" 130 + echo "=== Done ===" 131 + echo "" 132 + echo "Site root: $SITE/" 133 + echo "" 134 + echo "Key pages:" 135 + echo " /index.html — site home" 136 + echo " /blog/index.html — blog index" 137 + echo " /notebooks/index.html — notebooks index" 138 + echo " /notebooks/foundations/index.html — foundations of CS" 139 + echo " /projects/index.html — projects" 140 + echo " /reference/ — API reference docs" 141 + echo " /reference/odoc-interactive-extension/ — interactive demos" 142 + 143 + if $SERVE; then 144 + echo "" 145 + echo "Starting HTTP server on http://localhost:8080" 146 + cd "$SITE" 147 + exec python3 -m http.server 8080 148 + fi
+28
deploy-live.sh
··· 1 + #!/bin/bash 2 + # Deploy the site to jon.recoil.org (live/production server). 3 + # 4 + # Usage: 5 + # ./deploy-live.sh # rsync _site/ to live server 6 + # ./deploy-live.sh --build # build first, then deploy 7 + 8 + set -euo pipefail 9 + 10 + MONO=$(cd "$(dirname "$0")" && pwd) 11 + SITE="$MONO/_site" 12 + TARGET="jon.recoil.org" 13 + DEST="/var/www/jon.recoil.org/" 14 + 15 + for arg in "$@"; do 16 + case "$arg" in 17 + --build) "$MONO/build-site.sh" ;; 18 + esac 19 + done 20 + 21 + if [ ! -d "$SITE" ]; then 22 + echo "Error: $SITE does not exist. Run ./build-site.sh first." 23 + exit 1 24 + fi 25 + 26 + echo "=== Deploying to $TARGET ===" 27 + rsync -avz --delete "$SITE/" "$TARGET:$DEST" 28 + echo "=== Deployed to https://$TARGET/ ==="
+28
deploy-test.sh
··· 1 + #!/bin/bash 2 + # Deploy the site to jon-test.ludl.am (test server). 3 + # 4 + # Usage: 5 + # ./deploy-test.sh # rsync _site/ to test server 6 + # ./deploy-test.sh --build # build first, then deploy 7 + 8 + set -euo pipefail 9 + 10 + MONO=$(cd "$(dirname "$0")" && pwd) 11 + SITE="$MONO/_site" 12 + TARGET="jon-test.ludl.am" 13 + DEST="/var/www/jon-test.ludl.am/" 14 + 15 + for arg in "$@"; do 16 + case "$arg" in 17 + --build) "$MONO/build-site.sh" ;; 18 + esac 19 + done 20 + 21 + if [ ! -d "$SITE" ]; then 22 + echo "Error: $SITE does not exist. Run ./build-site.sh first." 23 + exit 1 24 + fi 25 + 26 + echo "=== Deploying to $TARGET ===" 27 + rsync -avz --delete "$SITE/" "$TARGET:$DEST" 28 + echo "=== Deployed to https://$TARGET/ ==="
+4 -1
odoc-docsite/doc/index.mld
··· 1 - {0 odoc documentation site shell} 1 + {0 Odoc Documentation-site Shell} 2 + 3 + This plugin for odoc provides a more modern styling for odoc's output, including 4 + SPA-style navigation.
+3
odoc-interactive-extension/doc/index.mld
··· 1 1 {0 Interactive OCaml Extension for odoc} 2 + 3 + See the various notebooks in the sidebar for examples of this extension. 4 +
+6 -1
odoc/doc/odoc-parser/index.mld
··· 1 - {0 odoc comment parser} 1 + {0 The [odoc] comment parser} 2 + 3 + This is the parser for odoc-formatted comments and mld files. 4 + 5 + For API documentation see {!Odoc_parser}. 6 +
+5
odoc/doc/sherlodoc/index.mld
··· 1 1 {0 Sherlodoc search engine} 2 + 3 + This is the search engine used to provide client and server side search. 4 + 5 + For a full deployment, see {:https://doc.sherlocode.com/} 6 +
+4 -4
root.opam
··· 12 12 "camlp-streams" 13 13 "cmarkit" 14 14 "cmdliner" 15 - "conf-jq" 15 + "conf-jq" {with-test} 16 16 "cppo" 17 17 "crunch" 18 18 "decompress" ··· 37 37 "ocaml" 38 38 "ocamlfind" 39 39 "ocamlformat-lib" 40 - "odig" 40 + "odig" {with-test} 41 41 "opam-0install" 42 42 "opam-format" 43 43 "ppx_blob" 44 44 "ppx_deriving_yojson" 45 - "ppx_expect" 45 + "ppx_expect" {with-test} 46 46 "ppx_sexp_conv" 47 47 "ppxlib" 48 48 "progress" 49 49 "result" 50 50 "rresult" 51 51 "sexplib" 52 - "sexplib0" 52 + "sexplib0" {with-test} 53 53 "tyxml" 54 54 "uri" 55 55 "yojson"
+2 -1
site/blog/2026/03/weeknotes-2026-10.mld
··· 21 21 - I was interested in whether we'll be able to do inference in reasonable time using these 22 22 notebooks. {{:https://onnx.ai/}ONNX} has a web version of its runtime, so I got Claude to 23 23 make some bindings, and checked it was working by doing a sentiment analysis notebook. This 24 - is working nicely, so the next step is to do something a bit more useful. 24 + is working nicely, so the next step is to do something a bit more useful. Try it 25 + {{:/reference/onnxrt/sentiment_example.html}here}. 25 26 - The docs CI was again causing problems. This time it had decided that it had never built 26 27 anything, and therefore needed to rebuilt the entire world. However, despite being set up 27 28 as a custom dedicated runner, all its jobs were queued waiting to start. It turned out that