Publish, sync, diff, delete, discover, and export markdown documentation to/from Confluence Cloud. 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. Handles page creation, updates, deletion, cross-page link rewriting, Mermaid diagram rendering, hierarchy verification, diff/preview, and reverse export to markdown.
Publish a tree of markdown files to Confluence Cloud, maintaining hierarchy, cross-page links, and embedded diagrams.
Use this skill when the user wants to:
Before running any publish operation, ensure:
.confluence.json in project root and/or ~/.confluence.json for global defaults (see CONFIG.md)CONFLUENCE_EMAIL and CONFLUENCE_TOKEN exported in shell profile (recommended) or in a .env fileconfluence_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:
https://mycompany.atlassian.net/wiki)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"
}
}
Run the preflight script before any other operation:
python3 <skill_dir>/scripts/confluence_preflight.py
It validates the entire environment in a single pass:
atlassian-python-api, markdown).confluence.json) is found and has required fields (confluence_url, space_key, root_page_id)If the venv or dependencies are missing, the preflight tells you to run the setup script:
python3 <skill_dir>/scripts/confluence_setup_env.py
To skip the connectivity check (e.g. on repeated calls):
python3 <skill_dir>/scripts/confluence_preflight.py --skip-connectivity
After 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.
Always follow this sequence. Never skip the pre-flight checks or the publish plan step.
Run the pre-flight checks above. If any check fails, resolve it before proceeding.
Ask the user (or infer from their request) which files to publish:
.md file under docs_dirFor 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.
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:
.md cross-links to Confluence page-link macros using the manifestattachment: links to Confluence attachment macros--emoji is provided)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-run
Dry 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.
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.py
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.py
This walks the Confluence tree under root_page_id and creates .confluence-manifest.json.
Compare local markdown against what is currently on Confluence without publishing.
The diff normalizes both sides to the same representation before comparing:
.md links → Confluence link macros) to produce Confluence storage HTMLmarkdownifyThis 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.txt
Note: 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.
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-run
When 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.
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.
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).
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-run
Never 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.
<skill_dir>/.venv/bin/python <skill_dir>/scripts/validate_manifest.py
<skill_dir>/.venv/bin/python <skill_dir>/scripts/verify_hierarchy.py
--dry-run on publish_page.py to preview changes before committing..confluence-manifest.json) is auto-maintained by scripts. Do not edit it manually.--dry-run before surgical edits. Review the semantic diff and section integrity check before pushing.--check-sections to verify critical content survived the edit.grep or cat on 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 --output and 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).The publish script performs these transformations automatically:
<ac:structured-macro ac:name="code"> with proper language highlighting```mermaid blocks are rendered to PNG via mmdc (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)[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-isattachment: scheme (e.g. [Slides](attachment:slides.pdf)) are converted to <ac:link><ri:attachment …/></ac:link> macrosApply 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-run
Always use --dry-run first. Full usage details: references/SURGICAL_EDIT.md
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 56
Never revert without showing the dry-run plan first. Full usage details: references/VERSION_MANAGEMENT.md
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 json
CQL is Atlassian's query language for Confluence. Common operators: =, ~ (contains), AND, OR, NOT. Useful fields: type, space, title, text, creator, lastModified, label, ancestor.
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>"
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 json
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 |
| 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 |
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer