# Mark for Confluence: Git Markdown Publishing and Page Management

> Mark is a Go command-line tool for synchronizing Markdown documentation to Atlassian Confluence through its REST API. It suits teams that keep documentation in Git but publish it to Confluence, with explicit controls for page identity, hierarchy, attachments, and metadata.

**kovetskiy/mark** — Sync your markdown files with Confluence pages.

- Repository: https://github.com/kovetskiy/mark
- Website: https://samizdat.dev
- Stars: 1,613 · Forks: 244
- Language: Go
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/kovetskiy-mark

## Why Mark fits a Git-owned documentation workflow

Mark solves a specific publication problem: a team maintains Markdown in a Git repository but needs corresponding pages in Atlassian Confluence. Instead of manually copying content into Confluence's WYSIWYG editor, Mark reads local Markdown files and updates Confluence pages through the REST API. The intended users are documentation teams, developers, and organizations that already use Git for source-controlled documentation but require Confluence pages for access, review, or organizational structure.

The core decision is that the Markdown file remains the authoring source while Confluence acts as a synchronized destination. Mark can locate a page by its title, create it when it is absent, upload referenced attachments, translate Markdown into HTML, and update the page contents. The README also describes extended metadata headers that identify spaces, parents, folders, labels, properties, and other page attributes.

This is a publishing tool, not a general-purpose Confluence editor. Its value depends on whether the team accepts a file-based workflow and whether the existing Markdown can be mapped cleanly to Confluence pages. A document whose title is not unique, whose hierarchy is inconsistent, or whose attachment paths do not exist can create operational problems that a manual editor might expose more visibly.

## How Mark maps files to Confluence pages

Mark follows a file-to-page synchronization model. It reads a Markdown file, searches for a Confluence page by the relevant page name or metadata, creates the page if necessary, uploads listed attachments, converts the Markdown content to HTML, and sends the updated content to Confluence through the REST API. The repository layout separates command entry points under `cmd/` from Confluence integration code under `confluence/`, while the root package contains the synchronization behavior.

Page identity is deliberately part of the document. Mark supports legacy HTML comments such as `Space`, `Parent`, `Folder`, `Title`, `Attachment`, `Label`, `Property`, `Synchronized`, and `Image-Align`. When the `frontmatter` feature is enabled, the same information can be expressed as YAML front matter. The front matter must begin on the first line with three or more dashes and close at the next line of matching dashes. An unclosed block is rejected rather than uploaded as visible text.

There is an important merge rule when both metadata formats appear. HTML headers override matching scalar front matter values, while repeatable values for parents, folders, attachments, and labels are appended. The README also documents validation for values that are not strings or lists of strings, and it warns when it encounters an unread key. This makes typos visible instead of silently changing the target page.

The `Include` directive is retained for Confluence's include expander. Mermaid diagrams, D2 diagrams, macros, and other project-specific features are represented in the repository and dependency graph, but the README does not document every processing option. The supported surface should therefore be checked against the version being deployed rather than inferred from the directory names.

## Installing Mark and preparing the first publishing run

The repository declares Go 1.27.1 in `go.mod`. For a source build, the Makefile provides the documented build path. The command below downloads module dependencies and produces the `mark` binary in the repository directory. The `version` target depends on Git tag information, so the repository should be a checkout with its version metadata available.

Use the following commands for a source build:

```bash
make get
make build
```

The resulting binary is named `mark`. The README does not document a package-manager installation command or a standalone download URL. The repository also contains a Dockerfile, and `docker-compose.yaml` builds a Go builder image with `make build`, but the compose file requires `GOOS` and `GOARCH` environment variables. Those variables are not needed for the basic local `make build` path shown above.

A first path-based synchronization run can use the option documented by the README:

```bash
mark --parents-from-path --files "docs/**/*.md"
```

This tells Mark to match the selected Markdown files and derive page parents from directories. The README gives the resulting relationship as `docs/guides/setup.md` becoming `Guides > Setup`, and `docs/guides/deep/tuning.md` becoming `Guides > Deep > Tuning`. Before publishing, confirm that the selected files, Confluence credentials, and destination space are configured for the environment. The README does not specify the authentication flags or environment variables, so those must be taken from the deployed CLI documentation or source rather than guessed.

## Front matter, headers, and page hierarchy

Mark's metadata model is useful for documentation that must preserve a deliberate Confluence hierarchy. A front matter document can declare the space, parents, folders, title, attachments, labels, image alignment, and order. The relevant format is:

```yaml
---
space: <space key>
parents:
  - <parent 1>
  - <parent 2>
folders:
  - <folder 1>
  - <folder 2>
title: <title>
attachments:
  - <local path>
labels:
  - <label 1>
  - <label 2>
image-align: <left|center|right>
order: <whole number>
---
```

The `frontmatter` feature must be enabled when using this format. Because specifying `--features` replaces the defaults, the README gives this command when Mermaid, mentions, and front matter are all needed:

```bash
mark --features=mermaid --features=mention --features=frontmatter
```

If the default feature set is needed as well, the README says to include those features explicitly. That detail matters because replacing defaults can silently disable behavior that an existing documentation pipeline depends on.

Path-derived hierarchy has additional rules. Mark treats `index.md` and `README.md` as the page for their directory, not as a child page. A directory page title comes first from its own `Title` metadata, then from its leading heading when `--title-from-h1` is enabled, then from a `title:` entry in a `.pages` file, and finally from the directory name. The filename is never used for this title choice.

The `--parents-from-path-root` option can override the automatically inferred root. A manually supplied root that contains none of the selected files is rejected. Files outside that root are reported and published without derived parents. These rules make path synchronization predictable, but they also mean that selection patterns and directory indexes directly affect the Confluence tree.

## Collision handling, attachments, and unsupported metadata

Mark treats page titles as significant because a space holds one page of a given title. The README says that two documents requesting the same title request the same page, and that the second document could overwrite the first and move it under different parents. Mark refuses before publishing the second document, comparing titles the way Confluence does, without regard to case. This is a valuable guard against accidental content replacement, particularly when several directories contain documents that want a common title such as `Overview`.

Attachments are explicit in the metadata model. An `attachments` front matter key or repeated `Attachment` headers can name local paths, and Mark uploads them as part of synchronization. The project also includes attachment-focused source and test files, including `mark_attach_referenced_test.go` and `mark_escaped_attachment_test.go`, which indicates that attachment discovery and escaping are part of the implementation surface. The README does not document the resolution rules for every possible attachment reference, so missing files and relative paths should be checked in the selected working directory.

Unknown front matter keys are ignored with a warning. That policy is useful for sharing YAML blocks with a static site generator, but it also means Mark cannot distinguish an intended integration key from a typo. The README gives the example `date` and `draft` keys as shared metadata that Mark reports in the same way as an unrecognized key.

Header parsing is intentionally position-sensitive. Mark reads headers from the opening run of comments, and blank lines may separate groups of headers. Content after ordinary page text is published as text rather than interpreted as metadata. A nearly recognized header such as `Titel` is treated as an error because it appears to be a misspelled title header. This strictness prevents silent publication with missing page identity.

## Operational limits and maintenance signals

Mark is narrowly suited to Markdown-to-Confluence synchronization, and that boundary is important. It does not provide a documented bidirectional editing workflow, conflict resolution interface, rollback procedure, or alternative for editing pages directly in Confluence. The README explains that it creates or updates pages, but it does not document rollback if a generated page is overwritten or how two concurrent Git changes should be reconciled.

The project is not archived, and the last push was on 2026-10-12. The listed releases include `v16.22.0` on 2026-10-12, `v16.21.0` on 2026-10-08, and `v16.20.4` on 2026-09-30. These are concrete maintenance signals based on repository release and push records, but they do not establish compatibility with a particular Confluence instance or authentication setup. The module requires Go 1.27.1, so upgrading the build environment may be part of the adoption cost.

The Apache-2.0 license permits use and modification under its terms, subject to the license text and applicable notices. That is a repository-level licensing fact, not legal advice. The main operational costs are maintaining the Markdown conventions, reviewing generated page hierarchies, checking attachment paths, and testing changes against the target Confluence space. The strict duplicate-title refusal can prevent data loss, but it also requires teams to design titles consistently before enabling a broad file pattern.

## How Mark differs from manual Confluence publishing

The direct alternative is manual editing in Confluence's web editor. That approach does not require Mark-specific metadata or build tooling. It does not require Mark-specific front matter, feature flags, parent derivation rules, or a Go build.

Mark takes a different approach. Its source of truth is a local Markdown file, and its publication operation is repeatable through a command-line tool. That makes it suitable for documentation stored in Git, reviewable file changes, and generated page trees derived from repository directories. It can also map labels, folders, properties, attachments, and Mermaid or D2 content into the destination page. The trade-off is that contributors must understand the metadata rules and accept an automated publishing boundary.

Another practical distinction is failure behavior. Mark applies stricter checks to malformed front matter, missing headers, duplicate titles, invalid metadata types, and path roots. Those checks reduce silent corruption, but they also mean a batch run can stop before the second conflicting page is published. For a team that wants direct Confluence authoring, Mark is the wrong tool. For a team that wants Git to remain authoritative, its automated mapping is the relevant alternative.

## Conclusion

Adopt Mark when Markdown files in Git are the source of truth and Confluence is the publishing destination. Do not choose it for editing documentation directly in Confluence or when a Git-independent page workflow is required. Verify the Markdown header format, attachment paths, parent naming, duplicate titles, and the required Go 1.27.1 toolchain before the first publishing run.

## FAQ

### How do I install and build Mark?

The repository declares Go 1.27.1. The documented source-build path is to run `make get` and then `make build`, which downloads dependencies and creates the `mark` binary.

### How does Mark create a Confluence hierarchy from Markdown files?

Use `mark --parents-from-path --files "docs/**/*.md"`. Mark derives parent pages from directory names, while `index.md` and `README.md` represent the page for their directory.

### What happens if two Markdown files use the same Confluence page title?

Mark refuses to publish the second document because a Confluence space has one page with a given title. The comparison ignores case, matching the behavior described for Confluence.

## Sources

- [kovetskiy/mark on GitHub](https://github.com/kovetskiy/mark)
- [License: Apache-2.0](https://github.com/kovetskiy/mark/blob/master/LICENSE)
- [Project website](https://samizdat.dev)
- [README](https://github.com/kovetskiy/mark/blob/master/README.md)
- [Releases](https://github.com/kovetskiy/mark/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kovetskiy-mark
