Every input carried a description, and most of them restated the field name:
"Comment ID" for comment_id, "Board ID" for board_id, "JQL query string" for
query. That is a label, not help. An operator filling get_incidents for the
first time has no way to learn from it that the fetch appends its own
created >= watermark clause and an ORDER BY, that writing either breaks it,
that the watermark box is filled by the alert rule rather than by hand, or that
a run makes a single call and silently drops whatever exceeds max.
103 input fields rewritten to answer two questions instead: what goes in this
box, and where do I get it. Formats are shown by example rather than named —
2026-09-30 rather than "yyyy-mm-dd", soc,phishing rather than "comma-separated"
— and every field holding an id now names the command that returns it:
get_id_by_attribute for an assignee, board_list for a board, get_comments for
a comment, get_issue for an attachment, get_link_types for a link type and for
which issue belongs on which side of it.
Fields that replace rather than append say so, since labels and components
quietly drop whatever is left out.
A personal access token silently outranked Basic credentials. Anything left in
pat — an email pasted into the wrong field, a token from a decommissioned Data
Center — became the Authorization header, and Atlassian answered "Client must
be authenticated to access this resource." That sentence names no field, so the
search starts at the URL, the API version, the token itself: everywhere except
the one field that caused it.
Basic authentication now wins whenever username and api_key are both set, and
pat serves the rest, so a token left behind cannot outrank credentials someone
has just filled in. A lone username, or a lone api_key, is not a pair and does
not claim the request. A 401 or 403 says which method was used and whether the
other was configured and ignored.
Three configurations that cannot work are refused with the reason rather than
sent to Jira:
- no usable credential, where an empty username/api_key pair was being
base64-encoded into a valid-looking header;
- the Cloud gateway URL with an empty cloud_id, which addresses no site, so
every path under it is a dead link and Jira replies with an HTML 404 that
explains nothing;
- a cloud_id set against any other host, where it is not an address at all,
only a path segment that does not exist.
Credentials are stripped before use: one pasted with a trailing newline
corrupts the header and reads back as a wrong password.
Error bodies are condensed instead of dumped. Jira's 404 page is four hundred
lines of AUI markup, stylesheet links and inline scripts around one sentence,
and it was going into the test modal whole; what surfaces now is the <title>
and the readable text, capped. A 2xx that is not JSON — a login page, an SSO
redirect, a proxy standing in for the API — reports what answered and the URL
the redirects landed on, in place of a JSON parser offset.
Config descriptions now say which fields pair with which deployment, and which
credential is used when both are present.
Applied to all 27 scripts; the seven shared helper blocks stay identical across
them.
Jira Cloud and On-Prem/Data Center (27 commands): JQL ingestion with an
OCSF mapper and JQL query, full issue lifecycle (create/get/edit/delete,
transitions, assign), comments, remote web links and issue links,
attachments (upload/download/delete), field and user lookups, and agile
boards/sprints/epics. Basic (email + API token) or Personal Access Token
authentication; API v3 + ADF bodies on Cloud, v2 on On-Prem.
Stdlib-only, no extra Python dependencies.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>