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.
What it does
md-to-adf takes a Markdown file and converts it to the JSON-based Atlassian Document Format (ADF) that Confluence Cloud requires for its REST API. It handles headings, paragraphs, bold/italic/code inline formatting, fenced code blocks, bullet and ordered lists, blockquotes, horizontal rules, tables, and Mermaid diagrams. Once converted, the built-in upload command creates or updates a Confluence page in a single step, so you can keep documentation in version control and push it to Confluence with one command.
Install
pip
pip install md-to-adf
npm (installs the Python package via pip automatically)
npm install -g md2adf
Homebrew
brew tap imzak31/md-to-adf
brew install md-to-adf
Quick start
Convert a Markdown file to ADF JSON:
md-to-adf convert docs/my-page.md
Convert and write to a file:
md-to-adf convert docs/my-page.md --output my-page.adf.json
Convert and validate the output:
md-to-adf convert docs/my-page.md --validate
Upload to Confluence:
md-to-adf upload docs/my-page.md \
--title "My Page" \
--space ENG \
--parent 12345
Upload using environment variables (no flags needed after setup):
export MD_TO_ADF_DOMAIN=myorg.atlassian.net
export MD_TO_ADF_EMAIL=me@example.com
export MD_TO_ADF_TOKEN=my-api-token
export MD_TO_ADF_SPACE=ENG
md-to-adf upload docs/my-page.md --title "My Page"
Setup
Run the interactive wizard to store your Confluence credentials once:
md-to-adf init
The wizard prompts for your Confluence domain, email address, and API token, then writes them to ~/.md-to-adf/config.toml. After running init, the upload command works without any flags.
To generate a Confluence API token, visit: https://id.atlassian.com/manage-profile/security/api-tokens
Configuration
Config file location: ~/.md-to-adf/config.toml
Example config file:
[confluence]
domain = "myorg.atlassian.net"
email = "me@example.com"
token = "my-api-token"
space_key = "ENG"
[mermaid]
strategy = "auto"
Settings reference
| 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
CLI Commands
init — Interactive setup wizard
md-to-adf init
Prompts for Confluence credentials and writes ~/.md-to-adf/config.toml.
convert — Convert Markdown to ADF
md-to-adf convert <file> [options]
| Option | Description |
|---|---|
--output FILE |
Write ADF JSON to FILE instead of stdout |
--validate |
Validate the ADF output after conversion |
--mermaid STRATEGY |
Mermaid handling: auto, macro, image, code |
Examples:
# Print ADF JSON to stdout
md-to-adf convert README.md
# Save to file and validate
md-to-adf convert docs/guide.md --output guide.adf.json --validate
upload — Upload to Confluence
md-to-adf upload <file> [options]
| Option | Description |
|---|---|
--title TEXT |
Page title (default: filename stem) |
--space KEY |
Confluence space key |
--parent ID |
Parent page ID |
--domain HOST |
Confluence domain |
--email EMAIL |
Atlassian account email |
--token TOKEN |
Atlassian API token |
--mermaid STRATEGY |
Mermaid handling strategy |
Examples:
# Upload using config file credentials
md-to-adf upload docs/architecture.md --title "Architecture Overview"
# Upload to a specific space with a parent page
md-to-adf upload docs/guide.md \
--title "User Guide" \
--space ENG \
--parent 98765
validate — Validate ADF JSON
md-to-adf validate <file>
Validates a Markdown file (by converting first) or a raw ADF JSON file against the ADF schema.
md-to-adf validate docs/my-page.md
md-to-adf validate output.adf.json
spaces — List Confluence spaces
md-to-adf spaces
Lists all spaces accessible with your configured credentials. Useful for finding space keys.
Mermaid Support
Mermaid diagrams in fenced code blocks (```mermaid) are handled according to the selected strategy:
| Strategy | Description |
|---|---|
auto |
Use macro if the Mermaid for Confluence app is installed, otherwise fall back to code |
macro |
Render as a Confluence Mermaid macro (requires the Mermaid app) |
image |
Render the diagram to a PNG and attach it to the page |
code |
Preserve the diagram source as a code block |
Set the strategy in config, env var, or per-command:
md-to-adf upload diagram.md --mermaid image
Claude Code Skill
md-to-adf ships a Claude Code skill that lets you upload the current file to Confluence from inside your editor with a single slash command.
Install the skill:
# Copy the skill to your Claude Code skills directory
cp -r /path/to/md-to-adf/skill ~/.claude/skills/md-to-confluence
Or install via the package (after pip install md-to-adf):
md-to-adf-install-skill
Use the skill inside Claude Code:
/md-to-confluence
The skill reads the current file, calls md-to-adf upload, and reports the resulting Confluence URL.
Python Library API
You can use md-to-adf as a library in your own Python projects:
from md_to_adf import convert, validate
# Convert Markdown string to ADF dict
markdown = "# Hello\n\nThis is **bold** text."
adf = convert(markdown)
print(adf) # {"version": 1, "type": "doc", "content": [...]}
# Validate an ADF dict
errors = validate(adf)
if errors:
print("Validation errors:", errors)
else:
print("Valid ADF document")
Upload programmatically:
from md_to_adf import convert
from md_to_adf.confluence.auth import build_token_auth_header
from md_to_adf.confluence.client import ConfluenceClient
adf = convert(open("docs/page.md").read())
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")
print(f"Published: https://myorg.atlassian.net/wiki{result['_links']['webui']}")
Contributing
- Fork the repository and create a feature branch.
- Install development dependencies:
pip install -e ".[dev]" - Run the test suite:
pytest tests/ -v - Ensure all tests pass and add tests for new functionality.
- Open a pull request with a clear description of the change.
The test suite covers the converter, validator, CLI, and Confluence client (with mocked HTTP). New features should include unit tests.
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.0.1.tar.gz.
File metadata
- Download URL: md_to_adf-1.0.1.tar.gz
- Upload date:
- Size: 33.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b862f092cd18aab76b05bbd709a6c2b3e0e9663988686e4cc566d6830b16b0e0
|
|
| MD5 |
da4f5ba7eb7f804d42c551e846c18e9e
|
|
| BLAKE2b-256 |
37a2e7834f87fb110900feef067bbda2bc0930bf26613f3824ec4b4deb334c7e
|
Provenance
The following attestation bundles were made for md_to_adf-1.0.1.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.0.1.tar.gz -
Subject digest:
b862f092cd18aab76b05bbd709a6c2b3e0e9663988686e4cc566d6830b16b0e0 - Sigstore transparency entry: 1111725985
- Sigstore integration time:
-
Permalink:
imzak31/md_to_adf@b5befae928624f171239f2182efff48888d1cfa0 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/imzak31
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5befae928624f171239f2182efff48888d1cfa0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file md_to_adf-1.0.1-py3-none-any.whl.
File metadata
- Download URL: md_to_adf-1.0.1-py3-none-any.whl
- Upload date:
- Size: 25.0 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 |
6a01e68e4af61851dad70dba158a7958ffd17ed8070611cd064dbefe249b330f
|
|
| MD5 |
cba2213a5b2299f8fc1e113c173f4ec4
|
|
| BLAKE2b-256 |
3d0d5ef2bacd7e3e6b52d38bccc6b342d559f345e16e270e2e3770ca30aadf63
|
Provenance
The following attestation bundles were made for md_to_adf-1.0.1-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.0.1-py3-none-any.whl -
Subject digest:
6a01e68e4af61851dad70dba158a7958ffd17ed8070611cd064dbefe249b330f - Sigstore transparency entry: 1111726031
- Sigstore integration time:
-
Permalink:
imzak31/md_to_adf@b5befae928624f171239f2182efff48888d1cfa0 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/imzak31
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b5befae928624f171239f2182efff48888d1cfa0 -
Trigger Event:
push
-
Statement type: