~bigbes/confluence-md-utilities

e0e81bc6 — Eugene Blikh a month ago
chore: rename module to go.bigb.es/confluence-md-utilities
5fabfe01 — Eugene Blikh 2 months ago
feat: add verify command, improve round-trip fidelity
0d193103 — Eugene Blikh 2 months ago
feat: add ability for local install

clone

read-only
https://git.srht.bigb.es/~bigbes/confluence-md-utilities
read/write
git@git.srht.bigb.es:~bigbes/confluence-md-utilities

You can also use your local clone with git send-email.

#mdcx

Markdown to Confluence XML converter with bidirectional sync for self-hosted Confluence Server/Data Center.

Converts Markdown to Confluence storage format XML and back. Pull pages from Confluence, edit locally as Markdown, push changes back. Template-aware embedding preserves metadata tables, changelogs, inline comment markers, user references, and attachment images through round-trips.

#Install

go install go.bigb.es/confluence-md-utilities/cmd/mdcx@latest

Or build locally with just:

just install

#Commands

#convert

Markdown to Confluence XML.

mdcx convert input.md -o output.xml
cat input.md | mdcx convert > output.xml

#embed

Convert Markdown and insert between marker comments in an existing Confluence document, preserving everything outside the markers (metadata table, TOC, changelog, etc.).

mdcx embed input.md --template template.xml -o output.xml

Template must contain marker comments:

<!-- MD_CONTENT_START -->
<!-- MD_CONTENT_END -->

#extract

Extract content between markers from a Confluence XML document and convert back to Markdown.

mdcx extract input.xml -o output.md
mdcx extract input.xml --raw    # raw Confluence XML, no conversion

#pull

Fetch a page from Confluence and convert to Markdown.

mdcx pull "https://confluence.example.com/pages/viewpage.action?pageId=12345" -o page.md
mdcx pull "https://confluence.example.com/display/TEAM/Page+Title" -o page.md
mdcx pull "https://confluence.example.com/display/TEAM/Page+Title" --raw -o page.xml

#push

Convert local Markdown and update a Confluence page.

# Replace entire page body
mdcx push "https://confluence.example.com/display/TEAM/Page" page.md

# Template mode: only replace content between markers, keep everything else
mdcx push "https://confluence.example.com/display/TEAM/Page" page.md --template

# With version message
mdcx push "https://confluence.example.com/display/TEAM/Page" page.md -m "Updated intro"

#fmt

Pretty-print Confluence storage XML with syntax highlighting.

mdcx fmt page.xml
mdcx fmt page.xml --color=force     # force colors even when piped
mdcx fmt page.xml --color=disabled  # no colors
mdcx fmt page.xml -o formatted.xml  # write to file (colors auto-disabled)

Colors: tags in blue/magenta/cyan by namespace, attributes in yellow, values in green, CDATA and comments in gray. Enabled by default when output is a terminal.

Block elements get their own lines with indentation. Short <li>, <h1>-<h6>, <th>, <td> stay on one line when content fits. Lines longer than 120 characters are wrapped at word boundaries (UTF-8 aware). CDATA content is preserved as-is.

#Authentication

pull and push require a Personal Access Token:

# Via environment variable
export CONFLUENCE_TOKEN="your-token-here"
mdcx pull "https://confluence.example.com/display/TEAM/RFC-42" -o rfc.md

# Via flag
mdcx pull --token "your-token" "https://confluence.example.com/display/TEAM/RFC-42" -o rfc.md

#Typical workflow

export CONFLUENCE_TOKEN="..."

# Pull
mdcx pull "https://confluence.example.com/display/TEAM/RFC-42" -o rfc.md

# Edit
vim rfc.md

# Push back, preserving template structure
mdcx push "https://confluence.example.com/display/TEAM/RFC-42" rfc.md --template -m "Updated requirements"

#Shell completions

# Bash
source <(mdcx completion bash)

# Zsh (add to your .zshrc)
mdcx completion zsh > "${fpath[1]}/_mdcx"

# Fish
mdcx completion fish | source

#Supported elements

Markdown Confluence XML
# Heading <h1> ... <h6>
**bold** <strong>
*italic* <em>
~~strike~~ <del>
`code` <code>
Fenced code blocks <ac:structured-macro ac:name="code"> with CDATA
- item / 1. item <ul>/<ol> with <li>
Nested lists Nested <ul>/<ol> inside <li>
- [x] task <ac:task-list>/<ac:task>
[text](url) <a href="...">
![alt](url) <ac:image><ri:url .../>
> blockquote <ac:structured-macro ac:name="info"> (info panel)
--- <hr/>
GFM tables <table> with <th>/<td> wrapped in <p>

#Round-trip preservation

Confluence-specific elements that have no Markdown equivalent are preserved through round-trips using HTML spans:

Confluence element Markdown representation
<ac:inline-comment-marker ac:ref="UUID"> <span data-inline-comment="UUID">text</span>
<ac:link><ri:user ri:userkey="KEY"/></ac:link> <span data-user-key="KEY"/>
<ac:image><ri:attachment ri:filename="F"/></ac:image> <span data-attachment="F"/>

These are converted back to proper Confluence tags on push.

#License

MIT