Jira writing
Battle-tested agent skills for engineering workflows β worktrees, task implementation, PR review, Jira/Confluence. For Claude Code, Kiro, and any skill-aware agent.
npx -y skills add atomgunlk/skills --skill jira-writingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 22 days oldThe repository was created 22 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when creating or editing Jira issues via the Atlassian MCP (createJiraIssue / editJiraIssue) β composing descriptions and acceptance criteria, bulk-editing or find-replacing across ticket bodies, or when a link must render as an inline smartlink chip (π card). Symptoms β "link shows as plain text not a chip", "chips survive a markdown round-trip" (they don't), <custom data-type="smartlink">, ADF vs markdown, renaming a field across ticket bodies, acceptance criteria / EARS notation.
SKILL.md
7.8 KB, ~1.8k tokens by cl100k_base, as published. Nobody here has run it
Writing Jira issues (Atlassian MCP)
Overview
Two facts drive everything here:
editJiraIssuereplaces the entire description β there is no append/patch. AlwaysgetJiraIssuefirst (someone may have edited it) and send the whole body back.contentFormat: "markdown"authors prose, headings, bullets, tables, and code blocks fine β but it cannot express ADF-only nodes: smartlink chips (inlineCard), mentions, status lozenges, dates, emoji, media. Re-saving a body that contains any of them as markdown silently destroys them.
Creating a new issue
createJiraIssuewithcontentFormat: "markdown"for plain content. Issue type names vary per project β when unsure, confirm viagetJiraProjectIssueTypesMetadata/getJiraIssueTypeMetaWithFields(also reveals required custom fields) instead of letting the create call fail.- Description shape: Context β Acceptance criteria (EARS, see below) β Out of scope.
- Chip needed in a brand-new issue β author the whole doc as ADF (
contentFormat: "adf") from the start.
Editing β decision rule
Fetch first: getJiraIssue responseContentFormat: "markdown".
- Body is plain markdown (no
<custom β¦>tags, no mention/emoji artifacts) β edit the markdown, send back withcontentFormat: "markdown". - Body contains any
<custom data-type=β¦>tag or other non-markdown artifact β re-fetch withresponseContentFormat: "adf", mutate only the target text nodes, send the whole doc back withcontentFormat: "adf". Line breaks inside a paragraph are{"type":"hardBreak"}nodes. Don't hand-rebuild tables/code blocks in ADF β copy fetched nodes verbatim. The markdown projection is lossy (no mentionaccountId, no chipdata-id) β an ADF edit body can never be reconstructed from markdown; it must be the fetched doc mutated in place.
The chip β the one thing markdown can't do
An inline smartlink chip (π card showing the page title) is ONLY expressible as an ADF inlineCard node, placed inline inside a paragraph, with no text child (Atlassian resolves the title server-side):
{ "type": "inlineCard", "attrs": { "url": "https://site.atlassian.net/wiki/spaces/ABC/pages/123456789" } }
Send it with contentFormat: "adf" as part of a full {"type":"doc","version":1,"content":[...]} document.
Traps β do NOT do these (all empirically fail)
| What you'll be tempted to do | Reality |
|---|---|
Put <custom data-type="smartlink">URL</custom> in a markdown body | That string is a read-side serialization artifact of an existing inlineCard, NOT an input syntax. Markdown stores it as literal text β renders as the literal text, never a chip. |
Trust that it "round-trips" (fetch markdown back, <custom> still there) | Round-trip proves nothing β literal text survives a text round-trip because it's dumb text. Not proof of a chip. |
Send a bare URL (or [text](url)) in markdown and expect auto-convert | Bare-URLβsmartlink auto-detect happens in the Jira UI on paste, NOT in the MCP markdownβADF converter. Via the API it stays a plain link. |
The only path to a chip is an ADF inlineCard node.
Bulk edits & dispatching to subagents
A field-rename or find-replace across several tickets whose bodies contain ADF-only nodes is the exact case this skill exists for β the chip/mention is incidental to your task, so it's easy to treat the edit as "just text" and re-save markdown, silently downgrading every one. It is NOT just text. Also scope the match: case-sensitive, and leave URL slugs / code identifiers (user-service) untouched.
When you fan the edits out (one subagent per ticket), subagents will not discover this skill on their own. The orchestrator must bake the requirement into each subagent's prompt verbatim:
Edit via ADF:
getJiraIssueresponseContentFormat: "adf"β mutate only the target text nodes βeditJiraIssuecontentFormat: "adf"sending the whole doc. Never re-save a markdown body that contains<custom data-type=β¦>tags β that renders chips/mentions as literal text. Then verify by re-fetching ADF and confirming theinlineCard(and other custom) nodes still exist, and report the verification per ticket.
Don't assume a subagent preserved chips because it reported "done."
Verify (don't trust round-trip)
"The <custom> tag is still there when I re-fetch" and "the chips still look fine" are NOT verification. Verify each edited ticket independently β confirming one says nothing about the others.
Re-fetch with responseContentFormat: "adf". A real chip is a node {"type":"inlineCard","attrs":{"url":...}}. In the markdown projection it shows as <custom data-type="smartlink" data-id="id-N"> β the data-id is the tell of a genuine inlineCard (a failed literal-text attempt has no data-id). Or look at the Jira UI: π card = worked, literal <custom...> text = failed.
Acceptance criteria β EARS (house style)
Acceptance criteria in a description ARE a list of EARS clauses β one trigger β one testable "shall". Not Given/When/Then, not free-form bullets. If the source material arrives as Gherkin or prose, convert it.
| Pattern | Form | Use for |
|---|---|---|
| Ubiquitous | The system shall β¦ | always-true invariants; regression ("leave X unchanged"); permission-as-rule |
| Event-driven | When <trigger>, the system shall β¦ | an action / event happens |
| State-driven | While <state>, the system shall β¦ | during a state (running, offline) |
| Unwanted | If <condition>, then the system shall β¦ | error / invalid / timeout / reject |
| Optional | Where <feature configured>, the system shall β¦ | a configurable/toggleable feature only |
Example: "Only MANAGER role can export" β The system shall show the Export action only to users with the MANAGER role. (Ubiquitous). "Export fails" β If report generation fails, then the system shall show an error toast. (Unwanted)
Gotcha (observed): permission/role β Ubiquitous or Event-driven, NOT Where. Where is for features that can be turned on/off (config/build flag), not user state or role.
Converting existing AC β EARS without dropping goals: map every source item β β₯1 EARS clause; count-in must equal count-covered. Make implicit error/timeout/state cases explicit Unwanted/State-driven clauses β don't merge them away. Split a compound source bullet into multiple clauses rather than one vague "shall".
Common mistakes
- Adding a
textchild or alinkmark to the inlineCard β degrades to a plain hyperlink. inlineCard carries onlyattrs.url. - Pass the ADF as the parsed
{"type":"doc",β¦}object βcreateJiraIssuedocuments a JSON-string form as accepted, but the object form is the one verified to work on both create and edit. blockCard/embedCard= full-width card on its own line; useinlineCardfor the inline chip.- Chip renders as raw URL until Jira's resolver fetches the title; the editing account must have permission to view the target page or it degrades to a plain link.
- Guessing
issueTypeName("Story" vs localized/renamed types) instead of checking project metadata.
Related
Confluence page edits (WAF-blocked HTML bodies, whole-body replace, large-page limits) β use the confluence-writing skill.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.