confluence-publisher
Skill4 starsChanged 8 months agoMITView on GitHub
Publish, sync, diff, delete, discover, and export markdown documentation to/from Confluence Cloud (*.atlassian.net/wiki/*). Use when the user asks to publish, update, delete, preview, diff, or export markdown files to Confluence, or when they want to verify existing Confluence pages against local docs. Also supports surgical HTML edits (targeted find/replace without overwriting manual formatting), version comparison (diff two page versions), version history browsing, page revert, CQL search, page comments (list/add/reply/edit/delete/resolve/unresolve plus likes reads and threaded child traversal), page listing by space, and space listing. Handles page creation, updates, deletion, cross-page link rewriting, Mermaid diagram rendering, hierarchy verification, diff/preview, and reverse export to markdown.
- Reads credentials
- Installs packages
In this repository10 other files it gives its agents.
- bitbucket-managerSkill
- codebase-analyzerSkill
- codex-subagentSkill
- eks-pod-opsSkill
- jenkins-managerSkill
- jira-managerSkill
- review-promptsSkill
- sbt-build-testSkill
- skill-creatorSkill
- super-reviewSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
27 rules. About 0 are common, 22 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈22
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 29
Use this skill when the user wants to:
- Distinctive: line 31
Update existing Confluence pages from local markdown
- Distinctive: line 32
Delete Confluence pages (by manifest file key or page ID)
- Distinctive: line 33
Verify that Confluence pages match local docs (hierarchy, titles, content)
- Distinctive: line 45
Before running any publish operation, ensure:
- Very specific: line 53
If no config is found anywhere, help the user create one.
- Very specific: line 70
If .confluence.json does not exist anywhere, help the user create one by asking for:
- Distinctive: line 97
Run the preflight script before any other operation:
- Distinctive: line 110
If the venv or dependencies are missing, the preflight tells you to run the setup script:
- Distinctive: line 122
After setup, all subsequent script commands must use the venv Python:
- Distinctive: line 128
If no config is found anywhere, do NOT proceed — instead help the user create one.
- Distinctive: line 132
Always follow this sequence.
- Distinctive: line 136
Run the pre-flight checks above.
- Distinctive: line 140
Ask the user (or infer from their request) which files to publish:
- Very specific: line 141
All: every .md file under docs_dir
- Distinctive: line 169
Wait for explicit user approval before proceeding: If the user asks to change titles, parent pages, or skip files, update the plan and …
- Distinctive: line 173
Run the publish script for each file in hierarchical order (parents before children):
- Very specific: line 193
Use --dry-run to preview what would be published without making any changes:
- Distinctive: line 209
After publishing, offer to run verification:
- Distinctive: line 223
If the user already has pages on Confluence and wants to build a manifest from them:
- Distinctive: line 289
When exporting the full tree, the script also updates the manifest with discovered pages.
- Distinctive: line 333
Remove Confluence pages and their manifest entries.
- Distinctive: line 350
Never run delete without explicit user approval: Before executing, list every page that will be deleted (title and ID) and wait for the …
- Distinctive: line 367
Never print or log credentials: Only confirm that the environment variables are set.
- Distinctive: line 370
If a page create fails, stop and report the error — do not continue with children of that page.
- Very specific: line 374
When using surgical edit, prefer --check-sections to verify critical content survived the edit.
- Distinctive: line 430
Search Confluence content using CQL (Confluence Query Language):
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Confluence Publisher
Publish a tree of markdown files to Confluence Cloud, maintaining hierarchy, cross-page links, and embedded diagrams.
When to use this skill
Use this skill when the user wants to:
- Publish one or more markdown files to Confluence
- Update existing Confluence pages from local markdown
- Delete Confluence pages (by manifest file key or page ID)
- Verify that Confluence pages match local docs (hierarchy, titles, content)
- Discover existing Confluence pages and build a local manifest
- Validate that a manifest is consistent with both disk and Confluence
- Apply targeted edits to a Confluence page without overwriting manual formatting (surgical edit)
- Compare two versions of a Confluence page (version diff)
- Browse page version history or fetch content from a specific version
- Revert a page to a previous version
- Manage Confluence page comments and read like counts/users for pages and comments
- List pages in a space with title/status/type filters
Prerequisites
Before running any publish operation, ensure:
- Config:
.confluence.jsonin project root and/or~/.confluence.jsonfor global defaults (see CONFIG.md) - Credentials:
CONFLUENCE_EMAILandCONFLUENCE_TOKENexported in shell profile (recommended) or in a.envfile - Python deps: installed via
confluence_setup_env.py(shared venv in skill dir)
Config is auto-discovered — scripts search CWD upward, then ~/.confluence.json. If both exist, they are deep-merged (project-level wins). No --config flag needed.
If no config is found anywhere, help the user create one. For users with one Atlassian instance, a global ~/.confluence.json covers the shared settings:
{
"confluence_url": "https://mycompany.atlassian.net/wiki",
"credentials": { "username_env": "CONFLUENCE_EMAIL", "token_env": "CONFLUENCE_TOKEN" }
}Then a minimal per-project .confluence.json only needs:
{
"space_key": "DOCS",
"root_page_id": "123456"
}If .confluence.json does not exist anywhere, help the user create one by asking for:
- Confluence base URL (e.g.
https://mycompany.atlassian.net/wiki) - Space key
- Root page ID (the parent page under which all docs live)
- Which directory contains the markdown files (default: project root)
Configuration
Config is loaded from .confluence.json (project root) and/or ~/.confluence.json (global). If both exist, they are deep-merged (project-level wins). See references/CONFIG.md for the full schema.
Full single-file example:
{
"confluence_url": "https://mycompany.atlassian.net/wiki",
"space_key": "DOCS",
"root_page_id": "123456",
"docs_dir": ".",
"credentials": {
"username_env": "CONFLUENCE_EMAIL",
"token_env": "CONFLUENCE_TOKEN"
}
}Pre-flight checks
Run the preflight script before any other operation:
python3 <skill_dir>/scripts/confluence_preflight.pyIt validates the entire environment in a single pass:
- Python 3.10+ is available
- Virtual environment exists and dependencies are installed (
atlassian-python-api,markdown) - Config file (
.confluence.json) is found and has required fields (confluence_url,space_key,root_page_id) - Credentials — env vars are set (never prints values)
- Connectivity — API is reachable, space and root page exist
If the venv or dependencies are missing, the preflight tells you to run the setup script:
python3 <skill_dir>/scripts/confluence_setup_env.pyTo skip the connectivity check (e.g. on repeated calls):
python3 <skill_dir>/scripts/confluence_preflight.py --skip-connectivityAfter setup, all subsequent script commands must use the venv Python:
<skill_dir>/.venv/bin/python <skill_dir>/scripts/publish_page.py ...If no config is found anywhere, do NOT proceed — instead help the user create one. For users with one Atlassian instance, suggest a global ~/.confluence.json with shared settings (URL, credentials) and a per-project .confluence.json with just space_key and root_page_id.
Workflow
Always follow this sequence. Never skip the pre-flight checks or the publish plan step.
Step 1 — Validate configuration
Run the pre-flight checks above. If any check fails, resolve it before proceeding.
Step 2 — Determine scope
Ask the user (or infer from their request) which files to publish:
- All: every
.mdfile underdocs_dir - Changed: files modified since last publish (check git diff or timestamps)
- Specific: a list of files the user names
Step 3 — Build the publish plan
For each file in scope, determine whether it is a create or update by checking the manifest (.confluence-manifest.json). If no manifest exists, treat all files as creates.
Present the plan to the user in this exact format (see references/PUBLISH_PLAN_FORMAT.md):
╔══════════════════════════════════════════════════════════════╗
║ CONFLUENCE PUBLISH PLAN ║
╠══════════════════════════════════════════════════════════════╣
║ Target: https://mycompany.atlassian.net/wiki ║
║ Space: DOCS ║
║ Root: "My Project Docs" (id=123456) ║
╠══════════════════════════════════════════════════════════════╣
║ # │ Action │ File │ Title ║
║────┼────────┼─────────────────────────┼───────────────────────║
║ 1 │ UPDATE │ README.md │ My Project Docs ║
║ 2 │ CREATE │ plan/README.md │ Design & Plan ║
║ 3 │ UPDATE │ plan/architecture.md │ Architecture ║
╠══════════════════════════════════════════════════════════════╣
║ Creates: 1 │ Updates: 2 │ Skipped: 0 │ Total: 3 ║
╚══════════════════════════════════════════════════════════════╝Wait for explicit user approval before proceeding. If the user asks to change titles, parent pages, or skip files, update the plan and present it again.
Step 4 — Execute
Run the publish script for each file in hierarchical order (parents before children):
<skill_dir>/.venv/bin/python <skill_dir>/scripts/publish_page.py \
--file <relative_path> \
--title "<title>" \
--mode <create|update> \
[--page-id <id>] # for updates, from manifest \
[--parent-id <id>] # for creates, from manifest or root_page_id \
[--emoji <codepoint>] # page icon emoji, e.g. 1f399 for 🎙️The script automatically:
- Converts markdown to Confluence storage format
- Renders Mermaid diagrams to PNG and uploads as attachments
- Rewrites
.mdcross-links to Confluence page-link macros using the manifest - Converts
attachment:links to Confluence attachment macros - Sets the page emoji icon (if
--emojiis provided) - Updates the manifest with the resulting page ID
Use --dry-run to preview what would be published without making any changes:
<skill_dir>/.venv/bin/python <skill_dir>/scripts/publish_page.py \
--file <relative_path> \
--title "<title>" \
--mode <create|update> \
[--page-id <id>] \
[--parent-id <id>] \
--dry-runDry run still renders markdown transformations (mermaid counts, link rewrites, body size) but does not create/update pages, upload attachments, set emoji, or update the manifest.
Step 5 — Verify (optional but recommended)
After publishing, offer to run verification:
# Validate manifest entries against disk and Confluence
<skill_dir>/.venv/bin/python <skill_dir>/scripts/validate_manifest.py
# Show the full page tree on Confluence
<skill_dir>/.venv/bin/python <skill_dir>/scripts/verify_hierarchy.pyOther operations
Discover existing pages
If the user already has pages on Confluence and wants to build a manifest from them:
<skill_dir>/.venv/bin/python <skill_dir>/scripts/discover_pages.pyThis walks the Confluence tree under root_page_id and creates .confluence-manifest.json.
Diff / Preview
Compare local markdown against what is currently on Confluence without publishing.
The diff normalizes both sides to the same representation before comparing:
- Local markdown is transformed through the publish pipeline (mermaid blocks → placeholders,
.mdlinks → Confluence link macros) to produce Confluence storage HTML - Remote Confluence page storage HTML is fetched and mermaid image macros are replaced with matching placeholders
- Both HTML strings are converted to markdown via
markdownify - A unified diff is produced from the two normalized markdown strings
This eliminates false positives from mermaid diagrams and cross-page links. Minor whitespace differences may still appear due to round-trip formatting.
# Diff a single file
<skill_dir>/.venv/bin/python <skill_dir>/scripts/diff_pages.py --file README.md
# Diff all manifest entries
<skill_dir>/.venv/bin/python <skill_dir>/scripts/diff_pages.py --all
# Summary only (changed/unchanged counts, no full diff)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/diff_pages.py --all --summary
# Save diff output to file (avoids terminal truncation for large pages)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/diff_pages.py --file README.md --output /tmp/diff-report.txtNote: The diff script exits with code 1 if any changes or new pages are detected, and code 0 if everything is unchanged. This is informational (like the diff command), not an error — do not treat exit code 1 as a failure.
Output truncation: For large pages, the diff output may exceed the terminal/tool output limit and get truncated. Use --output /tmp/diff-report.txt to save to a file, then read it with your file-reading tool.
Present the diff output to the user before publishing so they can review what would change.
Export from Confluence
Pull Confluence pages back into local markdown files (reverse sync). Useful for bootstrapping local docs from an existing Confluence space, or for recovering content.
# Export a single page by ID, URL, or tiny link
<skill_dir>/.venv/bin/python <skill_dir>/scripts/export_pages.py \
--page https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456/My+Page
# Export using a Confluence tiny link (/wiki/x/...)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/export_pages.py \
--page https://mycompany.atlassian.net/wiki/x/sYjwQ
# Export a single page to a specific file
<skill_dir>/.venv/bin/python <skill_dir>/scripts/export_pages.py --page 123456 -o docs/setup.md
# Export all manifest entries (overwrites local files)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/export_pages.py --manifest
# Export full tree under root_page_id (discovers and exports everything)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/export_pages.py --tree
# Dry run — show what would be exported without writing files
<skill_dir>/.venv/bin/python <skill_dir>/scripts/export_pages.py --tree --dry-runWhen exporting the full tree, the script also updates the manifest with discovered pages.
Always confirm with the user before running --manifest or --tree exports, as they overwrite local files.
Attachments
The publish script supports uploading file attachments alongside a page:
<skill_dir>/.venv/bin/python <skill_dir>/scripts/publish_page.py \
--file docs/setup.md --title "Setup Guide" --mode update --page-id 123456 \
--attachments "docs/images/diagram.png,docs/files/schema.pdf"To upload attachments without modifying page content, use --attachments-only:
# Upload files to a page without touching its content
<skill_dir>/.venv/bin/python <skill_dir>/scripts/publish_page.py \
--attachments-only --page-id 123456 \
--attachments "images/diagram.png,images/chart.png"Never use --file /dev/null to upload attachments — it will wipe the page content. Always use --attachments-only instead.
Attachment paths are relative to docs_dir. Multiple files are comma-separated. If an attachment file is not found, a warning is printed but the page publish still succeeds.
Mermaid diagram PNGs are uploaded automatically — no need to list them in --attachments.
Attachment links in markdown
To link to an uploaded attachment from within the page content, use the attachment: URL scheme:
[My Presentation.pdf](attachment:My Presentation.pdf)
[Architecture Diagram](attachment:arch-overview.png)During publish, these are automatically converted to Confluence <ac:link><ri:attachment …/></ac:link> macros that link directly to the attachment on the page.
The filename in attachment: must exactly match the filename used in --attachments (or the name of a previously uploaded attachment on the page).
Delete pages
Remove Confluence pages and their manifest entries. Supports deletion by manifest file key or direct page ID.
# Delete by manifest file path
<skill_dir>/.venv/bin/python <skill_dir>/scripts/delete_page.py --file plan/old-design.md
# Delete multiple files
<skill_dir>/.venv/bin/python <skill_dir>/scripts/delete_page.py \
--file "plan/old-design.md,plan/deprecated.md"
# Delete by page ID (not in manifest)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/delete_page.py --page-id 123456
# Dry run — show what would be deleted without deleting
<skill_dir>/.venv/bin/python <skill_dir>/scripts/delete_page.py --file plan/old-design.md --dry-runNever run delete without explicit user approval. Before executing, list every page that will be deleted (title and ID) and wait for the user to confirm. Deletion is irreversible unless the page is recovered from Confluence trash. When in doubt, use --dry-run first.
Validate only
<skill_dir>/.venv/bin/python <skill_dir>/scripts/validate_manifest.pyVerify hierarchy only
<skill_dir>/.venv/bin/python <skill_dir>/scripts/verify_hierarchy.pyImportant rules
- Never publish or delete without showing the plan first and getting explicit user approval. Deletion is destructive and irreversible (except via Confluence trash recovery). When in doubt, use
--dry-runonpublish_page.pyto preview changes before committing. - Never print or log credentials. Only confirm that the environment variables are set.
- Publish parents before children so that parent IDs are available for child creation.
- The manifest file (
.confluence-manifest.json) is auto-maintained by scripts. Do not edit it manually. - If a page create fails, stop and report the error — do not continue with children of that page.
- Cross-page links are best-effort: if a target page is not in the manifest, the link is left as-is.
- Always use
--dry-runbefore surgical edits. Review the semantic diff and section integrity check before pushing. - Never revert a page without showing the dry-run plan first and getting explicit user approval. Revert creates a new version — the old version remains in history.
- When using surgical edit, prefer
--check-sectionsto verify critical content survived the edit. - Never use
greporcaton fetched Confluence HTML files — they are single-line files that will truncate in the terminal and produce unreadable output. Instead, save to a file with--outputand read it using your IDE's file-reading tool, or write a small Python script to extract the specific section you need (e.g., find a table between two headings).
Markdown transformation details
The publish script performs these transformations automatically:
- Markdown → Confluence storage format: Headings, tables, lists, inline code, bold/italic all convert to Confluence XHTML
- Code blocks → Confluence code macros: Fenced code blocks with language tags become
<ac:structured-macro ac:name="code">with proper language highlighting - Mermaid diagrams → PNG attachments:
```mermaidblocks are rendered to PNG viammdc(Mermaid CLI), uploaded as page attachments, and replaced with<ac:image>macros. If Node.js/npx is unavailable, diagrams fall back to plain code blocks (no failure) - Cross-page links → Confluence page links: Links like
[Setup Guide](./setup.md)are resolved via the manifest and rewritten to<ac:link>macros pointing to the correct Confluence page by title. Unresolvable links (target not in manifest) are left as-is - Attachment links → Confluence attachment macros: Links using the
attachment:scheme (e.g.[Slides](attachment:slides.pdf)) are converted to<ac:link><ri:attachment …/></ac:link>macros
Surgical edit
Apply targeted find/replace edits to a page's storage HTML without overwriting the entire page. Also supports structural element replacement (tables, sections, lists), markdown-to-HTML section replacement, and appending new sections.
# Simple find/replace (always dry-run first)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/surgical_edit.py \
--page 1079706804 --find "old text" --replace "new text" --dry-run
# Replace a section from markdown
<skill_dir>/.venv/bin/python <skill_dir>/scripts/replace_element.py \
--page 1079706804 --heading "Testing" --element section \
--new-md /tmp/new-section.md --dry-run
# Render existing mermaid code blocks to images
<skill_dir>/.venv/bin/python <skill_dir>/scripts/render_mermaid.py \
--page 1079706804 --dry-runAlways use --dry-run first. Full usage details: references/SURGICAL_EDIT.md
Version management
Browse version history, diff two versions, fetch content at any version, or revert to a previous version.
# Diff version 56 against latest
<skill_dir>/.venv/bin/python <skill_dir>/scripts/diff_versions.py \
--page 1079706804 --from-version 56
# List version history
<skill_dir>/.venv/bin/python <skill_dir>/scripts/page_versions.py \
--page 1079706804 --list
# Revert (dry run first, then --confirm)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/page_versions.py \
--page 1079706804 --revert 56Never revert without showing the dry-run plan first. Full usage details: references/VERSION_MANAGEMENT.md
Search (CQL)
Search Confluence content using CQL (Confluence Query Language):
# Search pages by title
<skill_dir>/.venv/bin/python <skill_dir>/scripts/search_pages.py \
--cql 'type=page AND space=DOCS AND title~"API"'
# Search with limit and JSON output
<skill_dir>/.venv/bin/python <skill_dir>/scripts/search_pages.py \
--cql 'type=page AND text~"deployment"' --limit 50 --format jsonCQL is Atlassian's query language for Confluence. Common operators: =, ~ (contains), AND, OR, NOT. Useful fields: type, space, title, text, creator, lastModified, label, ancestor.
Comments
List and add comments on Confluence pages:
# List footer comments
<skill_dir>/.venv/bin/python <skill_dir>/scripts/page_comments.py list \
--page-id 123456
# List inline comments
<skill_dir>/.venv/bin/python <skill_dir>/scripts/page_comments.py list \
--page-id 123456 --inline
# List as JSON
<skill_dir>/.venv/bin/python <skill_dir>/scripts/page_comments.py list \
--page-id 123456 --format json
# Add a footer comment (body is Confluence storage HTML)
<skill_dir>/.venv/bin/python <skill_dir>/scripts/page_comments.py add \
--page-id 123456 --body "<p>This looks good. Ship it.</p>"List spaces
Browse available Confluence spaces:
# List all spaces
<skill_dir>/.venv/bin/python <skill_dir>/scripts/list_spaces.py
# Filter by type
<skill_dir>/.venv/bin/python <skill_dir>/scripts/list_spaces.py --type global
# JSON output
<skill_dir>/.venv/bin/python <skill_dir>/scripts/list_spaces.py --format jsonFuture capabilities
These operations can be added to this skill in the future:
| Capability | Description |
| Bulk rename | Rename Confluence pages when local titles change |
| Labels/tags | Auto-apply Confluence labels based on directory structure or markdown frontmatter |
| Page permissions | Set view/edit restrictions on published pages |
| Content appearance | Set page width (full-width vs default) via content properties |
Troubleshooting
| Problem | Cause | Fix |
python3: command not found | Python not installed | macOS: brew install python3 / Linux: apt install python3 |
ModuleNotFoundError: atlassian | Dependencies not installed | Run python3 <skill_dir>/scripts/confluence_setup_env.py |
401 Unauthorized | Bad credentials | Verify env vars are set and token has page write access |
404 Page not found | Wrong page ID in manifest | Run discover_pages.py to rebuild manifest |
Title conflict | Page title already exists in space | Use a unique title or update the existing page |
| Mermaid diagrams not rendering | Node.js/npx not installed | Install Node.js or diagrams will fall back to code blocks |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

