| name | acli |
| description | Atlassian CLI (official `acli` binary, v1.3+ as of 2026) for Jira Cloud, Confluence Cloud, and org admin tasks from the terminal. Use whenever the user wants to create, view, edit, transition, assign, clone, archive, comment on, link, or bulk-operate on Jira work items; list or manage projects, boards, sprints, filters, dashboards, or custom-field definitions; create or update Confluence spaces, pages, or blog posts; activate/deactivate users at the org level; or authenticate to Atlassian from a shell or CI pipeline. Triggers on: `acli`, Atlassian CLI, Jira from the terminal, Confluence from the terminal, bulk Jira operations, scripting Jira, automate Jira tickets, transition a bunch of issues, create issues from a JSON/CSV file, CI pipeline that touches Jira, log in to Jira CLI, switch Atlassian sites, API-token auth for Jira. Use this skill even when the user does not say the word `acli` — if the task is CLI-driven Jira or Confluence work, this is the right tool. Do NOT use for: Atlassian MCP server work (that is a different integration), REST-API-only workflows where no CLI is involved, Bitbucket command-line needs (acli does not cover Bitbucket yet), or the legacy Appfire/Bob Swift `acli` tool (a different product that happens to share the binary name). The Atlassian MCP server is OPT-IN, documented in docs/mcp/. |
| license | MIT |
| compatibility | ["claude-code","cursor","codex","opencode"] |
| allowed-tools | Bash(acli:*) |
| complementary_categories | ["issue-tracker"] |
Atlassian CLI (acli)
acli is Atlassian's official command-line tool for Jira Cloud, Confluence Cloud, and org admin operations. It replaces terminal-based Jira automation that previously required raw REST calls, and unifies Jira + Confluence + admin actions behind one binary with one credential store per product.
This skill teaches how to drive acli for any intent: one-off commands, batch mutations, scripted pipelines, and CI jobs. Repo-specific integration (how this skill plugs into the host repo's workflow, TMS modality, project conventions, anti-patterns) lives in the companion file <repo-core>/references/acli-integration.md — load it on demand. See "Navigation" below.
Why this skill exists
acli has several traits that make it easy to misuse:
- Silent pagination truncation.
workitem search without --paginate returns the first page only — no warning. Scripts that count or iterate keys read the wrong number of items.
- Auth is per-product.
acli jira auth login does not authenticate acli admin, acli confluence, or acli rovodev. There is also a top-level acli auth for global OAuth (newer surface). Each scope has its own session.
- The "work item" vs "issue" split. The CLI renamed commands (
jira issue → jira workitem) but the JSON response still has a top-level issues[] array and CSV inputs still use issueType/parentIssueId spellings. Mixing old and new terminology in the same script works, but confuses readers.
- Unknown subcommands fail silently. Typing
acli jira workflow --help does NOT error — it falls back to acli jira --help with exit 0. So "no error" ≠ "command exists". Always verify by checking the help body actually changed.
- Hard limits the docs do not advertise.
acli cannot list custom fields, edit custom-field values on existing items, manage workflows, manage issue types, or touch project versions/components. See references/gotchas.md.
The body below covers the core that applies to almost every session. The references/ directory holds the deep material — load only the one you need.
Composable Skills (auto-resolved at skill entry)
acli is itself the canonical issue-tracker skill. The category typically has no T3 skills that overlap — acli is the tool surface, not a borrower of community skills.
Steps for protocol consistency:
- Read
complementary_categories from this skill's frontmatter (issue-tracker).
- Resolve via the host repo's skill-registry cache (
.claude/skills/REGISTRY.md, built by scripts/build-skill-registry.ts). Fallback: scan the session-start system-reminder skill list.
- Apply the threshold rule per the host repo's skill-composition strategy doc (T1 / T3 silent; T4 ASK).
- The Atlassian MCP fallback documented below is OPT-IN, not a skill — enable manually via
docs/mcp/.
Expected matches: typically none. Repo-specific composability (which workflow skills load this) lives in <repo-core>/references/acli-integration.md §Composability.
Skip step if the catalog is unavailable; log skill_resolution: "fallback-inline" plus missing: [<categories>] per the strategy doc's composability fallback contract.
Fallback: Atlassian MCP
Opt-in only: this MCP is NOT enabled in the default boilerplate. To use it, copy the atlassian block from docs/mcp/<agent>.template.* into .mcp.json / opencode.jsonc, ensure ATLASSIAN_* in .env are set, and restart the agent. Behavior below applies only after opt-in.
If acli is not installed or authenticated, fall back to the Atlassian MCP server (MCP tool namespace: mcp__atlassian__* or similar — check the MCP tool list for the exact prefix in the current environment).
When to prefer MCP over acli:
acli binary is not installed in the environment.
acli auth fails and cannot be fixed in the current session.
- The operation is one of the documented
acli blind spots: enumerate custom fields, edit custom-field values on existing work items, manage workflows / issue types / priorities / resolutions / project versions / components, upload attachments, add watchers, add an item to a sprint.
When to prefer acli over MCP:
- Bulk operations (acli consumes far fewer tokens per call).
- Scripting / CI pipelines.
- Operations that return large result sets (MCP payloads inflate token usage).
Coverage parity: MCP and acli overlap for issues, projects, boards, sprints, comments, and basic Confluence ops. For org-admin user lifecycle and Confluence space CRUD, acli is more direct. For schema/admin reads (field catalog, workflow definitions), MCP/REST is the only viable path.
Command structure
acli <product> [<feature>] <action> [flags]
| Product | Purpose |
|---|
jira | Jira Cloud — work items, projects, boards, sprints, filters, dashboards, custom-field definitions |
confluence | Confluence Cloud — spaces (CRUD), blog posts, page view |
admin | Organization admin — API-key auth, user lifecycle |
auth | Global OAuth (cross-product, newer top-level surface) |
rovodev | Rovo Dev AI coding agent (separate beta product) |
feedback | Send feedback or a bug report to Atlassian |
config | Atlassian Government Cloud configuration (gov-cloud) |
completion | Generate shell-autocompletion script (bash / zsh / fish / powershell) |
Every level has --help. Use it aggressively when unsure:
acli --help
acli jira --help
acli jira workitem --help
acli jira workitem create --help
Quick start
echo "$ATLASSIAN_API_TOKEN" | acli jira auth login \
--site "<your-site>.atlassian.net" \
--email "you@example.com" \
--token
acli jira auth status
acli jira workitem create --project "{{PROJECT_KEY}}" --type "Task" --summary "Draft the Q3 OKRs"
acli jira workitem search --jql "project = {{PROJECT_KEY}} AND status = 'To Do'" --paginate --json
acli jira workitem transition --jql "project = {{PROJECT_KEY}} AND assignee = currentUser()" \
--status "In Progress" --yes --ignore-errors
Repo-specific quick start: when the host repo defines its own workflow (status names, project keys, slug-resolved custom fields), see <repo-core>/references/acli-integration.md — it documents the project-flavored variant of the steps above.
Top-level command map
Jira (acli jira)
| Subcommand | What it covers |
|---|
auth | login · logout · status · switch — API-token or OAuth |
workitem | archive · assign · attachment (list / delete) · clone · comment (create / delete / list / update / visibility) · create · create-bulk · delete · edit · link (create / delete / list / type) · search · transition · unarchive · view · watcher (list / remove) |
project | archive · create · delete · list · restore · update · view |
board | create · delete · get · list-projects · list-sprints · search |
sprint | create · delete · list-workitems · update · view |
filter | add-favourite · change-owner · get · get-columns · list · reset-columns · search · update |
dashboard | search |
field | cancel-delete · create · delete · update — custom-field DEFINITIONS only, NOT values, and no listing |
Confluence (acli confluence)
| Subcommand | What it covers |
|---|
auth | login · logout · status · switch — same model as jira auth |
space | archive · create · list · restore · update · view (full CRUD) |
blog | create · list · view |
page | view (read-only as of v1.3.18 — page CRUD not yet exposed) |
Admin (acli admin)
| Subcommand | What it covers |
|---|
auth | login · logout · status · switch — API key |
user | activate · deactivate · delete · cancel-delete |
The selector pattern (the thing to internalize)
Most mutating workitem commands (edit, transition, assign, archive, clone, comment create) accept one of these target selectors:
| Selector | When to use |
|---|
--key KEY-1,KEY-2 | You already know the exact keys |
--jql "..." | You want everything matching a JQL query |
--filter 10001 | You want to reuse a saved Jira filter |
--from-file f | You have a file listing keys (archive/unarchive/assign) |
When the selector matches many items, the command is a batch operation. Two flags almost always matter:
-y, --yes — skip the interactive confirmation prompt. Required in CI; if omitted the command hangs waiting on stdin. Note: this flag does NOT exist on admin user delete / admin user cancel-delete (use --ignore-errors there instead).
--ignore-errors — do not abort the batch when a single item fails.
Output and piping
All list/search/view commands support three shapes:
- default table (human-readable)
--json (for jq / scripts)
--csv (spreadsheet-friendly)
Example pipe patterns:
acli jira workitem search --jql "project = {{PROJECT_KEY}}" --count
acli jira workitem search --jql "project = {{PROJECT_KEY}}" --paginate --csv > team.csv
acli jira workitem view {{PROJECT_KEY}}-123 --json | jq '.fields.summary'
The JSON shape from workitem search has a top-level issues array (not workitems) — the Jira REST v3 wire format shows through.
Publishing rich text (the default workflow)
Jira stores rich-text content (descriptions, comments, and any rich-text field) as ADF — Atlassian Document Format, a JSON tree of typed nodes (heading, paragraph, bulletList, orderedList, codeBlock, blockquote, rule, table, panel, expand) with inline marks (strong, em, code, link, strike).
acli accepts ADF JSON in every rich-text input. acli never converts markdown — passing # Heading to --description or --body stores the literal string # Heading wrapped in a single ADF paragraph.
⚠️ Asymmetry: create supports custom-field rich text, edit does NOT.
acli workitem create --from-json accepts custom fields via additionalAttributes (ADF doc payloads work). acli workitem edit --from-json hard-rejects every custom-field shape (additionalAttributes, fields, flat customfield_X) with exit 1 + unknown field error. No silent drop, no escape hatch in the binary. To update or correct a rich-text custom field on an existing work item, you MUST use the REST PUT workaround documented below — acli cannot do it.
To publish anything richer than plain prose, use this three-step workflow by default:
1. Author the content in Markdown.
2. Convert MD → ADF JSON using scripts/md-to-adf.ts.
3. Pass the ADF JSON to the matching acli flag — or, for cases acli cannot cover, into a REST body.
The bundled converter
Location: .claude/skills/acli/scripts/md-to-adf.ts. Runtime: Bun.
CLI usage:
bun .claude/skills/acli/scripts/md-to-adf.ts input.md output.adf.json
cat input.md | bun .claude/skills/acli/scripts/md-to-adf.ts - output.adf.json
bun .claude/skills/acli/scripts/md-to-adf.ts input.md > output.adf.json
Programmatic usage (when batching across many fields or many work items in one script):
import { mdToAdf, validateAdf } from "./.claude/skills/acli/scripts/md-to-adf.ts";
const adf = mdToAdf(markdownString);
const { valid, errors } = validateAdf(adf);
Covered markdown subset: headings 1–6, bullet lists, ordered lists, nested lists (indentation-based), GFM tables (| a | b | + |---|---| separator), panels (GitHub-alert blockquotes), expand blocks (<details><summary>), Jira-native emoji (:short_name:), status lozenges ({status:color|TEXT}), mentions (@[Name](accountId)), fenced code blocks (with optional language tag), inline code, bold, italic (snake_case-safe), strikethrough, links, blockquotes, horizontal rule, paragraphs.
Rich-block syntax cheat-sheet:
| Markdown you write | ADF node produced |
|---|
| H1 | H2 | then | --- | --- | then body rows | table (header row → tableHeader, body → tableCell; inline marks work inside cells; | escapes a literal pipe) |
> [!NOTE] / [!INFO] (blue) · [!TIP] / [!SUCCESS] (green) · [!IMPORTANT] (purple) · [!WARNING] (yellow) · [!CAUTION] / [!ERROR] (red), then > body lines | panel with panelType info / success / note / warning / error. Body re-parsed as Markdown (can hold lists, code, etc.) |
| Two-space (or deeper) indentation under a list item | nested bulletList / orderedList inside that listItem; depth = indent width; bullet/ordered mix per level |
<details> / <summary>Title</summary> / body / </details> | expand with attrs.title; body re-parsed as Markdown |
:white_check_mark: :x: :warning: … any :short_name: | emoji node (Jira resolves the shortName; curated status marks also carry a Unicode text fallback). Inline code is parsed first, so a colon inside `code` is safe |
{status:green|DONE} (colors: neutral purple blue red yellow green) | status node — the coloured lozenge/pill for transition states. localId not required (Jira injects none on publish) |
@[Display Name](accountId) | mention node. The accountId is supplied explicitly (resolve it via /rest/api/3/user/search — see references/adf-authoring-style.md §mentions); a bare @name is NOT converted |
Media (images / videos) are NOT Markdown —  does not work, because an ADF media node needs the opaque media-services UUID of an uploaded file. Use the bundled helper scripts/jira-attach-media.ts instead (upload → resolve UUID → emit/publish the mediaSingle > media node). Example: bun scripts/jira-attach-media.ts BUG-123 ./repro.png --caption "Repro step 3" --publish. Full recipe + when-to-use in references/adf-authoring-style.md §media.
Out of scope (extend the converter if your project needs them): nestedExpand (expand inside a table cell).
This section covers HOW Markdown becomes ADF. For WHEN to reach for a table vs a panel vs a nested list — i.e. how to make field content visually scannable instead of flat prose — see references/adf-authoring-style.md. Workflow skills cite that file at each point they fill a Jira rich-text field.
Validation gate (fail fast before Jira)
The converter validates its output by default against an embedded ADF allowlist, then refuses to write and exits non-zero if the document is invalid. This turns an opaque Jira HTTP 400 INVALID_INPUT at publish time into a node-level diagnostic at author time. The gate is zero-dependency — it does NOT use @atlaskit/adf-utils (that package transitively pulls ProseMirror + Statsig and breaks the converter's zero-dep contract). The rules are inlined in md-to-adf.ts.
What it catches: unknown node types, unknown / invalid marks, code co-occurring with strong/em/strike/underline/subsup/textColor (the HTTP 400 combined-marks bug), heading level outside 1–6, missing link href, empty text nodes, illegal containment (e.g. a paragraph directly under a bulletList), and a malformed root (type ≠ doc or version ≠ 1).
bun .claude/skills/acli/scripts/md-to-adf.ts input.md out.adf.json --no-validate
bun .claude/skills/acli/scripts/md-to-adf.ts --check field.adf.json
Recommended habit: after splicing ADF into a --from-json create payload or a REST PUT body (where the wrapper is assembled outside the converter), run --check on each ADF field before sending. The gate is necessary but not sufficient — a round-trip GET of the field after write is still the only way to catch server-side coercion (Jira silently drops some invalid nodes).
Recipe by Jira surface
| Surface | How to publish ADF | Notes |
|---|
description on workitem create | --from-json payload, description key holds an ADF doc | Custom-field values live in additionalAttributes of the same payload, same ADF shape |
description on workitem edit | --description-file <file> accepts a JSON file containing an ADF doc | acli auto-detects ADF vs plain text by file content |
Rich-text custom field on workitem create | additionalAttributes.customfield_NNNNN = ADF doc inside --from-json | Same shape as description |
| Rich-text custom field on an existing item | acli cannot do this — use REST PUT workaround. PUT /rest/api/3/issue/{KEY} with {"fields": {customfield_NNNNN: <ADF>}} via curl | acli workitem edit hard-rejects additionalAttributes, fields, and flat customfield_X with ✗ Error: json: unknown field …. Confirmed empirically. See gotcha #4 + dedicated workaround section below. |
| Comment create | comment create --body-file <file> (alias -F) accepts ADF | The --body (plain) flag remains plain text only |
| Comment update | comment update --body-adf <file> | Dedicated ADF flag |
Worked end-to-end example
cat > /tmp/desc.md <<'MD'
- As a user
- I want X
- So that Y
Some context paragraph with **bold** and `inline_code`.
MD
cat > /tmp/ac.md <<'MD'
Given a valid input
When the user submits
Then the response is 200 OK
MD
bun .claude/skills/acli/scripts/md-to-adf.ts /tmp/desc.md /tmp/desc.adf.json
bun .claude/skills/acli/scripts/md-to-adf.ts /tmp/ac.md /tmp/ac.adf.json
jq -n \
--arg pk "{{PROJECT_KEY}}" \
--slurpfile desc /tmp/desc.adf.json \
--slurpfile ac /tmp/ac.adf.json \
'{
projectKey: $pk,
type: "Story",
summary: "Example summary",
description: $desc[0],
labels: ["example"],
additionalAttributes: {
customfield_NNNNN: $ac[0]
}
}' > /tmp/story.json
acli jira workitem create --from-json /tmp/story.json --json
Batch pattern (many work items, many rich fields)
When the task is to populate N work items with M rich-text fields each, the converter scales linearly with negligible overhead. Recommended pattern:
- Write one generator script (
generate.ts) that holds the per-field Markdown content for every item as inline string literals.
- The script imports
mdToAdf and converts every field in-process — no shell hop per conversion.
- The script writes one
create --from-json payload per item (/tmp/item-N.json).
- A shell loop runs
acli jira workitem create --from-json /tmp/item-N.json --json per file, capturing the new key from stdout.
- For comments, follow the same approach: write the comment Markdown inline, convert in-process, post with
acli jira workitem comment create -k <KEY> -F /tmp/comment-N.adf.json.
This pattern scales cleanly to dozens of items in one run. The bottleneck is authoring quality, not the conversion mechanic.
WORKAROUND: Editing rich-text custom fields on existing work items (REST PUT)
This is the only working path as of acli v1.3.18 — there is no acli-native channel for editing custom-field values on existing items. The recipe below is the turnkey workaround.
Prerequisites. Three env vars must be exported in the current shell. They are loaded automatically by the project tooling (bun claude, bun opencode, or direnv) from .env:
ATLASSIAN_URL — e.g. https://your-domain.atlassian.net
ATLASSIAN_EMAIL — the API-token owner's email
ATLASSIAN_API_TOKEN — the API token paired with the email
Recipe.
cat > /tmp/new.md <<'MD'
- with **bold**, `inline code`, and a [link](https://example.com)
MD
bun .claude/skills/acli/scripts/md-to-adf.ts /tmp/new.md /tmp/new.adf.json
jq -n --slurpfile adf /tmp/new.adf.json \
'{fields: {customfield_NNNNN: $adf[0]}}' > /tmp/put.json
curl -sS -w "\nHTTP %{http_code}\n" \
-u "$ATLASSIAN_EMAIL:$ATLASSIAN_API_TOKEN" \
-X PUT "$ATLASSIAN_URL/rest/api/3/issue/{{PROJECT_KEY}}-123" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
--data-binary @/tmp/put.json
Reference. Official Atlassian REST v3 PUT endpoint:
https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-put
Empirical proof this is the only path. Three variants tested against acli workitem edit --from-json on a real workitem:
Payload shape sent to acli edit | Result |
|---|
{issues:[...], additionalAttributes:{customfield_X:<ADF>}} | ✗ Error: json: unknown field "additionalAttributes" · exit 1 |
{issues:[...], fields:{customfield_X:<ADF>}} | ✗ Error: json: unknown field "fields" · exit 1 |
{issues:[...], customfield_X:<ADF>} | ✗ Error: json: unknown field "customfield_X" · exit 1 |
Same ADF doc through REST PUT: HTTP 204 OK.
Batch variant. Loop the recipe per --data-binary @/tmp/put-N.json and capture HTTP codes:
for KEY in {{PROJECT_KEY}}-1 {{PROJECT_KEY}}-2 {{PROJECT_KEY}}-3; do
status=$(curl -sS -o /dev/null -w "%{http_code}" \
-u "$ATLASSIAN_EMAIL:$ATLASSIAN_API_TOKEN" \
-X PUT "$ATLASSIAN_URL/rest/api/3/issue/$KEY" \
-H "Content-Type: application/json" \
--data-binary @/tmp/put-"$KEY".json)
echo "$KEY -> HTTP $status"
done
When this becomes unnecessary. If Atlassian adds an additionalAttributes-style channel to acli workitem edit, retire this workaround and update the recipe table.
Why this is the default
- Authoring in Markdown is fast, reviewable in pull requests, diffable.
- The conversion is deterministic — the same Markdown always produces the same ADF tree.
- One workflow covers every rich-text surface uniformly: descriptions, comments, custom fields, all the same three steps.
- Identifier-heavy prose (snake_case, kebab-case) survives the conversion because the italic detection has word-boundary guards.
Anti-patterns — NEVER do these (tool-level)
These are tool-level anti-patterns intrinsic to the acli binary and its REST companion. They apply regardless of host repo. Gotchas describe surprising behavior to remember; anti-patterns describe actions to refuse outright. Both apply.
- T1. NEVER hand-author raw ADF JSON for descriptions, comments, or rich-text custom fields. Use
scripts/md-to-adf.ts — deterministic, diffable, snake_case-safe, and avoids the combined-marks bug (inline code co-occurring with strong/em causes HTTP 400).
- T2. NEVER hardcode Jira
customfield_NNNNN IDs in scripts or AI output that consumes acli. Resolve via the host project's slug catalog (see the host repo's acli-integration.md). IDs differ per workspace; slugs travel.
- T3. NEVER assume
acli accepts custom-field input on workitem edit. It hard-rejects every shape (additionalAttributes, fields, flat customfield_X) with exit 1. Use the REST PUT /rest/api/3/issue/{KEY} workaround documented above — there is no acli-native path.
- T4. NEVER run a bulk
acli mutation (transition, edit, comment, link, archive) without first verifying acli jira auth status. Silent auth expiry cascades into HTTP 401s mid-loop, leaving the batch half-applied with no clean rollback.
Repo-specific anti-patterns (workflow abstraction, project-key portability, TMS modality boundaries, prod-workspace safety, CI batching, version pinning, sync-script auth) live in <repo-core>/references/acli-integration.md. Load it whenever a session touches the host repo's Jira workflow.
Six gotchas to keep in mind always
--paginate is opt-in. Default limit is server-side (30–50 depending on command). No warning on truncation. If you are counting, iterating, or making decisions based on the result, pass --paginate.
- Custom fields on
workitem create go through additionalAttributes in --from-json. Numeric IDs only (customfield_NNNN), no name-addressing. Documented value shapes in the create template are: {"value": "..."} (single-select), bare number, bare string. workitem edit actively REJECTS custom-field input — hard error, exit 1, not a silent drop (empirically confirmed across additionalAttributes, fields, and flat customfield_X shapes). For editing custom-field values on existing items, the only working path is REST PUT /rest/api/3/issue/{KEY} via curl using the session env vars — see the "WORKAROUND" subsection in "Publishing rich text" above, plus references/gotchas.md §4 and references/workitem.md.
acli cannot enumerate custom fields. acli jira field only does create/update/delete/cancel-delete. To discover field IDs, use workitem view --json | jq against an item that has the field set, or call GET /rest/api/3/field directly. There is no in-CLI listing. Host repos typically cache the catalog under .agents/ and resolve fields by slug — see <repo-core>/references/acli-integration.md.
- Transitions match by status name, not transition ID. When two transitions lead to the same status with different validators, the CLI picks one and may fail. No
--transition-id escape hatch exists — fall back to REST if this hits.
- Trace IDs are the only debug signal. An
unexpected error, trace id: XXXXXXXX line is all you get on backend failures. Capture and log the trace ID always; Atlassian Support needs it.
workitem link create flag names are misleading — --out and --in are EMPIRICALLY INVERTED relative to Jira's outward/inward semantics. Running acli jira workitem link create --out X --in Y --type Dependencies produces "Y depends on X" — NOT "X depends on Y" as the flag names suggest. Y becomes the outward party (the one that performs the outward verb, e.g. "depends on" / "blocks" / "causes"); X becomes the inward party. Confirmed empirically against Dependencies; the same inversion applies to ALL outward-asymmetric link types (Blocks, Blocking, Causes, Duplicate, Cloners, Defect, Test, Test Automation, Test Design, Test Execute). Symmetric types (Relates) are immune — direction is lost either way. Reverse-mapping rule of thumb: --out takes the PREREQUISITE (the inward partner in Jira's UI); --in takes the DEPENDENT (the outward partner in Jira's UI). Mandatory verification after every link create: run acli jira workitem link list --key <expected-dependent> --json and confirm the response shows outwardIssueKey: <expected-prerequisite>. If the direction is wrong, delete the link and recreate with swapped flags. Deep recipe + per-type mapping table → references/workitem.md.
Top-level utilities
Quick-reference for the top-level surface that doesn't fit under a product. None of these need a separate reference file — they're documented here in full.
acli completion — shell autocompletion
acli completion bash > /etc/bash_completion.d/acli
acli completion zsh > "${fpath[1]}/_acli"
acli completion fish > ~/.config/fish/completions/acli.fish
acli completion powershell > acli.ps1
Each subcommand prints a shell script to stdout. Pipe to the location your shell expects (above are the conventional paths).
acli feedback — report a problem to Atlassian
acli feedback \
--summary "JSON shape on edit --generate-json is misleading" \
--details "The template doesn't include additionalAttributes for custom fields..." \
--email "you@example.com" \
--time "1h" \
--attachments error.log,trace.txt
Flags: -s, --summary (required-ish), -d, --details (required-ish), -e, --email, -t, --time (estimated timeframe like 1h, 15m), -a, --attachments (multiple files).
acli auth — global OAuth (newer surface)
A top-level OAuth login that authenticates across products in one step. Distinct from per-product jira auth / admin auth / confluence auth. Use the per-product login for token-based CI; use the global one for interactive multi-product browsing.
acli auth login
acli auth status
acli auth switch
acli auth logout
See references/auth.md for the full auth model.
acli config gov-cloud — Atlassian Government Cloud
acli config gov-cloud --enable
acli config gov-cloud --status
Niche — only relevant if your org is on Atlassian Government Cloud. Not used in standard commercial Jira/Confluence.
Navigation — when to load which reference
Load the reference that matches the user's current need. Do not preload all of them.
| If the user wants to… | Load |
|---|
| Log in, switch sites, handle tokens, authenticate in CI | references/auth.md |
| Work with Jira tickets (create, edit, transition, search, bulk, comments, links, watchers, custom-field shapes) | references/workitem.md |
| Manage projects, boards, sprints, filters, dashboards, custom-field definitions | references/project-board-sprint.md |
| Work with Confluence spaces, blogs, pages | references/confluence.md |
| Run org-level admin tasks (API key, user lifecycle) | references/admin.md |
| Pipe output, produce JSON/CSV, dry-run, run on CI/CD | references/output-and-automation.md |
| Diagnose surprising behavior, known bugs, REST fallback points | references/gotchas.md |
| Publish rich text to descriptions, comments, or custom fields | Inline section "Publishing rich text" + scripts/md-to-adf.ts |
| Make Jira field content visually excellent (when to use tables / panels / nested lists for readability) | references/adf-authoring-style.md |
Plug acli into the host repo's workflow (TMS modality, slug catalog, project conventions, anti-patterns specific to this repo) | <repo-core>/references/acli-integration.md |
Working style
-
Default to Markdown authoring for any rich-text field. Never pass raw markdown to --description, --body, or any custom-field value — acli does not convert markdown. Use scripts/md-to-adf.ts to produce ADF, then pass the JSON. See "Publishing rich text" above.
-
Prefer API-token auth in scripted contexts. --web / OAuth is for humans at a terminal.
-
Always pass --yes in CI for any mutating command (where the flag exists).
-
Always pass --paginate when a downstream script consumes the result.
-
Scaffold complex payloads with --generate-json (create, edit, project create, project update, link create, create-bulk). Pipe to a file, edit, submit with --from-json. Note: --generate-json is static — it does NOT introspect the actual project schema, so for custom-field shapes you may need to view a real item.
-
Capture the trace ID on any failure and surface it when reporting to the user.
-
Do not invent flags. When unsure, run acli <path> --help — it is authoritative and version-pinned to the installed binary. Convention: every multi-word flag is kebab-case (--from-json, --searcher-key, --filter-id, --order-by). camelCase variants will fail.
-
Verify subcommand existence before assuming. Unknown subcommands silently fall back to parent help with exit 0 — they do NOT error. Read the help body, don't trust the exit code.
-
Know what acli cannot do. All of the following require REST or MCP — acli does not cover them as of v1.3.18:
- Enumerate custom fields (
field has no list).
- Edit custom-field values on existing work items (
workitem edit does not document custom-field input).
- Manage workflows, workflow schemes, statuses, or transition definitions.
- Manage issue types, priorities, resolutions, project versions, project components.
- Add a work item to a sprint (
JRACLOUD-97107).
- Upload attachments, add watchers.
- Retrieve the cached auth token for reuse in another tool.
- Bitbucket operations (out of scope entirely).
- Confluence page CRUD beyond
page view (as of v1.3.18 — space and blog have full CRUD).
See references/gotchas.md for the full list with REST recipes.
Installation (reference only)
Users usually already have acli installed. If not, point them at:
- Official guide: https://developer.atlassian.com/cloud/acli/guides/install-acli/
- macOS:
brew tap atlassian/homebrew-acli && brew install acli
- Linux (Debian/Ubuntu):
apt install acli (after adding the Atlassian apt repo)
- Linux (RHEL/Fedora):
yum install acli (after adding the Atlassian yum repo)
- Windows: PowerShell
curl install (no Chocolatey/MSI yet)
- CI one-liner (Linux):
curl -LO "https://acli.atlassian.com/linux/1.3.18/acli_linux_amd64/acli" && chmod +x acli
Pin to a version URL in production pipelines — latest/ has caused same-day mass failures. Each release is supported for six months. Run acli --version to check.