panforge is a from scratch Go port of the Ruby panrun script. It is a wrapper around pandoc that allows you to specify compile commands (like output formats and Pandoc arguments) directly in the YAML header of your Markdown files.
- Pandoc must be installed and available in your
PATH. - Go (1.25+ recommended) for building from source.
go install github.com/rapjul/panforge/cmd/panforge@latestgit clone https://github.com/rapjul/panforge.git
cd panforge
go install ./cmd/panforgeTo quickly get started with a new file or configuration:
# Generate a sample Markdown file with YAML frontmatter
panforge init --markdown
# OR generate a default config file
panforge init --config
# Generate a sample Markdown file to convert to specific output formats
panforge init -m -t pdf,docxpanforge [flags] <file>This acts as a transparent wrapper around pandoc, reading configuration from the YAML header of input.md to determine how to process it.
panforge generally passes unknown arguments through to pandoc. However, since panforge uses some flags (like -f/--force) that conflict with pandoc's flags (e.g., -f/--from), strict flag parsing may consume them.
To safely pass flags directly to pandoc without interference, use the -- separator:
# Correctly pass -f/--from to pandoc
panforge input.md -- -f markdown
# Pass arbitrary flags
panforge input.md -- --toc --toc-depth=2-t, --target <format>: Specifically target one or more output formats defined in the YAML header. Can be used multiple times.-o, --output <file>: Override the output filename.-a, --all: Process all formats defined in the YAML header (this is also the default behavior if no targets are specified).-f, --force: Force overwrite of existing output files without prompting.-d, --dry-run: Print thepandoccommands that would be executed without running them.-v, --verbose: Enable verbose logging.-q, --quiet: Suppress standard output messages.-w, --watch: Watch input file for changes and automatically re-run.--log <file>: Append logs to the specified file.
To pass arguments directly to the underlying pandoc command (not recommended, use the YAML header instead), you can append them after the input file or arguments.
panforge supports shell completion for Bash, Zsh, Fish, and PowerShell. This includes dynamic completion for output formats and input files.
To generate the completion script:
source <(panforge completion bash)source <(panforge completion zsh)panforge completion fish | sourceTo load completions for every session, correct the above commands to write to your shell's completion directory or config file (e.g., ~/.bashrc or ~/.zshrc).
panforge looks for configuration files in the following order:
- XDG Specification:
$XDG_CONFIG_HOME/panforge/(e.g.,~/.config/panforge/on Linux/macOS) - Windows:
%APPDATA%/panforge/ - Default:
~/.config/panforge/(ifXDG_CONFIG_HOMEis unset)
You can place your default.yaml or other config files in this directory.
panforge looks for strictly structured metadata in the YAML header of your Markdown file.
You can define a list of formats to generate using the outputs key, or a map of configurations using the output key.
Allows specifying per-format options.
---
title: My Document
output:
html:
to: html5
standalone: true
css: style.css
pdf:
pdf-engine: xelatex
variable:
geometry: margin=2cm
---Running panforge file.md on the above will generate both an HTML and a PDF file.
Simple list of formats.
---
outputs:
- html
- docx
---Any key inside an output block is translated to a Pandoc argument.
The following rules apply:
key: value->--key=valuekey: true->--keykey: [list]->--key=item1 --key=item2 ...key: {map}-> (varies, usually not directly mapped to simple flags, butvariablesandmetadataare special cases)
Options at the root of the YAML header are treated as variables or metadata by panforge if they match known configuration keys, otherwise they are passed to pandoc as metadata.
Special keys processed by panforge:
output/outputs: Defines targets.filename-template: (Optional) Template for output filenames (e.g.,"{title}_{date}.{ext}").- Supported template variables include:
{date}and{time}(formatted asYYYY-MM-DDandHH:MM:SS, respectively){title}and{title-slug}(iftitleis a string){author}and{author-slug}(ifauthoris a string){ext}(file extension)
- If
slugify-filenameis enabled,{title}and{author}will be slugified any time they are used (e.g.,my-titleinstead ofmy title)
- Supported template variables include:
slugify-filename: (Optional) Boolean to enable/disable filename slugification (default:false).
This project is designed for Minimal Maintenance.
- Dependencies: All Go dependencies are vendored in the
vendor/directory. This ensures the project can always be built even if upstream repositories disappear or make incompatible changes. - CI/CD: Workflows are pinned to specific versions (Go 1.25, GoReleaser v2) to prevent "bit rot" where CI breaks simply because a tool updated.
- Versioning: The project uses semantic versioning (e.g.,
v1.2.3). - Branches: The project uses a single branch (
main) for development and releases.
If you need to update dependencies:
- Run
go get -u ./...(or update specific packages). - Run
go mod tidy. - Run
go mod vendorto update thevendor/directory. - Commit changes.
This project uses Lefthook for fast, Go-native git hooks.
-
Install:
go install github.com/evilmartians/lefthook@latest go install github.com/google/yamlfmt/cmd/yamlfmt@latest
-
Setup: Run
lefthook installin the repo root. -
Run Manually:
lefthook run pre-commit.
For development instructions, please see CONTRIBUTING.md.