
Create Page
- 1 installs
- 1 repo stars
- Updated April 10, 2026
- ericfisherdev/claude-plugins
Creates Confluence pages via a Python script with space-lookup caching and markdown-to-Confluence conversion.
About
Creates new Confluence pages through a bundled Python script that caches space lookups and converts markdown with a --markdown flag. A developer uses it whenever adding a wiki page or publishing documentation to Confluence.
- Creates Confluence pages via a Python script with space-lookup caching
- Converts markdown to Confluence format with the --markdown flag
Create Page by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,361 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ericfisherdev/claude-plugins --skill create-pageAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1 |
| Last updated | April 10, 2026 |
| Repository | ericfisherdev/claude-plugins ↗ |
What it does
Creates Confluence pages via a Python script with space-lookup caching and markdown-to-Confluence conversion.
Files
Create Confluence Page
IMPORTANT: Always use this skill's Python script for creating Confluence pages. This skill uses caching for space lookups and provides token-efficient output.
Markdown Content Handling
CRITICAL: When uploading markdown content to Confluence, you MUST use the --markdown flag:
- Files with `.md` extension → ALWAYS add
--markdown - Content containing markdown syntax (headers with #, lists with -, code blocks with ``
) → ALWAYS add--markdown` - User asks to upload/publish a markdown file → ALWAYS add
--markdown
Without the --markdown flag, markdown content will appear as raw unformatted text in Confluence.
# CORRECT - markdown file with --markdown flag
python scripts/create_confluence_page.py --space DEV --title "Docs" \
--body-file README.md --markdown
# WRONG - markdown will show as raw text
python scripts/create_confluence_page.py --space DEV --title "Docs" \
--body-file README.mdQuick Start
Use the Python script at scripts/create_confluence_page.py:
# Create page in a space
python scripts/create_confluence_page.py --space DEV --title "New Feature Spec"
# Create with content
python scripts/create_confluence_page.py --space DEV --title "API Docs" \
--body "<p>API documentation content here</p>"
# Create from markdown file (automatically converted)
python scripts/create_confluence_page.py --space DEV --title "README" \
--body-file /path/to/README.md --markdown
# Create under a parent page
python scripts/create_confluence_page.py --space DEV --title "Child Page" \
--parent 123456
# Create from a file
python scripts/create_confluence_page.py --space DEV --title "README" \
--body-file /path/to/content.htmlOptions
| Option | Description |
|---|---|
--space, -s | Space key (required) |
--title, -t | Page title (required) |
--body, -b | Page body in storage format (HTML) or markdown |
--body-file | Read body content from file |
--markdown, -m | Convert body content from markdown to Confluence format |
--parent, -p | Parent page ID (creates under this page) |
--parent-title | Parent page title (alternative to ID) |
--labels, -l | Comma-separated labels to add |
--format, -f | Output: compact (default), text, json |
Content Format
Confluence uses "storage format" (XHTML-based). Common elements:
<!-- Paragraph -->
<p>Regular text paragraph</p>
<!-- Headings -->
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<!-- Lists -->
<ul>
<li>Unordered item</li>
</ul>
<ol>
<li>Ordered item</li>
</ol>
<!-- Code block -->
<ac:structured-macro ac:name="code">
<ac:parameter ac:name="language">python</ac:parameter>
<ac:plain-text-body><![CDATA[print("Hello")]]></ac:plain-text-body>
</ac:structured-macro>
<!-- Info panel -->
<ac:structured-macro ac:name="info">
<ac:rich-text-body><p>Info message</p></ac:rich-text-body>
</ac:structured-macro>
<!-- Link to another page -->
<ac:link><ri:page ri:content-title="Page Title"/></ac:link>Common Workflows
Create Simple Documentation Page
python scripts/create_confluence_page.py \
--space DEV \
--title "Setup Guide" \
--body "<h1>Setup Guide</h1><p>Follow these steps...</p>"Create Page Under Existing Parent
# Find parent page ID first, then create under it
python scripts/create_confluence_page.py \
--space DEV \
--title "API Reference" \
--parent-title "Developer Documentation"Create Page with Labels
python scripts/create_confluence_page.py \
--space DEV \
--title "Architecture Decision Record" \
--labels "adr,architecture,decision" \
--body "<p>Decision: Use microservices</p>"Create from Markdown
# Native markdown support (recommended)
python scripts/create_confluence_page.py \
--space DEV --title "README" --body-file README.md --markdown
# Alternative: via pandoc for advanced markdown features
pandoc -f markdown -t html README.md | \
python scripts/create_confluence_page.py \
--space DEV --title "README" --body-file -Output Formats
compact (default):
CREATED|123456|New Feature Spec|DEV
URL:https://yoursite.atlassian.net/wiki/spaces/DEV/pages/123456text:
Page Created: New Feature Spec
ID: 123456
Space: DEV
URL: https://yoursite.atlassian.net/wiki/spaces/DEV/pages/123456json:
{"id":"123456","title":"New Feature Spec","space":"DEV","url":"..."}Environment Setup
Requires environment variables:
CONFLUENCE_BASE_URL- e.g.,https://yoursite.atlassian.netCONFLUENCE_EMAIL- Your Atlassian account emailCONFLUENCE_API_TOKEN- API token from Atlassian account settings
Reference
For detailed options, see references/options-reference.md.
Create Page - Options Reference
Required Arguments
| Option | Short | Type | Description |
|---|---|---|---|
--space | -s | string | Space key where the page will be created |
--title | -t | string | Page title |
Optional Arguments
| Option | Short | Type | Default | Description |
|---|---|---|---|---|
--body | -b | string | empty | Page body in Confluence storage format (HTML) or markdown |
--body-file | - | path | - | Read body content from file (use '-' for stdin) |
--markdown | -m | flag | false | Convert body content from markdown to Confluence format |
--parent | -p | string | - | Parent page ID (creates as child page) |
--parent-title | - | string | - | Parent page title (alternative to --parent) |
--labels | -l | string | - | Comma-separated labels to add |
--format | -f | choice | compact | Output format: compact, text, json |
Content Format
Confluence uses "storage format" which is XHTML-based. Key elements:
Basic Formatting
<p>Paragraph text</p>
<strong>Bold</strong>
<em>Italic</em>
<u>Underline</u>
<h1>Heading 1</h1>
<h2>Heading 2</h2>Lists
<ul>
<li>Unordered item 1</li>
<li>Unordered item 2</li>
</ul>
<ol>
<li>Ordered item 1</li>
<li>Ordered item 2</li>
</ol>Tables
<table>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
</table>Code Block
<ac:structured-macro ac:name="code">
<ac:parameter ac:name="language">python</ac:parameter>
<ac:parameter ac:name="title">Example</ac:parameter>
<ac:plain-text-body><![CDATA[
def hello():
print("Hello, World!")
]]></ac:plain-text-body>
</ac:structured-macro>Info/Warning/Note Panels
<!-- Info panel (blue) -->
<ac:structured-macro ac:name="info">
<ac:rich-text-body><p>Information message</p></ac:rich-text-body>
</ac:structured-macro>
<!-- Note panel (yellow) -->
<ac:structured-macro ac:name="note">
<ac:rich-text-body><p>Note message</p></ac:rich-text-body>
</ac:structured-macro>
<!-- Warning panel (red) -->
<ac:structured-macro ac:name="warning">
<ac:rich-text-body><p>Warning message</p></ac:rich-text-body>
</ac:structured-macro>Links
<!-- External link -->
<a href="https://example.com">Link text</a>
<!-- Link to another Confluence page -->
<ac:link><ri:page ri:content-title="Page Title"/></ac:link>
<!-- Link to page in specific space -->
<ac:link><ri:page ri:space-key="SPACE" ri:content-title="Page Title"/></ac:link>Output Format Details
compact
CREATED|{page_id}|{title}|{space_key}
URL:{confluence_url}text
Page Created: {title}
ID: {page_id}
Space: {space_key}
Parent ID: {parent_id} (if applicable)
URL: {confluence_url}json
{
"id": "page_id",
"title": "Page Title",
"space": "SPACEKEY",
"parentId": "parent_id",
"url": "https://..."
}Error Codes
| Exit Code | Meaning |
|---|---|
| 0 | Success - page created |
| 1 | Error - space not found, parent not found, or API error |
Environment Variables
| Variable | Required | Description |
|---|---|---|
CONFLUENCE_BASE_URL | Yes | Confluence instance URL |
CONFLUENCE_EMAIL | Yes | Atlassian account email |
CONFLUENCE_API_TOKEN | Yes | API token from Atlassian account settings |
#!/usr/bin/env python3
"""
Create a Confluence page with token-efficient output.
Usage:
python create_confluence_page.py --space SPACE --title TITLE [options]
Examples:
python create_confluence_page.py --space DEV --title "New Page"
python create_confluence_page.py --space DEV --title "Docs" --body "<p>Content</p>"
python create_confluence_page.py --space DEV --title "Child" --parent 123456
"""
import argparse
import json
import os
import sys
from pathlib import Path
# Add shared module to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / "shared"))
from confluence_cache import ConfluenceCache
from markdown_converter import markdown_to_confluence
def format_compact(page: dict, base_url: str) -> str:
"""Format created page as compact output."""
url = f"{base_url}/wiki/spaces/{page['space']}/pages/{page['id']}"
return f"CREATED|{page['id']}|{page['title']}|{page['space']}\nURL:{url}"
def format_text(page: dict, base_url: str) -> str:
"""Format created page as readable text."""
url = f"{base_url}/wiki/spaces/{page['space']}/pages/{page['id']}"
lines = [
f"Page Created: {page['title']}",
f"ID: {page['id']}",
f"Space: {page['space']}",
]
if page.get("parentId"):
lines.append(f"Parent ID: {page['parentId']}")
lines.append(f"URL: {url}")
return "\n".join(lines)
def format_json(page: dict, base_url: str) -> str:
"""Format created page as JSON."""
url = f"{base_url}/wiki/spaces/{page['space']}/pages/{page['id']}"
output = {
"id": page["id"],
"title": page["title"],
"space": page["space"],
"url": url,
}
if page.get("parentId"):
output["parentId"] = page["parentId"]
return json.dumps(output)
def main():
parser = argparse.ArgumentParser(
description="Create a Confluence page"
)
parser.add_argument(
"--space", "-s",
required=True,
help="Space key"
)
parser.add_argument(
"--title", "-t",
required=True,
help="Page title"
)
parser.add_argument(
"--body", "-b",
default="",
help="Page body in storage format (HTML) or markdown (with --markdown)"
)
parser.add_argument(
"--body-file",
help="Read body content from file (use '-' for stdin)"
)
parser.add_argument(
"--markdown", "-m",
action="store_true",
help="Treat body content as markdown and convert to Confluence format"
)
parser.add_argument(
"--parent", "-p",
help="Parent page ID"
)
parser.add_argument(
"--parent-title",
help="Parent page title (alternative to --parent)"
)
parser.add_argument(
"--labels", "-l",
help="Comma-separated labels to add"
)
parser.add_argument(
"--format", "-f",
choices=["compact", "text", "json"],
default="compact",
help="Output format (default: compact)"
)
args = parser.parse_args()
# Check environment
base_url = os.environ.get("CONFLUENCE_BASE_URL", "")
if not base_url:
print("ERROR: CONFLUENCE_BASE_URL environment variable required", file=sys.stderr)
sys.exit(1)
# Initialize cache
cache = ConfluenceCache()
try:
# Get space ID
space = cache.get_space_by_key(args.space)
if not space:
# Try to refresh spaces
cache.refresh_spaces()
space = cache.get_space_by_key(args.space)
if not space:
print(f"ERROR: Space '{args.space}' not found", file=sys.stderr)
sys.exit(1)
space_id = space["id"]
# Get body content
body = args.body
if args.body_file:
if args.body_file == "-":
body = sys.stdin.read()
else:
with open(args.body_file, "r") as f:
body = f.read()
# Convert markdown to Confluence format if requested
if args.markdown and body:
body = markdown_to_confluence(body)
# Resolve parent
parent_id = args.parent
if args.parent_title and not parent_id:
parent_page = cache.get_page_by_title(args.space, args.parent_title)
if parent_page:
parent_id = parent_page["id"]
else:
print(f"ERROR: Parent page '{args.parent_title}' not found in space {args.space}", file=sys.stderr)
sys.exit(1)
# Build request payload (using v2 API)
payload = {
"spaceId": space_id,
"title": args.title,
"body": {
"representation": "storage",
"value": body or "<p></p>" # Empty paragraph if no body
}
}
if parent_id:
payload["parentId"] = parent_id
# Create page
result = cache._api_request("/pages", method="POST", data=payload)
page_data = {
"id": result["id"],
"title": result["title"],
"space": args.space,
"parentId": parent_id,
}
# Add labels if specified
if args.labels:
label_list = [l.strip() for l in args.labels.split(",") if l.strip()]
if label_list:
label_payload = [{"name": label} for label in label_list]
try:
cache._api_request(
f"/pages/{result['id']}/labels",
method="POST",
data=label_payload
)
except RuntimeError as e:
print(f"Warning: Failed to add labels: {e}", file=sys.stderr)
# Invalidate related caches
cache.invalidate_page(result["id"])
# Format output
if args.format == "compact":
output = format_compact(page_data, base_url)
elif args.format == "text":
output = format_text(page_data, base_url)
else:
output = format_json(page_data, base_url)
print(output)
except EnvironmentError as e:
print(f"ERROR: {e}", file=sys.stderr)
sys.exit(1)
except RuntimeError as e:
print(f"ERROR: {e}", file=sys.stderr)
sys.exit(1)
except ConnectionError as e:
print(f"ERROR: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()