---
title: AsciiBinder AsciiDoc to Markdown to Astro
description: Two workflows that convert an AsciiBinder AsciiDoc corpus to Markdown and build it as an Astro site, on demand or weekly. Fork them and run them yourself; the OpenShift docs are the test corpus because they are the hardest one.
created: "2026-08-26"
author: Gabriel McGoldrick
tags:
  - topic/asciidoc
  - topic/migration
---

# AsciiBinder AsciiDoc to Markdown to Astro {#asciibinder-asciidoc-to-markdown-to-astro}

The OpenShift documentation is a good stress test for the DogsBay Asciidoc to Markdown converter. It is based on AsciiBinder and has:

- A topic map instead of a directory tree
- Multiple product distros sharing one source
- Several hundred symlinks so `include::` resolves at any depth
- Attributes threaded through nearly every page.
- 20,000+ `.adoc` files, of which ~12,000 belong to the `openshift-enterprise` distro.

[**dogsbay/openshift-docs-markdown**](https://github.com/dogsbay/openshift-docs-markdown) runs the Asciidoc to Markdown conversion on a schedule and commits the result. You can fork it and have your own copy building in about seven minutes of wall-clock time, most of which is waiting on npm.

:::note{title="AsciiDoc to Markdown — part 8 of 10"}
1. [Converting AsciiDoc to Markdown](/blog/converting-asciidoc-to-markdown/)
2. [Why existing AsciiDoc converters lose your structure](/blog/why-existing-converters-lose-structure/)
3. [Why Jinja is the right target](/blog/why-jinja-is-the-right-target/)
4. [Mapping AsciiDoc variables to Jinja](/blog/asciidoc-variables-in-jinja/)
5. [Mapping AsciiDoc conditionals to Jinja](/blog/asciidoc-conditionals-in-jinja/)
6. [Mapping AsciiDoc ifeval to Jinja](/blog/asciidoc-ifeval-in-jinja/)
7. [Mapping AsciiDoc includes and level offsets to Jinja](/blog/asciidoc-includes-in-jinja/)
8. **AsciiBinder AsciiDoc to Markdown to Astro** — you are here
9. [AsciiBinder AsciiDoc to Markdown to MkDocs](/blog/asciibinder-adoc-to-markdown-mkdocs/)
10. [AsciiBinder AsciiDoc to Markdown to Docusaurus](/blog/asciibinder-adoc-to-markdown-docusaurus/)
:::

## What is in the repo {#what-is-in-the-repo}

There is one branch per upstream version. The `main` holds only the two workflows while the content lives on a branch named after the upstream ref it mirrors.

```
main                    the two workflows, nothing else
enterprise-4.22
  markdown/             11,885 .md — the converted source
  site/                 the generated Astro project
  site/dist/            1,799 built HTML pages
  dogsbay.config.yml
  MIGRATION.md          what survived conversion, and what did not
```

The `markdown/` folder is ordinary Markdown, and its history is a changelog of what upstream changed and what the converter did with it.

## Fork the repo and use GitHub Actions to run the conversion online {#fork-the-repo-and-use-github-actions-to-run-the-conversion-online}

1. **Fork** [dogsbay/openshift-docs-markdown](https://github.com/dogsbay/openshift-docs-markdown).
2. Open the **Actions** tab and enable workflows. GitHub disables them on forks by default.
3. Manually run the action named **1. Convert AsciiDoc → Markdown**. The inputs default to `enterprise-4.22` and `openshift-enterprise`. Any `enterprise-*` upstream branch works.
4. When it finishes, manually run the action named **2. Build HTML site** against the same branch.

It takes roughly **115 seconds** for the conversion and **325 seconds** for the build and deploy, with most of the time spent downloading the packages from npm.

All of it runs on GitHub's runners, so you need nothing installed locally to get this far — a browser and a fork are enough.

### Where your site appears {#where-your-site-appears}

Workflow 2 publishes to GitHub Pages and turns Pages on for you, so there is no Settings trip. Your copy lands at:

```
https://<your-username>.github.io/openshift-docs-markdown/
```

## Pages to check {#pages-to-check}

| Page | Why it is interesting |
| --- | --- |
| [https://dogsbay.github.io/openshift-docs-markdown/installing/installing_bare_metal/upi/installing-bare-metal/](https://dogsbay.github.io/openshift-docs-markdown/installing/installing_bare_metal/upi/installing-bare-metal/) | 75 `include::` directives resolved into one 1.1 MB page |
| [https://dogsbay.github.io/openshift-docs-markdown/rest_api/monitoring_apis/prometheus-monitoring-coreos-com-v1/](https://dogsbay.github.io/openshift-docs-markdown/rest_api/monitoring_apis/prometheus-monitoring-coreos-com-v1/) | the largest page in the corpus — 604 KB of Markdown |
| [https://dogsbay.github.io/openshift-docs-markdown/welcome/oke_about/](https://dogsbay.github.io/openshift-docs-markdown/welcome/oke_about/) | a comparison table built from AsciiDoc span cells (`2+h\|`) |
| [https://dogsbay.github.io/openshift-docs-markdown/tutorials/dev-app-web-console/](https://dogsbay.github.io/openshift-docs-markdown/tutorials/dev-app-web-console/) | UI icons rendered *inside* sentences |

Those links point at this repo's build, so you can look before forking anything.

:::note{title="Why the workflows live on main"}
`workflow_dispatch` reads the workflow file from the branch you select, so keeping both on `main` means one file to maintain rather than one per version.
:::

## Running it on a schedule {#running-it-on-a-schedule}

Workflow 1 already carries a default weekly schedule:

```yaml
on:
  workflow_dispatch:
    inputs:
      upstream_ref:
        default: "enterprise-4.22"
      distro:
        default: "openshift-enterprise"
  schedule:
    - cron: "0 5 * * 1"     # Mondays 05:00 UTC
```

A fork inherits it, so a weekly refresh needs nothing beyond enabling Actions. The scheduler disables cron on repositories with no activity for 60 days, and it runs schedules only on the **default branch**, which is why `main` holds the workflows.

## Running the OpenShift conversion to Markdown locally {#running-the-openshift-conversion-to-markdown-locally}

Everything above runs on GitHub's machines. Running the conversion locally needs two things:

- **git**, for the clone.
- **Node.js 22** and the `npx` that ships with it.

There is nothing extra to install — `npx` fetches the CLI on first use, and `site dev` installs the generated project's own dependencies when it first runs.

```bash
git clone --depth 1 --branch enterprise-4.22 \
  https://github.com/openshift/openshift-docs.git

npx dogsbay migrate-asciidoc ./openshift-docs -o ./out \
  --distro openshift-enterprise \
  --site-name "OpenShift Container Platform" \
  -a product_title="OpenShift Container Platform" \
  -a product_version=4.22 \
  -a openshift_enterprise=true
```

That writes `out/markdown/`, a `dogsbay.config.yml` and a `MIGRATION.md`. To see it as a site:

```bash
cd out && npx dogsbay site dev
```

`site dev` rebuilds the content and installs the scaffold's dependencies on first run, so there is no separate install step. On a laptop the build is about **50 seconds** and peaks near **1.5 GB** of memory.

### The attribute settings {#the-attribute-settings}

The `-a` flags matter to the conversion. OpenShift's AsciiDoc is dense with `ifdef::openshift-enterprise[]` and `{product-title}` — more than 50,000 attribute references and 6,000 conditionals survive into the Markdown.

The conversion writes them into `dogsbay.config.yml` and leaves the Markdown templated: `{{ product_title }}` stays a variable, `{% if openshift_enterprise %}` stays a conditional. They only resolve when you build the site for a specific version and distro.

`--distro` is specified  at conversion time, because the topic map gives the same file different **labels** per distro — the same page is "Fedora CoreOS" for OKD and "Red Hat Enterprise Linux CoreOS" for Enterprise — so a distro-neutral nav would carry duplicates rather than a superset.

## What to look at once it runs {#what-to-look-at-once-it-runs}

`site dev` serves on **http://localhost:4321** by default. There is no base path on a local build, so the slugs below map straight onto it — `http://localhost:4321/welcome/oke_about/` and so on. If you would rather not run anything, the same pages are live at [dogsbay.github.io/openshift-docs-markdown](https://dogsbay.github.io/openshift-docs-markdown/).

Start with `MIGRATION.md` in the output directory: it reports what survived conversion and what did not. Then these five, each chosen because it breaks a different part of a converter.

**`/installing/installing_bare_metal/upi/installing-bare-metal/`** — 75 `include::` directives resolved into one page, 1.1 MB served. Modular AsciiDoc at its most extreme: almost none of this page's text lives in its own file.

**`/support/gathering-cluster-data/`** — 32 includes and 18 conditionals in 5 KB of source. This is the attribute machinery doing its job; view the Markdown behind it and you will see `{% if %}` blocks that only resolve at build time.

**`/rest_api/monitoring_apis/prometheus-monitoring-coreos-com-v1/`** — the largest page in the corpus, 604 KB of Markdown and 3.4 MB served. Generated Kubernetes API reference: deeply nested definition lists, thousands of rows, and a good check that nothing quietly truncates.

**`/welcome/oke_about/`** — a product comparison table built from AsciiDoc span cells (`2+h|`). Column spans are where table conversion usually falls apart: the label cell spans two columns and the row has to stay one row.

**`/tutorials/dev-app-web-console/`** — UI icons *inside* sentences, from `image:fa-plus-circle.png[title="Quick create menu"]`. An inline image that renders as a block splits the sentence around it, which is obvious to a reader and invisible to a test that only counts pages.
