ref: 4a5ec63ec0db33d4070adeb3838f6192f282a48c bliz/README.md -rw-r--r-- 4.6 KiB
4a5ec63eCadence Ember Add paragraph count to gemlog intro 1 year, 2 months ago


Incredibly easy, interpolated server-side scripting for Gemini.

#Project navigation

#Get started

  1. Clone the repo
  2. Run ./certs.fish and follow the prompts
  3. Run ./main.fish
  4. Point your Gemini browser at gemini://localhost/


  • fish shell
  • socat

#About Bliz

Bliz is an extension to text files to allow interpolated shell scripting - in this case, the fish shell. Of course, the shell can call any other program to embed content from.

It's intended to be used to generate gemtext dynamically, but it can just as easily generate any kind of text file.

Some use cases of dynamic content and server-side scripting:

  • Display constantly changing infomation like the time of day, lunar cycle, or weather forecast.
  • Automatically maintained back/forward navigation between dated blog posts.
  • Embedded word count for articles, calculated in real-time from the file itself.
  • Toys and games, potentially?

See /serve/scripting.bliz for an example .bliz script.


#Request handling

The Gemini request URL accesses a file on the file system.

All files (except for those with extension .bliz) will be sent as-is with automatically calculated MIME for the Gemini header. This includes text, images, media, binary streams, whatever.

Accessing a directory returns a directory listing.

#Bliz scripting

Files with extension .bliz activate bliz scripting mode. In scripting mode, Bliz reads the text file line by line and does different things depending on the contents of that line. No Gemini header is automatically inserted for .bliz files, you must create it manually.

  • %%%

Lines starting with %%% toggle shell script mode. When shell script mode is on, each line will be evaluated and its contents inserted into the document at that point.

It's like preformatted gemtext, but for scripts.

  • %

Lines starting with % with a following space evaluate a single line of shell script and insert the result into the document.


% ls -lpB (dirname $blizfile) # insert a directory listing into the page
  • anything else

All other lines are text and will be unchanged, except if they contain variable interpolation.

  • variable interpolation

%$variable in normal text will insert the contents of the shell variable variable inline into the document. To type %$ without activating this mode, escape it with a backslash.


See available settings in /src/config.fish. Override settings by editing /personal/config.fish.

#Writing custom functions

Add your functions to /personal/script-includes.fish. They will be available inside all .bliz scripts.

#Automatic reloading

Everything configurable is reloaded on every new request. There should be no need to restart the server unless something goes terribly, horribly wrong.

#Scripting tips

  • Use code like gem_header 20 'text/gemini' in script mode at the very top of the file to generate and send a Gemini header. You MUST send exactly one header in the execution of a .bliz script.
  • Use the variable $blizfile to access the path on disk of the currently evaluating file.
  • Shell functions and variables will be preserved between includes and script blocks in the same file, but will not carry over to other requests.
  • Take care that variables and functions that you define do not confict with variables and functions that are being used to evaluate the script. I suggest prefixing your functions and variables with a short name, e.g. cadence_get_time, j_get_time, my_get_time.
  • Bliz script blocks can of course generate gemtext markup.

#Security concerns

Shell scripts have the power to do great harm. You are the one writing the shell scripts.

The only data that a user can input in the Gemini protocol is a single URL - the URL of the page they want to load.

.bliz script execution is not sandboxed, but it is unlikely that a user will be able to exploit unexpected flaws in your script using weird inputs, because they only have one input.

For this reason, I believe that .bliz scripts that you write are exactly as safe as shell scripts that you write that take no input. I sugges that, when writing .bliz scripts, you should take exactly the same amount of caution that you take while writing personal shell scripts, since they are exactly as capable as each other.