Hello World: How This Blog Was Built

A technical walkthrough of how this blog was architected using Quarto, GitHub Actions, and CloudFlare Pages.
Author

Ishaat Chowdhury

Published

March 17, 2026

CautionAI-Generated Content

This post was entirely generated by AI (GitHub Copilot). It exists solely to test the site’s rendering pipeline and will remain as a transparent artifact of the blog’s setup process. All subsequent posts on this blog are written by a human.

Introduction

Every blog needs a first post, and what better way to break in a new site than to document how it was built? This post walks through the architecture and tooling behind Screeching Into The Void — a blog built for long-form written content like book reviews and essays, where academic-style citations are a first-class feature.

The stack is straightforward: Quarto for authoring and static site generation [1], GitHub Actions for continuous integration [2], and CloudFlare Pages for hosting [3].

Why Quarto?

Quarto is an open-source scientific and technical publishing system that turns markdown into polished HTML, PDF, and other formats [1]. For a blog focused on long-form writing, Quarto offers several advantages over other static site generators:

  1. Native citation support. Quarto uses Pandoc’s citation engine under the hood, which means you can write [@AuthorKey2024] in your markdown and get properly formatted references in any citation style [4]. This blog uses the IEEE style, which renders in-text citations as numbered references like [1] — clean and unobtrusive for a blog context.

  2. Bootswatch theme integration. Quarto ships with 25 Bootswatch themes [5] and supports light/dark theme pairing out of the box [6]. This site uses the flatly and darkly pair, which are designed to work together with matching typography and spacing.

  3. Markdown-first workflow. Posts are plain .qmd files (Quarto-flavored markdown) with YAML front matter. No JavaScript framework, no build toolchain beyond Quarto itself.

Architecture

The deployment pipeline follows a pattern that Quarto’s CI documentation describes as “Local Execution with CI Rendering” [7] — though in this case there’s no computational code to execute locally, since all posts are pure prose.

┌─────────────┐     ┌──────────────┐     ┌──────────────┐
│ Write .qmd  │────▶│ GitHub Actions│────▶│ CloudFlare   │
│ + refs.bib  │     │ quarto render │     │ Pages        │
│ git push    │     │ pages-action  │     │ serves _site │
└─────────────┘     └──────────────┘     └──────────────┘

Why not CloudFlare Pages’ built-in build?

CloudFlare Pages can build sites directly from source, but Quarto isn’t in its default build environment. While you can install Quarto via a custom build command, using GitHub Actions with the official Quarto setup action [8] gives better control over the build environment, version pinning, and failure diagnostics.

The workflow is minimal — install Quarto, render the site, and deploy the _site/ directory using CloudFlare’s own GitHub Action [9]:

steps:
  - uses: actions/checkout@v4
  - uses: quarto-dev/quarto-actions/setup@v2
  - run: quarto render
  - uses: cloudflare/pages-action@v1
    with:
      apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
      accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
      projectName: screechingintothevoid
      directory: _site

This also enables PR preview deploys — every pull request gets its own CloudFlare Pages preview URL, which is useful for reviewing draft posts before they go live.

Why CloudFlare Pages specifically?

CloudFlare Pages is a static site hosting platform that serves content from CloudFlare’s global CDN [3]. Beyond the standard static hosting features, it supports deploying any static HTML output [10], which is exactly what Quarto produces. The platform’s AI bot blocking capabilities and broader security features were the deciding factor over alternatives like Netlify or GitHub Pages.

Site Structure

The blog uses a date-organized directory structure for posts:

posts/
└── 2026/
    ├── 001-hello-world/
    │   ├── index.qmd
    │   └── refs.bib
    └── 002-next-post/
        ├── index.qmd
        └── refs.bib

Year folders provide top-level grouping, and three-digit zero-padded sequence numbers give filesystem ordering within each year. This is a deliberate trade-off: Quarto’s URLs are tied directly to the filesystem path [1], so the directory structure is the URL structure. The resulting URLs look like /posts/2026/001-hello-world/.

The home page uses Quarto’s listing feature [11] with a recursive glob pattern to discover all posts regardless of nesting depth:

listing:
  contents: "posts/**/index.qmd"
  sort: "date desc"
  type: default
  categories: true

Navigation is kept minimal — just a top navbar [12] with the site title, an About page link, search, and the automatic light/dark theme toggle. No sidebars, no complex hierarchy. It’s a blog, not a documentation site.

Citations and the IEEE Style

Each post gets its own refs.bib file containing BibTeX entries for that post’s references. A shared posts/_metadata.yml file sets the citation style globally using the IEEE CSL file [13], so individual posts don’t need to repeat the configuration.

The IEEE style was chosen because its numbered [1] format is concise and well-suited to hyperlinked text — readers can glance at the reference list without inline citations disrupting the flow of prose [4].

Post Scaffolding

New posts are created with a single command using mise [14], a polyglot task runner:

mise run new-post "My Post Title"

This runs a bash script that auto-detects the current year, finds the next sequence number, slugifies the title, and creates the directory with a boilerplate index.qmd and empty refs.bib. Posts are created as drafts by default — set draft: false in the front matter when ready to publish.

How This Blog Was Actually Built: Spec-Driven Development with OpenSpec

The entire setup described in this post — every config file, workflow, and script — was implemented by an AI coding assistant (GitHub Copilot [15]) following a structured specification process using OpenSpec [16].

What is OpenSpec?

