Your docs live in Git. Your company lives in Confluence. Every team I've
worked with solved this the same way: somebody copies the README into a wiki
page, and from that moment there are two versions of the truth, and one of
them is always lying.
The existing fixes have never sat right with me:
- Embed macros (the most popular category on the Atlassian Marketplace) render your Markdown inside a macro on the page. The content isn't really a Confluence page — search treats it as a blob, PDF export mangles it, and if the app is ever uninstalled, your "documentation" is an empty box. And to work at all, the app needs to reach your repository: an OAuth grant or a token to your Git host, stored in somebody else's cloud. If your repo is behind a VPN or self-hosted, it simply can't work.
- One-time importers get the content in as real pages, once. Then the repo moves on and the wiki starts lying again.
I wanted the third thing: real, native Confluence pages that stay in sync
with Git — without the wiki ever holding a credential to my repository.
So I built it, and the architecture turned out to be the interesting part.
Push, don't pull
The trick is to invert the direction. Instead of the Confluence app reaching
out to Git (pull), your own CI pushes to the app (push):
git push → your CI (diff + sign) → HTTPS → Forge app → native Confluence pages On every push to main, a CI job diffs HEAD~1..HEAD, takes the changed
Markdown files, signs the payload with HMAC-SHA256 using a per-repository
secret, and POSTs it to a web trigger. The app verifies the signature,
converts Markdown to Confluence storage format, and creates or updates one
page per file.
What falls out of this design for free:
- No credentials in the wiki. The app never calls GitHub, GitLab, or anything else. It cannot leak repo access it does not have.
- Private, self-hosted, VPN-only repos just work. The only thing that reads your repository is your own CI runner, with permissions it already has.
- The app runs entirely on Atlassian's infrastructure (Forge, zero egress), which qualifies it for Atlassian's "Runs on Atlassian" program — the strictest data-residency badge the Marketplace has. Your docs never touch my servers, because there are no servers.
The pages it writes are ordinary Confluence pages: searchable, exportable,
permissioned, versioned, and they survive even if you uninstall the app. The
space sidebar mirrors your repo's folder structure; renamed files move their
page, deleted files archive it (never delete), and unchanged files are
skipped by content hash so a full-repo push costs nothing.
Diagrams: render where the tools are
Mermaid and PlantUML were the fun sub-problem. Most apps render diagrams on a
vendor server — egress again, plus size limits. RepoPages renders them in
your CI, where installing mmdc and plantuml is trivial, and ships the
SVG alongside the Markdown. The page embeds the image; the diagram source
travels with it in a collapsed, search-indexed block. (Getting SVGs to
survive Confluence's Word export rasterizer deserves its own post — short
version: no HTML labels, explicit 2x dimensions.)
The security model, in one paragraph
One endpoint, HMAC-SHA256 over the raw body, per-repo secrets generated
server-side and stored in Forge's encrypted secret storage, shown once,
rotatable. Static responses, so the endpoint can't be used to read anything.
Payloads are schema-validated with size caps; raw HTML in Markdown is mapped
against an allowlist, never passed through; SVGs are validated and scripts
rejected. The whole contract is pinned by test vectors shared between the app
and the open-source CI client, so neither side can drift.
Setup is three steps
- In Confluence settings, add a mapping: repository → space (the secret and URL are shown once).
- Add two secrets to your repo:
REPOPAGES_URL,REPOPAGES_SECRET. - Commit the ready-made workflow file (GitHub Action / GitLab job / plain Python script — the client is a single stdlib-only file, open source at github.com/repopages-app/ci).
Every push to main now updates the wiki. Full-tree import for the first run.
What it doesn't do (yet)
Honesty section: images in your Markdown aren't synced yet (you get a visible
note in place); diagrams are Mermaid/PlantUML only; and edits people make in
Confluence are detected and preserved — turning them into pull requests back
to your repo is built on the CI side and coming to the app next.
Try it
RepoPages is live on the Atlassian Marketplace —
free while it's new: https://marketplace.atlassian.com/apps/3052580529/repopages-real-pages-from-git-markdown?hosting=cloud&tab=overview
The CI client and its docs: https://github.com/repopages-app/ci
The app site and privacy policy: https://repopages.app
I'm a solo developer and this just cleared Atlassian's review (Runs on
Atlassian, security questionnaire, the works). If you try it, I will
personally read every piece of feedback — and if your docs pipeline does
something it can't handle, I want to hear about it.

