Skip to main content

runspec-jira

A full-featured Jira runnable for runspec, ported from the Atlassian MCP server onto atlassian-python-api — covering Jira Software/Core and Service Desk (JSM), on Cloud and Server/Data Center. One runnable — jira — with ~37 verbs. pip install it into a venv and it's discoverable by runspec local, runspec serve (MCP), and runspec-console.

runspec serve flattens each verb into a leaf MCP tool (jira_get-issue, …). Read verbs are autonomy = "autonomous"; writes are autonomy = "confirm".

The narrower one-runnable-per-project JSM option, runspec-jsm, is unchanged — use this package when you want the full Jira surface.

Install

pip install runspec-jira

Verbs

Area Verbs
Issues get-issue, create-issue, update-issue, assign-issue, delete-issue
Search search (JQL), get-project-issues
Transitions list-transitions, transition-issue
Comments add-comment, edit-comment
Links get-link-types, create-issue-link, link-to-epic, create-remote-issue-link, remove-issue-link
Worklog get-worklog, add-worklog
Projects get-all-projects, search-projects, get-project-components, get-project-issue-types, get-create-fields
Fields / users search-fields, get-user-profile, search-assignable-users
Watchers get-watchers, add-watcher, remove-watcher
Service desk list-request-types, list-request-type-fields, raise-request, get-request
Request types by name create-request, update-request, describe-request-types — one call, friendly field names
Project admin list-project-roles, get-role-members, add-to-role, remove-from-role, check-user-access
Customers list-customers, add-customers, remove-customers, list-organizations, add-to-organization
Attachments list-attachments, download-attachments, add-attachment, remove-attachment

Compact output

get-issue, search and get-project-issues return a compact view by default, so an agent gets what it needs without a 20 KB API payload:

jira get-issue --key PROJ-1                          # essentials + counts of comments, links, …
jira get-issue --key PROJ-1 --include comments,links # add parts
jira get-issue --key PROJ-1 --raw                    # the raw Jira REST response
jira search --jql 'project = PROJ' --start 25        # compact rows; truncated / next_start for paging

In an interactive terminal these print readable text. Agents, pipes, the console's Forms tab and schedulers get JSON.

Auth — env vars only

export JIRA_URL=https://your-org.atlassian.net
# Cloud (API token):
export JIRA_USERNAME=you@example.com
export JIRA_API_TOKEN=<api-token>
# …or Server/DC (Personal Access Token):
export JIRA_PERSONAL_TOKEN=<pat>

Cloud vs Server/DC is detected from a .atlassian.net host or set with JIRA_CLOUD. Every verb takes --env, selecting JIRA_<ENV>_* prefixed vars. The PAT can instead ride the runspec-console secret channel via the optional --jira-pat (a password-typed arg, refused on the CLI, kept out of logs). JSON-object args (--additional-fields, --fields, --visibility, --worklog-json, --field-values) are passed as strings and parsed in the core.

jira search --jql "project = OPS AND status = 'In Progress'"
jira create-issue --project OPS --summary "Disk full on db-01" --issue-type Incident
jira transition-issue --issue OPS-42 --transition Done

Public Python API

The pure logic is in runspec-jira-core — over atlassian-python-api, no runspec dependency, no entry points. Every op takes a JiraConfig first arg and raises JiraError, so a private wrapper can inject credentials and bake in a default project_key / service_desk_id / env:

from runspec_jira_core import config_from_env, build_client, get_issue

cfg = config_from_env(env="prod")
issue = get_issue(cfg, "OPS-42")

Raising and editing requests in one call

raise-request needs a request type id and a JSON object keyed by customfield_* ids in JSM's wire shapes, so an agent first calls list-request-types and list-request-type-fields. create-request / update-request skip that — name the project and request type, key fields by name or portal label, and pass plain values:

jira create-request --project HR --request-type "New starter" \
  --values '{"Summary": "Welcome Sam", "Office": "Leeds", "Equipment": ["Laptop"], "Location": "UK > Leeds"}'
jira update-request --key HR-42 --values '{"Office": "London"}'

A wrong field or option comes back with the closest match and the request type's full field list, so a second attempt is right without a discovery call.

A department package with typed verbs

For the handful of projects a department uses every day, generate one typed verb per request type into your own wrapper package, so the agent sees each form as the tool's input schema (options as choice, required fields marked) and raises in one call with no discovery at all. Other projects stay reachable through the generic verbs above.

python -m runspec_jira_core.codegen --runnable mydept \
  --project HR --project PAY --project FAC --project IT --project SEC --project PROC \
  --toml mydept/runspec.toml --manifest mydept/jsm_request_types.json

This splices [mydept.commands.raise-hr-new-starter]-style tables between markers in your runspec.toml (hand-written verbs outside the markers are kept) and writes a manifest to ship as package data. --request-type '*laptop*' narrows the set; --check in CI fails when a form changed in Jira. Dispatch:

from importlib.resources import files
from runspec_jira_core import load_manifest, manifest_arg_names, run_generated_command, update_request, manifest_signatures

MANIFEST = load_manifest(files("mydept") / "jsm_request_types.json")

def dispatch(spec, cfg):
    cmd = spec.runspec_command
    if cmd in MANIFEST["commands"]:
        values = {name: spec.get(name).value for name in manifest_arg_names(MANIFEST, cmd)}
        return run_generated_command(cfg, MANIFEST, cmd, values, on_behalf_of=spec.get("on-behalf-of").value)
    if cmd == "update-request":  # edits resolve offline for the generated types
        return update_request(cfg, spec.key.value, spec.values.value, signatures=manifest_signatures(MANIFEST))
    ...

Request type and option ids differ between instances: when --env points at an instance other than the one the manifest was generated from, the raise is re-resolved by project + request type name.

Development

python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
ruff check . && ruff format --check .
pytest

Metadata

Release files for runspec-jira 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for runspec-jira 0.5.0
File Size Uploaded
runspec_jira-0.5.0.tar.gz 20.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for runspec-jira 0.5.0
File Interpreter ABI Platform
runspec_jira-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 35.8 kB

Release files / runspec_jira-0.5.0.tar.gz

Download URL runspec_jira-0.5.0.tar.gz
Size 20.4 kB
Tags Source
SHA-256 checksum
How to use checksums
fc56b5beea868b1a081621c8ccd8d9b322b12600e970745404640eaeb62ca4c8
BLAKE2b-256 checksum
How to use checksums
2577c2f664508abca169ff5f222e32f8bcc3b1697d314eb7c315f08264afd1f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / runspec_jira-0.5.0-py3-none-any.whl

Download URL runspec_jira-0.5.0-py3-none-any.whl
Size 15.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
43f1c70c67ebac3a42b980c3ebae06cdeaac7bdd17e7c74ccb9c673a652f5c9d
BLAKE2b-256 checksum
How to use checksums
7c61d53d0c2a06618320a89c58dd950fc7932d04dcb1b138b924fb11bc309432
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page