gempost is a minimal static site generator for publishing a blog (gemlog) on the Gemini protocol.
You store metadata about each gemlog post in a sidecar YAML file, and gempost generates a gemtext index page and an Atom feed.
You can use a Tera template to customize the format of the index page. You can also use a template to customize the format of the gemlog posts themselves, such as to add a copyright footer or a navigation header to each post. See Examples for examples of both.
The metadata in the sidecar YAML file allows you to generate an Atom feed with rich metadata, but most of this metadata is optional and not necessary to generate a working feed.
To install gempost, you must first install Rust. Then, you can install gempost with Cargo.
cargo install gempost
You can initialize a new gempost project like this:
gempost init ./capsule
This will create a directory ./capsule/
that looks like this:
capsule/
├── gempost.yaml
├── posts/
│ ├── hello-world.gmi
│ └── hello-world.yaml
├── static/
│ └── index.gmi
└── templates/
├── index.tera
└── post.tera
This includes:
- An example
gempost.yaml
config file to get you started. You'll need to edit this to set your capsule's title and URL. - Some basic templates you can use as-is or customize.
- A "hello world" example post for your gemlog, with its accompanying sidecar metadata file.
- A static
index.gmi
for your capsule root.
Edit the gempost.yaml
and you're ready to build your capsule!
cd ./capsule
gempost build
Your capsule will be generated in the ./public/
directory. You'll need a
Gemini server like Agate to actually serve
your capsule over the Gemini protocol. Check out Awesome
Gemini for a more complete
list of Gemini servers.
You can add a new post to your gemlog with gempost new <slug>
. This creates a
.gmi
file in the ./posts/
directory with an accompanying .yaml
metadata
file. See examples/metadata.yaml for an example of
all the different values you can set in the YAML metadata file. Only some are
required.
You can add new static content to your capsule (anything that's not your
gemlog) by putting it in the ./static/
directory. If a file in the static
directory conflicts with one generated by gempost, the one if the static
directory will win.
You can customize the index page and post page templates in the ./templates/
directory from their defaults. They use the
Tera text templating language, which is
similar to the popular Jinja templating language. See the
Templates section below for a list of all the variables that are
available inside these template.
Running gempost init
will generate minimal index page and post page templates
you can use to get started. These will probably be fine for most users.
However, if you want to see more complex examples of what you can do with templates, the examples below make use of more of the post metadata to provide more rich output. You can use these templates as-is, or as a guide to write your own.
- See examples/index.tera for an example of an index page template.
- See examples/post.tera for an example of a post page template.
Additionally, see examples/metadata.yaml for an example of a sidecar gemlog post metadata file showing all the possible fields.
The index page template has access to:
- A
feed
variable which is a Feed object.
The post page template has access to:
- A
feed
variable which is a Feed object. - An
entry
variable which is an Entry object for the current post.
All dates are in RFC 3339 format, which looks like this:
2006-01-02T15:04:05Z07:00
name
(string) The name of the authoremail
(string, optional) The author's email addressuri
(string, optional) A URI describing the author
url
(string) The URL of the posttitle
(string) The title of the postbody
(string) The gemtext body of the postupdated
(string) When the post was last updatedsummary
(string, optional) The summary of the postpublished
(string, optional) When the post was originally publishedauthor
(Author object, optional) The author of the postrights
(string, optional) The copyright and license information for the postlang
(string, optional) The RFC 5646 language code for the language the post is written in (e.g.en
,de
)categories
(array of strings) The list of categories the post belongs to
capsule_url
(string) The URL of your capsule's homepagefeed_url
(string) The URL of the Atom feedindex_url
(string) The URL of the gemlog index pagetitle
(string) The title of the feedupdated
(string) When any post in the feed was last updatedsubtitle
(string, optional) The subtitle of the feedrights
(string, optional) The copyright and license information for the feedauthor
(Author object, optional) The primary author of the feedentries
(array of Entry objects) The list of posts in the feed, sorted reverse-chronologically by publish date or, if no publish date, last updated date
Here are some miscellaneous suggestions for working with gempost.
You can check your gempost project directory into a VCS of your choice if you
like; just make sure you configure it to ignore the ./public/
directory!
If your Gemini server expects to find your capsule in a particular directory,
you can change the location of the ./public/
directory from its default in
the gempost.yaml
. Note that file paths in the gempost.yaml
do not support
tilde expansion.
Every post must have a unique ID to generate the Atom feed. Atom require that this be a globally unique URI that never ever changes. So, as an alternative to using your post URL, which might change, you can use a UUID URN:
urn:uuid:165b10e8-78c9-45ba-83ef-2f7bd5d89725
Running gempost new
will automatically assign a UUID post ID.
Each post must have a time last updated and, optionally, time originally published. To get the current time in RFC 3339 format—the format gempost expects—you can use this command on *nix platforms:
date --rfc-3339 seconds
Check out these other awesome static site generators for gemlogs: