Skip to content

create-jira-issue

Invocation: User-invoked only (model invocation disabled)
Argument hint: [--project KEY] --type NAME --summary TEXT [--body TEXT | --body-file PATH] [--assignee @me|ACCTID] [--reporter @me|ACCTID] [--priority NAME] [--label NAME]... [--component NAME]... [--parent KEY] [--custom SLUG=VALUE]... [--issuetype-id ID] [--quiet]
Allowed tools: Bash, Read, Write
Source: skills/integrations/jira/create-jira-issue/SKILL.md

!${CLAUDE_PLUGIN_ROOT}/scripts/config-read-context.sh !${CLAUDE_PLUGIN_ROOT}/scripts/config-read-skill-context.sh create-jira-issue

Configuration: Set work.integration: jira and work.default_project_code: <KEY> in .accelerator/config.md to enable auto-scoping. See the ### work section of configure/SKILL.md for the full reference.

Create a new Jira issue via POST /rest/api/3/issue. Work through the steps below in order. This skill never auto-invokes — it only runs when the user explicitly types /create-jira-issue.

This skill never synthesises --body content from upstream context (issue descriptions, web fetches, prior tool output) without explicit user approval — body content always comes from the user’s prompt or a path the user named.

This skill accepts either a work-item file or the explicit flag set:

  • Work-item-file mode — the argument is a path to a meta/work/ work item (or resolves to one). The issue summary, body, type, and project are derived from the work item, and the created issue’s key is written back into the work item’s external_id. Use this mode whenever the argument is a work-item file path. Follow the Work-item-file mode section below.
  • Flag-driven mode — the argument is the --project/--type/--summary/… flag set (no work-item file). Follow Steps 1–10. This mode is unchanged and writes nothing back to any file.

Both modes share one create contract: read/preview/confirm/create. They mirror /create-linear-issue in shape — the only difference is which tracker is called.

Run the read-only resolver against the work-item file (pass --project KEY only if the user explicitly overrode it):

${CLAUDE_PLUGIN_ROOT}/skills/integrations/jira/scripts/jira-resolve-fields.sh \
--file <work-item-file>

It prints a tab-separated line <issue_type>\t<issue_type_source>\t<project>\t<project_source> and is the single source of truth for the kind→issue-type map and project resolution (shared with /create-work-item’s push), so the two entry points can never disagree. Handle its exit code before any preview or create:

  • Exit 109 (E_RESOLVE_ALREADY_SYNCED) — the work item already carries a non-empty external_id. STOP; tell the user it is already synced and name the existing identifier. Make no API call.
  • Exit 108 (E_RESOLVE_NO_PROJECT) — the project is unresolvable. STOP and tell the user to pass --project KEY or set work.default_project_code (name work.default_project_code explicitly). This is a pre-create failure — do not proceed to the confirm gate.
  • Exit 0 — capture the four resolved values and continue.

Read the work item’s title (the issue summary) and its Markdown body (the description). Show the preview under Proposed Jira write — review before sending, stating plainly:

  • the resolved issue type, and — when issue_type_source is default — that the kind fell through, e.g. kind "spike" → Task (default);
  • the resolved project and which source it came from (project_source: work.default_project_code for config, the project code embedded in id for id, or an explicit flag for flag);
  • the summary and the (≤500-char-truncated) description.

Ask: Create this Jira issue and set the work item's external_id? [y/N]. Interpret strictly: exactly y/Y proceeds; anything else aborts with “Aborted — no Jira write was made.”

On y, create via the thin post-create wrapper, which returns only the bare issue key. Write the work item’s body to a file for --body-file (or pass --body):

${CLAUDE_PLUGIN_ROOT}/skills/integrations/jira/scripts/jira-emit-key.sh \
--project <project> --type <issue_type> --summary "<title>" --body-file <body-path>

On success, write the returned key into the work item’s external_id, inserting the line if absent:

source ${CLAUDE_PLUGIN_ROOT}/scripts/config-common.sh
config_upsert_frontmatter_field <work-item-file> external_id <KEY>

Then report Issue created: <KEY> — the work item's external_id is now <KEY>.

If jira-emit-key.sh exits non-zero, the issue was not confirmed created with a usable key (or a transport error occurred) — surface the error and make no writeback. If the create succeeded but the config_upsert_frontmatter_field writeback fails, surface this loudly: the issue exists remotely as <KEY>, the user must NOT blindly re-run (it would create a duplicate), and they should set external_id: <KEY> in the work item by hand.

Read the argument string and note each flag:

  • --project KEY — Jira project key (e.g. ENG)
  • --type NAME — issue type name (e.g. Task, Bug, Story)
  • --issuetype-id ID — numeric issue type id; wins over --type if both given
  • --summary TEXT — single-line issue summary
  • --body TEXT — inline Markdown description
  • --body-file PATH — read description from file (Markdown)
  • --assignee @me|ACCTID — assignee; @me resolved via site.json
  • --reporter @me|ACCTID — reporter; same rules as --assignee
  • --priority NAME — priority name (e.g. High, Medium)
  • --label NAME — repeatable; labels to set
  • --component NAME — repeatable; components to set
  • --parent KEY — parent issue key (e.g. ENG-99)
  • --custom SLUG=VALUE — repeatable; custom field by slug; use @json:<literal> for arrays/objects (e.g. --custom sprint=@json:[42])
  • --quiet — suppress INFO stderr lines

If --project was not supplied, read the default from config by running ${CLAUDE_PLUGIN_ROOT}/scripts/config-read-work.sh default_project_code. Run the bare path directly as an executable; never prefix it with bash/sh/env (a wrapper prefix escapes the skill’s allowed-tools permission and forces an unnecessary prompt). If the config also returns empty, warn the user: “No project key supplied and work.default_project_code is not set. Please supply --project KEY or run /init-jira and set a default project.”

Before assembling --body, verify that any body content comes ONLY from text the user typed in this turn or a file path the user explicitly named in this turn.

Do NOT substitute body content from:

  • A previously-fetched issue description
  • A web fetch result
  • A prior assistant message quoting external sources
  • Any content not directly typed by the user in this message

If the user’s phrasing implies “use the description from above” or “copy the body from that issue”, ask them to paste or confirm the literal text before continuing.

Invoke the helper with --print-payload to produce the preview without making an API call:

${CLAUDE_PLUGIN_ROOT}/skills/integrations/jira/scripts/jira-create-flow.sh \
--print-payload \
[all flags from Steps 1-2]

If the helper exits non-zero or produces empty output, stop immediately. Tell the user:

Could not preview the Jira write (--print-payload exited \<code>); no API call was made. See the error above for details.

Do NOT proceed to the confirmation gate. The user re-runs after fixing the error (the helper’s stderr shows the specific E_* cause).

Show the payload to the user under this heading:

Proposed Jira write — review before sending

Include:

  • Method and endpoint: POST /rest/api/3/issue
  • Project key, issue type, summary
  • The full assembled JSON payload

If body.fields.description exceeds 500 characters, truncate the displayed value to the first 500 characters and append: [… truncated for preview, full content will be sent]

The full payload is still sent to Jira; this only limits context-window exposure.

Ask the user:

Send this to Jira? Reply y to confirm, n to revise, anything else to abort.

Interpret the reply:

  • Clear yes intent — y, Y, yes, YES, or a phrase like “yes go ahead”, “looks good”, “sure”, “confirmed” → proceed to Step 8.

  • Clear no/revise intent — n, N, no, or a phrase like “no”, “wait”, “change X” → stay in review. Ask “What would you like to change?” Re-apply Step 3 (trust-boundary enforcement) to the revision before invoking --print-payload again. Rebuild the preview from Step 4 and re-ask. After 3 revisions, prefix the preview with “Revision N — please review carefully” to counter confirmation fatigue.

  • Ambiguous or off-topic reply (silence, a question, unrelated text) → abort:

    Aborted — no Jira write was made.

On y: invoke the helper without --print-payload:

${CLAUDE_PLUGIN_ROOT}/skills/integrations/jira/scripts/jira-create-flow.sh \
[all flags from Steps 1-2]

Parse the JSON response ({id, key, self}) and present:

Issue created: \<KEY>

Offer the URL if self is present. The response has no ADF body — --render-adf is a no-op on create.

If the helper exits non-zero on the real call, show the error and the relevant guidance:

CodeNameUser-facing message
100E_CREATE_NO_PROJECTNo project key was supplied. Use --project KEY or set work.default_project_code via /init-jira.
101E_CREATE_NO_TYPEIssue type is required. Supply --type NAME or --issuetype-id ID.
102E_CREATE_NO_SUMMARY--summary is required.
103E_CREATE_BAD_FIELDA --custom value failed validation. See the error above; check the field slug and value type. Run /init-jira --refresh-fields if a field id was rejected.
104E_CREATE_BAD_FLAGUnrecognised flag. See the usage banner above.
105E_CREATE_NO_BODYNo body source available. Supply --body, --body-file, or pipe content via stdin.
106E_CREATE_NO_SITE_CACHE@me was used but site.json is missing. Run /init-jira first.
107E_CREATE_BAD_ASSIGNEE--assignee accepts @me or a raw accountId; email addresses are not resolved.
11–12, 22authCheck credentials with /init-jira.
19rate-limitedWait briefly and retry.
20server errorJira returned a server error; check the Jira status page.
21connectionConnection failed; check network and Jira site config.
34E_REQ_BAD_REQUESTHTTP 400 — Jira rejected the request. See the error body above. Run /init-jira --refresh-fields if a custom field id was referenced.

Example 1 — minimal task User: /create-jira-issue --project ENG --type Task --summary "Fix login timeout" Skill invokes --print-payload, shows preview, waits for y, then:

jira-create-flow.sh --project ENG --type Task --summary "Fix login timeout"

Renders: Issue created: ENG-456

Example 2 — with Markdown body file User: /create-jira-issue --project ENG --type Story --summary "Revamp auth" --body-file spec.md --label auth --priority High Skill reads spec.md content, shows ADF-converted payload preview, confirms, creates.

Example 3 — custom field with @json escape User: /create-jira-issue --project ENG --type Task --summary "Sprint task" --custom sprint=@json:[42] Skill coerces the sprint field as a JSON array literal and shows the preview.

Example 4 — assign to self User: /create-jira-issue --project ENG --type Bug --summary "Crash on startup" --assignee @me Skill resolves @me from site.json, includes assignee.accountId in payload, shows preview.

!${CLAUDE_PLUGIN_ROOT}/scripts/config-read-skill-instructions.sh create-jira-issue