Agent Skills Framework Extension
PDF Publishing Patterns Skill
When to Use This Skill
Use this skill when implementing pdf publishing patterns patterns in your codebase.
How to Use This Skill
- Review the patterns and examples below
- Apply the relevant patterns to your implementation
- Follow the best practices outlined in this skill
Automated PDF generation from Markdown with custom branding, table of contents, headers/footers, and CI/CD integration.
Core Capabilities
- Markdown to PDF - High-quality PDF generation
- Custom Branding - Logos, colors, and styling
- TOC Generation - Automatic table of contents
- Headers/Footers - Page numbers and metadata
- Document Merging - Multi-file PDF compilation
Pandoc PDF Generation
#!/usr/bin/env bash
# generate-pdf.sh - Professional PDF generation with Pandoc
set -euo pipefail
# Configuration
INPUT_MD="$1"
OUTPUT_PDF="${2:-output.pdf}"
TEMPLATE_DIR="templates"
ASSETS_DIR="assets"
# Metadata
TITLE="${PDF_TITLE:-Documentation}"
AUTHOR="${PDF_AUTHOR:-CODITECT}"
DATE="${PDF_DATE:-$(date +%Y-%m-%d)}"
VERSION="${PDF_VERSION:-1.0}"
# Styling
MARGIN_TOP="${MARGIN_TOP:-1in}"
MARGIN_BOTTOM="${MARGIN_BOTTOM:-1in}"
MARGIN_LEFT="${MARGIN_LEFT:-1in}"
MARGIN_RIGHT="${MARGIN_RIGHT:-1in}"
FONT_SIZE="${FONT_SIZE:-11pt}"
log_info() { echo "[INFO] $1"; }
log_error() { echo "[ERROR] $1" >&2; }
generate_pdf() {
log_info "Generating PDF: $OUTPUT_PDF"
# Create metadata file
cat > metadata.yaml <<EOF
---
title: "$TITLE"
author: "$AUTHOR"
date: "$DATE"
version: "$VERSION"
documentclass: report
geometry:
- top=$MARGIN_TOP
- bottom=$MARGIN_BOTTOM
- left=$MARGIN_LEFT
- right=$MARGIN_RIGHT
fontsize: $FONT_SIZE
toc: true
toc-depth: 3
numbersections: true
header-includes: |
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[L]{$TITLE}
\fancyhead[R]{v$VERSION}
\fancyfoot[C]{\thepage}
\usepackage{graphicx}
\usepackage{xcolor}
\definecolor{linkcolor}{RGB}{0, 102, 204}
\hypersetup{
colorlinks=true,
linkcolor=linkcolor,
urlcolor=linkcolor
}
---
EOF
# Generate PDF with Pandoc
pandoc \
metadata.yaml \
"$INPUT_MD" \
-o "$OUTPUT_PDF" \
--pdf-engine=xelatex \
--template="$TEMPLATE_DIR/custom.latex" \
--highlight-style=tango \
--listings \
--number-sections \
--toc \
--toc-depth=3 \
--variable mainfont="DejaVu Sans" \
--variable monofont="DejaVu Sans Mono" \
--variable fontsize="$FONT_SIZE" \
--variable geometry:"top=$MARGIN_TOP, bottom=$MARGIN_BOTTOM, left=$MARGIN_LEFT, right=$MARGIN_RIGHT"
rm metadata.yaml
log_info "PDF generated successfully: $OUTPUT_PDF"
}
generate_pdf
Custom LaTeX Template
% custom.latex - Custom Pandoc LaTeX template with branding
\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(papersize)$$papersize$paper,$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$}
% Fonts
\usepackage{fontspec}
\setmainfont{$mainfont$}
\setmonofont{$monofont$}
% Page geometry
\usepackage[
top=$geometry.top$,
bottom=$geometry.bottom$,
left=$geometry.left$,
right=$geometry.right$
]{geometry}
% Headers and footers
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[L]{\small\textit{$title$}}
\fancyhead[R]{\small v$version$}
\fancyfoot[C]{\thepage}
\renewcommand{\headrulewidth}{0.4pt}
% Colors
\usepackage{xcolor}
\definecolor{linkcolor}{RGB}{0, 102, 204}
\definecolor{codebackground}{RGB}{245, 245, 245}
% Hyperlinks
\usepackage{hyperref}
\hypersetup{
colorlinks=true,
linkcolor=linkcolor,
urlcolor=linkcolor,
pdftitle={$title$},
pdfauthor={$author$}
}
% Code highlighting
\usepackage{listings}
\lstset{
backgroundcolor=\color{codebackground},
basicstyle=\ttfamily\small,
breaklines=true,
frame=single,
numbers=left,
numberstyle=\tiny,
showstringspaces=false
}
% Graphics
\usepackage{graphicx}
% Title page
\title{
\vspace{2in}
\includegraphics[width=2in]{assets/logo.png}\\
\vspace{0.5in}
{\Huge\bfseries $title$}\\
\vspace{0.2in}
{\Large Version $version$}
}
\author{$author$}
\date{$date$}
\begin{document}
% Custom title page
\maketitle
\thispagestyle{empty}
\newpage
% Table of contents
$if(toc)$
\tableofcontents
\newpage
$endif$
% Document body
$body$
\end{document}
Python PDF Generator
#!/usr/bin/env python3
"""
PDF generation with custom branding using ReportLab.
Provides more control than Pandoc for complex layouts.
"""
from reportlab.lib.pagesizes import letter, A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak, Image, TableOfContents
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
import markdown
from pathlib import Path
class PDFGenerator:
def __init__(self, output_path: str, title: str, author: str, version: str):
self.output_path = output_path
self.title = title
self.author = author
self.version = version
self.doc = SimpleDocTemplate(
output_path,
pagesize=letter,
topMargin=1*inch,
bottomMargin=1*inch,
leftMargin=1*inch,
rightMargin=1*inch
)
self.story = []
self.styles = getSampleStyleSheet()
self._setup_custom_styles()
def _setup_custom_styles(self):
"""Create custom paragraph styles."""
# Title style
self.styles.add(ParagraphStyle(
name='CustomTitle',
parent=self.styles['Heading1'],
fontSize=24,
textColor=colors.HexColor('#003366'),
spaceAfter=30,
alignment=TA_CENTER
))
# Heading styles
self.styles.add(ParagraphStyle(
name='CustomHeading1',
parent=self.styles['Heading1'],
fontSize=18,
textColor=colors.HexColor('#003366'),
spaceBefore=20,
spaceAfter=12
))
# Code style
self.styles.add(ParagraphStyle(
name='Code',
parent=self.styles['Code'],
fontSize=9,
fontName='Courier',
backColor=colors.HexColor('#f5f5f5'),
borderWidth=1,
borderColor=colors.HexColor('#cccccc'),
borderPadding=5
))
def add_cover_page(self, logo_path: str = None):
"""Add custom cover page."""
if logo_path and Path(logo_path).exists():
logo = Image(logo_path, width=2*inch, height=2*inch)
logo.hAlign = 'CENTER'
self.story.append(Spacer(1, 2*inch))
self.story.append(logo)
self.story.append(Spacer(1, 0.5*inch))
# Title
title = Paragraph(self.title, self.styles['CustomTitle'])
self.story.append(title)
self.story.append(Spacer(1, 0.2*inch))
# Version
version_text = Paragraph(f"Version {self.version}", self.styles['Normal'])
version_text.hAlign = 'CENTER'
self.story.append(version_text)
self.story.append(Spacer(1, 0.5*inch))
# Author
author_text = Paragraph(f"by {self.author}", self.styles['Normal'])
author_text.hAlign = 'CENTER'
self.story.append(author_text)
self.story.append(PageBreak())
def add_table_of_contents(self):
"""Add table of contents."""
toc = TableOfContents()
toc.levelStyles = [
ParagraphStyle(name='TOCHeading1', fontSize=14, leftIndent=20, spaceBefore=5, spaceAfter=5),
ParagraphStyle(name='TOCHeading2', fontSize=12, leftIndent=40, spaceBefore=3, spaceAfter=3),
ParagraphStyle(name='TOCHeading3', fontSize=10, leftIndent=60, spaceBefore=2, spaceAfter=2),
]
self.story.append(Paragraph("Table of Contents", self.styles['CustomHeading1']))
self.story.append(toc)
self.story.append(PageBreak())
def add_markdown_content(self, markdown_path: str):
"""Convert Markdown to PDF paragraphs."""
content = Path(markdown_path).read_text()
# Convert markdown to HTML
html = markdown.markdown(content, extensions=['fenced_code', 'tables', 'toc'])
# Parse HTML and convert to ReportLab elements
# This is simplified - production would use HTMLParser
lines = html.split('\n')
for line in lines:
if line.startswith('<h1>'):
text = line.replace('<h1>', '').replace('</h1>', '')
self.story.append(Paragraph(text, self.styles['CustomHeading1']))
elif line.startswith('<h2>'):
text = line.replace('<h2>', '').replace('</h2>', '')
self.story.append(Paragraph(text, self.styles['Heading2']))
elif line.startswith('<p>'):
text = line.replace('<p>', '').replace('</p>', '')
self.story.append(Paragraph(text, self.styles['Normal']))
self.story.append(Spacer(1, 0.1*inch))
elif line.startswith('<code>'):
text = line.replace('<code>', '').replace('</code>', '')
self.story.append(Paragraph(text, self.styles['Code']))
def add_header_footer(self, canvas, doc):
"""Add header and footer to each page."""
canvas.saveState()
# Header
canvas.setFont('Helvetica', 9)
canvas.drawString(1*inch, doc.height + 1.5*inch, self.title)
canvas.drawRightString(doc.width + 1*inch, doc.height + 1.5*inch, f"v{self.version}")
# Footer
canvas.drawCentredString(doc.width/2 + 1*inch, 0.5*inch, f"Page {doc.page}")
canvas.restoreState()
def generate(self):
"""Generate the PDF."""
self.doc.build(
self.story,
onFirstPage=self.add_header_footer,
onLaterPages=self.add_header_footer
)
# Usage
if __name__ == '__main__':
generator = PDFGenerator(
output_path='documentation.pdf',
title='CODITECT Documentation',
author='AZ1.AI',
version='1.0'
)
generator.add_cover_page(logo_path='assets/logo.png')
generator.add_table_of_contents()
generator.add_markdown_content('README.md')
generator.generate()
print("✅ PDF generated: documentation.pdf")
CI/CD PDF Publishing
# .github/workflows/publish-docs.yml
name: Publish Documentation PDF
on:
push:
branches: [main]
paths:
- 'docs/**/*.md'
release:
types: [published]
jobs:
generate-pdf:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Pandoc
run: |
wget https://github.com/jgm/pandoc/releases/download/3.1.9/pandoc-3.1.9-1-amd64.deb
sudo dpkg -i pandoc-3.1.9-1-amd64.deb
- name: Install LaTeX
run: |
sudo apt-get update
sudo apt-get install -y texlive-xetex texlive-fonts-recommended
- name: Generate PDF
run: |
bash scripts/generate-pdf.sh docs/README.md documentation.pdf
- name: Upload PDF artifact
uses: actions/upload-artifact@v4
with:
name: documentation-pdf
path: documentation.pdf
- name: Attach to Release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v1
with:
files: documentation.pdf
Usage Examples
Generate Branded PDF from Markdown
Apply pdf-publishing-patterns skill to convert Markdown documentation to professional PDF with custom branding
Multi-Document PDF Compilation
Apply pdf-publishing-patterns skill to merge multiple Markdown files into single PDF with table of contents
Automated PDF Publishing in CI/CD
Apply pdf-publishing-patterns skill to setup GitHub Actions workflow for automatic PDF generation on documentation changes
Success Output
When successfully implementing PDF publishing patterns:
✅ SKILL COMPLETE: pdf-publishing-patterns
Completed:
- [x] Pandoc PDF generation script created with custom LaTeX template
- [x] Metadata YAML configuration generated (title, author, date, version)
- [x] Custom branding applied (logo, colors, headers/footers)
- [x] Table of contents auto-generated with 3-level depth
- [x] Page numbers and metadata headers/footers configured
- [x] CI/CD workflow setup for automated PDF generation on doc changes
- [x] PDF artifact uploaded and attached to releases
Outputs:
- generate-pdf.sh script with Pandoc configuration
- custom.latex template with branding
- Generated PDF file at specified output path
- .github/workflows/publish-docs.yml (if CI/CD integration)
- PDF artifact attached to GitHub releases (if release workflow)
Completion Checklist
Before marking this skill as complete, verify:
- Pandoc and XeLaTeX installed and functional
- generate-pdf.sh script created with metadata configuration
- Custom LaTeX template includes branding (logo, colors, fonts)
- Table of contents generated with proper depth (toc-depth: 3)
- Headers show document title and version
- Footers show page numbers
- Code blocks styled with highlighting and line numbers
- Hyperlinks colored and functional in PDF
- PDF generates without LaTeX errors
- Output PDF verified to match expected formatting
- CI/CD workflow (if applicable) triggers on docs/** changes
- PDF artifact uploads successfully to releases
Failure Indicators
This skill has FAILED if:
- ❌ Pandoc not installed or wrong version (need 3.1.9+)
- ❌ XeLaTeX not available (texlive-xetex package missing)
- ❌ LaTeX compilation errors (syntax errors in template)
- ❌ Table of contents missing from generated PDF
- ❌ Logo image not found or fails to render
- ❌ Headers/footers not appearing on pages
- ❌ Code blocks not highlighted or improperly formatted
- ❌ Hyperlinks not working in PDF (broken links)
- ❌ CI/CD workflow fails to generate PDF artifact
- ❌ PDF not attached to GitHub releases
When NOT to Use
Do NOT use this skill when:
- Publishing HTML documentation only (no PDF needed)
- Interactive documentation required (use Docusaurus, GitBook)
- Frequent updates with version control (use web-based docs)
- Documentation needs embedded videos or interactive elements
- Target audience prefers web over downloadable PDFs
Use alternatives instead:
- For HTML docs → Use Docusaurus, GitBook, MkDocs
- For interactive elements → Use web-based documentation platforms
- For frequently updated docs → Use hosted documentation sites
- For API docs → Use Swagger/OpenAPI, Redoc
- For live collaboration → Use Notion, Confluence
Anti-Patterns (Avoid)
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Hardcoding metadata in template | Must edit template for each doc | Use YAML metadata variables |
| Missing logo path validation | Build fails if logo not found | Check file exists before Pandoc call |
| No CI/CD caching | Slow builds, installs Pandoc every time | Cache Pandoc/LaTeX in workflow |
| Ignoring LaTeX errors | Silent failures, incomplete PDFs | Check exit codes, fail on errors |
| Fixed margins for all docs | Poor formatting for different content | Use environment variables for margins |
| No version in filename | Overwrites previous PDFs | Include version: documentation-v1.2.pdf |
Principles
This skill embodies CODITECT automation principles:
- #1 Recycle → Extend → Re-Use → Create - Reuses custom.latex template across all PDF generations
- #3 Self-Provisioning - CI/CD workflow auto-installs Pandoc and LaTeX dependencies
- #4 Keep It Simple - Clear Bash script with environment variables for configuration
- #5 Eliminate Ambiguity - YAML frontmatter explicitly defines all metadata
- #6 Clear, Understandable, Explainable - Comments in scripts and templates explain each section
- #10 Complete Execution - End-to-end automation from Markdown to published PDF
Full Standard: CODITECT-STANDARD-AUTOMATION.md
Integration Points
- documentation-patterns - Documentation standards
- cicd-pipeline-design - Automated publishing
- project-organization-patterns - Documentation structure