Caravel is centered around plugins. In caravel, absolutely every functionnality is a plugin.

The way it works is basically folding over list. For instance, for the interface, we start with a widget which is a webkit web_view and a list of functions of type widget -> widget. Let's say we have the following functions: f1 - add a container to widget (this adds scrolling to the web_view), f2 - add an address bar, f3 - add a menu bar, f4 - pack in a window.
Let g the function taking a widget as its first argument, applying it to its second argument and returning that: let g a b = b a.
Now, we use a fold over the list functions = [ f1; f2; f3; f4 ] :
  List.fold_left g web_view functions
This is equivalent to:
  g (g (g (g web_view f1) f2) f3) f4
Considering g, this can be again translated:
  f4 (f3 (f2 (f1 web_view)))
This is taking the web_view, wrapping it in a container, adding an address bar around that, and wrapping everything in a window.

That's basically how things are done: start with the most simple element (or the one we have the less control over), apply a function and get a result, apply another function to the result, and apply yet another function to that result, and so on.
That makes everything very flexible. It is certainly heavier than other solutions but it is assumed the cost will be very small compared to the requirements of a full web rendering engine. Another problem is that everything may not be doable easily that way but that's only the basic approach (there will be facilities like callbacks and global variables through a shared hashtable for instance).


You wouldn't mix widgets and network requests so things are split into several categories which are independant processing units. To enhance reliability and safety (and maybe speed), each of these independant processing units is in a different thread^Wprocess. This would enable a clear separation of the rendering process (which is written in C/C++ and manipulates untrusted data) and of the process(es) dealing with private/local data.


Each category is reachable through RPC (ocamlnet's). To avoid the need to write boilerplate code, each category interface must be described in a .x (XDR). This file is then processed in order to make every function of the interface callable. There should be no need to worry about rpc when writing the code for a plugin or a category.
