Skip to Content

What’s New

Release notes for acs2md, newest first. Conversion behaviour comes from the shared Climakers ADF engine, so most output changes apply to acp2md as well.


Latest

Space conversion runs concurrently

space convert now converts 4 pages at once by default. Conversion is network-bound, so overlapping a few pages hides most of the per-page API latency. --concurrency 1 restores strictly sequential conversion.

Output is identical at any setting — pages are collected in input order regardless of which worker finishes first, so the directory layout, --rewrite-links and the summary counts do not change. See Throughput.

Retry-After is honoured

When Confluence answers a throttled request with 429 or 503 and names a delay, the client now waits exactly that long instead of guessing. This is what makes raising --concurrency safe: the server sets the pace rather than the client discovering it by failing.

A delay longer than 60 seconds is surfaced rather than slept, so a command never looks hung, and waiting is interruptible.

The retry backoff defaults changed, and upgrading does not reach an existing install. They were raised from 10ms/100ms to 500ms/30s, but a config file materialises every default when it is created and configuration beats defaults. An older install keeps a 70 ms total budget across three attempts, which cannot outlast a real throttling window. Run acs2md doctor to check, then see Retries and rate limiting.

Images can be written as sidecar files

--image-sidecars saves each image to attachments/<page-id>/ beside the Markdown and links it relatively, instead of embedding a base64 data URI. The export stays self-contained either way — what changes is line length.

On one real page: 1,440,451 B and a 244,311-character line as base64, against 12,100 B and 379 characters as sidecars. Across a space it also deduplicates — an image reused on ten pages is stored once.

--obsidian turns this on, because base64 was the last thing in that preset that did not render in Obsidian.

Obsidian output

A full preset — callouts, heading anchors Obsidian resolves, and image sidecars — plus --wikilinks, --inline-tags, --panel-style and --media-dimensions. See Obsidian Vaults.

Every command reports how long it took

✅ Sync complete! ✅ Converted: 835 ⏱️ Took: 2m 14s

The figure covers the whole command, API calls and image downloads included. Page-level commands print the timing to stderr, never stdout, so redirects and pipes stay clean.

A second Ctrl+C force-quits

The first interrupt cancels cleanly and lets pages already in flight unwind, which is not instant when several are converting at once. Previously any further Ctrl+C was swallowed and a run that looked stuck could not be stopped.

Fixes

  • --debug produced no output at all. It set the log level but left the destination at its default, which discards everything. It now logs to stderr unless --log-file says otherwise.
  • A broken log.level, log.format or unwritable log.file blocked every command — including the config commands that repair it. Those now fall back to working settings for the run and name the key to change.
  • A global flag placed before an exempt command made it demand a licence or validate the configuration. acs2md --log-file x.log doctor treated --log-file as the command name, so doctor — the command you run to diagnose licensing — refused to start on an unlicensed machine.
  • space get --sync could delete files outside the output directory.
  • Two concurrent saves could corrupt the sync state, because every save wrote through the same fixed temporary filename.
  • An invalid http.client.proxy is now an error rather than a warning-and-continue. Silently sending traffic direct when asked to route it is, on a corporate network, worth stopping for.

v1.0.5

This release changed default Markdown output for pages containing panels, and for anyone using --include-metadata. Both actions below are no-ops if you never wrote the corresponding setting.

Action: check image.max_size_bytes

The default dropped to 2 MB, but a configuration written before this release almost certainly pins the old 10485760 — permissive enough to inline a page background and produce a file no editor will lay out. Configuration beats defaults, so it keeps winning:

acs2md config get image.max_size_bytes # 10485760 means the old value is pinned acs2md config set image.max_size_bytes 2097152

acp2md reads its own configuration, so run the same pair there if you use it.

Front matter carries display names and mentions link to people profiles. Where an export is published outside the organisation, --resolve-users=false keeps opaque account IDs instead.

Panels render as GitHub alerts

> [!NOTE], > [!TIP], > [!WARNING], > [!CAUTION] replace the previous emoji-labelled blockquote. Alerts render on GitHub and Obsidian. Panel types with no alert equivalent keep the emoji form. --panel-style=emoji restores the old output.

Front matter is proper YAML

--include-metadata now emits deterministic, correctly quoted YAML that Obsidian reads as Properties and Jekyll, Hugo and Pandoc parse:

BeforeNow
Title, AuthorID, CreatedAt, ID, LastOwnerID, OwnerID, ParentID, ParentType, Position, SpaceID, Status, SubType, VersionAuthorID, VersionCreatedAt, VersionMessage, VersionMinorEdit, VersionNumbertitle, tags, author, created, updated, source, space, status, version, id, parent_id, owner_id

Dates are YYYY-MM-DD, tags comes from the page’s Confluence labels, source is the browser URL, and empty fields are omitted. The dropped fields were Confluence bookkeeping no Markdown consumer used.

Labels are fetched automatically

With front matter enabled, tags is populated without passing --include-labels. On space convert, labels are not part of the bulk page listing, so --include-labels (default true) controls one extra request per page — set it to false to skip that cost.

The table of contents previously emitted GitHub-style slug anchors regardless of target. --panel-style=obsidian (and therefore --obsidian) now emits anchors Obsidian resolves.


See also

Last updated on