Skip to main content

Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more

Project description

mk2conf — MkDocs / Zensical to Confluence

License: GPL v3 Python 3.12+ PyPI Downloads Latest Release CI Release codecov Ruff mypy security: bandit

A Python CLI tool that compiles MkDocs-flavoured Markdown into native Confluence storage XHTML and publishes it directly to Confluence Cloud. It is a compiler/transpiler, not an HTML converter — every construct maps to its native Confluence equivalent, so pages look and behave like hand-authored Confluence content.

It also bridges the gap between Confluence reviewers and developers: the sync-comments command turns open Confluence page comments into GitHub pull request review threads, and auto-resolves them in Confluence when the PR is merged.

Zensical compatibleZensical is the modern successor to MkDocs + Material for MkDocs. Since it uses the same mkdocs.yml format and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.


Installation

Requires Python 3.12+. The PyPI package is mkdocs2confluence; the CLI command is mk2conf.

pip install mkdocs2confluence
# or, for an isolated install:
pipx install mkdocs2confluence

To use the mk2conf pdf subcommand, install the optional PDF extra:

pip install "mkdocs2confluence[pdf]"

WeasyPrint requires system libraries (Pango, Cairo) — install them for your platform:

Platform Command
macOS brew install pango
Ubuntu / Debian apt install libpango-1.0-0 libpangoft2-1.0-0
Windows 11 choco install gtk-runtime — or download the GTK3 runtime installer and add its bin\ folder to your PATH

From source (see Setup.md):

git clone https://github.com/jeckyl2010/mkdocs2confluence.git
cd mkdocs2confluence && uv sync

Quick start

# Inspect the Confluence storage XHTML for a page
mk2conf preview --page index.md

# Open a live browser preview — rebuilds on every file save
mk2conf preview --page index.md --watch
mk2conf preview --section Guide --watch

# Dry-run: see what would be published without touching Confluence
mk2conf publish --dry-run

# Publish all nav pages to Confluence
mk2conf publish

# Export a nav section to a stand-alone PDF document
mk2conf pdf --section Guide --out guide.pdf

# Sync open Confluence comments to GitHub review PRs
mk2conf sync-comments

# Resolve Confluence comments when their review PRs are merged
mk2conf sync-comments --check-merges

Configuration

Add a confluence: block to your mkdocs.yml:

confluence:
  base_url: https://yourorg.atlassian.net
  space_key: TECH
  email: user@example.com
  token: !ENV CONFLUENCE_API_TOKEN   # never hardcode the token
  parent_page_id: "123456"           # optional root page
  mermaid_render: kroki              # "kroki" (default) | "kroki:https://your-kroki" | "none"
  full_width: true                   # default: true

The confluence: block is also accepted under extra: (MkDocs strict-mode compatible):

extra:
  confluence:
    base_url: https://yourorg.atlassian.net
    space_key: TECH
    ...

The API token is read from (in priority order):

  1. token: in mkdocs.yml — typically via !ENV CONFLUENCE_API_TOKEN
  2. CONFLUENCE_API_TOKEN environment variable
  3. MK2CONF_TOKEN environment variable

Additional fields for sync-comments

confluence:
  # ... base fields above ...
  github_repo: owner/repo        # required for sync-comments
  github_token: !ENV GITHUB_TOKEN  # falls back to GITHUB_TOKEN env var
  github_base_branch: main       # default: main

Your first publish

Once you have added the confluence: block (see above), this is all you need to get from zero to a live Confluence page:

# 1. Set your API token (add this to your shell profile or CI secrets)
export CONFLUENCE_API_TOKEN=your_api_token_here

# 2. Preview one page locally to verify the output before touching Confluence
mk2conf preview --page docs/index.md --watch

# 3. Dry-run to see exactly what would be created or updated
mk2conf publish --dry-run

# 4. Publish
mk2conf publish

That is it. mk2conf reads mkdocs.yml in the current directory, compiles every page listed in nav:, mirrors the hierarchy under parent_page_id, and skips any page that has not changed since the last run.


Commands

mk2conf preview

Compile and inspect output locally — no Confluence API calls. Mermaid diagrams are rendered via Kroki unless mermaid_render: none is set.

mk2conf preview [--config PATH] --page PATH [--out FILE] [--html] [--watch]
mk2conf preview [--config PATH] --section SECTION [--out FILE] [--watch]
Flag Default Description
--config PATH ./mkdocs.yml Path to mkdocs.yml
--page PATH (required unless --section) Relative path to the Markdown file
--section SECTION (none) Nav section title to render, slash-separated for nested sections (e.g. Guide or Guide/Setup). Renders all pages in that subtree as a browseable HTML index.
--out FILE stdout Write output to a file or directory
--html off Render macros as styled browser-viewable HTML
--watch off Serve on http://localhost:8765 and auto-rebuild on file changes. Implies --html. Ctrl+C to stop.

--html is for local review only — the actual Confluence storage XHTML is the --html-free output.


mk2conf publish

Compile all pages in nav: and publish to Confluence Cloud.

mk2conf publish [--config PATH] [--page PATH] [--section SECTION] [--dry-run] [--report FILE] [--prune]
Flag Default Description
--config PATH ./mkdocs.yml Path to mkdocs.yml
--page PATH (all nav pages) Publish a single page only
--section SECTION (whole nav) Publish only a nav subtree, slash-separated for nested sections (e.g. Guide or Guide/Setup)
--dry-run off Print the publish plan; no Confluence API writes
--report FILE (none) Write a JSON publish report
--prune off Delete managed pages no longer in nav:. Only pages stamped by mk2conf are eligible — manually-created Confluence pages are never touched. Ignored on partial (--page / --section) runs.

Publish behaviour

  • Only nav: pages are published — pages absent from the nav are never touched (natural draft gate).
  • Pages with ready: false in front matter are skipped, even if listed in nav:.
  • Section nodes (nav groups without a page) become empty parent pages, mirroring the nav hierarchy.
  • Local assets are uploaded as Confluence page attachments automatically.
  • Unchanged pages are skipped — a sha256 hash of the compiled output is stored as a hidden page property; pages with identical content since the last run produce no version bump and no notification.

Mermaid rendering

mermaid_render Behaviour
kroki (default) Render via https://kroki.io. PNGs cached in ~/.cache/mk2conf/mermaid/.
kroki:https://your-kroki Render via a self-hosted Kroki instance.
none Fall back to a code macro labelled mermaid.

If Kroki is unreachable the run continues, falling back to the code macro for affected diagrams.

Styling from extra.css

If mkdocs.yml lists extra_css: files, mk2conf reads them and applies a whitelisted set of CSS properties as inline style="..." attributes on Confluence output.

Selector Applied to
th, thead th Table header cells
td Table body cells
h1h6 Headings
code (not pre code) Inline code spans

Supported properties: background-color, color, font-weight, font-style, font-size, text-align, border. CSS custom properties (var(--name)) are resolved automatically, including chained variables and var(--name, fallback) syntax.

Complex Material theme overrides (compound selectors, color-mix(), @media, :has()) are silently skipped. For best results, maintain a small dedicated overrides file:

/* confluence-overrides.css */
:root { --primary: #d20014; }
th  { background-color: var(--primary); color: white; font-weight: 600; }
h1, h2, h3 { color: var(--primary); }
code { background-color: #f5f5f5; }
extra_css:
  - stylesheets/extra.css                   # full Material theme
  - stylesheets/confluence-overrides.css    # simple Confluence-targeted styles

mk2conf pdf

Export a nav section or single page to a stand-alone, printer-ready PDF document. Requires pip install "mkdocs2confluence[pdf]".

mk2conf pdf [--config PATH] (--section SECTION | --page PATH) [--out FILE] [--author TEXT] [--doc-version TEXT] [--quiet]
Flag Default Description
--config PATH ./mkdocs.yml Path to mkdocs.yml
--section SECTION (required unless --page) Export a nav subtree by section title
--page PATH (required unless --section) Export a single page
--out FILE <section-or-page>.pdf Output PDF path
--author TEXT (none) Author name printed on the cover page
--doc-version TEXT (none) Document version printed on the cover page
--quiet off Suppress progress output

The PDF includes a cover page, table of contents with page numbers, and one chapter per nav page with automatic page breaks. Code blocks avoid mid-block splits; Mermaid diagrams appear as embedded PNGs (same Kroki-rendered images used for Confluence).


mk2conf sync-comments

Bridge Confluence page/inline comments to GitHub pull request review threads. Non-technical reviewers comment in Confluence; developers address feedback on a GitHub feature branch; Confluence comments are auto-resolved when the PR is merged.

mk2conf sync-comments [--config PATH] [--check-merges] [--force] [--dry-run] [--quiet]
Flag Default Description
--config PATH ./mkdocs.yml Path to mkdocs.yml
--check-merges off Check tracked PRs for merges and auto-resolve Confluence comments
--force off Re-sync pages that already have an open review PR
--dry-run off Print what would be synced without making any API calls
--quiet off Suppress progress output

Required config (add to the confluence: block in mkdocs.yml):

confluence:
  # ... base fields ...
  github_repo: owner/repo            # required for sync-comments
  github_token: !ENV GITHUB_TOKEN    # falls back to GITHUB_TOKEN env var
  github_base_branch: main           # default: main

Workflow:

  1. Run mk2conf publish first — generates .mk2conf-pages.json mapping source files to Confluence page IDs.
  2. Run mk2conf sync-comments — for each page with open Confluence comments, creates a mk2conf/review/{slug} branch and PR, then posts each comment as a GitHub review thread. Inline comments with a text selection are anchored to the matching source line; page-level comments fall back to file-level review threads. Every thread body includes a View in Confluence deep-link that opens Confluence focused on the exact comment.
  3. Developer addresses feedback on the branch, pushes changes, and merges the PR.
  4. Run mk2conf sync-comments --check-merges — detects merged PRs, adds a resolution reply to each Confluence comment with the commit info, and marks the comments as resolved.

State files (add to .gitignore):

File Purpose
.mk2conf-pages.json Source path → Confluence page ID map, written after each publish
.mk2conf-sync-state.json Tracks open/merged review PRs and their associated comment IDs

Supported Markdown features

Block elements

Feature Confluence output
ATX headings ####### <h1><h6>
Paragraphs <p>
Fenced code blocks code macro with language, title, and line numbers
Bullet lists <ul>/<li>
Ordered lists <ol>/<li>
Task lists - [x] / - [ ] Native <ac:task-list> / <ac:task> macros
Tables (GFM pipe syntax) <table> with header and column alignment
Blockquotes <blockquote>
Horizontal rules --- <hr/>

Inline elements

Feature Confluence output
**bold** / __bold__ <strong>
*italic* <em>
~~strikethrough~~ <s>
~subscript~ <sub> (pymdownx.tilde)
^superscript^ <sup> (pymdownx.caret)
^^inserted^^ <u> (pymdownx.caret insert)
`inline code` <code>
[text](url) <a href="...">
https://bare-url <a href="..."> (autolink)
[text](file.pdf) <ac:link><ri:attachment .../> (uploaded as attachment)
![alt](src) <ac:image> with <ri:attachment> (local) or <ri:url> (remote)
![alt](src){ width="400" } <ac:image ac:width="400"> — also supports height and align
<br> / <br/> / trailing \ <br />
<sub> / <sup> / <u> / <small> Direct XHTML passthrough
<mark>text</mark> <span style="background-color: yellow;">
<kbd>text</kbd> <code>
++ctrl+alt+del++ <code>Ctrl</code>+<code>Alt</code>+<code>Del</code> (pymdownx.keys)
<s>text</s> / <del>text</del> <span style="text-decoration: line-through;">

MkDocs / Material extensions

Feature Confluence output
--8<-- file includes Resolved before parsing
Admonitions !!! type "title" info / tip / warning / note macro
Danger admonitions (danger, error, bug) Red panel macro with 🚨 prefix
Collapsible admonitions ??? type expand macro
Content tabs === "Label" expand macros (one per tab)
Details blocks ??? "title" expand macro
Footnotes [^1] Superscript anchor links + Footnotes section at page bottom
Mermaid diagrams PNG via Kroki, uploaded as attachment (<ac:image ac:align="center">)
Internal links [text](page.md) Native Confluence page link; #fragment anchors preserved
awesome-pages nav (.pages files) Fully supported
Edit link banner info macro linking back to source in GitHub/GitLab
Grid cards <div class="grid cards" markdown> Native ac:layout multi-column sections (auto-detects 1/2/3 columns from card count)

YAML front matter → Page Properties

A YAML front matter block is converted to a Confluence Page Properties macro, making it queryable via the Page Properties Report macro.

---
title: "Architecture Proposal  IAM"
subtitle: "Hybrid Identity Hub"
documentId: AP-IAM-2026
version: "0.1"
lastUpdated: 2026-01-12
author: "Anders Hybertz"
tags: [architecture, iam]
ready: true
status: in-progress
---
Field Notes
title Used as the Confluence page title on publish
subtitle Rendered as italic lead paragraph above the properties table
tags Also applied as Confluence page labels
ready true → ✅ Ready · false → 📝 Draft (skips publish)
status Sets the Confluence page status badge — common values: rough-draft, in-progress, ready-for-review (space-specific values are also supported). Not shown in the properties table.
other fields Title-cased key, value stringified

If repo_url + edit_uri are set in mkdocs.yml, an Edit Source row links to the source file. If site_url is set, a Published Page row links to the rendered MkDocs site.

Abbreviation expansion

MkDocs abbreviation definitions (*[ABBR]: Full term) are rendered as inline superscript anchor links. The first occurrence of each abbreviation in body text gets a superscript number (API¹) that links to a numbered glossary appended at the bottom of the page. Subsequent occurrences are left as plain text. Abbreviations that only appear in headings or other non-expandable contexts are included in the glossary as plain numbered entries (no inline back-link). Uses only native Confluence storage format — no plugins required.


Known limitations

Feature Behaviour
Admonition styling tip, info, warning, note use Confluence's fixed native macro colours. danger, error, bug use a custom red panel macro with 🚨 prefix. All other types are mapped to the nearest native macro.
Abbreviation tooltips No native tooltip support. First occurrence gets a superscript anchor link (API¹); all definitions collected in a numbered glossary at the bottom of the page. No plugins required.
Page ordering Confluence sorts child pages alphabetically; the v2 REST API has no write endpoint for ordering.
Code language aliases Short aliases (py, js, yml, ts, sh) are passed through as-is; Confluence requires full language names for syntax highlighting.
Unrecognised blocks Preserved as a visible warning macro — no content is silently lost.

Architecture

Architecture

Each stage is a separate Python module under src/mkdocs_to_confluence/. The plan phase makes all API read calls (find existing pages); the execute phase makes all write calls, ensuring parent pages always exist before their children.

The sync/ package is a self-contained pipeline for the sync-comments command: it fetches Confluence comments, anchors them to source lines, posts them as GitHub review threads via GraphQL, and resolves them on PR merge. The ReviewPlatformClient Protocol keeps GitHub-specific code isolated so future GitLab or Azure DevOps adapters slot in without touching the core.


Development

See Setup.md for environment setup.

uv run pytest -q                        # run tests
uv run ruff check src tests             # lint
uv run vulture src --min-confidence 80  # dead code check
uv run mypy src                         # type-check
uv run bandit -r src -ll                # security scan

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mkdocs2confluence-0.8.2.tar.gz (185.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mkdocs2confluence-0.8.2-py3-none-any.whl (128.0 kB view details)

Uploaded Python 3

File details

Details for the file mkdocs2confluence-0.8.2.tar.gz.

File metadata

  • Download URL: mkdocs2confluence-0.8.2.tar.gz
  • Upload date:
  • Size: 185.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.10 {"installer":{"name":"uv","version":"0.11.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for mkdocs2confluence-0.8.2.tar.gz
Algorithm Hash digest
SHA256 2e67ee0af6126a8c6fa8bfeea5629beda60b8a72a3051573f821acd4d884fd1c
MD5 c82e21b395bf4af60e27c647ae25a926
BLAKE2b-256 dd60de60c4d1fece4eea6ae55503cc6f9aca172ef068eb766543f65916d02d77

See more details on using hashes here.

File details

Details for the file mkdocs2confluence-0.8.2-py3-none-any.whl.

File metadata

  • Download URL: mkdocs2confluence-0.8.2-py3-none-any.whl
  • Upload date:
  • Size: 128.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.10 {"installer":{"name":"uv","version":"0.11.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for mkdocs2confluence-0.8.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f27b9d61165b9ff23b62a0d51f22995f1a5741fba8371beb051822f498d97698
MD5 422c453359bcbef738b2f2ea3b22850c
BLAKE2b-256 668b08cb2a6f7a48e308ec1d752e051d374b89412d03fe673658f04db7307ca4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page