Install
$ agentstack add skill-bm629-agent-skills-atlassian-rest-ops ✓ 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 Used
- ● 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-rest-ops
Overview
This skill lets an agent perform any Confluence Cloud (v2) or Jira Cloud (v3) operation by calling the REST API directly with curl — no SDK, no pip dependency. The REST API is the complete API surface, including writes such as creating a Confluence page. The agent consumes the credentials the caller injected, looks up an endpoint in a bundled OpenAPI spec via an endpoint index + a $ref-resolver, constructs the curl, and parses the JSON. Confluence and Jira differ on several axes (base URL, pagination, errors, rich-text), so this skill carries per-API patterns rather than one generic shape.
When to activate
- ✅ Performing a Confluence Cloud v2 operation (create/get/update/search pages, spaces, attachments, …).
- ✅ Performing a Jira Cloud v3 operation (create/search/transition issues, comments, …).
- ✅ A write or operation you need done programmatically against the Atlassian REST API (e.g. creating a Confluence page).
Do NOT activate when:
- The target is Atlassian Server / Data Center (this skill is Cloud + API-token only).
- You only need credential setup — credentials are provided by the caller; this skill does not provision or resolve them (see
references/credentials.mdfor the contract it consumes).
Workflow
Step 1 — Receive the injected credentials
The caller has already resolved the account and injected what this operation needs — consume it; do not look for a record yourself. You receive from context:
base_urlandemail(and the capability the account acts under) — as context values, not read from a file.- The token, by an ordered load rule the context carries the variable NAME for. Resolve that name as: the project-level
.envvalue if that file exists and defines the var, else the environment variable of that name — project.envis tried first (that is how a project.envoverrides a global env var). The token value is never in the context prose — only its variable name;curlreads the value from the environment. The project root is supplied by the context; perform no scope resolution or directory walk to find the.env, and it is project.env, not.envrc.
Then bridge these into the example scripts' fixed vars ATLASSIAN_EMAIL / ATLASSIAN_BASE_URL / ATLASSIAN_API_TOKEN (same bridge as before; only the inputs now come from context). Full contract + the bridge: [references/credentials.md](references/credentials.md).
Step 2 — Find the endpoint
Scan [assets/endpoint-index.md](assets/) (one line per operation: METHOD path — summary (operationId)) for the operation you need. Never load a full spec into context — they are multi-MB.
Step 3 — Resolve the call shape
Run the resolver: python3 scripts/endpoint.py . It dereferences that one operation from the bundled OpenAPI spec ($ref-resolved) and prints the method, path, params, request/response schema, and a curl skeleton. (scripts/endpoint.py + its validation are added during augmentation; see Progressive disclosure.)
Step 4 — Construct + run the curl
Apply the per-API patterns from [references/patterns.md](references/patterns.md):
- Auth (both):
curl -u "$email:$"(HTTP Basic). - Base URL: Confluence →
/wiki/api/v2/; Jira →/(paths already include/rest/api/3/…). - Rich-text bodies (the easy-to-get-wrong part) — see [
references/rich-text.md](references/rich-text.md): Jira uses ADF as a raw JSON object; Confluence uses{representation, value}whereatlas_doc_formatmeans the ADF JSON stringified andstoragemeans an XHTML string. If your source is Markdown (e.g. a formatted comment), convert it to ADF withpython3 scripts/md_to_adf.pyin acurl -uargument; the subprocess reads it from the environment. The token lives only in.env(gitignored). - Resolve before constructing. Build a request body/params from the
$ref-resolved schema (Step 3) or the verified rich-text formats — never from a guessed/remembered field set. - Per-API, not generic. Apply Confluence vs Jira patterns correctly (base URL, pagination, rich-text, errors) — they differ.
- Rich-text: Jira ADF = raw object; Confluence
atlas_doc_format= stringified ADF invalue. Do not mix them. - This skill never writes credentials. Credentials are provided by the caller; this skill never provisions or resolves them.
Preferences (override-able):
- Prefer the newer Jira issue search
GET /rest/api/3/search/jql(nextPageToken) over the legacy/search(startAt). - Request only needed fields (
fields=on Jira,body-format=on Confluence) to keep responses small.
Gotchas
- Rich-text mismatch. Sending a raw ADF object to Confluence
atlas_doc_format(instead of a stringified one), or a stringified blob to Jira (instead of a raw object), is the most common failure. Confluencevalueis always a string. - Base-URL difference. Confluence paths are relative to
…/wiki/api/v2; Jira paths already include/rest/api/3. Don't double-prefix or drop/wiki. $refchains. The request body is rarely inline in the spec — it$refs a schema (which may$reffurther). Use the resolver (Step 3); a rawgrepof the spec won't give you the full shape.- Legacy vs new Jira search.
GET /rest/api/3/searchis being deprecated forGET /rest/api/3/search/jql; pagination differs (startAtvsnextPageToken). - Rate limits. Jira returns HTTP 429 with a
Retry-After; honor it. Confluence may return 413 on oversized bodies. - Confluence delete is two-stage (verified live, applies to pages, blogposts, and other content).
DELETE /pages/{id}(or/blogposts/{id}) only trashes it (returns 204, butGETstill returns it withstatus: trashed). To remove permanently, callDELETE //{id}?purge=true— which only works once trashed (purge-without-trash is a no-op). A plain delete is not full removal. - Jira
/search/jqlrejects unbounded JQL (verified live). Ordering-only or empty JQL →400 ErrorCollection("Unbounded JQL queries are not allowed here"). Always include a search restriction (e.g.project = X,created >= -30d).
Anti-patterns
- Guessing the body. Don't hand-write a request body from memory of "what Jira issues look like" — resolve the schema; field requirements change per project/screen.
- Echoing the token. Never
echo $TOKEN, never paste it into a command you print, never write its value into any file. Reference the env var insidecurlonly. - Loading the whole spec. Don't
cat/read the multi-MB OpenAPI JSON into context — scan the index, resolve one op. - One-size-fits-all. Don't apply Jira's pagination/errors/ADF to Confluence or vice-versa.
- SDK creep. Don't reach for
atlassian-python-api/pip install—curl+ the resolver cover every endpoint.
Output
This skill produces API side effects (the requested Confluence/Jira operation) and returns the parsed JSON response to the calling agent. It writes no files of its own (it only consumes the caller-injected credentials). For write operations it reports the created/updated resource (id, key, URL); for reads it returns the result set, following pagination as needed. The abstract consumer is the calling agent (or a sub-agent) that needs the operation performed; secrets never enter that output.
Related
- [
references/credentials.md](references/credentials.md) — the credential contract this skill consumes (caller-injected fields + the ordered token-load rule + the bridge into the fixed vars). - The REST-direct + bundled-OpenAPI-spec pattern generalizes to other API providers.
Progressive disclosure
Heavy content lives in subfolders, loaded only on demand:
- [
references/patterns.md](references/patterns.md) — per-API patterns: auth, base URL, pagination (Confluence cursor vs Jira offset/token), response envelopes, errors, rate limits,expand. Load in Steps 4–5. - [
references/rich-text.md](references/rich-text.md) — ADF (Jira, raw object) and Confluence body representations (storage/atlas_doc_format, value-as-string) with worked examples + the cross-API gotcha. Load when building a request body. - [
references/credentials.md](references/credentials.md) — the credential contract this skill consumes: caller-injected fields, the ordered token-load rule, the bridge into the fixed vars, honest-secret handling. Load in Step 1. - [
references/sources.md](references/sources.md) — provenance (Atlassian official docs + the bundled spec versions).
Added during augmentation (Phase 2.C), referenced above:
assets/confluence-v2.json,assets/jira-v3.json— the bundled OpenAPI specs (authoritative; queried, never loaded wholesale).assets/endpoint-index.md— one line per operation, for discovery (Step 2).scripts/endpoint.py+scripts/endpoint.py.validation.md— thepython3$ref-resolver (Step 3).scripts/.sh+.validation.md— the four validated examplecurls (create Confluence page, Confluence list, Jira create issue, Jira search).scripts/md_to_adf.py+.validation.md— a stdlib Markdown -> ADF converter. Pipe a Markdown comment/description through it to post it as native ADF (headings, bold, code, links, lists, GFM tables render instead of showing raw##/|):python3 scripts/md_to_adf.py the ADF object for the Jira{"body": ...}`.
Standalone usage (optional, not required)
This is a convenience for a human running the skill by hand outside agent-flow — it is not a dependency of the skill. The skill's normative contract is caller-injection (Step 1); this appendix is only the manual-operator bridge.
To run by hand, populate the three fixed vars yourself from a .service-accounts.yaml record + its .env token, then run the scripts. An example record:
accounts:
- name: atlassian-work
provider: atlassian
base_url: https://workco.atlassian.net
email: me@workco.com
token_env: ATLASSIAN_WORK_API_TOKEN # the var holding the token value; value lives in .env (gitignored)
set -a; source .env; set +a # loads $ATLASSIAN_WORK_API_TOKEN, never prints it
export ATLASSIAN_EMAIL="me@workco.com"
export ATLASSIAN_BASE_URL="https://workco.atlassian.net"
export ATLASSIAN_API_TOKEN="$ATLASSIAN_WORK_API_TOKEN"
bash scripts/create-confluence-page.sh ""
Get an API token at id.atlassian.com → Security → "Create API token". The value is referenced by name only, never printed.
Body budget
description≤ 1,024 chars (agentskills.io cap).- Body ≤ ~500 lines / 5,000 tokens — kept in context every turn; per-API detail lives in
references/. assets/*.jsonare large (queried on disk, never loaded into context).
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: bm629
- Source: bm629/agent-skills
- 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.