{"id":32532547,"url":"https://github.com/pchuri/confluence-cli","last_synced_at":"2026-05-03T12:00:39.267Z","repository":{"id":301364892,"uuid":"1009026205","full_name":"pchuri/confluence-cli","owner":"pchuri","description":"A powerful command-line interface for Atlassian Confluence","archived":false,"fork":false,"pushed_at":"2026-04-29T13:21:54.000Z","size":466,"stargazers_count":155,"open_issues_count":7,"forks_count":41,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-29T13:41:34.406Z","etag":null,"topics":["api-client","atlassian","automation","cli","command-line","confluence","developer-tools","documentation","javascript","nodejs","productivity","wiki"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/confluence-cli","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pchuri.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-26T13:10:15.000Z","updated_at":"2026-04-29T13:22:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"e1ca6ede-ecec-42e2-b357-1a40668a905d","html_url":"https://github.com/pchuri/confluence-cli","commit_stats":null,"previous_names":["pchuri/confluence-cli"],"tags_count":72,"template":false,"template_full_name":null,"purl":"pkg:github/pchuri/confluence-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchuri%2Fconfluence-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchuri%2Fconfluence-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchuri%2Fconfluence-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchuri%2Fconfluence-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pchuri","download_url":"https://codeload.github.com/pchuri/confluence-cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchuri%2Fconfluence-cli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32555850,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T00:31:16.350Z","status":"online","status_checked_at":"2026-05-03T02:00:09.297Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","atlassian","automation","cli","command-line","confluence","developer-tools","documentation","javascript","nodejs","productivity","wiki"],"created_at":"2025-10-28T12:48:59.113Z","updated_at":"2026-05-03T12:00:39.239Z","avatar_url":"https://github.com/pchuri.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Confluence CLI\n\nA powerful command-line interface for Atlassian Confluence that allows you to read, search, and manage your Confluence content from the terminal.\n\n## Features\n\n- 📖 **Read pages** - Get page content in text or HTML format\n- 🔍 **Search** - Find pages using Confluence's powerful search\n- ℹ️ **Page info** - Get detailed information about pages\n- 🏠 **List spaces** - View available Confluence spaces\n- ✏️ **Create pages** - Create new pages with support for Markdown, HTML, or Storage format\n- 📝 **Update pages** - Update existing page content and titles\n- 🗑️ **Delete pages** - Delete (or move to trash) pages by ID or URL\n- 📎 **Attachments** - List, download, upload, or delete page attachments\n- 🏷️ **Properties** - List, get, set, and delete content properties (key-value metadata)\n- 💬 **Comments** - List, create, and delete page comments (footer or inline)\n- 📦 **Export** - Save a page and its attachments to a local folder\n- 🛠️ **Edit workflow** - Export page content for editing and re-import\n- 🔀 **Profiles** - Manage multiple Confluence instances with named configuration profiles\n- 🔒 **Read-only mode** - Profile-level write protection for safe AI agent usage\n- 🔄 **Format conversion** - Convert between Markdown, HTML, Storage, and text formats locally (no server required)\n- 🔧 **Easy setup** - Simple configuration with environment variables or interactive setup\n\n## Installation\n\n### Homebrew (macOS/Linux)\n\n```bash\nbrew install pchuri/tap/confluence-cli\n```\n\n### npm\n\n```bash\nnpm install -g confluence-cli\n```\n\nOr run directly with npx:\n```bash\nnpx confluence-cli\n```\n\n## Claude Code Integration\n\nconfluence-cli ships as a [Claude Code plugin](https://docs.anthropic.com/en/docs/claude-code/plugins). Once installed, Claude Code understands all confluence-cli commands automatically and receives updates when the skill is improved.\n\n### Option 1: Install as Plugin (recommended)\n\nAdd the marketplace and install the plugin:\n\n```bash\n/plugin marketplace add pchuri/confluence-cli\n/plugin install confluence@pchuri-confluence-cli\n```\n\n### Option 2: Install Skill manually\n\nIf you prefer not to use the plugin system, copy the skill documentation into your project:\n\n```bash\nconfluence install-skill\n```\n\nThis creates `.claude/skills/confluence/SKILL.md` in your current directory. Claude Code picks it up automatically.\n\n## Quick Start\n\n1. **Initialize configuration:**\n   ```bash\n   confluence init\n   ```\n\n2. **Read a page:**\n   ```bash\n   confluence read 123456789\n   ```\n\n3. **Search for pages:**\n   ```bash\n   confluence search \"my search term\"\n   ```\n\n4. **List child pages:**\n   ```bash\n   confluence children 123456789\n   ```\n\n5. **Create a new page:**\n   ```bash\n   confluence create \"My New Page\" SPACEKEY --content \"Hello World!\"\n   ```\n\n6. **Update a page:**\n   ```bash\n   confluence update 123456789 --content \"Updated content\"\n   ```\n\n## Configuration\n\n### Option 1: Interactive Setup\n```bash\nconfluence init\n```\n\nThe wizard helps you choose the right API endpoint and authentication method. It recommends `/wiki/rest/api` for Atlassian Cloud domains (e.g., `*.atlassian.net`) and `/rest/api` for self-hosted/Data Center instances, then prompts for Basic (email/username + token/password), Bearer, or client-certificate (mTLS) authentication.\n\n### Option 2: Non-interactive Setup (CLI Flags)\n\nProvide all required configuration via command-line flags. Perfect for CI/CD pipelines, Docker builds, and AI coding agents.\n\n**Complete non-interactive mode** (all required fields provided):\n```bash\nconfluence init \\\n  --domain \"company.atlassian.net\" \\\n  --api-path \"/wiki/rest/api\" \\\n  --auth-type \"basic\" \\\n  --email \"user@example.com\" \\\n  --token \"your-api-token\"\n```\n\n**Scoped API token** (recommended for agents — least privilege):\n```bash\n# Replace \u003cyour-cloud-id\u003e with your actual Cloud ID\nconfluence init \\\n  --domain \"api.atlassian.com\" \\\n  --api-path \"/ex/confluence/\u003cyour-cloud-id\u003e/wiki/rest/api\" \\\n  --auth-type \"basic\" \\\n  --email \"user@example.com\" \\\n  --token \"your-scoped-token\"\n```\n\n**Named profile** (save to a specific profile):\n```bash\nconfluence --profile staging init \\\n  --domain \"staging.example.com\" \\\n  --api-path \"/rest/api\" \\\n  --auth-type \"bearer\" \\\n  --token \"your-personal-access-token\"\n```\n\n**mTLS profile** (self-hosted or reverse-proxied Confluence APIs):\n```bash\nconfluence --profile corp init \\\n  --domain \"docs.example.com\" \\\n  --api-path \"/confluence/rest/api\" \\\n  --auth-type \"mtls\" \\\n  --tls-client-cert \"~/.certs/client.pem\" \\\n  --tls-client-key \"~/.certs/client.key\" \\\n  --tls-ca-cert \"~/.certs/ca-chain.pem\"\n```\n\n**Cookie authentication profile** (Enterprise SSO):\n```bash\nconfluence --profile sso init \\\n  --domain \"confluence.company.com\" \\\n  --api-path \"/rest/api\" \\\n  --auth-type \"cookie\" \\\n  --cookie \"JSESSIONID=abc123xyz...\"\n\n# Multiple cookies are also supported:\nconfluence --profile sso init \\\n  --domain \"confluence.company.com\" \\\n  --auth-type \"cookie\" \\\n  --cookie \"JSESSIONID=abc123; XSRF-TOKEN=xyz789\"\n```\n\n**Hybrid mode** (some fields provided, rest via prompts):\n```bash\n# Domain and token provided, will prompt for auth method and email\nconfluence init --domain \"company.atlassian.net\" --token \"your-api-token\"\n\n# Email indicates basic auth, will prompt for domain and token\nconfluence init --email \"user@example.com\" --token \"your-api-token\"\n```\n\n**Available flags:**\n- `-d, --domain \u003cdomain\u003e` - Confluence domain (e.g., `company.atlassian.net`)\n- `-p, --api-path \u003cpath\u003e` - REST API path (e.g., `/wiki/rest/api`)\n- `-a, --auth-type \u003ctype\u003e` - Authentication type: `basic`, `bearer`, `mtls`, or `cookie`\n- `-e, --email \u003cemail\u003e` - Email or username for basic authentication\n- `-t, --token \u003ctoken\u003e` - API token or password\n- `-c, --cookie \u003ccookie\u003e` - Cookie for Enterprise SSO authentication (e.g., `\"JSESSIONID=...\"`)\n- `--tls-client-cert \u003cpath\u003e` - Client certificate for mTLS authentication\n- `--tls-client-key \u003cpath\u003e` - Client private key for mTLS authentication\n- `--tls-ca-cert \u003cpath\u003e` - Optional CA certificate chain for mTLS authentication\n- `--read-only` - Enable read-only mode (blocks all write operations)\n\n⚠️ **Security note:** While flags work, storing tokens in shell history is risky. Prefer environment variables (Option 3) for production environments.\n\n### Option 3: Environment Variables\n```bash\nexport CONFLUENCE_DOMAIN=\"your-domain.atlassian.net\"\nexport CONFLUENCE_API_TOKEN=\"your-api-token\"      # or password for on-premise (alias: CONFLUENCE_PASSWORD)\nexport CONFLUENCE_EMAIL=\"your.email@example.com\"  # required for basic auth (alias: CONFLUENCE_USERNAME for on-premise)\nexport CONFLUENCE_API_PATH=\"/wiki/rest/api\"         # Cloud default; use /rest/api for Server/DC\n# Optional: set to 'bearer' for self-hosted/Data Center instances\nexport CONFLUENCE_AUTH_TYPE=\"basic\"\n# Optional: select a named profile (overridden by --profile flag)\nexport CONFLUENCE_PROFILE=\"default\"\n```\n\n**mTLS environment variables**:\n```bash\nexport CONFLUENCE_DOMAIN=\"docs.example.com\"\nexport CONFLUENCE_API_PATH=\"/confluence/rest/api\"\nexport CONFLUENCE_AUTH_TYPE=\"mtls\"\nexport CONFLUENCE_TLS_CLIENT_CERT=\"~/.certs/client.pem\"\nexport CONFLUENCE_TLS_CLIENT_KEY=\"~/.certs/client.key\"\nexport CONFLUENCE_TLS_CA_CERT=\"~/.certs/ca-chain.pem\"  # optional\n```\n\n**Cookie environment variables** (Enterprise SSO):\n```bash\nexport CONFLUENCE_DOMAIN=\"confluence.company.com\"\nexport CONFLUENCE_API_PATH=\"/rest/api\"\nexport CONFLUENCE_AUTH_TYPE=\"cookie\"\nexport CONFLUENCE_COOKIE=\"JSESSIONID=abc123xyz...\"\n```\n\n**Scoped API token** (recommended for agents):\n```bash\nexport CONFLUENCE_DOMAIN=\"api.atlassian.com\"\nexport CONFLUENCE_API_PATH=\"/ex/confluence/\u003cyour-cloud-id\u003e/wiki/rest/api\"\nexport CONFLUENCE_AUTH_TYPE=\"basic\"\nexport CONFLUENCE_EMAIL=\"user@example.com\"\nexport CONFLUENCE_API_TOKEN=\"your-scoped-token\"\n```\n\n`CONFLUENCE_API_PATH` defaults to `/wiki/rest/api` for Atlassian Cloud domains and `/rest/api` otherwise. Override it when your site lives under a custom reverse proxy or on-premises path. `CONFLUENCE_AUTH_TYPE` defaults to `basic` when an email is present and falls back to `bearer` otherwise. For `mtls`, set `CONFLUENCE_TLS_CLIENT_CERT` and `CONFLUENCE_TLS_CLIENT_KEY`; `CONFLUENCE_TLS_CA_CERT` is optional.\n\n**Custom domains on Confluence Cloud:**\n\nIf your Confluence Cloud instance uses a custom domain (e.g., `wiki.example.org` instead of `*.atlassian.net`), the CLI may misidentify it as a Server/Data Center instance and produce broken link formats. Set `CONFLUENCE_FORCE_CLOUD=true` to override the automatic detection:\n\n```bash\nexport CONFLUENCE_FORCE_CLOUD=true\n```\n\nOr add `\"forceCloud\": true` to your profile in `~/.confluence-cli/config.json`:\n\n```json\n{\n  \"profiles\": {\n    \"default\": {\n      \"domain\": \"wiki.example.org\",\n      \"forceCloud\": true\n    }\n  }\n}\n```\n\n**Link rendering on Cloud (`linkStyle`):**\n\nSome Cloud instances — particularly custom-domain Cloud setups — fail to render smart links (`\u003ca data-card-appearance=\"inline\"\u003e`) and show \"Cannot handle: DefaultLink\" errors instead. If you hit this, set `linkStyle` to `plain` to emit simple `\u003ca href\u003e` tags, which render reliably everywhere:\n\n```bash\nexport CONFLUENCE_LINK_STYLE=plain\n```\n\nOr per-profile:\n\n```json\n{\n  \"profiles\": {\n    \"default\": {\n      \"domain\": \"wiki.example.org\",\n      \"forceCloud\": true,\n      \"linkStyle\": \"plain\"\n    }\n  }\n}\n```\n\nValid values: `smart` (Cloud smart links), `plain` (simple `\u003ca href\u003e`), `wiki` (Server/DC `ac:link`). When unset, the CLI picks `smart` for Cloud and `wiki` for Server/DC — existing behavior is unchanged.\n\n**Read-only mode** (recommended for AI agents):\n```bash\nexport CONFLUENCE_READ_ONLY=true\n```\nWhen set, all write operations (`create`, `update`, `delete`, etc.) are blocked at the CLI level. The environment variable overrides the profile's `readOnly` setting.\n\n### Getting Your API Token\n\n**Atlassian Cloud:**\n1. Go to [Atlassian Account Settings](https://id.atlassian.com/manage-profile/security/api-tokens)\n2. Click \"Create API token\"\n3. Give it a label (e.g., \"confluence-cli\")\n4. Copy the generated token\n\n**Atlassian Cloud — Scoped API Token** (recommended for agents and automation):\n\nScoped tokens restrict access to specific Atlassian products and permissions, following the principle of least privilege. They use a different API gateway (`api.atlassian.com`) instead of your site domain.\n\n1. Create a scoped token in your [Atlassian Admin settings](https://admin.atlassian.com)\n2. Find your Cloud ID by visiting `https://\u003cyour-site\u003e.atlassian.net/_edge/tenant_info`\n3. Configure with:\n   - **Domain:** `api.atlassian.com`\n   - **API path:** `/ex/confluence/\u003cyour-cloud-id\u003e/wiki/rest/api`\n   - **Auth type:** `basic` (email + scoped token)\n\n**Required scopes for scoped API tokens:**\n\nWhen creating a scoped token, select the following [classic scopes](https://developer.atlassian.com/cloud/confluence/scopes-for-oauth-2-3LO-and-forge-apps/) based on your needs:\n\n| Scope | Required for |\n|-------|-------------|\n| `read:confluence-content.all` | Reading pages and blog posts (`read`, `info`) |\n| `read:confluence-content.summary` | Reading content summaries and metadata (`read`, `info`) |\n| `read:confluence-space.summary` | Listing spaces (`spaces`) |\n| `search:confluence` | Searching content (`search`) |\n| `readonly:content.attachment:confluence` | Downloading attachments (`attachments --download`) |\n| `write:confluence-content` | Creating and updating pages (`create`, `update`) |\n| `write:confluence-file` | Uploading attachments (`attachments --upload`) |\n| `write:confluence-space` | Managing spaces |\n\nFor **read-only** usage, select at minimum: `read:confluence-content.all`, `read:confluence-content.summary`, `read:confluence-space.summary`, and `search:confluence`.\n\n**On-premise / Data Center:** Use your Confluence username and password for basic authentication.\n\n**mTLS-protected Confluence APIs:** Some self-hosted or reverse-proxied deployments authenticate at the TLS layer with a client certificate instead of sending an application-level token. In these environments, configure `authType=mtls` and provide certificate paths via CLI flags or environment variables. No `Authorization` header will be sent in mTLS mode.\n\n**Enterprise SSO with Cookie Authentication:** For Confluence instances behind Enterprise SSO (SAML, OAuth, Okta, etc.) where API tokens or Basic/Bearer auth are not available, you can authenticate using session cookies. After logging in through your browser, extract the session cookie (typically `JSESSIONID` or similar) from your browser's dev tools and configure it via the `--cookie` flag or `CONFLUENCE_COOKIE` environment variable. The cookie is sent in the `Cookie` header instead of an `Authorization` header. Note that session cookies typically expire, so you'll need to refresh them periodically. For security, prefer `CONFLUENCE_COOKIE` env var or interactive prompt over `--cookie` flag since command-line arguments may be visible in shell history and process listings.\n\n## Usage\n\n### Read a Page\n```bash\n# Read by page ID\nconfluence read 123456789\n\n# Read native Confluence storage content\nconfluence read 123456789 --format storage\n\n# Read in markdown format\nconfluence read 123456789 --format markdown\n\n# Read by URL (must contain pageId parameter)\nconfluence read \"https://your-domain.atlassian.net/wiki/viewpage.action?pageId=123456789\"\n```\n\nUse `--format storage` when you need Confluence's native storage representation, especially for macros and other Confluence-specific markup.\n\n### Get Page Information\n```bash\nconfluence info 123456789\n\n# Emit machine-readable metadata\nconfluence info 123456789 --format json\n```\n\nExample JSON shape:\n```json\n{\n  \"id\": \"123456789\",\n  \"title\": \"Architecture Overview\",\n  \"type\": \"page\",\n  \"status\": \"current\",\n  \"spaceKey\": \"ENG\",\n  \"parentId\": \"100200300\",\n  \"version\": 7,\n  \"url\": \"https://your-domain.atlassian.net/wiki/spaces/ENG/pages/123456789/Architecture+Overview\"\n}\n```\n\n### Search Pages\n```bash\n# Basic search\nconfluence search \"search term\"\n\n# Limit results\nconfluence search \"search term\" --limit 5\n```\n\n### List or Download Attachments\n```bash\n# List all attachments on a page\nconfluence attachments 123456789\n\n# Filter by filename and limit the number returned\nconfluence attachments 123456789 --pattern \"*.png\" --limit 5\n\n# Download matching attachments to a directory\nconfluence attachments 123456789 --pattern \"*.png\" --download --dest ./downloads\n```\n\n### Upload Attachments\n```bash\n# Upload a single attachment\nconfluence attachment-upload 123456789 --file ./report.pdf\n\n# Upload multiple files with a comment\nconfluence attachment-upload 123456789 --file ./a.pdf --file ./b.png --comment \"v2\"\n\n# Replace an existing attachment by filename\nconfluence attachment-upload 123456789 --file ./diagram.png --replace\n```\n\n### Delete Attachments\n```bash\n# Delete an attachment by ID\nconfluence attachment-delete 123456789 998877\n\n# Skip confirmation\nconfluence attachment-delete 123456789 998877 --yes\n```\n\n### Content Properties\n```bash\n# List all properties on a page\nconfluence property-list 123456789\n\n# Get a specific property\nconfluence property-get 123456789 my-key\n\n# Set a property (creates or updates with auto-versioning)\nconfluence property-set 123456789 my-key --value '{\"color\":\"#ff0000\"}'\n\n# Set a property from a JSON file\nconfluence property-set 123456789 my-key --file ./property.json\n\n# Delete a property\nconfluence property-delete 123456789 my-key\n\n# Skip confirmation on delete\nconfluence property-delete 123456789 my-key --yes\n```\n\n### Comments\n```bash\n# List all comments (footer + inline)\nconfluence comments 123456789\n\n# List inline comments as markdown\nconfluence comments 123456789 --location inline --format markdown\n\n# Create a footer comment\nconfluence comment 123456789 --content \"Looks good to me!\"\n\n# Create an inline comment\nconfluence comment 123456789 \\\n  --location inline \\\n  --content \"Consider renaming this\" \\\n  --inline-selection \"foo\" \\\n  --inline-original-selection \"foo\"\n\n# Reply to a comment\nconfluence comment 123456789 --parent 998877 --content \"Agree with this\"\n\n# Delete a comment\nconfluence comment-delete 998877\n```\n\nInline comment creation note (Confluence Cloud): Creating inline comments requires editor-generated highlight metadata (`matchIndex`, `lastFetchTime`, `serializedHighlights`, plus the selection text). The public REST API does not provide these fields, so inline creation and inline replies can fail with a 400 unless you supply the full `--inline-properties` payload captured from the editor. Footer comments and replies are fully supported.\n\n### Export a Page with Attachments\n```bash\n# Export page content (markdown by default) and all attachments\nconfluence export 123456789 --dest ./exports\n\n# Custom content format/filename and attachment filtering\nconfluence export 123456789 --format html --file content.html --pattern \"*.png\"\n\n# Skip attachments if you only need the content file\nconfluence export 123456789 --skip-attachments\n```\n\n### List Spaces\n```bash\nconfluence spaces\n```\n\n### List Child Pages\n```bash\n# List direct child pages\nconfluence children 123456789\n\n# List all descendants recursively\nconfluence children 123456789 --recursive\n\n# Display as tree structure\nconfluence children 123456789 --recursive --format tree\n\n# Show page IDs and URLs\nconfluence children 123456789 --show-id --show-url\n\n# Limit recursion depth\nconfluence children 123456789 --recursive --max-depth 3\n\n# Output as JSON for scripting\nconfluence children 123456789 --recursive --format json \u003e children.json\n```\n\n`children --format json` returns structured metadata for each page, including `id`, `title`, `type`, `status`, `spaceKey`, `parentId`, `version`, and `url`. Recursive output also includes `depth`, and when available, `ancestors`.\n\nExample recursive JSON item:\n```json\n{\n  \"pageId\": \"123456789\",\n  \"childCount\": 2,\n  \"children\": [\n    {\n      \"id\": \"200300400\",\n      \"title\": \"Child Page\",\n      \"type\": \"page\",\n      \"status\": \"current\",\n      \"spaceKey\": \"ENG\",\n      \"parentId\": \"123456789\",\n      \"version\": 4,\n      \"url\": \"https://your-domain.atlassian.net/wiki/spaces/ENG/pages/200300400/Child+Page\",\n      \"depth\": 1,\n      \"ancestors\": [\n        {\n          \"id\": \"123456789\",\n          \"type\": \"page\",\n          \"title\": \"Architecture Overview\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Find a Page by Title\n```bash\n# Find page by title\nconfluence find \"Project Documentation\"\n\n# Find page by title in a specific space\nconfluence find \"Project Documentation\" --space MYTEAM\n```\n\n### Create a New Page\n```bash\n# Create with inline content and markdown format\nconfluence create \"My New Page\" SPACEKEY --content \"**Hello** World!\" --format markdown\n\n# Create from a file\nconfluence create \"Documentation\" SPACEKEY --file ./content.md --format markdown\n```\n\n### Create a Child Page\n```bash\n# Create child page with inline content\nconfluence create-child \"Meeting Notes\" 123456789 --content \"This is a child page\"\n\n# Create child page from a file\nconfluence create-child \"Tech Specs\" 123456789 --file ./specs.md --format markdown\n```\n\n### Copy Page Tree\n```bash\n# Copy a page and all its children to a new location\nconfluence copy-tree 123456789 987654321 \"Project Docs (Copy)\"\n\n# Copy with maximum depth limit (only 3 levels deep)\nconfluence copy-tree 123456789 987654321 --max-depth 3\n\n# Exclude pages by title (supports wildcards * and ?; case-insensitive)\nconfluence copy-tree 123456789 987654321 --exclude \"temp*,test*,*draft*\"\n\n# Control pacing and naming\nconfluence copy-tree 123456789 987654321 --delay-ms 150 --copy-suffix \" (Backup)\"\n\n# Dry run (preview only)\nconfluence copy-tree 123456789 987654321 --dry-run\n\n# Quiet mode (suppress progress output)\nconfluence copy-tree 123456789 987654321 --quiet\n```\n\nNotes:\n- Preserves the original parent-child hierarchy when copying.\n- Continues on errors: failed pages are logged and the copy proceeds.\n- Exclude patterns use simple globbing: `*` matches any sequence, `?` matches any single character, and special regex characters are treated literally.\n- Large trees may take time; the CLI applies a small delay between sibling page creations to avoid rate limits (configurable via `--delay-ms`).\n- Root title suffix defaults to ` (Copy)`; override with `--copy-suffix`. Child pages keep their original titles.\n- Use `--fail-on-error` to exit non-zero if any page fails to copy.\n\n### Update an Existing Page\n```bash\n# Update title only\nconfluence update 123456789 --title \"A Newer Title for the Page\"\n\n# Update content only from a string\nconfluence update 123456789 --content \"Updated page content.\"\n\n# Update content from a file\nconfluence update 123456789 --file ./updated-content.md --format markdown\n\n# Update both title and content\nconfluence update 123456789 --title \"New Title\" --content \"And new content\"\n```\n\n### Move a Page to New Parent\n\n```bash\n# Move page by ID\nconfluence move 123456789 987654321\n\n# Move page and rename it\nconfluence move 123456789 987654321 --title \"Relocated Page\"\n\n# Move using URLs (for convenience)\nconfluence move \"https://domain.atlassian.net/wiki/viewpage.action?pageId=123456789\" \\\n                \"https://domain.atlassian.net/wiki/viewpage.action?pageId=987654321\"\n```\n\n**Note:** Pages can only be moved within the same Confluence space. Cross-space moves are not supported.\n\n### Delete a Page\n```bash\n# Delete by page ID (prompts for confirmation)\nconfluence delete 123456789\n\n# Delete by URL\nconfluence delete \"https://your-domain.atlassian.net/wiki/viewpage.action?pageId=123456789\"\n\n# Skip confirmation (useful for scripts)\nconfluence delete 123456789 --yes\n```\n\n### Edit Workflow\nThe `edit` and `update` commands work together to create a seamless editing workflow.\n```bash\n# 1. Export page content to a file (in Confluence storage format)\nconfluence edit 123456789 --output ./page-to-edit.xml\n\n# 2. Edit the file with your preferred editor\nvim ./page-to-edit.xml\n\n# 3. Update the page with your changes\nconfluence update 123456789 --file ./page-to-edit.xml --format storage\n```\n\n### Profile Management\n```bash\n# List all profiles and see which is active\nconfluence profile list\n\n# Switch the active profile\nconfluence profile use staging\n\n# Add a new profile interactively\nconfluence profile add staging\n\n# Add a new profile non-interactively\nconfluence profile add staging --domain \"staging.example.com\" --auth-type bearer --token \"xyz\"\n\n# Add a read-only profile (blocks all write operations)\nconfluence profile add agent --domain \"company.atlassian.net\" --auth-type basic --email \"bot@example.com\" --token \"xyz\" --read-only\n\n# Remove a profile\nconfluence profile remove staging\n\n# Use a specific profile for a single command\nconfluence --profile staging spaces\n```\n\n### Read-Only Mode\n\nRead-only mode blocks all write operations at the CLI level, making it safe to hand the tool to AI agents (Claude Code, Copilot, etc.) without risking accidental edits.\n\n**Enable via profile:**\n```bash\n# During init\nconfluence init --read-only\n\n# When adding a profile\nconfluence profile add agent --domain \"company.atlassian.net\" --token \"xyz\" --read-only\n```\n\n**Enable via environment variable:**\n```bash\nexport CONFLUENCE_READ_ONLY=true   # overrides profile setting\n```\n\nWhen read-only mode is active, any write command (`create`, `create-child`, `update`, `delete`, `move`, `edit`, `comment`, `attachment-upload`, `attachment-delete`, `property-set`, `property-delete`, `comment-delete`, `copy-tree`) exits with code 1 and prints an error message.\n\n`confluence profile list` shows a `[read-only]` badge next to protected profiles.\n\n### View Usage Statistics\n```bash\nconfluence stats\n```\n\n## Commands\n\n| Command | Description | Options |\n|---|---|---|\n| `init` | Initialize CLI configuration | `--read-only` |\n| `read \u003cpageId_or_url\u003e` | Read page content | `--format \u003chtml\\|text\\|storage\\|markdown\u003e` |\n| `info \u003cpageId_or_url\u003e` | Get page information | `--format \u003ctext\\|json\u003e` |\n| `search \u003cquery\u003e` | Search for pages | `--limit \u003cnumber\u003e` |\n| `spaces` | List available spaces | `--limit \u003cnumber\u003e` |\n| `find \u003ctitle\u003e` | Find a page by its title | `--space \u003cspaceKey\u003e` |\n| `children \u003cpageId\u003e` | List child pages of a page | `--recursive`, `--max-depth \u003cnumber\u003e`, `--format \u003clist\\|tree\\|json\u003e`, `--show-url`, `--show-id` |\n| `create \u003ctitle\u003e \u003cspaceKey\u003e` | Create a new page or folder | `--content \u003cstring\u003e`, `--file \u003cpath\u003e`, `--format \u003cstorage\\|html\\|markdown\u003e`, `--type \u003cpage\\|folder\u003e` |\n| `create-child \u003ctitle\u003e \u003cparentId\u003e` | Create a child page or folder | `--content \u003cstring\u003e`, `--file \u003cpath\u003e`, `--format \u003cstorage\\|html\\|markdown\u003e`, `--type \u003cpage\\|folder\u003e` |\n| `copy-tree \u003csourcePageId\u003e \u003ctargetParentId\u003e [newTitle]` | Copy page tree with all children | `--max-depth \u003cnumber\u003e`, `--exclude \u003cpatterns\u003e`, `--delay-ms \u003cms\u003e`, `--copy-suffix \u003ctext\u003e`, `--dry-run`, `--fail-on-error`, `--quiet` |\n| `update \u003cpageId\u003e` | Update a page's title or content | `--title \u003cstring\u003e`, `--content \u003cstring\u003e`, `--file \u003cpath\u003e`, `--format \u003cstorage\\|html\\|markdown\u003e` |\n| `move \u003cpageId_or_url\u003e \u003cnewParentId_or_url\u003e` | Move a page to a new parent location | `--title \u003cstring\u003e` |\n| `delete \u003cpageId_or_url\u003e` | Delete a page by ID or URL | `--yes` |\n| `edit \u003cpageId\u003e` | Export page content for editing | `--output \u003cfile\u003e` |\n| `attachments \u003cpageId_or_url\u003e` | List or download attachments for a page | `--limit \u003cnumber\u003e`, `--pattern \u003cglob\u003e`, `--download`, `--dest \u003cdirectory\u003e` |\n| `attachment-upload \u003cpageId_or_url\u003e` | Upload attachments to a page | `--file \u003cpath\u003e`, `--comment \u003ctext\u003e`, `--replace`, `--minor-edit` |\n| `attachment-delete \u003cpageId_or_url\u003e \u003cattachmentId\u003e` | Delete an attachment from a page | `--yes` |\n| `comments \u003cpageId_or_url\u003e` | List comments for a page | `--format \u003ctext\\|markdown\\|json\u003e`, `--limit \u003cnumber\u003e`, `--start \u003cnumber\u003e`, `--location \u003cinline\\|footer\\|resolved\u003e`, `--depth \u003croot\\|all\u003e`, `--all` |\n| `comment \u003cpageId_or_url\u003e` | Create a comment on a page | `--content \u003cstring\u003e`, `--file \u003cpath\u003e`, `--format \u003cstorage\\|html\\|markdown\u003e`, `--parent \u003ccommentId\u003e`, `--location \u003cinline\\|footer\u003e`, `--inline-selection \u003ctext\u003e`, `--inline-original-selection \u003ctext\u003e`, `--inline-marker-ref \u003cref\u003e`, `--inline-properties \u003cjson\u003e` |\n| `comment-delete \u003ccommentId\u003e` | Delete a comment by ID | `--yes` |\n| `property-list \u003cpageId_or_url\u003e` | List all content properties for a page | `--format \u003ctext\\|json\u003e`, `--limit \u003cnumber\u003e`, `--start \u003cnumber\u003e`, `--all` |\n| `property-get \u003cpageId_or_url\u003e \u003ckey\u003e` | Get a content property by key | `--format \u003ctext\\|json\u003e` |\n| `property-set \u003cpageId_or_url\u003e \u003ckey\u003e` | Set a content property (create or update) | `--value \u003cjson\u003e`, `--file \u003cpath\u003e`, `--format \u003ctext\\|json\u003e` |\n| `property-delete \u003cpageId_or_url\u003e \u003ckey\u003e` | Delete a content property by key | `--yes` |\n| `export \u003cpageId_or_url\u003e` | Export a page to a directory with its attachments | `--format \u003chtml\\|text\\|markdown\u003e`, `--dest \u003cdirectory\u003e`, `--file \u003cfilename\u003e`, `--attachments-dir \u003cname\u003e`, `--pattern \u003cglob\u003e`, `--referenced-only`, `--skip-attachments` |\n| `profile list` | List all configuration profiles | |\n| `profile use \u003cname\u003e` | Set the active configuration profile | |\n| `profile add \u003cname\u003e` | Add a new configuration profile | `-d, --domain`, `-p, --api-path`, `-a, --auth-type`, `-e, --email`, `-t, --token`, `--protocol`, `--read-only` |\n| `profile remove \u003cname\u003e` | Remove a configuration profile | |\n| `convert` | Convert between content formats locally (no server required) | `--input-file \u003cpath\u003e`, `--output-file \u003cpath\u003e`, `--input-format \u003cmarkdown\\|storage\\|html\u003e`, `--output-format \u003cmarkdown\\|storage\\|html\\|text\u003e` |\n| `stats` | View your usage statistics | |\n\n**Global option:** `--profile \u003cname\u003e` — Use a specific profile for any command (overrides `CONFLUENCE_PROFILE` env var and active profile).\n\n## Examples\n\n```bash\n# Setup\nconfluence init\n\n# Read a page as text\nconfluence read 123456789\n\n# Read a page as HTML\nconfluence read 123456789 --format html\n\n# Get page details\nconfluence info 123456789\n\n# Search with limit\nconfluence search \"API documentation\" --limit 3\n\n# List spaces\nconfluence spaces\n\n# Move a page to a new parent\nconfluence move 123456789 987654321\n\n# Move and rename\nconfluence move 123456789 987654321 --title \"New Title\"\n\n# Upload and delete an attachment\nconfluence attachment-upload 123456789 --file ./report.pdf\nconfluence attachment-delete 123456789 998877 --yes\n\n# Create a folder (no content body required)\nconfluence create \"Engineering Docs\" MYSPACE --type folder\nconfluence create-child \"Sub-folder\" 123456789 --type folder\n\n# View usage statistics\nconfluence stats\n\n# Profile management\nconfluence profile list\nconfluence profile use staging\nconfluence --profile staging spaces\n\n# Convert markdown to Confluence storage format (no server required)\nconfluence convert --input-file doc.md --input-format markdown --output-format storage\n\n# Pipe conversion via stdin/stdout\necho \"# Hello\" | confluence convert --input-format markdown --output-format storage\n\n# Convert storage format back to markdown\nconfluence convert -i page.xml -o page.md --input-format storage --output-format markdown\n```\n\n## Markdown Marker Conventions\n\nWhen converting markdown to Confluence storage format (via `confluence convert`, `create`, or `update`), the following paragraph-level markers produce native Confluence macros. Each marker round-trips back to its markdown form when going storage → markdown.\n\n### Callout macros — `INFO`, `WARNING`, `NOTE`\n\nA blockquote whose first line is `**INFO**`, `**WARNING**`, or `**NOTE**` becomes the corresponding Confluence macro:\n\n```markdown\n\u003e **INFO**\n\u003e Heads up — this is an info box.\n\n\u003e **WARNING**\n\u003e Watch out for this.\n\n\u003e **NOTE**\n\u003e Side note for the reader.\n```\n\nThe reverse direction emits the same `\u003e **INFO**` / `\u003e **WARNING**` / `\u003e **NOTE**` blockquote form, so multi-paragraph bodies round-trip cleanly. The bare `[!info]` / `[!warning]` / `[!note]` shorthand is still accepted on input for backwards compatibility.\n\nA blockquote without one of these markers stays a **plain blockquote** (`\u003cblockquote\u003e…\u003c/blockquote\u003e`) — `\u003e …` is treated as a quotation, not an alert. Use the markers above when you want a callout.\n\n### `**TOC**` — Table of Contents\n\nA paragraph containing only `**TOC**` becomes a Confluence Table of Contents macro using the macro's default heading levels:\n\n```markdown\n**TOC**\n```\n\n### `**ANCHOR: id**` — anchor\n\nA paragraph containing only `**ANCHOR: my-section**` becomes a Confluence anchor macro with the given id:\n\n```markdown\n**ANCHOR: my-section**\n```\n\n### `**EXPAND: title** … **EXPAND_END**` — collapsible expand macro\n\nWrap a block of content between `**EXPAND: title**` and `**EXPAND_END**` markers (each on its own paragraph) to render it as a Confluence expand macro with a collapsible body:\n\n````markdown\n**EXPAND: Show generated code**\n\n```js\nconst x = 1;\n```\n\n**EXPAND_END**\n````\n\nThe body may contain any content that is converted earlier in the pipeline (code blocks, tables, callout blockquotes). The reverse direction emits the same `**EXPAND: title**` / `**EXPAND_END**` markers so the conversion round-trips.\n\nInline markdown inside the title (`*em*`, backtick code, links, `~~strike~~`) is stripped at capture time — Confluence's storage normalizer treats macro titles as plain text and will silently truncate or reject HTML in a `\u003cac:parameter\u003e`. Title-less expand macros created in the Confluence UI still convert to `\u003cdetails\u003e/\u003csummary\u003e` blocks.\n\n### `[text](#id)` — same-page anchor link\n\nA standard markdown link whose href starts with `#` becomes an `ac:link` with `ac:anchor`, rendering as an in-page jump in Confluence:\n\n```markdown\nSee [the anchor](#my-section) above.\n```\n\nThis works under all three `linkStyle` modes (`smart`, `wiki`, `plain`) — the anchor-link conversion runs before the general `\u003ca href\u003e` handling.\n\n## Development\n\n```bash\n# Clone the repository\ngit clone https://github.com/pchuri/confluence-cli.git\ncd confluence-cli\n\n# Install dependencies\nnpm install\n\n# Run locally\nnpm start -- --help\n\n# Run tests\nnpm test\n\n# Lint code\nnpm run lint\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Roadmap\n\n- [x] **Create and update pages** ✅\n- [ ] Page templates\n- [ ] Bulk operations\n- [ ] Export pages to different formats\n- [ ] Integration with other Atlassian tools (Jira)\n- [x] Page attachments management (list, download, upload, delete)\n- [x] Comments\n- [ ] Reviews\n\n## Support \u0026 Feedback\n\n### 💬 We'd love to hear from you!\n\nYour feedback helps make confluence-cli better for everyone. Here's how you can share your thoughts:\n\n#### 🐛 Found a bug?\n1. Check the [Issues](https://github.com/pchuri/confluence-cli/issues) page\n2. Create a new [bug report](https://github.com/pchuri/confluence-cli/issues/new?template=bug_report.md)\n\n#### 💡 Have a feature idea?\n1. Create a [feature request](https://github.com/pchuri/confluence-cli/issues/new?template=feature_request.md)\n2. Join our [Discussions](https://github.com/pchuri/confluence-cli/discussions) to chat with the community\n\n#### 📝 General feedback?\n- Share your experience with a [feedback issue](https://github.com/pchuri/confluence-cli/issues/new?template=feedback.md)\n- Rate us on [NPM](https://www.npmjs.com/package/confluence-cli)\n- Star the repo if you find it useful! ⭐\n\n#### 🤝 Want to contribute?\nCheck out our [Contributing Guide](CONTRIBUTING.md) - all contributions are welcome!\n\n### 📈 Usage Analytics\n\nconfluence-cli tracks command usage statistics **locally** on your machine (`~/.confluence-cli/stats.json`). No data is sent to any external server. This includes:\n- Command usage counts (success/error)\n\nYou can view your stats with `confluence stats`, or disable tracking by setting: `export CONFLUENCE_CLI_ANALYTICS=false`\n\n---\n\nMade with ❤️ for the Confluence community\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpchuri%2Fconfluence-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpchuri%2Fconfluence-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpchuri%2Fconfluence-cli/lists"}