external/tgd-skills/tgd-jira-auto-sync/SKILL.md
Parse TASKS.md and auto-create Jira Data Center issues in a single Sprint. Use as conditional skill in /tgd-plan phase after TASKS.md is generated.
npx skillsauth add seikaikyo/dash-skills tgd-jira-auto-syncInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Parses the TASKS.md produced by /tgd-plan and creates Jira issues in the company's Jira Data Center instance, all assigned to a single Sprint. Uses curl + Jira REST API v2 — no external CLI binary needed, works behind company proxies.
The user MUST provide these before the skill runs:
JIRA_URL = https://jira.company.com (Data Center base URL)
JIRA_TOKEN = Personal Token (PAT)
JIRA_PROJECT = Project key (e.g. ENG, FE, BE) — 必填
Setup (one-time):
# Test connection (Bearer auth)
curl -x "" -s -H "Authorization: Bearer $JIRA_TOKEN" "$JIRA_URL/rest/api/2/myself" | python3 -m json.tool
If it returns user info, auth works. If 401/403, check credentials or proxy settings.
Priority Mapping:
Map TASKS.md priority to Jira priority names (check your instance via curl -x "" $JIRA_URL/rest/api/2/priority):
Company networks often intercept HTTPS. If curl fails with SSL errors or timeouts:
# Option 1: Set proxy (if Jira is external or proxy is required to reach it)
export HTTPS_PROXY=http://proxy.company.com:8080
# Option 2: Bypass proxy for internal Jira Data Center (if proxy is globally set but Jira is on intranet)
# Use curl -x "" to bypass the proxy
curl -x "" -s -H "Authorization: Bearer $JIRA_TOKEN" ...
# Option 3: MITM proxy re-signs TLS — point curl at the company CA bundle
curl --cacert /path/to/company-ca-bundle.crt ...
# or: export CURL_CA_BUNDLE=/path/to/company-ca-bundle.crt
Never disable certificate verification (curl -k, NODE_TLS_REJECT_UNAUTHORIZED=0).
The request carries your Jira PAT — sending it over an unverified connection hands
the token to whoever can intercept. Ask IT for the CA bundle path instead.
The skill parses the canonical TASKS.md format defined in
tgd-planning-and-task-breakdown (the only TASKS.md format). Per task section:
## Task 1: [User Story Title] (Story ID: US-01)
### 1. Context & Goal
[Goal + **Priority**: High/Medium/Low + **Dependencies**]
### 2. Technical Design
[Schema / API contract]
### 3. Acceptance Criteria (BDD)
- **AC-1.1** — **Given** [context] **When** [action] **Then** [result]
- **Regression**: Yes [R] / No
- **Test**: `tests/path` (present once /tgd-develop has run)
### 4. Files Likely Touched
- `src/foo.py`
Extract per task: number, title (summary), Context & Goal (description),
Priority, the AC-<task>.<n> criteria, and Files Likely Touched. Keep the
original AC ids — they are the traceability link back to TASKS.md.
Read $TGD_DIR/<feature-name>/TASKS.md and extract each task block:
Step 2a: Fetch Available Issue Types for the Project Use the Jira REST API v2 (Jira 9.0+ DC compliant) to get all available issue types for the project.
curl -x "" -s \
"$JIRA_URL/rest/api/2/issue/createmeta/$JIRA_PROJECT/issuetypes" \
-H "Authorization: Bearer $JIRA_TOKEN" \
-H "Content-Type: application/json" > /tmp/jira_issuetypes.json
Parse and present issue types:
# JIRA_PROJECT must be exported to the environment for the heredoc to see it
python3 << 'PYEOF'
import json, os
data = json.load(open("/tmp/jira_issuetypes.json"))
issuetypes = data.get("values", [])
print(f"📌 Project: {os.environ['JIRA_PROJECT']}")
print("Available Issue Types:")
for i, it in enumerate(issuetypes, 1):
print(f" [{i}] {it['name']} (ID: {it['id']})")
PYEOF
🛑 Action: Present the issue type list to the user. Default to Story if present. Store their choice as
ISSUE_TYPE_ID.
Step 2b: Fetch Required Fields for the Selected Issue Type
Query the exact metadata for the chosen ISSUE_TYPE_ID. This returns only the fields available for that specific issue type in this project, including required flags and allowed values.
curl -x "" -s \
"$JIRA_URL/rest/api/2/issue/createmeta/$JIRA_PROJECT/issuetypes/$ISSUE_TYPE_ID" \
-H "Authorization: Bearer $JIRA_TOKEN" \
-H "Content-Type: application/json" > /tmp/jira_meta.json
Parse and present required custom fields:
python3 << 'PYEOF'
import json, subprocess, os
meta = json.load(open("/tmp/jira_meta.json"))
fields = meta.get("fields", {})
project_key = os.environ['JIRA_PROJECT']
print(f"🔍 Required Custom Fields for {project_key} (IssueType ID: {os.environ['ISSUE_TYPE_ID']}):")
required_fields = []
for field_id, field_info in fields.items():
if field_info.get("required") and field_id not in ("summary", "description", "project", "issuetype", "priority", "labels", "reporter"):
required_fields.append({
"id": field_id,
"name": field_info["name"],
"schema": field_info.get("schema", {}),
"allowed_values": field_info.get("allowedValues", [])
})
for rf in required_fields:
schema = rf["schema"]
allowed = rf["allowed_values"]
field_id = rf["id"]
# Case 1: Has static allowedValues (Dropdown, select, components)
if allowed:
options = [v.get("name", v.get("value", str(v))) for v in allowed]
print(f" • {field_id}: {rf['name']} (type: {schema.get('type')}) - Options: {options}")
# Case 2: Dynamic Epic Link / Parent (Fetch existing epics in project)
elif "epic" in rf["name"].lower() or "parent" in rf["name"].lower():
print(f" • {field_id}: {rf['name']} (type: {schema.get('type')}) - Dynamic Epic Link")
print(" 🔍 Querying active Epics in JIRA...")
# Run JQL to get Epics
try:
res = subprocess.run([
"curl", "-x", "", "-s",
"-H", f"Authorization: Bearer {os.environ.get('JIRA_TOKEN')}",
f"{os.environ.get('JIRA_URL')}/rest/api/2/search?jql=project={project_key}+AND+issuetype=Epic&maxResults=50&fields=key,summary"
], capture_output=True, text=True)
epics_data = json.loads(res.stdout)
epics = epics_data.get("issues", [])
if epics:
print(" Available Epics:")
for ep in epics:
print(f" - [{ep['key']}] {ep.get('fields', {}).get('summary')}")
else:
print(" ⚠️ No Epics found in this project.")
except Exception as e:
print(f" ⚠️ Failed to query Epics: {str(e)}")
# Case 3: Standard open input (string, date, number)
else:
print(f" • {field_id}: {rf['name']} (type: {schema.get('type')}) - [Open text/value input]")
if not required_fields:
print(" ✅ No required custom fields.")
print("\n===META_JSON===")
print(json.dumps(meta))
PYEOF
🛑 Agent Interaction Guide (Mandatory): When you find required fields, you MUST ask the user one-by-one or in a clean list. Follow this conversational style:
🔍 I found the following required fields for project [ENG] with IssueType [Story]: 1. customfield_10100: "Component" (type: option) Options: [1] Backend [2] Frontend [3] Database 👉 Please reply with the number or name to select. 2. customfield_10200: "Epic Link" (type: string) Options (Active Epics found via JQL): [1] [ENG-100] User Auth Redesign [2] [ENG-101] Core Database Migration 👉 Please reply with the number or Epic Key. 3. customfield_10300: "Target Release Date" (type: date) 👉 Please reply with the value (Format: YYYY-MM-DD).Do not guess or skip. Store all user answers and dynamically build the payload under
fields.
For each parsed task, construct a JSON payload and create a Jira issue.
📝 Summary Format Rule (Mandatory):
The summary MUST be structured in the classic User Story format and strictly under 255 characters.
Format: [feature-name] As a <user role>, I want <action/goal> so that <benefit>
💡 Example:
[jwt-auth] As a user, I want to login via email to access my secure dashboard
📝 Description Format Rule (Mandatory):
The Agent MUST construct the DESCRIPTION variable using this Wiki Markup structure. Do NOT deviate from this format.
h3. Background
{noformat}
<Why is this needed? Current pain point or context from PRD/SPEC.>
{noformat}
h3. Goal
{noformat}
<What exactly are we building? The desired measurable outcome.>
{noformat}
h3. Acceptance Criteria
{noformat}
AC-<task>.<n> (copy the exact id from TASKS.md — it is the traceability link):
Given <initial context>
When <action occurs>
Then <expected result>
{noformat}
h3. Technical Notes
{noformat}
Files Likely Touched:
- <path/to/file1>
- <path/to/file2>
Estimate: <X points>
{noformat}
# 1. Export variables for the Python script (avoids bash escaping hell)
export SUMMARY="[<feature-name>] Task Title"
export PRIORITY="High"
export DESCRIPTION="h3. Background..."
export FEATURE_NAME="<feature-name>"
# 2. Construct the payload via Python
python3 << 'EOF' > /tmp/jira_payload.json
import json, os
payload = {
"fields": {
"project": { "key": os.environ['JIRA_PROJECT'] },
"summary": os.environ['SUMMARY'],
"issuetype": { "id": os.environ['ISSUE_TYPE_ID'] },
"priority": { "name": os.environ['PRIORITY'] },
"labels": ["tgd", os.environ['FEATURE_NAME']],
"description": os.environ['DESCRIPTION']
}
}
# Add any custom required fields discovered in Step 2
# payload['fields']['customfield_XXXX'] = { "value": user_provided_value }
print(json.dumps(payload))
EOF
# 3. Execute the API call
curl -x "" -s -X POST \
"$JIRA_URL/rest/api/2/issue" \
-H "Authorization: Bearer $JIRA_TOKEN" \
-H "Content-Type: application/json" \
-d @/tmp/jira_payload.json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('key','ERROR: '+d.get('errorMessages',str(d))[0]))"
Mandatory fields vary by company and project. When a field is required, inject it into the JSON payload using the correct data type:
// Dropdown / Select List (Single Choice)
"customfield_10100": { "value": "High" },
// Component/s (Multi-select)
"components": [{ "name": "Backend" }, { "name": "Database" }],
// Fix Version/s (Multi-select)
"fixVersions": [{ "name": "v1.2.0" }],
// Epic Link / Parent (String)
"customfield_10011": "PROJ-1001",
// User Picker (Single User)
"customfield_10300": { "name": "elon.wang" },
// Text / Text Area (String)
"customfield_10400": "Some internal notes here.",
// Labels
"labels": ["tgd", "jwt-auth", "urgent"]
⚠️ Warning: The
schema.typereturned bycreatemetadetermines the structure.
option→{ "value": "..." }array→[{ "name": "..." }]string→"..."directly.
Scenario: feature-name = jwt-auth, Task = "Implement Login API"
{
"fields": {
"project": { "key": "ENG" },
"summary": "[jwt-auth] As a user, I want to login via email and password to access my dashboard",
"issuetype": { "id": "10000" },
"priority": { "name": "High" },
"labels": ["tgd", "jwt-auth"],
"description": "h3. Background\n{noformat}\nCurrently, the system has no authentication. All endpoints are public, causing data leakage risks.\n{noformat}\n\nh3. Goal\n{noformat}\nImplement a secure POST /login endpoint that validates credentials and returns a JWT token valid for 24 hours.\n{noformat}\n\nh3. Acceptance Criteria\n{noformat}\nAC-1.1:\nGiven a registered user with valid credentials\nWhen they POST to /api/login\nThen they receive a 200 OK with a JWT token in the body\n\nAC-1.2:\nGiven an unregistered user or wrong password\nWhen they POST to /api/login\nThen they receive 401 Unauthorized and no token\n{noformat}\n\nh3. Technical Notes\n{noformat}\nFiles:\n- src/auth/login.py\n- tests/test_login.py\n- config/settings.py (JWT_SECRET)\n{noformat}"
}
}
⚠️ Critical: The
summarymust always start with[<feature-name>]and follow the "As a... I want... So that..." format where possible. Keep it under 255 characters.
Output: Print each created issue key (e.g. ENG-1234).
If an issue creation fails, the script should:
JIRA_TOKEN$JIRA_URL/rest/api/2/priority and retry.sleep 1, if still fails skip and continueOutput a summary table:
| TASKS.md Task | Jira Key | Status |
|---------------|----------|--------|
| Task 1: xxx | ENG-1234 | ✅ Created |
| Task 2: yyy | ENG-1235 | ✅ Created |
| Task 3: zzz | - | ❌ Failed: ... |
In /tgd-plan, add as a conditional skill:
**Conditional (apply when relevant):**
- User wants Jira tickets? → `tgd-jira-auto-sync`
1. Ask for JIRA_URL, JIRA_PROJECT (必填), JIRA_TOKEN.
2. Query `createmeta` once to discover issue types + required fields. Let user choose issue type (default: Story). If required custom fields have allowedValues, present options.
3. Parse $TGD_DIR/<feature-name>/TASKS.md and create issues via REST API v2.
4. Report created issue keys.
/rest/api/2/) — works on all Data Center versions/rest/api/3/) — DC 8.0+, uses Atlassian Document Format (ADF) for description fields. If v3, description must be ADF JSON, not wiki markuph3., {noformat}) — simpler and universally compatibleIf the company Jira has required custom fields (e.g., Component, Fix Version, Severity), the create payload must include them:
"customfield_10100": {"value": "High"},
"components": [{"name": "Backend"}]
How to discover: Step 2's createmeta already includes all required fields and allowedValues. Use that result directly.
Company MITM proxies cause SSL certificate problem. Solutions:
REQUESTS_CA_BUNDLE or CURL_CA_BUNDLE to the company CA cert path — this is the only acceptable fix.curl -k, NODE_TLS_REJECT_UNAUTHORIZED=0): the request carries your Jira PAT.Data Center may throttle bulk creation. If creating 20+ issues:
sleep 0.5 between API calls/rest/batch/1.0/issue (if available on DC 9.0+)/tgd-plan generates TASKS.md| Rationalization | Reality | |---|---| | "I'll sync to Jira later" | Later never comes. Sync immediately after plan. | | "Manual Jira entry is fine" | Manual entry loses the link between TASKS.md and Jira. |
After execution, verify:
tools
Conduct comprehensive GDPR compliance assessments by evaluating data processing activities against EU Regulation 2016/679, including Article 30 records of processing, lawful basis validation, data subject rights implementation, Data Protection Impact Assessments (DPIAs) under Article 35, breach notification procedures, international transfer safeguards (SCCs, adequacy decisions), and technical/organizational measures under Article 32. Use when processing personal data of EU residents, preparing for supervisory authority audits, implementing privacy-by-design for new systems, scoping compliance gaps for M&A due diligence, assessing third-party processors, or responding to data subject access requests at scale. Incorporates 2026 guidance from ICO, EDPB, and post-Data (Use and Access) Act 2025 UK-GDPR considerations. Do not use for implementing specific Article 32 controls — use implementing-gdpr-data-protection-controls; or for DSAR automation — use implementing-gdpr-data-subject-access-request.
tools
Parse Windows forensic artifacts—$MFT/$J (MFTECmd), Prefetch (PECmd), registry hives (RECmd), shellbags, and Amcache—into normalized CSV/JSON with Eric Zimmerman's EZ Tools, then load results into Timeline Explorer for analysis. Use during DFIR/incident-response investigations, after triage collection (e.g. with KAPE), to establish program execution, file/folder access, and persistence evidence from acquired forensic images.
development
Build automated multi-turn adversarial attacks against conversational LLM targets using Microsoft PyRIT's RedTeamingOrchestrator, CrescendoOrchestrator (gradual escalation), and TreeOfAttacksWithPruningOrchestrator (adaptive branching), with scorer feedback loops and persisted conversation memory. Use when single-shot LLM scanning is insufficient and you need multi-turn, scorer-driven AI red-team campaigns against a chatbot or agent.
testing
Stand up MISP, enable and cache curated threat feeds (CIRCL, abuse.ch, Feodo Tracker), apply warninglists to suppress false positives, query indicators with PyMISP, and export attributes as auto-generated Suricata/Sigma/Wazuh detection rules. Use when maturing a MISP instance to actively drive detection, curating threat feeds with quality controls, or automating IOC-to-detection pipelines for the SIEM/IDS.