| name | atlassian-attachments |
| description | Attach documents, screenshots, PDFs, and files to Jira issues and Confluence pages via REST API. Use when uploading evidence, documentation, or media to Atlassian products. |
Atlassian Attachments Skill
Attach files, screenshots, and documents to Jira issues and Confluence pages using the Atlassian REST API.
Authentication Setup
API Token (Required)
Generate an API token at: https://id.atlassian.com/manage-profile/security/api-tokens
Environment Variables
export ATLASSIAN_DOMAIN="your-domain"
export ATLASSIAN_EMAIL="your-email@example.com"
export ATLASSIAN_API_TOKEN="your-api-token"
Setup via .envrc (Recommended)
If environment variables are not set, add them to .envrc in your project root for automatic loading with direnv:
# .envrc
export ATLASSIAN_DOMAIN="your-domain"
export ATLASSIAN_EMAIL="your-email@example.com"
export ATLASSIAN_API_TOKEN="your-api-token"
Then allow the file:
direnv allow
Security Note: Add .envrc to .gitignore to prevent committing credentials:
echo ".envrc" >> .gitignore
Check Environment Setup
# Verify variables are set
echo "Domain: ${ATLASSIAN_DOMAIN:-NOT SET}"
echo "Email: ${ATLASSIAN_EMAIL:-NOT SET}"
echo "Token: ${ATLASSIAN_API_TOKEN:+SET}"
If any show "NOT SET", prompt the user to configure .envrc.
Base URLs
Jira: https://{domain}.atlassian.net/rest/api/3
Confluence: https://{domain}.atlassian.net/wiki/rest/api
Jira REST API - Upload Attachments
Endpoint
POST https://{domain}.atlassian.net/rest/api/3/issue/{issueIdOrKey}/attachments
Required Headers
| Header | Value | Purpose |
|---|---|---|
X-Atlassian-Token |
no-check |
CSRF protection bypass (required) |
Content-Type |
multipart/form-data |
File upload format |
cURL Command
curl --location --request POST \
'https://your-domain.atlassian.net/rest/api/3/issue/PROJ-123/attachments' \
-u 'email@example.com:<api_token>' \
-H 'X-Atlassian-Token: no-check' \
--form 'file=@"./screenshots/bug-evidence.png"'
Python Example
import requests
from requests.auth import HTTPBasicAuth
def upload_jira_attachment(domain, email, api_token, issue_key, file_path):
url = f"https://{domain}.atlassian.net/rest/api/3/issue/{issue_key}/attachments"
auth = HTTPBasicAuth(email, api_token)
headers = {
"X-Atlassian-Token": "no-check"
}
with open(file_path, 'rb') as file:
files = {'file': file}
response = requests.post(url, auth=auth, headers=headers, files=files)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Upload failed: {response.status_code} - {response.text}")
# Usage
result = upload_jira_attachment(
domain="your-domain",
email="your-email@example.com",
api_token="your-api-token",
issue_key="PROJ-123",
file_path="./screenshots/bug-evidence.png"
)
Bash Script - Multiple Files
#!/bin/bash
DOMAIN="your-domain"
EMAIL="your-email@example.com"
API_TOKEN="your-api-token"
ISSUE_KEY="PROJ-123"
FILES_DIR="./qa-tests/screenshots/"
for file in "$FILES_DIR"*.png; do
echo "Uploading: $file"
curl --silent --location --request POST \
"https://${DOMAIN}.atlassian.net/rest/api/3/issue/${ISSUE_KEY}/attachments" \
-u "${EMAIL}:${API_TOKEN}" \
-H "X-Atlassian-Token: no-check" \
--form "file=@\"$file\""
echo " Done"
done
Confluence REST API - Upload Attachments
Endpoint
POST https://{domain}.atlassian.net/wiki/rest/api/content/{pageId}/child/attachment
Required Headers
| Header | Value | Purpose |
|---|---|---|
X-Atlassian-Token |
nocheck |
CSRF protection bypass (required) |
Content-Type |
multipart/form-data |
File upload format |
cURL Command - Basic Auth
curl -u "${USER_EMAIL}:${API_TOKEN}" \
-X POST \
-H "X-Atlassian-Token: nocheck" \
-F "file=@./diagram.png" \
-F "comment=Uploaded via REST API" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}/child/attachment"
cURL Command - Personal Access Token
curl -X POST \
-H "Authorization: Bearer ${PAT_TOKEN}" \
-H "X-Atlassian-Token: no-check" \
-H "Content-Type: multipart/form-data" \
-F "file=@./document.pdf" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}/child/attachment"
Python Example
import requests
from requests.auth import HTTPBasicAuth
def upload_confluence_attachment(domain, email, api_token, page_id, file_path, comment=""):
url = f"https://{domain}.atlassian.net/wiki/rest/api/content/{page_id}/child/attachment"
auth = HTTPBasicAuth(email, api_token)
headers = {
"X-Atlassian-Token": "nocheck"
}
with open(file_path, 'rb') as file:
files = {'file': file}
data = {'comment': comment} if comment else {}
response = requests.post(url, auth=auth, headers=headers, files=files, data=data)
if response.status_code in [200, 201]:
return response.json()
else:
raise Exception(f"Upload failed: {response.status_code} - {response.text}")
# Usage
result = upload_confluence_attachment(
domain="your-domain",
email="your-email@example.com",
api_token="your-api-token",
page_id="123456789",
file_path="./docs/architecture.png",
comment="Architecture diagram v2"
)
Get Page ID by Title
# Find page ID from title
curl -u "${EMAIL}:${API_TOKEN}" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content?title=Page%20Title&spaceKey=SPACE" \
| jq '.results[0].id'
Embed Attachment in Page Content
After uploading, the attachment is in the page's attachment list but NOT embedded in content. You must update the page body to display it.
Important: Use Markdown, Not Wiki Markup
| Format | Syntax | Works with API? |
|---|---|---|
| Wiki markup | !image.png! |
NO - Not converted |
| Markdown |  |
YES - Converted to storage format |
| Storage format | <ac:image>...</ac:image> |
YES - Native format |
Key insight: Markdown image syntax gets automatically converted to Confluence storage format when using the API.
CRITICAL: Storage Format for Attachments vs External URLs
When using storage format directly, you MUST use the correct element for referencing attachments:
| Reference Type | Element | Use Case |
|---|---|---|
| Page attachment | <ri:attachment ri:filename="..."/> |
Files uploaded to the page |
| External URL | <ri:url ri:value="..."/> |
External image URLs |
WRONG - Using ri:url for attachments (images won't display):
<ac:image ac:src="screenshot.png">
<ri:url ri:value="screenshot.png" />
</ac:image>
CORRECT - Using ri:attachment for uploaded files:
<ac:image>
<ri:attachment ri:filename="screenshot.png" />
</ac:image>
The ri:url element is for external URLs only. For files uploaded as attachments to the page, you MUST use ri:attachment with ri:filename.
Method 1: Markdown (Recommended)
Use representation: "wiki" with Markdown syntax:
curl -u "${EMAIL}:${API_TOKEN}" \
-X PUT \
-H "Content-Type: application/json" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}" \
-d '{
"version": {"number": NEW_VERSION},
"title": "Page Title",
"type": "page",
"body": {
"wiki": {
"value": "# My Page\n\nHere is the diagram:\n\n\n\nMore content here.",
"representation": "wiki"
}
}
}'
Method 2: Storage Format (Direct)
Use native Confluence storage format with representation: "storage":
curl -u "${EMAIL}:${API_TOKEN}" \
-X PUT \
-H "Content-Type: application/json" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}" \
-d '{
"version": {"number": NEW_VERSION},
"title": "Page Title",
"type": "page",
"body": {
"storage": {
"value": "<p>Here is the diagram:</p><ac:image ac:align=\"center\" ac:width=\"800\"><ri:attachment ri:filename=\"architecture.png\"/></ac:image>",
"representation": "storage"
}
}
}'
Storage Format Image Options
IMPORTANT: Always use <ri:attachment ri:filename="..."/> for page attachments, never <ri:url>.
RECOMMENDED for QA screenshots: Use ac:width="600" to prevent images from being too wide and hindering readability:
<!-- RECOMMENDED: Centered image with controlled width (best for QA screenshots) -->
<ac:image ac:align="center" ac:layout="center" ac:width="600">
<ri:attachment ri:filename="screenshot.png"/>
</ac:image>
<!-- Basic image (attachment) - will be full width, may be too large -->
<ac:image>
<ri:attachment ri:filename="screenshot.png"/>
</ac:image>
<!-- Element screenshots (smaller width for UI elements) -->
<ac:image ac:align="center" ac:layout="center" ac:width="400">
<ri:attachment ri:filename="button-element.png"/>
</ac:image>
<!-- Full-width diagram (use sparingly) -->
<ac:image ac:align="center" ac:layout="center" ac:width="800">
<ri:attachment ri:filename="architecture-diagram.png"/>
</ac:image>
<!-- As thumbnail (clickable to expand) -->
<ac:image ac:thumbnail="true">
<ri:attachment ri:filename="photo.jpg"/>
</ac:image>
<!-- With border -->
<ac:image ac:border="true" ac:width="400">
<ri:attachment ri:filename="ui-mockup.png"/>
</ac:image>
<!-- External URL (only for images NOT uploaded as attachments) -->
<ac:image>
<ri:url ri:value="https://example.com/external-image.png"/>
</ac:image>
Width Guidelines:
| Image Type | Recommended Width | Notes |
|---|---|---|
| Full page screenshots | 600 |
Readable without scrolling |
| Element screenshots | 300-400 |
Small UI components |
| Architecture diagrams | 800 |
Complex diagrams need more space |
| Thumbnails | Use ac:thumbnail="true" |
Clickable to expand |
Python Example - Upload and Embed
import requests
from requests.auth import HTTPBasicAuth
import json
def upload_and_embed_image(domain, email, api_token, page_id, file_path, alt_text=""):
base_url = f"https://{domain}.atlassian.net/wiki/rest/api"
auth = HTTPBasicAuth(email, api_token)
filename = file_path.split('/')[-1]
# 1. Upload attachment
upload_url = f"{base_url}/content/{page_id}/child/attachment"
headers = {"X-Atlassian-Token": "nocheck"}
with open(file_path, 'rb') as f:
files = {'file': f}
response = requests.post(upload_url, auth=auth, headers=headers, files=files)
if response.status_code not in [200, 201]:
raise Exception(f"Upload failed: {response.text}")
# 2. Get current page version
page_url = f"{base_url}/content/{page_id}?expand=body.wiki,version"
page = requests.get(page_url, auth=auth).json()
current_version = page['version']['number']
title = page['title']
# 3. Update page with embedded image using Markdown
update_url = f"{base_url}/content/{page_id}"
# Get existing content or start fresh
existing_content = page.get('body', {}).get('wiki', {}).get('value', '')
# Append image in Markdown format
new_content = f"{existing_content}\n\n"
payload = {
"version": {"number": current_version + 1},
"title": title,
"type": "page",
"body": {
"wiki": {
"value": new_content,
"representation": "wiki"
}
}
}
response = requests.put(
update_url,
auth=auth,
headers={"Content-Type": "application/json"},
data=json.dumps(payload)
)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Update failed: {response.text}")
# Usage
upload_and_embed_image(
domain="your-domain",
email="your-email@example.com",
api_token="your-api-token",
page_id="123456789",
file_path="./screenshots/feature-demo.png",
alt_text="Feature Demo Screenshot"
)
Complete Workflow Script
#!/bin/bash
# upload-and-embed.sh - Upload image and embed in Confluence page
DOMAIN="${ATLASSIAN_DOMAIN}"
EMAIL="${ATLASSIAN_EMAIL}"
API_TOKEN="${ATLASSIAN_API_TOKEN}"
PAGE_ID="$1"
FILE_PATH="$2"
FILENAME=$(basename "$FILE_PATH")
# 1. Upload the attachment
echo "Uploading ${FILENAME}..."
curl -s -u "${EMAIL}:${API_TOKEN}" \
-X POST \
-H "X-Atlassian-Token: nocheck" \
-F "file=@${FILE_PATH}" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}/child/attachment" > /dev/null
# 2. Get current page version
VERSION=$(curl -s -u "${EMAIL}:${API_TOKEN}" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}?expand=version" \
| jq '.version.number')
TITLE=$(curl -s -u "${EMAIL}:${API_TOKEN}" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}" \
| jq -r '.title')
# 3. Update page with embedded image (Markdown format)
NEW_VERSION=$((VERSION + 1))
echo "Embedding image in page (version ${NEW_VERSION})..."
curl -s -u "${EMAIL}:${API_TOKEN}" \
-X PUT \
-H "Content-Type: application/json" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}" \
-d "{
\"version\": {\"number\": ${NEW_VERSION}},
\"title\": \"${TITLE}\",
\"type\": \"page\",
\"body\": {
\"wiki\": {
\"value\": \"\",
\"representation\": \"wiki\"
}
}
}" > /dev/null
echo "Done! Image embedded in page."
Supported File Types
Jira Attachments
| Category | Extensions | Max Size |
|---|---|---|
| Images | .png, .jpg, .jpeg, .gif, .svg, .webp |
10 MB |
| Documents | .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx |
10 MB |
| Text | .txt, .md, .csv, .json, .xml, .yaml |
10 MB |
| Archives | .zip, .tar, .gz |
10 MB |
| Code | .js, .py, .java, .ts, .html, .css |
10 MB |
Confluence Attachments
| Category | Extensions | Max Size |
|---|---|---|
| Images | .png, .jpg, .jpeg, .gif, .svg |
25 MB |
| Documents | .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx |
100 MB |
| Media | .mp4, .mov, .mp3 |
100 MB |
| Design | .sketch, .fig, .psd, .ai |
100 MB |
Workflow Examples
Attach QA Screenshot to Jira Issue
# Single screenshot
curl --location --request POST \
"https://${DOMAIN}.atlassian.net/rest/api/3/issue/BUG-456/attachments" \
-u "${EMAIL}:${API_TOKEN}" \
-H "X-Atlassian-Token: no-check" \
--form "file=@./qa-tests/screenshots/QA-20250105-001/error-state.png"
Upload All Test Evidence
#!/bin/bash
ISSUE_KEY="$1"
SCREENSHOT_DIR="$2"
for file in "$SCREENSHOT_DIR"/*; do
echo "Uploading: $(basename $file)"
curl --silent --location --request POST \
"https://${DOMAIN}.atlassian.net/rest/api/3/issue/${ISSUE_KEY}/attachments" \
-u "${EMAIL}:${API_TOKEN}" \
-H "X-Atlassian-Token: no-check" \
--form "file=@\"$file\"" > /dev/null
done
echo "All files uploaded to ${ISSUE_KEY}"
Upload Documentation to Confluence Page
# Upload PDF to specific page
PAGE_ID="123456789"
curl -u "${EMAIL}:${API_TOKEN}" \
-X POST \
-H "X-Atlassian-Token: nocheck" \
-F "file=@./docs/api-specification.pdf" \
-F "comment=API Spec v3.0" \
"https://${DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}/child/attachment"
Attachment Naming Conventions
For QA Evidence
{test-id}-{description}-{timestamp}.{ext}
Examples:
- QA-20250105-001-login-error-20250105T143022.png
- QA-20250105-001-form-validation-20250105T143045.png
For Bug Reports
{issue-key}-{description}.{ext}
Examples:
- BUG-123-stack-trace.txt
- BUG-123-screenshot-before.png
- BUG-123-screenshot-after.png
For Documentation
{feature}-{version}-{type}.{ext}
Examples:
- auth-flow-v2-diagram.png
- api-v3-specification.pdf
- deployment-guide-v1.docx
QA Screenshot to Confluence Mapping
Local QA Structure vs Confluence Attachments
The QA test screenshots use a specific local directory structure that needs mapping when uploading to Confluence.
Local Structure (product-design plugin)
qa-tests/
├── active/
│ └── QA-20250105-001-login.md # Test document
└── screenshots/
└── QA-20250105-001/ # Test ID folder
├── 01-initial-state.png
├── 02-form-filled.png
├── 03-success-state.png
└── elements/
├── login-button.png
├── email-field.png
└── password-field.png
Confluence Attachment Names (Flattened)
When uploading to Confluence, flatten the structure with prefixed names:
| Local Path | Confluence Attachment Name |
|---|---|
QA-20250105-001/01-initial-state.png |
QA-20250105-001-01-initial-state.png |
QA-20250105-001/02-form-filled.png |
QA-20250105-001-02-form-filled.png |
QA-20250105-001/elements/login-button.png |
QA-20250105-001-elem-login-button.png |
QA-20250105-001/elements/email-field.png |
QA-20250105-001-elem-email-field.png |
Naming Rules
- Prefix with test-id: All screenshots get
{test-id}-prefix - Element prefix: Files from
elements/get-elem-infix - No nested folders: Confluence attachments are flat
- Preserve sequence: Keep
01-,02-numbering
Upload Script with Renaming
#!/bin/bash
# upload-qa-screenshots-confluence.sh
# Upload QA screenshots to Confluence with proper naming
TEST_ID="$1"
PAGE_ID="$2"
LOCAL_DIR="qa-tests/screenshots/${TEST_ID}"
# Upload main screenshots
for file in "$LOCAL_DIR"/*.png; do
filename=$(basename "$file")
# Prefix with test-id
new_name="${TEST_ID}-${filename}"
echo "Uploading: $new_name"
curl -s -u "${ATLASSIAN_EMAIL}:${ATLASSIAN_API_TOKEN}" \
-X POST \
-H "X-Atlassian-Token: nocheck" \
-F "file=@${file};filename=${new_name}" \
"https://${ATLASSIAN_DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}/child/attachment"
done
# Upload element screenshots with elem- infix
if [ -d "$LOCAL_DIR/elements" ]; then
for file in "$LOCAL_DIR/elements"/*.png; do
filename=$(basename "$file")
# Add elem- infix
new_name="${TEST_ID}-elem-${filename}"
echo "Uploading element: $new_name"
curl -s -u "${ATLASSIAN_EMAIL}:${ATLASSIAN_API_TOKEN}" \
-X POST \
-H "X-Atlassian-Token: nocheck" \
-F "file=@${file};filename=${new_name}" \
"https://${ATLASSIAN_DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}/child/attachment"
done
fi
echo "Done! All screenshots uploaded to page ${PAGE_ID}"
Python Upload with Mapping
import os
import requests
from requests.auth import HTTPBasicAuth
from pathlib import Path
def upload_qa_screenshots_to_confluence(
domain: str,
email: str,
api_token: str,
page_id: str,
test_id: str,
local_dir: str = "qa-tests/screenshots"
):
"""Upload QA screenshots with Confluence-compatible naming."""
base_url = f"https://{domain}.atlassian.net/wiki/rest/api"
auth = HTTPBasicAuth(email, api_token)
headers = {"X-Atlassian-Token": "nocheck"}
screenshot_dir = Path(local_dir) / test_id
uploaded = []
# Upload main screenshots
for file in screenshot_dir.glob("*.png"):
confluence_name = f"{test_id}-{file.name}"
with open(file, 'rb') as f:
files = {'file': (confluence_name, f, 'image/png')}
response = requests.post(
f"{base_url}/content/{page_id}/child/attachment",
auth=auth, headers=headers, files=files
)
if response.ok:
uploaded.append({"local": str(file), "confluence": confluence_name})
# Upload element screenshots
elements_dir = screenshot_dir / "elements"
if elements_dir.exists():
for file in elements_dir.glob("*.png"):
confluence_name = f"{test_id}-elem-{file.name}"
with open(file, 'rb') as f:
files = {'file': (confluence_name, f, 'image/png')}
response = requests.post(
f"{base_url}/content/{page_id}/child/attachment",
auth=auth, headers=headers, files=files
)
if response.ok:
uploaded.append({"local": str(file), "confluence": confluence_name})
return uploaded
# Generate mapping table for documentation
def generate_mapping_table(uploaded: list) -> str:
"""Generate markdown table of local-to-confluence name mapping."""
lines = ["| Local Path | Confluence Name |", "|------------|-----------------|"]
for item in uploaded:
lines.append(f"| `{item['local']}` | `{item['confluence']}` |")
return "\n".join(lines)
Updating Markdown References
After upload, update the QA test document to use Confluence attachment names:
Before (local references):


After (Confluence references):


Automated Reference Update Script
import re
from pathlib import Path
def update_qa_doc_for_confluence(qa_doc_path: str, test_id: str) -> str:
"""Update QA doc image references for Confluence."""
content = Path(qa_doc_path).read_text()
# Pattern: ./screenshots/{test-id}/filename.png
# Replace with: {test-id}-filename.png
content = re.sub(
rf'\./screenshots/{test_id}/([^)]+\.png)',
rf'{test_id}-\1',
content
)
# Pattern: ./screenshots/{test-id}/elements/filename.png
# Replace with: {test-id}-elem-filename.png
content = re.sub(
rf'{test_id}-elements/([^)]+\.png)',
rf'{test_id}-elem-\1',
content
)
return content
Fixing Broken Image References in Existing Pages
If a page was created with ri:url instead of ri:attachment, images won't display. To fix:
#!/bin/bash
# fix-confluence-image-refs.sh - Fix broken image references in Confluence page
PAGE_ID="$1"
# 1. Get current page content
curl -s -u "${ATLASSIAN_EMAIL}:${ATLASSIAN_API_TOKEN}" \
"https://${ATLASSIAN_DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}?expand=body.storage,version" \
> /tmp/page.json
VERSION=$(jq '.version.number' /tmp/page.json)
TITLE=$(jq -r '.title' /tmp/page.json)
# 2. Extract and fix the content
jq -r '.body.storage.value' /tmp/page.json > /tmp/content.html
# Fix: Replace ri:url with ri:attachment for local filenames (not full URLs)
# This converts: <ri:url ri:value="filename.png" />
# To: <ri:attachment ri:filename="filename.png" />
sed -i '' 's/<ri:url ri:value="\([^"]*\)" \/>/<ri:attachment ri:filename="\1" \/>/g' /tmp/content.html
# Remove ac:src attribute (not needed with ri:attachment)
sed -i '' 's/ ac:src="[^"]*"//g' /tmp/content.html
# 3. Update the page
NEW_VERSION=$((VERSION + 1))
CONTENT=$(cat /tmp/content.html | jq -Rs .)
curl -s -u "${ATLASSIAN_EMAIL}:${ATLASSIAN_API_TOKEN}" \
-X PUT \
-H "Content-Type: application/json" \
"https://${ATLASSIAN_DOMAIN}.atlassian.net/wiki/rest/api/content/${PAGE_ID}" \
-d "{
\"version\": {\"number\": ${NEW_VERSION}},
\"title\": \"${TITLE}\",
\"type\": \"page\",
\"body\": {
\"storage\": {
\"value\": ${CONTENT},
\"representation\": \"storage\"
}
}
}"
echo "Fixed image references in page ${PAGE_ID}"
Common symptoms of broken image references:
- Images show as broken/missing icons
- Images display with blob URLs like
blob:https://media.staging.atl-paas.net/... - Alt text shows but image doesn't load
Jira Attachment Commands
Add Attachment
Action: Add attachment to Jira issue
Issue: PROJ-123
File: /path/to/screenshot.png
Expected behavior:
- File uploaded to issue attachments
- Visible in Attachments section
- Downloadable by team members
List Attachments
Action: List all attachments on PROJ-123
Response format:
- screenshot.png (234 KB) - Added by John on 2025-01-05
- error-log.txt (12 KB) - Added by Jane on 2025-01-04
Delete Attachment
Action: Remove old-screenshot.png from PROJ-123
Note: Requires appropriate permissions
Confluence Attachment Commands
Add to Page
Action: Attach file to Confluence page
Space: TEAM
Page: "Sprint Review"
File: /path/to/presentation.pdf
Embed in Content
Action: Embed image in page content
Space: TEAM
Page: "Architecture Overview"
File: system-diagram.png
Position: After "System Components" heading
Width: 800px
Replace Attachment
Action: Update existing attachment
Space: TEAM
Page: "API Docs"
File: api-spec-v2.pdf
Replace: api-spec-v1.pdf
Integration with QA Workflows
Attach QA Test Evidence
When a QA test is executed:
Capture screenshots during test
qa-tests/screenshots/QA-20250105-001/ ├── 01-initial-state.png ├── 02-form-filled.png └── 03-error-state.pngCreate/update Jira issue
Create bug: "Login form validation not working" Project: QAAttach evidence
Attach all screenshots from qa-tests/screenshots/QA-20250105-001/ to the created issueAdd summary comment
"Test execution evidence attached: - [^01-initial-state.png] - Before test - [^02-form-filled.png] - Form with test data - [^03-error-state.png] - Error encountered"
Sync QA Documentation to Confluence
Action: Upload QA test procedure to Confluence
Steps:
1. Convert QA markdown to Confluence format
2. Create/update page in QA space
3. Attach all element screenshots
4. Embed screenshots in page content
Batch Operations
Upload Directory Contents
Prompt: "Upload all files from ./release-assets/ to the 'v2.0 Release' Confluence page"
Behavior:
- Scan directory for supported files
- Upload each file as attachment
- Report progress and results
Sync Screenshots to Issue
Prompt: "Sync screenshots from ./qa-tests/screenshots/PROJ-123/ to Jira issue PROJ-123"
Behavior:
- Compare local files with existing attachments
- Upload new files
- Optionally replace updated files
- Skip unchanged files
Error Handling
Common Errors
| Error | Cause | Resolution |
|---|---|---|
| File too large | Exceeds size limit | Compress or split file |
| Unsupported type | Extension not allowed | Convert to supported format |
| Permission denied | No attach permission | Request project/space access |
| Issue not found | Invalid issue key | Verify issue exists |
| Page not found | Invalid page title/space | Check space key and page title |
Handling Large Files
If file > max size:
1. For images: Compress or resize
2. For documents: Split into parts
3. For archives: Use cloud storage link instead
Alternative: Upload to cloud storage and link in description
Best Practices
Organization
- Use consistent naming - Follow naming conventions above
- Group related files - Attach all evidence for one issue together
- Add descriptions - Include context in comments
- Clean up old attachments - Remove outdated files
Performance
- Compress images before upload (PNG → optimized PNG or JPEG)
- Batch uploads when attaching multiple files
- Check existing attachments before uploading duplicates
Security
- Redact sensitive data from screenshots
- Check file contents before uploading logs
- Use appropriate spaces/projects for confidential docs
Confluence Macros for Attachments
Image Display
!filename.png! # Basic
!filename.png|width=600! # With width
!filename.png|thumbnail! # As thumbnail
File Links
[^filename.pdf] # Download link
[View Document^filename.pdf] # Custom link text
Gallery View
{gallery:include=*.png} # All PNG attachments
{gallery:include=screenshot-*} # Matching pattern
PDF Viewer
{viewfile:filename.pdf} # Inline PDF viewer
{viewfile:filename.pdf|height=600}