All writing

By Claude & Lemmih3 min read

Hackage without a server

hackage.aihc.app is a prototype Hackage built from Cloudflare Workers, D1, R2 and your browser, with every Haskell part compiled to WebAssembly by AIHC.

hackage.aihc.app is a prototype of hackage.haskell.org with no server. No VM, no database process, no documentation build farm. Here is what it looks like and how it is built.

Same package, two sites

The text-2.1.4 package page on hackage.aihc.app: a package header, tabs for Description, README, API, Dependencies, Dependents, Changelog and Cabal, the rendered README, and a package details card. The text-2.1.4 package page on hackage.haskell.org: the package description on the left, and the version list and dependency list on the right.
The text-2.1.4 package page at 1280×800. Drag the divider.

The data is the same Cabal file. The design is borrowed from crates.io: one page per package, with tabs for the README, API, dependencies, dependents, changelog and Cabal fields. Every page is rendered on the server and works without JavaScript.

The architecture

Architecture of hackage.aihc.app. The browser reads server-rendered HTML and runs aihc-haddock as WebAssembly in a Web Worker. On Cloudflare, the site Worker renders pages and parses Cabal files, the Workflow Worker runs the dependency solver and verifies uploads, D1 holds indexes and R2 holds files. hackage.haskell.org is only an upstream source.
Both Workers share the same D1 database and R2 bucket through bindings. Purple boxes are Haskell compiled to WebAssembly by AIHC.

hackage.haskell.org runs hackage-server, a long-running process on a machine that someone maintains. hackage.aihc.app has no machine:

  • Site Worker renders the pages and handles search and imports. It parses Cabal files with aihc-cabal-syntax, compiled to Wasm.
  • D1 holds versions and the search and dependency indexes. R2 holds the files: Cabal files, READMEs, source archives and documentation.
  • Workflow Worker runs the dependency solver, the same one the compiler uses, compiled to Wasm. It fetches only the Cabal files it needs, never the full Hackage index.

hackage.haskell.org stays the source of truth. The site only reads from it.

Documentation is built by the reader

Data.Text documentation on hackage.aihc.app: a module tree on the left, the module text in the middle, a contents list on the right, and a Community badge. Data.Text documentation on hackage.haskell.org: a contents sidebar on the left, the module header with copyright and license fields, and the module text.
Data.Text from text-2.1.4. The right-hand side was generated in a browser.

There is no documentation server. When a package has no docs, its API tab offers to build them. The browser downloads the sources and runs aihc-haddock, compiled to Wasm, in a Web Worker. The result is a JSON model of the API, which the browser uploads. The Worker renders it to HTML when someone reads the page, so readers need neither JavaScript nor Wasm.

An upload starts as a community result. The Workflow then rebuilds it with the same aihc-haddock binary, and marks it verified if the output matches.

Why this shape

Serverless. Nothing to patch, restart or keep running. Cost follows storage and requests, not uptime, and the expensive work runs on the reader’s CPU.

WebAssembly. The same compiler output runs in the browser, a Worker and a Workflow. Next up: a Haskell interpreter in the browser, so each package page gets a REPL with that package loaded.

Consistent styling. Documentation is data, so one renderer draws every package, in the same palette, fonts and light and dark themes as this blog.

What is missing

It is a prototype. There are no accounts or package uploads, only imported versions, and the generated docs still miss some types and cross-package links. The source is on GitHub. To try it, pick a package and open its API tab.