The CLI has three subcommands:

  1. eval evaluates a handlebars template from STDIN.
  2. get renders content from a content directory.
  3. serve starts an HTTP server.

serve is where the real action is, but the other two come in handy at times.

These commands all require a content directory, which is just the folder where your website lives. There are a bunch of sample content directories in the repository.

To learn more, run operator --help or operator <SUBCOMMAND> --help.

Quick Start

Let's run this website:

Then open http://localhost:8080 in your browser of choice.

Try making a change to the site (in operator-website/content) and restart the server to see the update.


When Operator starts up it crawls through your content directory to build a representation of your website. The site's routes and configuration are derived from this directory.

Operator needs to know what media type will be emitted by each content file. This is specified via file extensions (.html is text/html, .js is text/javascript, .png is image/png, and so on).

There are three different kinds of content files:

  1. Static files are served directly. For example, you can drop an image or html file into your content directory and it'll be served as is.

    Static files only have one extension (about.html, kittens.mp4, etc).

  2. Executables are run at request time, with standard output piped out as the response body. Any program that you can run from the command line will work (scripts, compiled programs, etc). The executable is invoked with no CLI arguments and with its working directory set to its own parent folder.

    An environment variable named OPERATOR_RENDER_DATA is provided to executables. Its value is render data encoded as JSON. This is the same data provided to handlebars templates.

    Executables have two extensions, with the first one indicating the media type of the executable's output (contact.html.py, styles.css.sh, dankmeme.jpg.exe, etc). Operator requires execute permissions on these files, and scripts will typically need a shebang so your OS knows how to interpret them.

    Operator doesn't care what the second extension is for executables, but you can use it to indicate the file type—for example, contact.html.py would be a Python script which outputs HTML. In executables the file type is usually not the same as its output type, although if you're feeling feisty then things like wat.js.js are certainly possible.

  3. Handlebars templates are compiled during server startup and rendered at request time. The heavy lifting is done by the handlebars Rust library which is largely compatible with the original JavaScript handlebars implementation. Operator provides some render data and a custom get helper to make your content composable.

    Like executables, handlebars templates also have two extensions. The first one indicates the media type, and the second one must be .hbs to tell Operator that it's a template (faq.html.hbs, metadata.json.hbs, etc).


Operator is only as secure as your content directory, so be careful! Here are some best practices: