Skip to main content

Marklas

CI PyPI Python License

Bidirectional converter between Markdown and Atlassian Document Format (ADF).

한국어 · 日本語


Why Marklas?

Confluence and Jira store documents in ADF — a verbose JSON structure. Marklas converts it to readable Markdown and back:

Markdown ⇄ ADF

ADF-only features (panels, mentions, colored text, etc.) are preserved as HTML elements with adf attributes, so the full structure survives a roundtrip:

<aside adf="panel" params='{"panelType":"info"}'>

This is an info panel — readable as plain Markdown.

</aside>

User <span adf="mention" params='{"id":"abc123"}'>@John</span> approved this.

Pass plain=True to strip roundtrip metadata and get clean Markdown for LLM consumption.

Installation

pip install marklas

Usage

from marklas import to_adf, to_md

# Markdown → ADF
adf = to_adf("## Hello\n\nThis is **bold**.")

# ADF → Markdown (with roundtrip metadata)
md = to_md(adf_document)

# ADF → Markdown (clean, no metadata)
plain_md = to_md(adf_document, plain=True)

# Roundtrip
original_adf = fetch_confluence_page()
markdown = to_md(original_adf)          # edit in any Markdown editor
restored_adf = to_adf(markdown)         # push back — structure preserved

Advanced Usage

For pipelines that need to modify the AST between parsing and rendering, use Transformer:

from marklas import Transformer, parse_md, render_adf
from marklas.ast import CodeBlock, Expand, Extension, Media, Node

t = Transformer()

# Replace: return a Node to substitute the original
@t.register(Media)
def _(node: Media) -> Media | None:
    if node.type == "external":
        uploaded = upload_attachment(page_id, node.url)
        return Media(type="file", id=uploaded.media_id, collection=uploaded.collection)
    return None

# Splice: return a list[Node] to expand one node into many
@t.register(CodeBlock)
def _(node: CodeBlock) -> list[Node] | None:
    if node.language == "mermaid":
        return [
            Expand(title="mermaid source", content=[node]),
            Extension(
                extension_key="mermaid-macro",
                extension_type="com.example.mermaid",
                parameters={"code": "".join(c.text for c in node.content)},
            ),
        ]
    return None

doc = parse_md(markdown)
new_doc = t(doc)
adf = render_adf(new_doc)

A handler returns one of three values:

Return Effect
None Skip — pass to the next handler, or leave unchanged
Node Replace the original node
list[Node] Splice multiple nodes in place of the original

Multiple handlers can be registered for the same type; they run in registration order and the first non-None result wins. The tree is traversed bottom-up, and nodes returned by a handler are not revisited.

Function Description
parse_md(md) Markdown → AST
parse_adf(adf) ADF JSON → AST
render_md(doc) AST → Markdown
render_adf(doc) AST → ADF JSON
Transformer Registry of typed visitors for AST rewriting

Token Efficiency

Markdown is significantly more compact than ADF JSON — critical for LLM-based workflows where every token counts.

ADF JSON Markdown Markdown (plain)
Tokens 2,173,468 858,970 560,765
Reduction 2.5x 3.9x

Measured on 204 real Confluence pages (compact JSON) using GPT-4o tokenizer (tiktoken).

Documentation

Development

uv sync --extra dev
uv run pytest -v

Download files

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

Source Distribution

marklas-0.8.6.tar.gz (50.5 kB view details)

Uploaded Source

Built Distribution

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

marklas-0.8.6-py3-none-any.whl (59.3 kB view details)

Uploaded Python 3

File details

Details for the file marklas-0.8.6.tar.gz.

File metadata

  • Download URL: marklas-0.8.6.tar.gz
  • Upload date:
  • Size: 50.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for marklas-0.8.6.tar.gz
Algorithm Hash digest
SHA256 9b2ef133e466986d5fea3997c7f7590c4faf10283e74f7b62173918f96e1eee5
MD5 3e2b2aa25a1b6deec2b66e8a964817bd
BLAKE2b-256 4720d0b4cd62958301c1c542da5a89bff347931b9f6dc1e3f347099f1b4fbe32

See more details on using hashes here.

Provenance

The following attestation bundles were made for marklas-0.8.6.tar.gz:

Publisher: publish.yml on byExist/marklas

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file marklas-0.8.6-py3-none-any.whl.

File metadata

  • Download URL: marklas-0.8.6-py3-none-any.whl
  • Upload date:
  • Size: 59.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for marklas-0.8.6-py3-none-any.whl
Algorithm Hash digest
SHA256 46da4627be55292df24294cad289b7d6b2bf327c0489f9334c7a8bd7a15a553a
MD5 29a3337e0714d80121923152870492ea
BLAKE2b-256 ba869e9b0ee1149d3f2667b4dcfccb9580e8e5e46f34cc8451f268afbede6b87

See more details on using hashes here.

Provenance

The following attestation bundles were made for marklas-0.8.6-py3-none-any.whl:

Publisher: publish.yml on byExist/marklas

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.8.6 This release

2 files

0.8.5

2 files

0.8.4

2 files

0.8.3

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.1

2 files

0.6.0

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.6

2 files

0.4.5

2 files

0.4.4

2 files

0.4.3

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page