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.
- Publish — compiles your full
nav:tree and pushes only changed pages (SHA-256 skip, no unnecessary version bumps or notifications). - What's New page — designate a
CHANGELOG.mdwithconfluence.changelogand mk2conf publishes it as a pinned top-level page on every run, so Confluence readers always have one place to see what changed. - AI changelog skill —
mk2conf install-skillinstalls a bundled AI skill into your editor (Claude Code, Copilot, Cursor, Hermes). It extracts git changes deterministically, decides whether they are significant, and drafts a dated entry inCHANGELOG.md— with selective links to the pages that carry the main changes. Bootstrap a project with--since 2026-05-01to generate the initial changelog from a date. - Review bridge —
sync-commentsturns open Confluence page comments into GitHub pull request review threads and auto-resolves them in Confluence when the PR is merged.
Zensical compatible — Zensical is the modern successor to MkDocs + Material for MkDocs. Since it uses the same
mkdocs.ymlformat and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.
Requires Python 3.12+. The PyPI package is mkdocs2confluence; the CLI command is mk2conf.
pip install mkdocs2confluence
# or, for an isolated install:
pipx install mkdocs2confluenceFrom source (see Setup.md):
git clone https://github.com/jeckyl2010/mkdocs2confluence.git
cd mkdocs2confluence && uv syncPublish docs automatically on every push — no local install needed:
- name: Publish docs to Confluence
uses: jeckyl2010/mkdocs2confluence@v1
with:
token: ${{ secrets.CONFLUENCE_API_TOKEN }}Full workflow — triggers on changes to docs/ or mkdocs.yml:
name: Publish docs
on:
push:
branches: [main]
paths: ['docs/**', 'mkdocs.yml']
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jeckyl2010/mkdocs2confluence@v1
with:
token: ${{ secrets.CONFLUENCE_API_TOKEN }}
prune: 'true'Available inputs: token (required), config, version, dry-run, section, page, prune, quiet. See docs/commands.md for details.
# Preview a page locally (no Confluence API calls)
mk2conf preview --page index.md --watch
# Dry-run: see what would be published
mk2conf publish --dry-run
# Publish all nav pages (and the changelog page if configured)
mk2conf publish
# Export a section to PDF
mk2conf pdf --section Guide --out guide.pdf
# Install the changelog AI skill into your editor
mk2conf install-skill
# Sync Confluence comments to GitHub PR review threads
mk2conf sync-commentsAdd 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" — also controls PlantUML rendering
full_width: true # default: true
attachment_preview: false # default: false — inline PDF/Office previews
changelog: CHANGELOG.md # optional: publish as a top-level "What's New" page
exclude_properties: # optional: front matter keys to hide from Page Properties
- source_documents
- internal_refexclude_properties lists raw front matter keys to omit from the Page Properties table (e.g. internal tooling fields). Matching is exact and case-sensitive; title, tags, and status keep their special behavior even if excluded from the table.
attachment_preview (bool, default false) renders links to local PDF/Office files (.pdf, .doc(x), .xls(x), .ppt(x)) as inline view-file previews instead of download links. Other file types always remain download links.
The confluence: block is also accepted under extra: for MkDocs strict-mode compatibility. The API token is read from token: in mkdocs.yml, then CONFLUENCE_API_TOKEN, then MK2CONF_TOKEN.
Set changelog: to a Markdown file path (relative to docs_dir) to have mk2conf publish it as a permanent top-level page on every full mk2conf publish run. The page title comes from YAML front matter title:; it defaults to "What's New" if absent.
confluence:
changelog: CHANGELOG.md # relative to docs_dir- The page does not need to appear in
nav:— it is always placed at the top level of the space (or underparent_page_idif set). - If it also appears in
nav:, it is published once; no duplication. --prunenever deletes it — it is a pinned page, not a nav-derived page.- Partial runs (
--page/--section) skip the changelog page, consistent with other publish behaviour. - Omit the key, or set it to an empty string, to disable the feature entirely.
Run mk2conf install-skill once after setting changelog: to install the changelog AI skill into your AI tool (Claude Code, Copilot, Cursor, Hermes). The skill analyses git changes to your docs since the last CHANGELOG.md commit and drafts an entry when the changes qualify as significant.
Your first publish:
export CONFLUENCE_API_TOKEN=your_api_token_here
mk2conf preview --page docs/index.md --watch # verify output locally
mk2conf publish --dry-run # check the plan
mk2conf publish # go live| docs/commands.md | Full flag reference for all five commands |
| docs/features.md | Supported Markdown / Material features and known limitations |
| Setup.md | Development environment setup |
Pipeline stages: loader → preprocess → IR → transforms → emitter → publisher.
The publisher is split into two phases:
planner.pybuilds a nav-ordered publish plan, compiles pages, and makes the read-side API calls needed to decide create vs update vs skip.executor.pyapplies that plan, performs the write-side API calls, uploads attachments, and wires parent/child relationships in nav order so parent pages always exist before their children.
publisher/pipeline.py remains a compatibility facade that re-exports the public publish surface used by the CLI and tests.
uv run pytest -q
uv run ruff check src tests
uv run mypy src
uv run vulture src --min-confidence 80