Two things arrive here by pull request: articles and calendar events.
The full, up-to-date guide for writing and submitting an article lives on the site itself:
→ How to submit your next article on foojay.io
It walks through creating your author profile, preparing your post folder, adding images, and delivering it (pull request, fork, or zip).
- Posts are contributed via pull request (fork the repo if you don't have write access).
- Create your post in a folder under
draft/<your-slug>/with the text inindex.md(orindex.adoc) and its images in the same folder. Copytemplate/post.md(ortemplate/post.adoc) as your starting point. A maintainer moves the folder intocontent/posts/<year>/<month>/<day>/<your-slug>/when it's published — you never need to pick that path yourself unless you want the post to be published on a specific date. In that case, clearly specify the preferred date in your pull request. - Markdown or AsciiDoc. Name the file
index.adocand write AsciiDoc instead, starting fromtemplate/post.adoc. Everything else is the same — same folder shape, same frontmatter, same checks. Markdown is shorter for ordinary prose and what most articles use; AsciiDoc is worth it for captions on code blocks, numbered callouts inside a snippet, admonitions, and tables that span cells. - New author? Add yourself as
content/authors/<your-slug>/_index.mdin the same PR (note the underscore — seetemplate/author.md). - Leave
date:as it is in the template. A maintainer sets it and moves your folder to match when the article is published. Only set it yourself if you need the article out on a particular day: it's a plain day (date: "2026-01-01"), with no time — the site is rebuilt once a day, at 07:00 UTC, so that is when articles go out and a time cannot make it earlier, only later, by missing that build. A future date schedules the post (it stays unbuilt and unlisted until then, and appears in "Coming soon" on the home page). - You don't need to build anything: the PR check validates your frontmatter and builds the site, so it catches a bad author slug or a missing image for you.
- If you do want to preview it, note that
draft/is deliberately not built —hugo server -Dwill not show it. Copy your folder tocontent/posts/<year>/<month>/<day>/<your-slug>/, runhugo server, and openhttp://localhost:1313/website/today/<your-slug>/. Previewing an AsciiDoc post locally also needs theasciidoctorbinary (gem install asciidoctor); without it Hugo stops withfailed to execute binary "asciidoctor". Nothing extra is needed for Markdown, and the PR check installs it either way.
See the guide linked above for the details.
foojay.io/calendar/ carries two kinds of event, and they arrive by two different routes. Pick the right one:
JUG meetups are pulled automatically, once a day, from the calendar each group
already publishes (its own .ics, a Google Calendar, or Meetup's export).
Nothing in this repo is hand-edited for them.
If your JUG's events are missing, the fix belongs upstream, in the
community-run World Wide JUGs directory:
add or correct your group's file there, giving it a calendar: (any iCal URL)
or a meetup: entry. It shows up on foojay's calendar at the next daily sync,
and on every other site that reads the directory too.
Conferences publish no feed anyone can subscribe to, so they are added by hand:
- Copy
template/event.yamltodata/events/<event-slug>.yaml. - Name the file after the event including its year —
devoxx-belgium-2026.yaml,jfokus-2027.yaml. Lowercase letters, digits and dashes only. Next year's edition is a new file, not an edit of this one. - Fill it in and open a pull request. Nothing else needs touching.
name: "Devoxx Belgium 2026"
type: "Conference"
url: "https://devoxx.be/"
start: "2026-10-05"
end: "2026-10-09"
venue: "Kinepolis Antwerpen"
city: "Antwerp"
country: "Belgium"| Field | Required | Notes |
|---|---|---|
name |
yes | Shown on the calendar. Include the year, like the filename. |
url |
yes | The event's own site — where the calendar sends a reader. |
start |
yes | YYYY-MM-DD. Add a time only when it matters: "2026-09-15T19:00:00+02:00", in the event's own UTC offset. Without one the event is shown as running all day. |
city |
yes unless online | |
country |
yes unless online | Feeds the "N countries" count. |
type |
no | "Conference" (the default), "Workshop", "Community Day", "Hackathon", "Webinar"… Shown next to the event. |
end |
no | YYYY-MM-DD, the last day, inclusive. Leave it out for a one-day event; a multi-day one is drawn as a band across those days. |
venue |
no | The building, if it's worth naming. |
online |
no | true for an online-only event; then city/country can be left out. |
Everything else is derived, so there is nothing to keep in step: the colour on the calendar comes from the filename, the month band from the dates, the counts in the page header from the entries themselves.
Two things worth knowing:
- Never add an event to
data/jug-events.json. That file is regenerated from the JUGs' calendar feeds and committed every day — a hand-written entry in it is gone within 24 hours. That is exactly whydata/events/exists. - You never have to come back and delete the file. An event drops off the calendar on its own the day after it ends. Removing it afterwards is welcome tidying, never urgent.
One file per event, so two people adding two conferences in the same week never
touch the same file and never get a merge conflict. The PR check
(jbang scripts/validate/Frontmatter.java) validates your entry — it will tell
you about a misspelled field, a date it can't read, or an end before the start.