
Jira Syntax
- 384 installs
- 73 repo stars
- Updated August 2, 2026
- netresearch/jira-skill
jira-syntax is a Claude Code skill that converts Markdown to Jira wiki markup, supplies bug and feature templates, and validates syntax before submission for developers who need readable Jira tickets.
About
jira-syntax is a Netresearch Claude Code skill (version 3.18.3) for authoring Jira descriptions, comments, and queries without broken formatting. It maps Markdown habits—headings, bold, code blocks, links, lists, and tables—to Jira wiki markup such as h2., *bold*, {code:java}, and [label|url], and ships two templates for bug reports and feature requests plus a validate-jira-syntax.sh checker. Developers reach for jira-syntax when pasting GitHub-flavored Markdown into Jira fields, preparing sprint-ready bug reports with reproduction steps, or drafting feature requests with acceptance criteria before handing tickets to jira-communication for API submission. The bundled quick-reference and cross-project GitLab link conventions reduce rework from common mistakes like ## headings, **bold**, or bare merge-request refs that Jira misrenders as images.
- Jira wiki markup formatting
- JQL query basics for filters
- Issue linking and hierarchy
- Sprint and epic field conventions
- Readable ticket templates for agents
Jira Syntax by the numbers
- 384 all-time installs (skills.sh)
- +17 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #816 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/netresearch/jira-skill --skill jira-syntaxAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 384 |
|---|---|
| repo stars | ★ 73 |
| Last updated | August 2, 2026 |
| Repository | netresearch/jira-skill ↗ |
How do you format Jira wiki markup correctly?
Write valid Jira descriptions, comments, and queries using JQL and wiki markup so tickets, epics, and sprint boards stay readable for engineers and PMs.
Who is it for?
Developers and tech leads who write Jira tickets daily and need Markdown-to-wiki conversion without broken tables, code blocks, or issue links.
Skip if: Teams that only need Jira REST API automation without formatting help, because API operations belong in the separate jira-communication skill.
When should I use this skill?
A developer is drafting or pasting Jira descriptions, comments, bug reports, feature requests, or JQL-backed ticket text that must use wiki markup instead of Markdown.
What you get
Jira-ready wiki markup text, validated bug-report and feature-request drafts, and syntax-check results from validate-jira-syntax.sh.
- Jira wiki markup text
- Validated bug or feature ticket draft
By the numbers
- Skill version 3.18.3 in the Netresearch jira-skill repository
- Includes 2 Jira templates: bug report and feature request
- Provides validate-jira-syntax.sh for automated wiki markup checking
Files
Jira Syntax
Jira wiki markup syntax, templates, and validation. For API operations, use the jira-communication skill.
Quick Syntax Reference
| Jira Syntax | Purpose | NOT this (Markdown) |
|---|---|---|
h2. Title | Heading | ## Title |
*bold* | Bold | **bold** |
_italic_ | Italic | *italic* |
{{code}} | Inline code | ` code ` |
{code:java}...{code} | Code block | `` `java `` |
| `[text\ | url]` | Link |
[PROJ-123] | Issue link | - |
[~username] | User mention | @username |
* item | Bullet list | - item |
# item | Numbered list | 1. item |
| `\ | \ | Header\ |
See references/jira-syntax-quick-reference.md for complete syntax documentation.
Available Templates
Bug Report
Path: templates/bug-report-template.md
Sections: Environment, Steps to Reproduce, Expected/Actual Behavior, Error Messages, Technical Notes
Feature Request
Path: templates/feature-request-template.md
Sections: Overview, User Stories, Acceptance Criteria, Technical Approach, Success Metrics
Syntax Validation
Run before submitting to Jira:
${CLAUDE_SKILL_DIR}/scripts/validate-jira-syntax.sh path/to/content.txtValidation Checklist
- [ ] Headings:
h2. Title(space after period) - [ ] Bold:
*text*(single asterisk) - [ ] Code blocks:
{code:language}...{code} - [ ] Lists:
*for bullets,#for numbers - [ ] Links:
[label|url]or[PROJ-123] - [ ] Tables:
||Header||and|Cell| - [ ] Colors:
{color:red}text{color} - [ ] Panels:
{panel:title=X}...{panel}
Common Mistakes
| ❌ Wrong | ✅ Correct |
|---|---|
## Heading | h2. Heading |
**bold** | *bold* |
` code ` | {{code}} |
[text](url) | `[text\ |
- bullet | * bullet |
h2.Title | h2. Title |
MR !42 (bare GitLab ref) | `[MR 42\ |
Integration with jira-communication Skill
Workflow: 1. Get template from jira-syntax 2. Fill content using Jira wiki markup 3. Validate with ${CLAUDE_SKILL_DIR}/scripts/validate-jira-syntax.sh 4. Submit via jira-communication skill
References
references/jira-syntax-quick-reference.md- Complete syntax documentationreferences/cross-project-refs.md- GitLab cross-project ref convention (group/project!N,group/project#N,group/project@tag) when linking to GitLab from Jiratemplates/bug-report-template.md- Bug report templatetemplates/feature-request-template.md- Feature request template${CLAUDE_SKILL_DIR}/scripts/validate-jira-syntax.sh- Automated syntax checker- Official Jira Wiki Markup
<!-- Managed by agent: keep sections & order; edit content, not structure. Last updated: 2025-12-12 -->
AGENTS.md — jira-syntax
Development guide for maintaining templates, references, and validation scripts.
Overview
Static content skill: templates, reference docs, and a validation script. No runtime dependencies.
Setup & environment
No special setup. Files are plain text/markdown/shell.
Build & tests
# Test validation script
scripts/validate-jira-syntax.sh templates/bug-report-template.mdCode style & conventions
Templates (`templates/`):
- Use actual Jira wiki markup, never Markdown
- Include section comments explaining purpose
- Test in real Jira before committing
References (`references/`):
- Keep
jira-syntax-quick-reference.mdas single source of truth - Examples must be copy-pasteable into Jira
Validation script:
- Bash with grep patterns
- Should catch common Markdown mistakes
Security & safety
- No executable code in templates
- No sensitive data in examples
PR/commit checklist
- [ ] All examples use valid Jira wiki markup
- [ ] Tested in actual Jira instance
- [ ] Updated quick-reference if adding new syntax
- [ ] Validation script catches the patterns
Good vs. bad examples
Template changes:
# ✓ Test paste into Jira before commit
# ✓ Update quick-reference if new syntax
# ✗ Assume Markdown works in Jira
# ✗ Add syntax without testingWhen stuck
- Paste content into real Jira to verify rendering
- Check official docs: https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa
House rules
- SKILL.md has the user-facing syntax reference
- This file is for maintaining the skill itself
---
Maintaining this file: See root AGENTS.md for convention reference.
[
{
"name": "convert_markdown_to_jira",
"prompt": "Convert this Markdown to Jira wiki format: **bold** text with [link](https://example.com) and `code`",
"assertions": [
{
"type": "content",
"pattern": "\\*bold\\*"
},
{
"type": "content",
"pattern": "\\[link\\|https://example\\.com\\]"
},
{
"type": "content",
"pattern": "\\{\\{code\\}\\}"
},
{
"type": "not_content",
"pattern": "\\*\\*bold\\*\\*"
}
]
},
{
"name": "bug_report_with_table",
"prompt": "Write a Jira bug report description with a table of reproduction steps (Step, Action, Expected, Actual) for a file upload bug",
"assertions": [
{
"type": "content",
"pattern": "\\|\\|.*Step.*\\|\\|"
},
{
"type": "content",
"pattern": "h[1-3]\\."
},
{
"type": "not_content",
"pattern": "^#{1,3} "
},
{
"type": "not_content",
"pattern": "\\*\\*"
}
]
},
{
"name": "format_code_block_in_jira",
"prompt": "Show me how to include a Java stack trace in a Jira comment with proper formatting",
"assertions": [
{
"type": "content",
"pattern": "\\{code(:java)?\\}"
},
{
"type": "not_content",
"pattern": "```"
}
]
},
{
"name": "escape_literal_block_tag_mention",
"prompt": "Write a short Jira QA comment in wiki markup with one finding line stating that all commands are documented in {code} blocks with command and output together, plus one real code block containing: ls -l",
"assertions": [
{
"type": "content",
"pattern": "\\\\\\{code\\\\\\}"
},
{
"type": "not_content",
"pattern": "\\{code\\}[^\\n]*[A-Za-z]"
}
]
}
]
Cross-Project References to GitLab Resources
When referencing GitLab merge requests, issues, tags, or commits from a Jira description, comment, or worklog, prefer the GitLab cross-project autolink syntax — even though Jira itself doesn't autolink GitLab paths, the cross-project form removes ambiguity for human readers and matches the convention used in GitLab itself.
Convention
| GitLab resource | Short form (single-project context) | Cross-project form (use this in Jira) |
|---|---|---|
| Merge request | !42 | group/project!42 |
| Issue | #123 | group/project#123 |
| Tag / commit / branch | vX.Y.Z | group/project@vX.Y.Z |
The same prefix characters (!, #, @) are what GitLab itself recognises for cross-project autolinks in markdown, commit messages, and MR descriptions — so a reader who pastes the reference into a GitLab UI will get a working link automatically.
In Jira wiki markup
Wrap the cross-project text inside the standard Jira link syntax [text|url]:
[jira/jira!25|https://git.netresearch.de/jira/jira/-/merge_requests/25]
[jira/jira@v9.12.3-2|https://git.netresearch.de/jira/jira/-/tags/v9.12.3-2]
[jira/jira#42|https://git.netresearch.de/jira/jira/-/issues/42]Why not just !25?
A bare !25 in a Jira issue forces the reader to guess which GitLab project it lives in — and to click to find out. A bare v9.12.3-2 is even worse: tag names are reused across many repos.
When an issue references multiple repos in the same group (e.g. jira/jira for the image build and jira/app for the deploy stack), the cross-project form is essential — !3 could be either repo's MR.
Inside {{...}} monospace
!, #, and @ all work inside {{...}}, but *unescaped `{`, `}` and ` inside a {{...}} block break Jira's parser**: a raw { makes the whole block render as raw text, and a *` pair turns bold mid-token. Escape them with a backslash (verified against the Jira Server 9.12 wiki renderer).
Broken — the block falls apart on the raw {, and backup- renders bold:
{{compose.example.{yml,override.pga.yml}}}
{{jira-*backup-*}}Correct — renders compose.example.{yml,override.pga.yml} and jira-*backup-* in monospace:
{{compose.example.\{yml,override.pga.yml\}}}
{{jira-\*backup-\*}}Splitting into separate {{...}} references also works when escaping would hurt readability.
The validate-jira-syntax.sh script catches the brace collision.
Jira Wiki Markup Syntax - Quick Reference
Complete reference for Jira's wiki markup syntax to ensure proper formatting in tickets, comments, and descriptions.
Table of Contents
- Text Formatting
- Headings
- Lists
- Links
- Code Blocks
- Tables
- Panels and Quotes
- Colors
- Special Blocks
- Line Breaks and Horizontal Rules
- Special Characters
- Emoticons
- Common Patterns
- Validation Checklist
- Common Mistakes to Avoid
Text Formatting
| Syntax | Output | Use Case |
|---|---|---|
*text* | text | Bold/strong emphasis |
_text_ | text | Italic/emphasis |
{{text}} | text | Monospace for code/paths |
-text- | ~~text~~ | Strikethrough |
+text+ | <u>text</u> | Underline/inserted text |
^text^ | text^superscript^ | Superscript |
~text~ | text~subscript~ | Subscript |
??text?? | text (citation) | Citation format |
Headings
h1. Heading Level 1 (largest)
h2. Heading Level 2
h3. Heading Level 3
h4. Heading Level 4
h5. Heading Level 5
h6. Heading Level 6 (smallest)Rules:
- Space required after
h1.throughh6. - One heading per line
- Use h2 for main sections, h3 for subsections
Lists
Bulleted Lists
* Level 1 item
** Level 2 nested item
*** Level 3 nested item
* Another level 1 itemNumbered Lists
# First item
## Nested item
## Another nested item
# Second itemMixed Lists
# Numbered item
#* Nested bullet
#* Another bullet
# Another numbered itemRules:
- Space after
*or# - Nesting uses additional symbols (
**,##) - Can mix list types with combined syntax (
#*)
Links
| Type | Syntax | Example |
|---|---|---|
| Issue Link | [KEY-123] | [PROJ-456] |
| User Mention | [~username] | [~john.doe] |
| External URL | [http://url] | [http://example.com] |
| Labeled Link | `[Label\ | url]` |
| Attachment | [^filename] | [^screenshot.png] |
[mailto:email] | [mailto:team@example.com] | |
| Anchor | {anchor:name} + [#name] | {anchor:intro} → [#intro] |
Code Blocks
Inline Code
Use {{code}} for inline monospace textCode Blocks with Syntax Highlighting
{code:java}
public class Example {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
{code}Supported Languages (Jira Server / Data Center):
The Jira Server source-code formatter accepts ONLY this fixed list. Using any other identifier (e.g. typoscript, rust, typescript, yml, shell) produces:
Unable to find source-code formatter for language: <name>. Available languages are: ...| Group | Identifiers |
|---|---|
| General-purpose | actionscript, ada, applescript, c, c#, c++, cpp, erlang, go, groovy, haskell, java, javascript, js, lua, objc, perl, php, python, r, ruby, scala, swift, visualbasic |
| Shell / scripting | bash, sh |
| Data / markup | css, html, json, sql, xml, yaml |
| Special | none (no highlighting), nyan, rainbow |
Notes:
- Use
c#/c++literally, notcsharp/cplusplus(thoughcppis also accepted). - There is no
typescript,rust,kotlin,dart,shell,yml,dockerfile,terraform, ortyposcriptformatter. - For unsupported languages, fall back to
{code:none}(or{noformat}) to preserve the block without highlighting.
{code:none}
[request && request.getNormalizedParams().getHttpHost() == "backend.example.de"]
page.meta.robots = noindex,noarchive
[END]
{code}Preformatted Text (No Highlighting)
{noformat}
Plain text without syntax highlighting
Preserves whitespace and formatting
{noformat}Block Tags Are Never Inline
{code}, {noformat}, {quote} and {panel} are block-level macros: the tag must stand alone on its own line. An unescaped tag inside a prose sentence opens a real block mid-line and swallows the rest of the line — the classic failure is writing about code blocks.
Broken — renders everything after "in" as an opened code block:
All commands are documented in {code} blocks with output.Correct — renders the literal text {code}:
All commands are documented in \{code\} blocks with output.Escape literal mentions of any block tag with backslashes: \{code\}, \{noformat\}, \{quote\}, \{panel\}. For inline monospace use {{...}}, never an inline {code} pair — even {code}one-liner{code} renders as a block, not inline.
scripts/validate-jira-syntax.sh flags inline block tags and unbalanced tag counts; run it on composed text before submitting to Jira.
Tables
Basic Table
||Header 1||Header 2||Header 3||
|Cell A1|Cell A2|Cell A3|
|Cell B1|Cell B2|Cell B3|Rules:
||for header cells (double pipe)|for regular cells (single pipe)- Rows must have same number of cells
- No trailing pipe at end of row
Example with Content
||Feature||Status||Owner||Priority||
|User Login|{color:green}Complete{color}|[~john.doe]|High|
|Password Reset|{color:yellow}In Progress{color}|[~jane.smith]|Medium|
|2FA|{color:red}Not Started{color}|Unassigned|Low|Panels and Quotes
Panel with Title and Background
{panel:title=Important Information|bgColor=#FFFFCE}
Content inside the panel
{panel}Panel Parameters:
title=text- Panel headingbgColor=#HEXCODE- Background colorborderStyle=solid|dashed- Border styleborderColor=#HEXCODE- Border colortitleBGColor=#HEXCODE- Title background
Quote Block
{quote}
Multi-line quoted text
Can span multiple paragraphs
{quote}Single Line Quote
bq. This is a block quote on one lineColors
{color:red}Red text{color}
{color:blue}Blue text{color}
{color:green}Green text{color}
{color:#FF0000}Hex color text{color}Named Colors:
red,blue,green,yellow,orange,purpleblack,white,gray,grey- Or use hex codes:
#FF0000,#00FF00,#0000FF
Special Blocks
Notice/Info Panels
{panel:title=⚠️ Warning|bgColor=#FFEBE9|borderColor=#FF0000}
This is a warning message
{panel}
{panel:title=ℹ️ Information|bgColor=#DEEBFF|borderColor=#0052CC}
This is an info message
{panel}
{panel:title=✅ Success|bgColor=#E3FCEF|borderColor=#00875A}
This is a success message
{panel}Expand/Collapse Section
{expand:title=Click to expand}
Hidden content that can be toggled
{expand}Line Breaks and Horizontal Rules
Line 1\\
Line 2 (line break with \\)
First paragraph
Second paragraph (blank line creates new paragraph)
----
Horizontal rule (4 dashes)Special Characters
--- (em-dash: —)
-- (en-dash: –)
\\ (line break)
\{escaped brace\}To escape special characters, use backslash: \*, \{, \[.
- Only escape characters Jira actually parses as markup —
*,_,-,+,^,~,{,[,|,\. Do not escape plain punctuation such as.,,, or:—\.renders the backslash literally and produces the wrong output. - Never escape inline monospace —
{{text}}is not a macro, so\{\{text\}\}is wrong. Only escape the opening brace of a macro name shown as prose (e.g.\{code\}). - Preserve existing backslash escapes — a source
\*,\_, or\{already suppresses Markdown markup; keep it as-is, because Jira uses the same\escape mechanism for the same characters.
Common gotcha: macro names in prose
Writing a macro name literally in prose (e.g. "commands wrapped in \{code\} blocks") without escaping breaks rendering — Jira parses the literal as the start of a code-block macro and either consumes the rest of the comment or pairs with the next unrelated occurrence it finds. The same trap applies to any macro that opens and closes with the same token: {noformat}…{noformat}, {quote}…{quote}, {color}…{color}, {panel}…{panel}, {anchor}…{anchor}, and so on.
Three ways to write the literal token safely, in order of preference:
| Approach | Example | When to use |
|---|---|---|
| Rephrase to avoid the token | commands shown as code blocks | First choice — readers don't need the macro name to understand the prose |
| Backslash-escape | \{code\} | When you genuinely need to show the macro name |
| Wrap in a code span | ` {{code}} ` | Last resort — some style guides ban inline {{monospace}} in favour of bold *term* for technical terms |
The backslash escape is the official Jira mechanism; the rephrase is editorial; the {{monospace}} wrap renders fine but is disliked by teams that reserve monospace for actual code spans rather than inline references.
A quick sanity check before posting: run skills/jira-syntax/scripts/validate-jira-syntax.sh <file> on your draft (from the repo root). The script verifies that the six paired macros (code, panel, color, noformat, quote, anchor) are balanced — every opener matches a closer, even with a language tag like {code:bash} — and catches Markdown leakage ( ` fences, [text](url) links, ` code ` spans), language declarations Jira Server does not recognise, and malformed table headers.
Emoticons
| Code | Emoji | Meaning |
|---|---|---|
:) | 🙂 | Happy |
:( | 🙁 | Sad |
:P | 😛 | Tongue |
:D | 😀 | Big smile |
;) | 😉 | Wink |
(y) | 👍 | Thumbs up |
(n) | 👎 | Thumbs down |
(!) | ⚠️ | Warning |
(?) | ❓ | Question |
(on) | 💡 | Light bulb on |
(off) | 🔌 | Light bulb off |
(*) | ⭐ | Star |
Common Patterns
Status Update Comment
h3. Status Update - 2025-11-06
h4. Completed
* Implemented user authentication
* Added unit tests (95% coverage)
* Updated documentation
h4. In Progress
* Integration testing
* Performance optimization
h4. Blocked
* Waiting for API key from [~admin]
* See [PROJ-123] for details
h4. Next Steps
# Deploy to staging environment
# Conduct security review
# Schedule production deploymentCode Review Comment
h3. Code Review Findings
h4. ✅ Approved Changes
* Clean separation of concerns
* Comprehensive error handling
* Well-documented functions
h4. 🔧 Suggestions
{code:java}
// Current implementation
public void processData(String input) {
// Process directly
}
// Suggested improvement
public void processData(String input) {
validateInput(input); // Add validation
// Process after validation
}
{code}
h4. ❌ Issues Found
* Missing null check on line 45
* Potential memory leak in {{DataProcessor}}
* Security vulnerability: [OWASP-A03|https://owasp.org/Top10/A03_2021-Injection/]
[~developer] Please address these before merging.Meeting Notes
h2. Sprint Planning Meeting - 2025-11-06
h3. Attendees
* [~pm] - Product Manager
* [~tech-lead] - Technical Lead
* [~dev1], [~dev2], [~dev3] - Development Team
h3. Agenda
# Review last sprint outcomes
# Plan current sprint scope
# Assign tasks and estimates
h3. Decisions
||Decision||Owner||Action Items||
|Implement caching layer|[~tech-lead]|[PROJ-500] - Research Redis options|
|Upgrade to Node 20|[~dev1]|[PROJ-501] - Test compatibility|
|Refactor authentication|[~dev2]|[PROJ-502] - Design proposal needed|
h3. Action Items
# [~pm] - Update roadmap with Q1 priorities
# [~tech-lead] - Schedule architecture review
# [~dev1] - Provide effort estimates by Friday
h3. Next Meeting
*Date:* 2025-11-13 10:00 AM
*Focus:* Sprint retrospectiveValidation Checklist
Before submitting, verify:
Headings
- [ ] Using
h1.throughh6.(not Markdown#) - [ ] Space after period (
h2. Titlenoth2.Title) - [ ] One heading per line
Text Formatting
- [ ]
*bold*not**bold** - [ ]
_italic_not*italic* - [ ]
{{code}}not `code`
Lists
- [ ]
*for bullets, not- - [ ]
#for numbers - [ ] Proper nesting (
**,##not spaces/tabs)
Code
- [ ]
{code:language}not ``language`` - [ ] Proper language identifier
- [ ] Closing
{code}tag
Links
- [ ]
[Label|url]not[Label](url) - [ ]
[PROJ-123]for issues - [ ]
[~username]for mentions
Tables
- [ ]
||for headers - [ ]
|for cells - [ ] Consistent column count
Colors
- [ ]
{color:name}text{color}format - [ ] Proper closing
{color}tag
Panels
- [ ] Opening
{panel:params} - [ ] Closing
{panel} - [ ] Valid parameters
Common Mistakes to Avoid
| ❌ Wrong | ✅ Correct | Note |
|---|---|---|
## Heading | h2. Heading | Markdown vs Jira |
**bold** | *bold* | Double asterisk is not bold |
` code ` | {{code}} | Markdown backticks don't work |
[text](url) | `[text\ | url]` |
- item | * item | Use asterisk for bullets |
h2.Title | h2. Title | Missing space after period |
{code} | {code:java} | Missing language identifier |
| `\ | Header\ | ` |
Resources
#!/bin/bash
# Jira Wiki Markup Syntax Validator
# Checks text for common Jira syntax errors and suggests corrections
set -e
# Colors for output
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# Counters
ERRORS=0
WARNINGS=0
# Function to print error
# Use pre-increment so the (( )) expression is the new (non-zero) value;
# `((ERRORS++))` returns the OLD value (0 on first call) and trips `set -e`.
error() {
echo -e "${RED}❌ ERROR:${NC} $1"
((++ERRORS))
}
# Function to print warning
warning() {
echo -e "${YELLOW}⚠️ WARNING:${NC} $1"
((++WARNINGS))
}
# Function to print success
success() {
echo -e "${GREEN}✅ $1${NC}"
}
# Function to check file
validate_file() {
local file="$1"
echo ""
echo "=========================================="
echo "Validating: $file"
echo "=========================================="
if [ ! -f "$file" ]; then
error "File not found: $file"
return
fi
local content=$(cat "$file")
local line_num=0
# Check for Markdown-style headings (## instead of h2.)
if echo "$content" | grep -qE "^##+ "; then
error "Found Markdown-style headings (##). Use Jira format: h2. Heading"
echo " Lines with issue:"
echo "$content" | grep -nE "^##+ " | head -5
fi
# Check for Markdown-style bold (**text** instead of *text*)
if echo "$content" | grep -qE "\*\*[^*]+\*\*"; then
warning "Found Markdown-style bold (**text**). Use Jira format: *text*"
echo " Examples found:"
echo "$content" | grep -oE "\*\*[^*]+\*\*" | head -3
fi
# Check for Markdown-style italic (_text_ is ok, but *text* for bold might be confused)
if echo "$content" | grep -qE "\*[^*]+\*\*[^*]+\*"; then
warning "Found potential Markdown-style italic mixed with bold"
fi
# Check for Markdown-style code blocks (``` instead of {code})
if echo "$content" | grep -qE "^\`\`\`"; then
error "Found Markdown code blocks (\`\`\`). Use Jira format: {code:language}"
echo " Lines with issue:"
echo "$content" | grep -nE "^\`\`\`" | head -5
fi
# Check for Markdown-style inline code (` instead of {{)
if grep -qE "\`[^\`]+\`" <<< "$content"; then
warning "Found Markdown inline code (\`code\`). Consider Jira format: {{code}}"
fi
# Check for unescaped { or } inside {{...}} monospace blocks. The Jira parser
# is greedy and breaks on raw inner braces, rendering the block as raw text
# (e.g. {{compose.example.{yml,override.pga.yml}}} renders verbatim).
# Backslash-escaped braces (\{ \}) render literally and are fine.
# Two failure modes:
# 1. {{ followed by another raw { before any } — e.g. {{path/{a,b}.txt}}
# or {{a{b}c}}.
# 2. A {{ block with an extra raw } before the closing }} — e.g. {{a}b}}.
# `([^...\\]|\\.)*` skips escaped characters so \{ and \} don't false-positive.
local brace_re='\{\{([^{}\\]|\\.)*\{|\{\{([^{}\\]|\\.)*\}([^{}\\]|\\.)*\}\}'
if grep -qE "$brace_re" <<< "$content"; then
error "Found unescaped { or } inside {{...}} monospace block — Jira parser will render it as raw text. Escape as \\{ \\} or split the reference."
echo " Lines with issue:"
grep -nE "$brace_re" <<< "$content" | head -3
fi
# Check for unescaped * inside {{...}} monospace blocks. Jira still parses
# inline markup inside {{...}}: a * pair turns bold mid-token
# (e.g. {{jira-*backup-*}} renders "backup-" bold). Escape as \*.
local star_re='\{\{([^{}*\\]|\\.)*\*'
if grep -qE "$star_re" <<< "$content"; then
warning "Found unescaped * inside {{...}} monospace block — renders as bold mid-token. Escape as \\* (e.g. {{jira-\\*backup-\\*}})."
echo " Lines with issue:"
grep -nE "$star_re" <<< "$content" | head -3
fi
# Check for Markdown-style links ([text](url) instead of [text|url])
if echo "$content" | grep -qE "\[([^\]]+)\]\(([^)]+)\)"; then
error "Found Markdown-style links ([text](url)). Use Jira format: [text|url]"
echo " Examples found:"
echo "$content" | grep -oE "\[([^\]]+)\]\(([^)]+)\)" | head -3
fi
# Check for headings without space after period (h2.Title instead of h2. Title)
if echo "$content" | grep -qE "^h[1-6]\.[^ ]"; then
error "Found headings without space after period. Use: h2. Title (not h2.Title)"
echo " Lines with issue:"
echo "$content" | grep -nE "^h[1-6]\.[^ ]" | head -5
fi
# Check for code blocks without language specification
# (skip escaped \{code\} literals and inline-monospace {{code}})
if grep -qE '(^|[^\\{])\{code\}[^{]' <<< "$content"; then
warning "Found {code} blocks without language. Consider: {code:java} for syntax highlighting"
fi
# Check for {code:LANG} using a language Jira Server's formatter does not recognize.
# Authoritative list from the server error message ("Available languages are: ...").
# Anything outside this set causes "Unable to find source-code formatter for language: X".
# Use Bash built-in pattern matching with literal-quoted needle so identifiers
# containing shell-significant characters (c#, c++) are compared verbatim.
local valid_langs="actionscript ada applescript bash c c# c++ cpp css erlang go groovy haskell html java javascript js json lua none nyan objc perl php python r rainbow ruby scala sh sql swift visualbasic xml yaml"
local search_langs=" $valid_langs "
while IFS= read -r lang; do
[ -z "$lang" ] && continue
# Templates ship `{code:language}` as a fill-in placeholder; warn rather than
# error so templates stay validatable until users substitute a real lang.
if [ "$lang" = "language" ]; then
warning "Found {code:language} placeholder — replace with an actual language before submitting to Jira"
continue
fi
if [[ "$search_langs" != *" $lang "* ]]; then
# Suggest the closest-fit valid language for common stumbles before
# falling back to the generic "use {code:none} or ..." message.
# Lower-case the identifier so `Dockerfile`, `Makefile` etc. match
# without per-variant case entries.
local hint=""
case "${lang,,}" in
hcl|tf|terraform|tofu) hint="{code:none} for HCL / Terraform / OpenTofu" ;;
dockerfile|containerfile) hint="{code:bash} (Dockerfile RUN lines lex acceptably as bash) or {code:none}" ;;
rust|rs) hint="{code:none} for Rust" ;;
kotlin|kt) hint="{code:java} (Kotlin lexes acceptably as Java) or {code:none}" ;;
typescript|ts|tsx) hint="{code:javascript} or {code:none}" ;;
shell|zsh|fish|console) hint="{code:bash} or {code:none}" ;;
make|makefile) hint="{code:none} for Makefile" ;;
ini|toml|conf|properties) hint="{code:none} for INI / TOML / config" ;;
diff|patch) hint="{code:none}" ;;
go-template|gotmpl|jinja|jinja2) hint="{code:none}" ;;
esac
if [ -n "$hint" ]; then
error "Unsupported {code:$lang} language. Jira Server rejects this; use $hint"
else
error "Unsupported {code:$lang} language. Jira Server rejects this; use {code:none} or one of: $valid_langs"
fi
fi
done < <(grep -oE '(^|[^\\{])\{code:[^}|\\]+' <<< "$content" | sed 's/.*{code://' | sort -u)
# Check for tables with incorrect header syntax (|Header| instead of ||Header||)
if echo "$content" | grep -qE "^\|[^|]+\|$" && ! echo "$content" | grep -qE "^\|\|"; then
warning "Potential table header without double pipes. Headers should use: ||Header||"
fi
# Check for unclosed {code} blocks
# Jira wiki markup uses {code} as both the opening and closing tag, so a
# correctly paired block always produces an even occurrence count.
# Use `grep -o ... | wc -l` to count each occurrence (not just matching
# lines), matching the {color} check below for consistency and to catch
# multiple tags on the same line.
# `(^|[^\\{])` skips escaped literals (\{code\}) and inline-monospace
# lookalikes ({{code}}) — both are prose, not block markup.
local code_count
code_count=$(grep -oE '(^|[^\\{])\{code[}:]' <<< "$content" | wc -l)
if [ $((code_count % 2)) -ne 0 ]; then
error "Mismatched {code} tags: odd number ($code_count) of occurrences (expected pairs)"
fi
# Check for unclosed {panel} blocks
# Same rule applies: {panel} opens and closes the block.
local panel_count
panel_count=$(grep -oE '(^|[^\\{])\{panel[}:]' <<< "$content" | wc -l)
if [ $((panel_count % 2)) -ne 0 ]; then
error "Mismatched {panel} tags: odd number ($panel_count) of occurrences (expected pairs)"
fi
# Check for unclosed {color} blocks
local color_count=$(echo "$content" | grep -o "{color" | wc -l)
if [ $((color_count % 2)) -ne 0 ]; then
warning "Potential unclosed {color} tag (odd number of occurrences)"
fi
# Check for unclosed {noformat}, {quote}, {anchor} blocks
# Same single-token open/close rule as {code}, {panel}, {color}: an odd
# occurrence count signals an unescaped literal in prose or a missing close.
for macro in noformat quote anchor; do
local mcount
mcount=$(grep -oE "(^|[^\\\\{])\{${macro}[}:]" <<< "$content" | wc -l)
if [ $((mcount % 2)) -ne 0 ]; then
warning "Potential unclosed {${macro}} tag (odd number of occurrences)"
fi
done
# Check for block-markup tags used inline. {code}, {noformat}, {quote} and
# {panel} are block-level macros: the tag must stand alone on its own line.
# An unescaped tag with other text on the same line opens the block
# mid-prose and swallows the rest of the line (classic case: writing
# *about* {code} in a sentence). Escape literal mentions as \{code\}.
# Escaped tags (\{code\}) and {{monospace}} lookalikes ({{code}}) are
# stripped per line BEFORE testing — a line-level exclusion would hide a
# genuine unescaped tag sharing a line with an escaped/monospace mention.
local inline_hits
inline_hits=$(awk '
{
line = $0
gsub(/\\\{(code|noformat|quote|panel)[^}]*\\\}/, "", line)
gsub(/\{\{(code|noformat|quote|panel)(:[^}]*)?\}\}/, "", line)
if (line ~ /\{(code|noformat|quote|panel)(:[^}]*)?\}/ &&
line !~ /^[[:space:]]*\{(code|noformat|quote|panel)(:[^}]*)?\}[[:space:]]*$/)
printf "%d:%s\n", NR, $0
}' <<< "$content" | head -3)
if [ -n "$inline_hits" ]; then
error "Block tag used inline — {code}/{noformat}/{quote}/{panel} must stand alone on their own line; escape literal mentions as \\{code\\}"
echo " Lines with issue:"
echo "$inline_hits"
fi
# Check for Markdown-style lists (- item instead of * item)
if echo "$content" | grep -qE "^- [^-]"; then
warning "Found Markdown-style bullets (- item). Jira prefers: * item"
fi
# Positive checks
if echo "$content" | grep -qE "^h[1-6]\. "; then
success "Found correctly formatted Jira headings"
fi
if echo "$content" | grep -qE "{code:[a-z]+}"; then
success "Found code blocks with language specification"
fi
if echo "$content" | grep -qE "\[~[a-z.]+\]"; then
success "Found user mentions ([~username])"
fi
if echo "$content" | grep -qE "\[[A-Z]+-[0-9]+\]"; then
success "Found issue links ([PROJ-123])"
fi
}
# Main script
echo "Jira Wiki Markup Syntax Validator"
echo "=================================="
if [ $# -eq 0 ]; then
echo "Usage: $0 <file1> [file2] [file3] ..."
echo ""
echo "Validates Jira wiki markup syntax in text files"
echo ""
echo "Example:"
echo " $0 issue-description.txt"
echo " $0 templates/*.md"
exit 1
fi
# Validate each file
for file in "$@"; do
validate_file "$file"
done
# Summary
echo ""
echo "=========================================="
echo "Validation Summary"
echo "=========================================="
echo "Files checked: $#"
echo -e "${RED}Errors: $ERRORS${NC}"
echo -e "${YELLOW}Warnings: $WARNINGS${NC}"
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
echo -e "${GREEN}✅ All checks passed!${NC}"
exit 0
elif [ $ERRORS -eq 0 ]; then
echo -e "${YELLOW}⚠️ No errors, but $WARNINGS warnings found${NC}"
exit 0
else
echo -e "${RED}❌ $ERRORS errors found - please fix before submitting to Jira${NC}"
exit 1
fi
Jira Bug Report Template
Use this template when creating bug reports in Jira with proper wiki markup syntax.
Template
h2. Bug Description
[Provide a clear, concise description of the bug]
h3. Environment
* *Browser:* Chrome 120.0
* *OS:* Windows 11
* *Version:* 2.1.0
* *Environment:* Production
h3. Steps to Reproduce
# Navigate to [specific page/feature]
# Perform [specific action]
# Observe [unexpected behavior]
h3. Expected Behavior
[Describe what should happen]
h3. Actual Behavior
[Describe what actually happens]
{panel:title=Error Message|bgColor=#FFEBE9}
{code:java}
[Paste error message or stack trace here]
{code}
{panel}
h3. Additional Context
* Frequency: [Always/Sometimes/Rare]
* User Impact: [Critical/High/Medium/Low]
* Workaround Available: [Yes/No]
h3. Screenshots
[^screenshot1.png]
[^screenshot2.png]
h3. Related Issues
* Blocks [PROJ-XXX]
* Related to [PROJ-YYY]
h3. Technical Notes
{code:javascript}
// Code snippet showing the issue
function problematicCode() {
// Details here
}
{code}
---
*Reported by:* [~username]
*Date:* YYYY-MM-DDExample - Filled Template
h2. Bug Description
Login button becomes unresponsive after failed authentication attempt, requiring page refresh to retry.
h3. Environment
* *Browser:* Chrome 120.0.6099.109
* *OS:* Windows 11
* *Version:* 2.3.1
* *Environment:* Production
h3. Steps to Reproduce
# Navigate to {{/login}} page
# Enter invalid credentials
# Click *Login* button
# Observe error message
# Try to enter correct credentials
# Click *Login* button again
# Button remains disabled
h3. Expected Behavior
After a failed login attempt, the login button should become active again, allowing users to retry with different credentials.
h3. Actual Behavior
The login button remains in a disabled state after the first failed attempt. Users must refresh the page to attempt login again.
{panel:title=Error in Browser Console|bgColor=#FFEBE9}
{code:javascript}
TypeError: Cannot read property 'reset' of null
at LoginForm.handleSubmit (login.js:45)
at onClick (login.js:23)
{code}
{panel}
h3. Additional Context
* Frequency: Always (100% reproduction rate)
* User Impact: High (blocks login functionality)
* Workaround Available: Yes (page refresh)
* Affects ~1000 daily users based on error logs
h3. Screenshots
[^login-disabled-state.png] - Login button stuck in disabled state
[^console-error.png] - Browser console showing error
h3. Related Issues
* Blocks [PROJ-234] - User authentication improvements
* Related to [PROJ-189] - Form validation refactoring
h3. Technical Notes
{code:javascript}
// Problem in LoginForm component
handleSubmit(event) {
event.preventDefault();
this.setState({ isSubmitting: true });
// Error occurs here if form ref is null
this.formRef.reset(); // BUG: formRef can be null
// Rest of submission logic
}
{code}
Suggested fix: Add null check before calling {{reset()}} method.
---
*Reported by:* [~john.smith]
*Date:* 2025-11-06Usage with jira-communication Skill
# Create the bug report using the script
uv run scripts/workflow/jira-create.py issue PROJ \
"Login button unresponsive after failed authentication" \
--type Bug \
--priority High \
--labels frontend,authentication,ux \
--description-file bug-description.txt
# Or with inline description (short version)
uv run scripts/workflow/jira-create.py issue PROJ \
"Login button unresponsive after failed authentication" \
--type Bug \
--priority HighChecklist Before Submitting
- [ ] h2. heading for main Description section
- [ ] h3. headings for subsections
- [ ] Numbered list (#) for Steps to Reproduce
- [ ] Bulleted list (*) for Environment details
- [ ] \{panel\} for error messages with appropriate bgColor
- [ ] \{code:language\} for code snippets with correct language
- [ ] [^filename] format for attachment references
- [ ] [PROJ-XXX] format for issue links
- [ ] [~username] format for user mentions
- [ ] bold for emphasis on key terms
- [ ] {{monospace}} for UI elements and paths
Jira Feature Request Template
Use this template when creating feature requests in Jira with proper wiki markup syntax.
Template
h2. Feature Overview
[Provide a brief summary of the feature]
h3. Business Value
* *User Impact:* [Describe who benefits and how]
* *Business Goal:* [Align with strategic objectives]
* *Priority Justification:* [Why this should be prioritized]
h3. User Stories
h4. As a [user type]
* I want to [action]
* So that [benefit]
h4. As a [another user type]
* I want to [action]
* So that [benefit]
h3. Acceptance Criteria
# [Specific, testable criterion]
# [Specific, testable criterion]
# [Specific, testable criterion]
h3. Functional Requirements
h4. Must Have
* Requirement 1
* Requirement 2
h4. Should Have
* Requirement 3
* Requirement 4
h4. Could Have
* Requirement 5
* Requirement 6
h3. Non-Functional Requirements
* *Performance:* [Response time requirements]
* *Security:* [Security considerations]
* *Scalability:* [Scale requirements]
* *Accessibility:* [WCAG compliance level]
h3. Technical Considerations
{code:language}
// Pseudocode or technical notes
{code}
h3. UI/UX Mockups
[^wireframe-01.png] - Main interface mockup
[^user-flow.png] - User journey diagram
h3. Dependencies
* Requires [PROJ-XXX] to be completed first
* Impacts [PROJ-YYY] - needs coordination
h3. Open Questions
? Question 1 - needs clarification
? Question 2 - requires decision
h3. Success Metrics
||Metric||Target||Measurement Method||
|User Adoption|80% of active users|Analytics tracking|
|Performance|< 200ms response|Performance monitoring|
|Satisfaction|4.5/5 rating|User surveys|
---
*Requested by:* [~username]
*Stakeholders:* [~pm], [~designer], [~engineer]Example - Filled Template
h2. Feature Overview
Implement bulk export functionality allowing users to export multiple projects to various formats (CSV, JSON, Excel) with customizable field selection.
h3. Business Value
* *User Impact:* 500+ power users currently export data manually one project at a time (30+ clicks per export)
* *Business Goal:* Reduce data export time by 90%, improving productivity and user satisfaction
* *Priority Justification:* #1 requested feature in Q4 2024 user survey (78% of respondents), competitive gap vs competitors
h3. User Stories
h4. As a Project Manager
* I want to export multiple projects at once with selected fields
* So that I can create consolidated reports without manual data entry
h4. As a Data Analyst
* I want to export historical project data in machine-readable formats
* So that I can perform advanced analytics in external tools
h4. As a Team Lead
* I want to schedule automated exports to run daily
* So that stakeholders receive up-to-date reports without manual intervention
h3. Acceptance Criteria
# User can select 1-100 projects for bulk export from project list
# Export supports CSV, JSON, and Excel formats
# User can customize which fields to include in export
# Export progress is shown with cancel option
# Completed exports are downloadable from exports history page
# Export file size limit is 50MB with pagination for larger datasets
# Exports are available for 30 days before auto-deletion
h3. Functional Requirements
h4. Must Have
* Multi-select checkbox interface for project selection
* Format selector (CSV, JSON, Excel)
* Field customization with drag-and-drop ordering
* Progress indicator during export generation
* Download link with expiration notice
* Export history page showing last 10 exports
h4. Should Have
* Search and filter for project selection
* Save field configurations as templates
* Email notification when export completes
* Preview sample data before full export
h4. Could Have
* Schedule recurring exports
* Share export links with team members
* Export directly to cloud storage (Google Drive, Dropbox)
* Advanced filtering within export data
h3. Non-Functional Requirements
* *Performance:* Export generation completes within 30 seconds for 50 projects
* *Security:* Exports encrypted at rest, only accessible to authorized users with audit trail
* *Scalability:* Support 1000 concurrent export requests
* *Accessibility:* WCAG 2.1 AA compliance for export interface
* *Browser Support:* Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
h3. Technical Considerations
{code:python}
# Proposed export architecture
class BulkExporter:
def export_projects(self, project_ids, format, fields):
# Use async task queue for processing
task = ExportTask.create(
projects=project_ids,
format=format,
fields=fields,
user=current_user
)
# Process in background
celery.send_task('exports.process_bulk', args=[task.id])
return task.id
def get_export_status(self, task_id):
# Return progress percentage and download link when complete
return ExportTask.get(task_id).status
{code}
*Database Impact:* New {{exports}} table for tracking, ~1GB storage for 30-day retention
*API Endpoints:*
* {{POST /api/exports}} - Initiate export
* {{GET /api/exports/:id}} - Check status
* {{GET /api/exports/:id/download}} - Download file
h3. UI/UX Mockups
[^bulk-export-interface.png] - Main export dialog with project selection
[^field-customization.png] - Field selector with drag-and-drop ordering
[^export-progress.png] - Progress indicator during generation
[^export-history.png] - Export history page design
h3. Dependencies
* Requires [PROJ-456] - Background task queue infrastructure
* Impacts [PROJ-789] - Storage quota system (needs capacity planning)
* Coordinates with [PROJ-321] - API rate limiting (exports count as API calls)
h3. Open Questions
? Should exports include archived projects or only active ones?
? What permission level is required to export data? (View vs Export permission)
? Should we support incremental exports (only new/changed data)?
? How to handle very large exports exceeding 50MB limit?
h3. Success Metrics
||Metric||Target||Measurement Method||
|User Adoption|60% of power users within 3 months|Analytics event tracking|
|Time Savings|90% reduction in export time|User session timing comparison|
|User Satisfaction|4.5/5 feature rating|In-app feedback survey|
|Export Volume|5000+ exports per month|Export usage dashboard|
|Error Rate|< 1% failed exports|Error monitoring logs|
{panel:title=Launch Plan|bgColor=#DEEBFF}
h4. Phase 1 - Beta (Week 1-2)
* Release to 50 beta users
* Gather feedback and fix critical bugs
h4. Phase 2 - Limited Release (Week 3-4)
* Release to 20% of user base
* Monitor performance and error rates
h4. Phase 3 - Full Release (Week 5+)
* Release to all users
* Announce via email and in-app notifications
{panel}
---
*Requested by:* [~sarah.johnson]
*Stakeholders:* [~product.manager], [~ux.designer], [~backend.lead], [~frontend.lead]
*Estimated Effort:* 3 sprints (6 weeks)
*Target Release:* Q1 2025Usage with jira-communication Skill
# Create the feature request using the script
uv run scripts/workflow/jira-create.py issue PROJ \
"Bulk export functionality for multiple projects" \
--type Story \
--priority High \
--labels feature-request,export,productivity \
--description-file feature-description.txt
# Or with inline description (short version)
uv run scripts/workflow/jira-create.py issue PROJ \
"Bulk export functionality for multiple projects" \
--type Story \
--priority HighChecklist Before Submitting
- [ ] h2. heading for Feature Overview
- [ ] h3. headings for all major sections
- [ ] h4. headings for User Stories and subsections
- [ ] Bulleted lists (*) for requirements and criteria
- [ ] Numbered lists (#) for Acceptance Criteria
- [ ] Tables (||header|| syntax) for Success Metrics
- [ ] \{code:language\} blocks for technical details
- [ ] \{panel\} for important launch/timeline information
- [ ] [^filename] for mockup/wireframe references
- [ ] [PROJ-XXX] format for dependency links
- [ ] [~username] format for stakeholder mentions
- [ ] bold for emphasis on metrics and targets
- [ ] {{monospace}} for technical terms and paths
- [ ] ? prefix for Open Questions
Related skills
How it compares
Pick jira-syntax when the blocker is readable wiki markup and templates; use a Jira API or MCP integration when automation and ticket creation are the goal.
FAQ
Does jira-syntax post tickets to Jira automatically?
jira-syntax does not call the Jira API. The skill formats descriptions and comments in wiki markup, validates syntax with validate-jira-syntax.sh, and pairs with the jira-communication skill when API submission is required.
What templates does jira-syntax include?
jira-syntax bundles two templates: bug-report-template.md with environment and reproduction sections, and feature-request-template.md with user stories, acceptance criteria, and success metrics for sprint-ready tickets.