gitmd2pdf

.gitmd2pdf.yml — Repository Configuration

A .gitmd2pdf.yml file checked into the root of your repository lets you control how gitmd2pdf compiles your markdown into a PDF — document metadata, which files to exclude, and the exact order in which content is rendered.

Premium feature. Free and Pro conversions ignore .gitmd2pdf.yml silently. Premium conversions with a valid config show a green Config applied ✓ badge below the Convert button; a config with a structure: key also shows a blue Custom structure ✓ badge.

Quick start

Drop this file at the repo root:

schema_version: 1

title: "My Project Docs"
author: "Your Name"
version: "1.0.0"
date: auto

ignore:
  - ".github/**"
  - "**/DRAFT-*.md"

Convert the repo as a Premium user. Result: the PDF's title page uses your metadata, files matching ignore: are left out, and every other .md file is rendered in filesystem order.

That's the minimum viable config. To go further, keep reading.

Full schema

# ─── Schema version (required in practice) ─────────────────────────
# Pins the config against a known parser. If omitted, the parser
# assumes v1. Future breaking changes will bump this.
schema_version: 1

# ─── Document metadata (all optional) ──────────────────────────────
title: "My Project Docs"
author: "Gene Myers"
version: "1.2.0"
date: "2026-04-18"       # or `auto` to use today's date

# ─── Files to exclude ──────────────────────────────────────────────
# Glob patterns matched against repo-root-relative paths.
# Applied BEFORE `structure:` is resolved, so an ignored file is
# gone even if something in `structure:` references it.
ignore:
  - "README.md"
  - "**/DRAFT-*.md"
  - "internal/**"
  - "node_modules/**"

# ─── Output hierarchy ──────────────────────────────────────────────
# If omitted entirely → fall back to filesystem hierarchy.
# If present → listed files appear in this order; any remaining
# (non-ignored) .md files are auto-appended afterward, indented
# to match their folder depth.
structure:

  # A pure grouping node — has a title but no file of its own
  - title: "Getting Started"
    children:
      - file: docs/intro.md
      - file: docs/install.md
        title: "Installation Guide"       # per-file title override

  # A node that IS a file, but also has children underneath it
  - title: "Architecture"
    file: design/overview.md
    children:
      - file: design/components.md
      - file: design/data-flow.md
        shift_headings: false             # opt out of auto-demotion

  # Glob-include a whole folder as a section
  - title: "API Reference"
    include: "api/**/*.md"                # sorted alphabetically by default
    sort: "filename"                      # or "manual"

  # Single-file entry, no children
  - title: "Appendix"
    file: misc/glossary.md

Node types

Field Purpose
title: Display title for this node. Overrides the file's own # H1 or front-matter title.
file: Path to a single .md file, relative to the repo root.
include: Glob that expands to multiple files. Mutually exclusive with file:.
children: Nested list of nodes underneath this one.
shift_headings: true (default) auto-demotes the file's headings to match YAML depth. false keeps them as written.
sort: For include:filename (default) or manual. frontmatter-order is planned for a future release.

Behavior rules

  1. No structure: key → walk the filesystem, render everything not in ignore:, nest by folder depth.
  2. structure: present → render listed files in the given order, then auto-append any remaining non-ignored .md files at the end. Each auto-appended file's TOC indent level equals its folder depth: a file at the repo root appears at indent 0, sub/foo.md at indent 1, a/b/c.md at indent 2, and so on. No synthetic group header is inserted; the tree shape is conveyed purely by indentation. If you want a named group for auto-appended files, add an explicit group node to structure: with the files you care about nested under it.
  3. Heading auto-shift — depth in YAML determines heading offset. A file at YAML depth 2 with # Foo / ## Bar becomes ## Foo / ### Bar in the PDF. Opt out per file with shift_headings: false.
  4. Per-file title: wins over front-matter title:, which wins over the file's first # H1.
  5. ignore: runs first — if a file matches ignore: it's gone, even if structure: references it (a warning is emitted).
  6. schema_version: — optional but recommended. Current version is 1. An unknown version emits a warning and falls back to the newest supported schema.
  7. Config path is fixed — the file must be named .gitmd2pdf.yml and sit at the repo root. No override path is supported.
  8. Top-level metadata onlytitle / author / version / date apply to the whole PDF. Per-file metadata overrides are not supported in the current schema.

Expected PDF outline

When the full example above is rendered against a repo containing the referenced files, the PDF outline should look like:

My Project Docs
├── Getting Started
│   ├── intro                         (← docs/intro.md)
│   └── Installation Guide            (← docs/install.md)
├── Architecture                      (← design/overview.md)
│   ├── components                    (← design/components.md)
│   └── data-flow                     (headings NOT shifted)
├── API Reference
│   └── (each file under api/**/*.md, sorted alphabetically)
└── Appendix                          (← misc/glossary.md)

Any .md file in your repo that isn't in ignore: and isn't referenced by structure: will auto-append at the end, indented by folder depth.

Badges after conversion

After a successful Premium repo conversion, gitmd2pdf shows a small status badge under the Repository URL card:

No badge means either:

Ready-made example configs

Copy either example below into the root of your repository as .gitmd2pdf.yml, push, and run a Premium repo conversion.

Example 1 — metadata + ignore only (triggers the green "Config applied" badge)

schema_version: 1

title: "My Document Repository — Basic Config Example"
author: "Mods Software"
version: "1.0.0"
date: auto

# Glob patterns matched against repo-root-relative paths.
ignore:
  - ".github/**"
  - "**/DRAFT-*.md"
  - "Testing/**"

Example 2 — full structure: tree using every node type (triggers both badges)

schema_version: 1

title: "My Document Repository — Custom Structure"
author: "Mods Software"
version: "1.0.0"
date: auto

ignore:
  - ".github/**"
  - "**/DRAFT-*.md"

# Explicit output hierarchy. Unlisted .md files are auto-appended at the
# end, indented by folder depth.
structure:

  # Grouping node — title only, no file of its own
  - title: "Introduction"
    children:
      - file: README.md
        title: "About This Repository"

  # Simple single-file node with a title override
  - title: "Planning"
    file: Planning/My Plan.md

  # Glob include — pulls every .md file under Projects/ in filename order
  - title: "Active Projects"
    include: "Projects/*.md"
    sort: filename

  # Grouping with per-file title overrides and a heading-shift opt-out
  - title: "Reference Examples"
    children:
      - file: Examples/Formatting Showcase.md
      - file: Examples/Image Examples.md
        title: "Embedding Images"
      - file: Examples/Edge Cases.md
        shift_headings: false

  # File-node that also has children nested underneath
  - title: "Quality Assurance"
    file: Testing/Test plan.md
    children:
      - file: Testing/Test Cases.md

# Any .md file not listed above (e.g. Reports/Monthly Status.md) auto-appends
# at the end of the PDF at its folder-depth.

Validation errors you might see

If your config is present but broken, the conversion will fail with a message starting with gitmd2pdf config:. Common ones:

Structure-specific warnings (emitted as [structure] in conversion logs) include missing files, zero-match globs, duplicate entries, and malformed structure: entries. The conversion still runs; warnings surface files you might not have meant to skip.

Non-Premium behavior

Free and Pro conversions ignore .gitmd2pdf.yml entirely. No warning, no error — the PDF is produced from the filesystem as if the file weren't there. The green and blue badges are how you verify Premium config loading actually ran.

If you're on Premium and still see no badge, the file is probably at a subfolder rather than the repo root, or the YAML has a parse error that's being swallowed — try loading the file through any YAML validator first to confirm.