Convert Markdown to Atlassian Document Format (ADF) and upload to Confluence
Project description
md-to-adf
Convert Markdown to Atlassian Document Format (ADF) and publish to Confluence Cloud.
Install
pip install md-to-adf # Python
npm install -g md2adf # Node (wraps the Python package)
brew tap imzak31/md-to-adf && brew install md-to-adf # macOS
Quick start
# 1. Set up your Confluence credentials (one-time)
md-to-adf init
# 2. Preview what will be uploaded
md-to-adf upload docs/ --dry-run
# 3. Push to Confluence
md-to-adf upload docs/ --space ENG
Titles are auto-extracted from each file's first # Heading. No --title flag needed.
CLI Commands
init — Set up credentials
md-to-adf init
Interactive wizard that saves your Confluence domain, email, and API token to ~/.md-to-adf/config.toml. Generate a token at https://id.atlassian.com/manage-profile/security/api-tokens.
upload — Push markdown to Confluence
md-to-adf upload <file|directory|glob> [options]
| Option | Description |
|---|---|
--space KEY |
Target Confluence space |
--title TEXT |
Override auto-extracted title (single file only) |
--page-id ID |
Update an existing page (single file only) |
--parent-id ID |
Create under a parent page |
--dry-run |
Preview files and titles without uploading |
--recursive |
Include markdown in subdirectories |
--mermaid STRATEGY |
Diagram handling: auto, macro, image, code |
# Single file
md-to-adf upload docs/architecture.md --space ENG
# Entire directory
md-to-adf upload docs/ --space ENG
# Glob pattern
md-to-adf upload "docs/*.md" --space ENG
# Preview first
md-to-adf upload docs/ --dry-run
# Update an existing page
md-to-adf upload docs/guide.md --page-id 12345
Batch uploads process each file independently — failures don't stop the rest. A summary is printed at the end.
convert — Generate ADF JSON
md-to-adf convert <file> [options]
| Option | Description |
|---|---|
--output FILE |
Write to file instead of stdout |
--validate |
Check ADF validity after conversion |
--compact |
Minified JSON output |
--mermaid STRATEGY |
Diagram handling strategy |
validate — Check ADF validity
md-to-adf validate docs/my-page.md
md-to-adf validate output.adf.json
spaces — List available spaces
md-to-adf spaces
Configuration
Config file: ~/.md-to-adf/config.toml
[confluence]
domain = "myorg.atlassian.net"
email = "me@example.com"
token = "my-api-token"
space_key = "ENG"
[mermaid]
strategy = "auto"
Settings can also be provided via environment variables or CLI flags:
| Setting | Config key | Env var | CLI flag |
|---|---|---|---|
| Domain | confluence.domain |
MD_TO_ADF_DOMAIN |
--domain |
confluence.email |
MD_TO_ADF_EMAIL |
--email |
|
| Token | confluence.token |
MD_TO_ADF_TOKEN |
--token |
| Space | confluence.space_key |
MD_TO_ADF_SPACE |
--space |
| Mermaid | mermaid.strategy |
MD_TO_ADF_MERMAID |
--mermaid |
Priority: CLI flags > env vars > config file > defaults
Use --debug on any command to see full error details.
Named spaces
For teams that publish to multiple spaces, add shortcuts to your config:
[spaces.eng]
key = "ENG"
name = "Engineering"
parent_id = "12345"
[spaces.product]
key = "PROD"
name = "Product Docs"
When uploading without --space, a picker appears if multiple spaces are configured. Recent spaces are tracked automatically.
Mermaid diagrams
Fenced mermaid code blocks are converted according to the selected strategy:
| Strategy | Description |
|---|---|
auto |
Confluence macro if available, otherwise code block |
macro |
Confluence Mermaid macro (requires the Mermaid app) |
image |
Render to PNG locally via mmdc and attach |
code |
Keep as a code block |
Claude Code integration
Install the /md-to-confluence skill to push markdown from Claude Code:
curl -sL https://raw.githubusercontent.com/imzak31/md_to_adf/main/skill/md-to-confluence.md \
-o ~/.claude/skills/md-to-confluence.md
Then use /md-to-confluence in any conversation. The skill runs --dry-run first to preview, then uploads on confirmation.
Python API
from md_to_adf import convert, validate
adf = convert("# Hello\n\nThis is **bold** text.")
errors = validate(adf) # [] if valid
from md_to_adf.confluence.auth import build_token_auth_header
from md_to_adf.confluence.client import ConfluenceClient
auth = build_token_auth_header("me@example.com", "my-api-token")
client = ConfluenceClient("myorg.atlassian.net", auth)
result = client.create_page(adf, space_key="ENG", title="My Page")
Contributing
- Fork and create a feature branch
pip install -e ".[dev]"pytest tests/ -v- Open a pull request
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file md_to_adf-1.1.0.tar.gz.
File metadata
- Download URL: md_to_adf-1.1.0.tar.gz
- Upload date:
- Size: 39.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
821359b6bc77b07774a920cecb69723eb473db64219c694c78558020e7abe8f5
|
|
| MD5 |
7a1efc96289e5cc252002e6134114a20
|
|
| BLAKE2b-256 |
bacdfd920bc2a3445e4f10c350de3bca316f7fda978946d75dc48bf18b8d8952
|
Provenance
The following attestation bundles were made for md_to_adf-1.1.0.tar.gz:
Publisher:
release.yml on imzak31/md_to_adf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
md_to_adf-1.1.0.tar.gz -
Subject digest:
821359b6bc77b07774a920cecb69723eb473db64219c694c78558020e7abe8f5 - Sigstore transparency entry: 1123225912
- Sigstore integration time:
-
Permalink:
imzak31/md_to_adf@9239a4adbe89b95617a3224d07dc51f4ac2c28b1 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/imzak31
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9239a4adbe89b95617a3224d07dc51f4ac2c28b1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file md_to_adf-1.1.0-py3-none-any.whl.
File metadata
- Download URL: md_to_adf-1.1.0-py3-none-any.whl
- Upload date:
- Size: 29.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e70bb739d8120ef7bdb39c6aea11a2d5f0d359df5e43bc52c1e7e867ee8a1fd0
|
|
| MD5 |
d53c2c761de6635ea9611cc093677c3a
|
|
| BLAKE2b-256 |
c3983d776c9fa044969a4ffe598d36365b52dd5e3031790c99c8c5fc26e3c358
|
Provenance
The following attestation bundles were made for md_to_adf-1.1.0-py3-none-any.whl:
Publisher:
release.yml on imzak31/md_to_adf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
md_to_adf-1.1.0-py3-none-any.whl -
Subject digest:
e70bb739d8120ef7bdb39c6aea11a2d5f0d359df5e43bc52c1e7e867ee8a1fd0 - Sigstore transparency entry: 1123225922
- Sigstore integration time:
-
Permalink:
imzak31/md_to_adf@9239a4adbe89b95617a3224d07dc51f4ac2c28b1 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/imzak31
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9239a4adbe89b95617a3224d07dc51f4ac2c28b1 -
Trigger Event:
push
-
Statement type: