This repo is website landing page for the US-RSE Association Conference 2026.
To preview the site locally, you'll need to install jekyll. Then go to the root of the directory and run (only needed once):
$ bundle installThen run
$ jekyll serve
# or
$ bundle exec jekyll serveand open your browser to http://localhost:4000/usrse26/.
If you are having trouble try rm -rf _site, followed by bundle update,
then bundle exec jekyll serve.
Build and run a Docker container to preview the site locally and support a local development workflow. If you do not already have Docker installed, please visit https://docs.docker.com/get-docker/ and follow the links to get started with Docker on your operating system.
Build the container image:
docker build -t us-rse-con-2024-website:latest .Run the container to access the website at the URL http://127.0.0.1:4000/usrse26/
$ docker run --rm -it -p 4000:4000 us-rse-con-2024-website:latest
Configuration file: /srv/jekyll/_config.yml
Source: /srv/jekyll
Destination: /srv/jekyll/_site
Incremental build: disabled. Enable with --incremental
Generating...
done in 1.616 seconds.
Auto-regeneration: enabled for '/srv/jekyll'
Server address: http://0.0.0.0:4000/usrse26/
Server running... press ctrl-c to stop.To develop the website, launch the container using the following command, where the source files are mounted into the container:
docker run --rm -it -p 4000:4000 \
-v $(pwd):/srv/jekyll \
us-rse-con-2024-website:latest \
bundle exec jekyll serve --host=0.0.0.0 --watch --draftsChange a source file, such as index.html for example, and save the changes. You will see Jekyll automatically regenerate the site,
after which you can reload the page in your browser to see the rendered changes.
The program page is generated from the program Google Sheet by scripts/build-program.js
(Node 18+, no dependencies). The "Schedule" tab drives _includes/program-schedule.html
(the list view), _includes/program-grid.html (the room × time grid view), _data/program.json,
and the two plain-text files described under
Program files for AI assistants; the "Posters" tab in the
same spreadsheet drives the Posters abstract page. Edit the sheet, not those files.
The Full Program page shows the list by default with a List / Grid toggle above it; the
grid lays each day out with rooms as columns and time down the side, breaks and other
venue-wide sessions spanning every column, and each card linking to its entry in the list.
The toggle, the reader's remembered choice, and card-to-list navigation are driven by
assets/js/program-view.js, and assets/css/program-grid.css styles the grid — both
hand-written and must ship alongside the generator. With JavaScript off the page is the
list alone: the toggle and the grid include ship hidden and are never revealed.
The sheet's core columns are Start, End, Location, Session Topic, Event Title, and Order.
Session rows may carry Session Format (used exactly as given — never inferred from the
topic; Break, Meal, and Registration render as muted rows, Plenary gets the highlighted
plenary treatment), Session Chair (shown next to the format), and Session Description
(Markdown). Event rows (rows with an Event Title) may also carry People (speakers as
"A, B and C"), Event Format (Bird of a Feather, Keynote, Notebook, Other, Paper, Plenary,
Poster, Random Access Microtalk, Talk, or Workshop), Event Description (the event's abstract,
as Markdown), and DOI (a bare DOI such as 10.5281/zenodo.123, or a full URL). When events
carry an Event Format other than "Other", the script also generates one abstract page per
format under pages/program/abstracts/ and the program menubar _data/menus/program.yml
linking those pages — both script-managed: they carry a generator banner, are pruned when
their format leaves the sheet, and must not be edited by hand.
Posters are the exception: the Posters page is built from the "Posters" tab rather than from Schedule rows. Its columns are Authors, Poster Title (or Title), Abstract (Markdown), and DOI, in any order; other columns are ignored and rows with no Poster Title are skipped. A Schedule event whose Event Format is "Poster" keeps its pill on the schedule and links into the Posters page — to the entry whose slugified title matches its own, otherwise to the top of the page — but never becomes an entry there. If the Posters tab is missing or renamed, the build fails rather than serving a stale page.
Each abstract page lists its entries as collapsed rows carrying the title and byline, with
the abstract behind a native <details> disclosure. Below the abstract, a metadata line
carries the DOI link when the row has one. An entry with no Event Description and no DOI
renders as a plain row with no control to open. Every abstract page also gets the theme's
sidebar contents list (menubar_toc, as on the Attend and Sponsor pages), one link per
entry, which is how a visitor gets a shareable link to a single abstract. The pages link two hand-written assets, so
both must ship alongside the generator: assets/css/abstracts.css styles the rows, and
assets/js/abstracts.js opens the entry a schedule deep link points at, drives the
expand/collapse-all control, and opens every entry for printing. The disclosure toggle
itself is native browser behavior — with JavaScript off the rows still open, minus the
expand-all control.
Rows still in the pre-2026 sheet layout — an Event Title with every other event column empty — are normalized while the sheet migrates: a "Session Chair: X" row sets the session's chair instead of listing as an event, and a "<title> by <names>" byline splits into a clean title plus People.
The sheet ID is intentionally not committed to the repo. The script reads it from the
PROGRAM_SHEET_ID environment variable — it is the long token in the sheet's
docs.google.com/spreadsheets/d/<id>/... URL.
The conference facts the generated files state — the site's absolute URL, the conference
name, its full name, its theme, and the year the sheet's "M/DD" dates fall in — are read
from _config.yml (url + baseurl, title, description, conf_theme_short,
conf_start_date), so Jekyll and the generator cannot disagree about them. Change them
there. A missing one fails the build rather than emitting a page with a blank in it. Two
values are deliberately not read: the room ordering and the -07:00 program timezone,
because conf_start_date ends -0900 and San Jose in October is UTC-7 — sourcing it would
restamp every session two hours off.
The generator also writes program/llms.txt and program/llms-full.txt, served at
https://us-rse.org/usrse26/program/llms.txt and .../llms-full.txt. They are the whole
schedule as plain text, for attendees who want an AI assistant to build them a personal
schedule; the Full Program page links both and shows an example prompt.
llms.txt carries every session and talk — times (wall-clock and ISO 8601), room, type,
chair, presenters, which sessions each one is concurrent with, and a link to each talk's
abstract entry. llms-full.txt is the same document with abstract text inlined.
"Concurrent with" is computed by comparing ISO ranges across the whole day, not by slot
grouping, so partially overlapping sessions are caught.
They live in a root-level program/ directory rather than under pages/ so Jekyll copies
them verbatim to _site/program/. That is deliberate: a static file is never
Liquid-processed, and abstract text out of the sheet may contain {{ or {% — the HTML
abstract pages have to escape exactly that. Giving these files front matter to set a
permalink would reintroduce the hazard for nothing. The directory does not collide with the
Full Program page, which has permalink: program/ and so writes _site/program/index.html.
Both are generated: they carry no banner (a comment would be noise in a file meant to be
read as prose), but they are rebuilt on every run and must not be edited by hand. The
renderer reads only the fields _data/program.json also carries, so it can be driven from
the committed JSON as well as from a fresh sheet fetch:
node scripts/build-program.js --from-jsonThat rewrites just the two .txt files, needs no sheet ID, and is the quickest way to see
a renderer change. It cannot rebuild the HTML includes or the abstract pages — those need
the _-prefixed internals that program.json deliberately drops.
The Check program llms.txt workflow (.github/workflows/check-program-llms.yml) runs
that same command on every pull request touching _data/program.json,
scripts/build-program.js, or program/, and fails if the result differs from what is
committed. On the normal path — the Rebuild program schedule workflow — the .txt files
and the program page are written in the same run and cannot drift; this catches the other
path, a pull request that edits the schedule data or the generator by hand without
regenerating. It is read-only, needs no secret, and works on pull requests from forks.
Rebuild from the live sheet:
PROGRAM_SHEET_ID=<sheet-id> node scripts/build-program.jsOr build offline from the checked-in fixtures, which need no sheet ID:
node scripts/build-program.js --file fixtures/schedule.csv --posters-file fixtures/posters.csvWith --file alone the Posters tab is skipped: every Schedule artifact is rebuilt, and an
existing generated posters.md is left in place rather than rebuilt or pruned.
Then preview the site as described above to see the regenerated program page.
The Rebuild program schedule workflow (.github/workflows/build-program.yml) rebuilds the
program daily and commits only when the schedule changed. It requires the sheet ID as a
repository secret (not a variable) so it stays out of the source and is masked in logs:
- Go to the repo's Settings → Secrets and variables → Actions → Secrets.
- Add a repository secret named
PROGRAM_SHEET_IDwith the sheet ID as its value.
Until the secret is set, scheduled runs skip quietly; a manual Run workflow fails with an explicit error instead, so you can tell the workflow is unconfigured rather than broken.
Every pull request gets a site preview from the CircleCI build-site job
(.circleci/config.yml), which runs bundle exec jekyll build and stores the resulting
_site as build artifacts. That job never runs scripts/build-program.js and has no access
to the sheet — the preview renders whatever versions of _includes/program-schedule.html
and _data/program.json are committed on the branch. So if a change should affect the
program page, commit the regenerated artifacts and the preview will reflect them; no
CircleCI configuration is needed.
scripts/ and fixtures/ are listed under exclude in _config.yml so the build tooling
is not copied into the built site or the preview artifacts.
There is an _include file, add-sponsor-logo.html, that can be used to add a
sponsor's logo anywhere on the website.
You can use the function by calling:
{% include add-sponsor-logo.html sponsor_url="some_url" logo_file="logo-filename.png" logo_alt="Some alt text for users" %}
See the include file for details on the variable names.
The logo files need to be added to the assets/img/sponsor-logos/ directory.
To add the sponsor logos to the main page, follow the same directions as above,
but make sure the include call is in the correct tier section for the sponsor.
For example, UIUC is a platinum sponsor, so they are added to the
<div class="row sponsor-platinum ...> block.