OpenSpec is a lightweight, open-source framework for spec-driven development with AI coding assistants [17]. The core idea is simple: before any code is written, the human and the AI align on what needs to be built through a series of structured artifacts — a proposal, design document, detailed specifications, and an implementation task list. This stands in contrast to “vibe coding,” where you prompt an AI and hope for the best.

OpenSpec uses a two-folder model [16]: openspec/specs/ holds the current state of the system’s specifications, while openspec/changes/ holds proposed changes that are in progress. Each change follows a schema (in this case, spec-driven) that defines the artifact pipeline:

proposal.md → design.md + specs/**/*.md → tasks.md → implementation

How the Conversation Went

The process started with an explore session — an interactive conversation where the human described what they wanted (a Quarto blog on CloudFlare Pages with academic citations) and the AI researched the feasibility, surfaced trade-offs, and helped make design decisions. Key decisions were made collaboratively:

  1. Deployment strategy: GitHub Actions + cloudflare/pages-action over CloudFlare’s built-in build (because Quarto isn’t in CF’s default build image).
  2. Theme: Flatly/darkly pair with automatic toggle.
  3. Citation style: IEEE [1] numbered format with per-post .bib files.
  4. URL structure: posts/{year}/{NNN}-{slug}/ after exploring and rejecting full date nesting (YYYY/MM/DD/slug) as too deep for the publishing frequency.
  5. Post scaffolding: mise task over a plain shell script, since mise was already in use.

Once all decisions were locked in, OpenSpec’s propose workflow generated the formal artifacts:

  • proposal.md — The “why”: a blog for long-form content with citations, deployed to CloudFlare Pages.
  • design.md — The “how”: five key technical decisions with rationale and alternatives considered.
  • specs/ — Four capability specifications (blog-scaffold, citation-system, deployment-pipeline, post-authoring), each with testable requirements written in SHALL/MUST language and WHEN/THEN scenarios.
  • tasks.md — 17 implementation tasks grouped into five phases, each a checkbox that the AI works through sequentially.

Why This Matters

The spec-driven approach had a concrete benefit: every file in this repository traces back to a requirement in a spec, which traces back to a decision in the design, which traces back to the motivation in the proposal. When the AI implemented the tasks, it wasn’t guessing — it was following a contract that both parties had agreed to.

For example, the scripts/new-post.sh script exists because of this requirement in specs/post-authoring/spec.md:

The task SHALL automatically determine the current year and the next available 3-digit zero-padded sequence number within that year’s directory.

And the ieee.csl file at the project root exists because of this design decision:

Download ieee.csl to the project root, reference it from posts/_metadata.yml so all posts inherit it.

The OpenSpec artifacts for this change live in openspec/changes/quarto-blog-setup/ and are committed to the repository — you can read the full proposal, design, specs, and task list to see exactly how the conversation between human and AI was structured.

What’s Next

With the infrastructure in place, the focus shifts to what matters: writing. Future posts will cover book reviews, essays, and other long-form explorations — all written by a human, with citations.

References

[1]
Quarto Development Team, “Creating a blog.” [Online]. Available: https://quarto.org/docs/websites/website-blog.html
[2]
GitHub, “GitHub actions documentation.” [Online]. Available: https://docs.github.com/en/actions
[3]
Cloudflare, “Cloudflare pages documentation.” [Online]. Available: https://developers.cloudflare.com/pages/
[4]
Quarto Development Team, “Citations and footnotes.” [Online]. Available: https://quarto.org/docs/authoring/citations.html
[5]
T. Park, “Bootswatch: Free themes for bootstrap.” [Online]. Available: https://bootswatch.com/
[6]
Quarto Development Team, “HTML theming.” [Online]. Available: https://quarto.org/docs/output-formats/html-themes.html
[7]
Quarto Development Team, “Publishing with CI.” [Online]. Available: https://quarto.org/docs/publishing/ci.html
[8]
Quarto Development Team, “GitHub actions for quarto.” [Online]. Available: https://github.com/quarto-dev/quarto-actions
[9]
Cloudflare, “GitHub action for cloudflare pages.” [Online]. Available: https://github.com/cloudflare/pages-action
[10]
Cloudflare, “Deploy a static HTML site to cloudflare pages.” [Online]. Available: https://developers.cloudflare.com/pages/framework-guides/deploy-anything/
[11]
Quarto Development Team, “Document listings.” [Online]. Available: https://quarto.org/docs/websites/website-listings.html
[12]
Quarto Development Team, “Website navigation.” [Online]. Available: https://quarto.org/docs/websites/website-navigation.html
[13]
Citation Style Language, “Citation style language styles repository.” [Online]. Available: https://github.com/citation-style-language/styles
[14]
mise Contributors, “Mise-en-place: tasks.” [Online]. Available: https://mise.jdx.dev/tasks/
[15]
GitHub, “GitHub copilot documentation.” [Online]. Available: https://docs.github.com/en/copilot
[16]
Fission AI, “OpenSpec: Spec-driven development for AI coding assistants.” [Online]. Available: https://github.com/Fission-AI/OpenSpec
[17]
Fission AI, “OpenSpec documentation.” [Online]. Available: https://openspec.dev/

Citation

BibTeX citation:
@online{chowdhury2026,
  author = {Chowdhury, Ishaat},
  title = {Hello {World:} {How} {This} {Blog} {Was} {Built}},
  date = {2026-03-17},
  url = {https://screechingintothevoid.com/posts/2026/001-hello-world/},
  langid = {en}
}
For attribution, please cite this work as:
I. Chowdhury, “Hello World: How This Blog Was Built.” [Online]. Available: https://screechingintothevoid.com/posts/2026/001-hello-world/