Install
$ agentstack add skill-upex-galaxy-agentic-qa-boilerplate-acli ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
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 /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 searchwithout--paginatereturns 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 logindoes not authenticateacli admin,acli confluence, oracli rovodev. There is also a top-levelacli authfor 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-levelissues[]array and CSV inputs still useissueType/parentIssueIdspellings. Mixing old and new terminology in the same script works, but confuses readers. - Unknown subcommands fail silently. Typing
acli jira workflow --helpdoes NOT error — it falls back toacli jira --helpwith exit 0. So "no error" ≠ "command exists". Always verify by checking the help body actually changed. - Hard limits the docs do not advertise.
aclicannot list custom fields, edit custom-field values on existing items, manage workflows, manage issue types, or touch project versions/components. Seereferences/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_categoriesfrom this skill's frontmatter (issue-tracker). - Resolve via the host repo's skill-registry cache (
.claude/skills/REGISTRY.md, built byscripts/build-skill-registry.ts). Fallback: scan the session-startsystem-reminderskill 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 /references/acli-integration.md §Composability.
Skip step if the catalog is unavailable; log skill_resolution: "fallback-inline" plus missing: [] 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/.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:
aclibinary is not installed in the environment.acliauth fails and cannot be fixed in the current session.- The operation is one of the documented
acliblind 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 [] [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
# 1. Authenticate against a site using an API token (scriptable path)
echo "$ATLASSIAN_API_TOKEN" | acli jira auth login \
--site ".atlassian.net" \
--email "you@example.com" \
--token
# 2. Verify
acli jira auth status
# 3. Create a work item
acli jira workitem create --project "{{PROJECT_KEY}}" --type "Task" --summary "Draft the Q3 OKRs"
# 4. Search with JQL — ALWAYS pass --paginate or --limit explicitly
acli jira workitem search --jql "project = {{PROJECT_KEY}} AND status = 'To Do'" --paginate --json
# 5. Transition one or many
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 /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 onadmin user delete/admin user cancel-delete(use--ignore-errorsthere 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(forjq/ scripts)--csv(spreadsheet-friendly)
Example pipe patterns:
# Count only
acli jira workitem search --jql "project = {{PROJECT_KEY}}" --count
# Save full result set to CSV
acli jira workitem search --jql "project = {{PROJECT_KEY}}" --paginate --csv > team.csv
# Extract a single field with jq
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
# stdin form
cat input.md | bun .claude/skills/acli/scripts/md-to-adf.ts - output.adf.json
# stdout form (omit output arg)
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); // returns { type: "doc", version: 1, content: [...] }
const { valid, errors } = validateAdf(adf); // gate ANY ADF before publishing
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 (`), **Jira-native emoji** (:shortname:), **status lozenges** ({status:color|TEXT}), **mentions** (@[Name](accountId)`), fenced code blocks (with optional language tag), inline code, bold, italic (snakecase-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 | | ` / Title / body / | expand with attrs.title; body re-parsed as Markdown | | :whitecheckmark: :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
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: upex-galaxy
- Source: upex-galaxy/agentic-qa-boilerplate
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.