Skip to content

[FEATURE] YAML front matter in Markdown that maps to content properties (e.g. page width) #260

Closed

Description

@franzen

Is your feature request related to a problem? Please describe.

Some page settings live outside the page body, as content properties. Page width is the
common one: content-appearance-published set to full-width
or fixed-width. In a docs-as-code workflow (read --format markdown → edit →
update --format markdown) those settings cannot be kept next to the content:

  • property-get / property-set ([FEATURE] Add support for content properties (get, set, update, delete) #37) work, but as separate commands. A page upload is then
    update plus one get and one set per property, driven by a mapping kept somewhere outside
    the Markdown file.
  • A front-matter block in the file is not recognised today. update --format markdown
    converts it as ordinary Markdown, so it ends up as visible content at the top of the page.
  • read --format markdown returns only the body, so anything a wrapper script puts at the
    top of the file is gone after the next read.

Describe the solution you'd like

An optional YAML front-matter block that the write commands apply as content properties and
that read can write back, so the Markdown file describes the whole page.

Writing (create, create-child, update with --format markdown): a leading block
delimited by --- lines is parsed as YAML and removed from the body before conversion. Its
properties map is applied as content properties after the body is saved.

---
properties:
  content-appearance-published: full-width
---

# Page title

Body text.
  • Each key is a content-property key; each value is the property value (any YAML value that
    serialises to JSON).
  • A property is written only when its current value differs, so an unchanged file causes no
    extra writes.
  • Properties not listed in the block are left alone. Removing a key from the block does not
    delete the property.
  • Top-level keys other than properties are ignored, which leaves room for later additions
    (title, labels) without breaking existing files.
  • A file without a front-matter block behaves exactly as today.

Reading (read --format markdown): opt-in, so current output does not change.

confluence read <id> --format markdown --front-matter content-appearance-published,SOME-OTHER-PROPERTY

This emits the same block for the listed keys that exist on the page, followed by the body.
With a stable key order, and no block when none of the keys exist, read → update → read
gives a byte-identical file.

Opt-out: a --no-front-matter flag on the write commands (or a profile setting) for users
whose pages legitimately start with a --- thematic break followed by text.

Describe alternatives you've considered

  • A wrapper around property-get / property-set (what we would do today). It runs per
    page after update, with the desired values kept in the build script rather than in the
    page's own file. Per-page differences need a separate list of page IDs.
  • A CLI flag such as update --width full-width. Simpler, but it covers one property and
    still keeps the setting outside the file.
  • Strip and re-insert the block in a wrapper. Possible on upload, but the wrapper then
    also has to rebuild the block after every read, duplicating what the CLI would do.

Use case

We keep a documentation space as Markdown files in git, one file per page, and round-trip
them with confluence read --format markdown and confluence update --format markdown.
Pages with wide tables need to be full-width, others are fine at the default. We want that
choice versioned and reviewed in the same file as the content, and applied by the same
upload.

Anyone who publishes Markdown to Confluence and needs a page-level setting that is stored as
a content property would benefit, without writing their own property sync.

Additional context

  • confluence-cli 2.25.8 (Homebrew), Confluence Cloud.
  • No existing issue covers this as far as I can find. [FEATURE] Add support for content properties (get, set, update, delete) #37 added the property-* commands
    this would build on.
  • An explicit key list on read seems safer than dumping every property: pages carry editor-
    and app-owned properties that should not be copied into source files or written back.
  • --format storage and --format html would be unchanged; front matter is a Markdown-only
    feature.

Implementation suggestions

  • Split the front matter off before the Markdown → storage conversion, in one place shared by
    create, create-child, update and convert, so offline convert output matches what
    update uploads.
  • Parse and validate the YAML before any network call, and fail on invalid YAML without
    uploading anything.
  • Apply the properties with the existing getProperty / setProperty client methods,
    skipping keys whose current value already matches.
  • Scoped API tokens may lack the content-property scopes even when page read/write works. If
    the block is present and the property call is rejected, fail with a clear message rather
    than saving the body and silently skipping the properties.
  • For read, fetch only the keys named in --front-matter and emit them in the order given,
    so the output is deterministic.

Activity

  1. pchuri commented on Oct 1, 2026

    @pchuri
    Owner

    Thanks for the thoughtful proposal and the detailed read/write semantics. Keeping selected page properties alongside Markdown is a useful docs-as-code feature, and the explicit property list on read and preservation of unlisted properties are sensible boundaries.

    Before implementation, there are two important behaviors to settle. First, saving the body and saving properties are separate API operations, so a property failure can leave the body already saved. We should report that partial result clearly and make retry behavior predictable. Second, front-matter detection should preserve existing Markdown documents that begin with thematic breaks; an explicit write opt-in would be a safe starting point.

    We should also define round-trip guarantees in terms of stable, normalized output, since the existing Markdown conversion can normalize formatting. These are design points to work through, not objections to the feature. We will review the scope and build on the existing property commands. Thanks again for the clear use case!

  2. pchuri commented on Oct 4, 2026

    @pchuri
    Owner

    Thank you again for such a thorough proposal. Here is a concrete direction for the open design points, and we'd appreciate your feedback before we start.

    Writing (create, create-child, update, markdown only)

    • Opt-in via a --front-matter flag, so files that start with a --- thematic break behave exactly as today. A profile setting could come later.
    • The block is parsed and validated before any network call; invalid YAML fails without uploading anything.
    • Only the properties map is applied; other top-level keys are ignored, as you suggested. Properties not listed are left alone, and unchanged values are not rewritten.

    Partial failure

    • The body is saved first, then the properties. If a property call fails (for example missing scopes), the command exits non-zero and says clearly that the body was saved and which keys failed. With --json, the result lists the keys that were applied and the ones that failed. Rerunning the same command is safe: already-matching properties are skipped.

    Reading

    • read --format markdown --front-matter key1,key2 as you proposed, emitting only the listed keys that exist, in the given order. We'd promise stable, normalized output rather than byte-identical files, since the markdown conversion can normalize formatting.

    Dependency

    • A YAML parser would become a direct dependency (it is only pinned through overrides today).

    Does this fit your workflow? In particular, would an opt-in flag on writes work for you, and is "stable and normalized" enough for the read → update → read round trip? Thanks for your patience and for the clear use case!

  3. franzen commented on Oct 5, 2026

    @franzen
    Author

    Thanks, this fits my workflow. An explicit --front-matter flag on writes works for me, and stable, normalized output is sufficient. Clear reporting of partial failures and safe retries also sounds good.

    To clarify the original goal: I want to easily set page width across all pages, or change it across selected pages using search-and-replace in the local Markdown files. Keeping the setting in each file lets me review those changes in git and apply them through the normal upload workflow.

    For example:

    ---
    properties:
      content-appearance-published: full-width
    ---

    I could then add or change that setting across the relevant files and upload them with front-matter processing enabled.

    The important round-trip guarantee for me is that reading with the selected property keys preserves those settings in the exported files, so they remain available for subsequent editing and uploading. Exact Markdown formatting is less important.

    No dedicated bulk command is needed for this proposal, processing each file through the existing commands would meet the use case.

    Happy with the direction you outlined.

  4. added a commit that references this issue on Oct 5, 2026
  5. github-actions commented on Oct 5, 2026

    @github-actions

    🎉 This issue has been resolved in version 2.28.0 🎉

    The release is available on:

    Your semantic-release bot 📦🚀

  6. pchuri commented on Oct 5, 2026

    @pchuri
    Owner

    This is now released in v2.28.0 (#273). Thanks again for the clear proposal and for confirming the direction.

    npm install -g confluence-cli@latest
    
    # export with the selected properties as front matter
    confluence read <pageId> --format markdown \
      --front-matter content-appearance-draft,content-appearance-published > page.md
    
    # edit page.md, then upload body + properties
    confluence update <pageId> --file page.md --format markdown --front-matter

    A few notes:

    • On Cloud, the editor also keeps content-appearance-draft, so setting it alongside content-appearance-published should keep the width after the next browser edit.
    • If a property fails after the body is saved, the command exits non-zero and lists the failed keys. Re-running update only retries what still differs.

    It hasn't been run against a live instance on our side yet, so feedback from your setup would be very welcome. Please reopen this issue or open a new one if anything doesn't behave as expected.

  7. franzen commented on Oct 6, 2026

    @franzen
    Author

    It works fine for me!

  8. pchuri commented on Oct 7, 2026

    @pchuri
    Owner

    Thanks for confirming, @franzen! Glad to hear it is working fine for you. Closing this issue now - feel free to reopen if anything comes up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions