Delivery Factory · Part 2 · Integration
The Jira part has no opinion.
The first stage of every run needs the ticket. The plugin that fetches it is built so small that every claim about it can be checked in the code: where the token goes, who says pass or fail, and who decides what the ticket means. Repo: agentic-jira
Checked in Code
Everything on this page was read in the plugin's scripts, skills and manifest, not only in its README. Paths are relative to plugins/jira/ unless said otherwise.
The parts
Four pieces, one job each
The Jira plugin plays one role in the pipeline: the tracker. These are all the parts it has.
pack.yamlmaps roles to skillsThe core asks for an operation such as
fetch_item. The manifest says which skill does it:fetch_item → fetch-item. It also carries the words intake looks for in a ticket: design keywords likedesign,figma,layout, and the headings for reproduction steps and acceptance criteria.skills/<op>/SKILL.mdruns a scriptThe model does no reasoning here. It runs one script and returns its output unchanged. The skill text says so directly: the script alone decides pass versus fail, so there is no branch in the skill.
skills/<op>/scripts/<op>.shdecidesEverything that can go right or wrong happens here: the input checks, the call to Jira, the file it writes, and the verdict.
scripts/md-to-adf.py,build-item-fields.pyFor writing back. They turn a Markdown draft into Jira's own document format and fields, used when a ticket is created or updated.
Six operations, the same shape each time: fetch an item, post a note, attach a file, list types, update an item, create an item.
The token
Working says nothing about what it exposes
A call that puts the token on the command line works. It also leaves the token where other programs can read it.
Every call goes through
- The token is part of the process arguments.
- Anything that lists running programs can read it, and so can shell history and logs.
- Nothing in the result tells you.
The same call, nothing to see
- The script reads the token from the environment.
- It gives curl a config block on standard input,
-K -. - The command line only shows flags and an output file.
# skills/fetch-item/scripts/fetch-item.sh:51
curl -sS -K - -o "$OUT_FILE" -w '%{http_code}' <<EOF
url = "https://${JIRA_SITE}/rest/api/3/issue/${ITEM_ID}"
user = "${JIRA_EMAIL}:${JIRA_API_TOKEN}"
header = "Accept: application/json"
EOF
All six scripts in the plugin call curl this way. The ticket key is checked against ^[A-Za-z][A-Za-z0-9_]*-[0-9]+$ before it goes into that block. The comment above the check gives the reason: a key with a line break in it could add its own url = or user = line.
If any of the three variables is missing, there is no crash. The script prints a fail that names them.
The script
What fetch-item does, in order
One file, about eighty lines, read top to bottom.
- No ticket key given: usage error, exit 2. This is the only exit that is not 0.
JIRA_SITE,JIRA_EMAILorJIRA_API_TOKENmissing: fail, naming them.- Ticket key not shaped like
ABC-123, or the site not a bare hostname: fail. - Call Jira with the token on standard input.
- curl error, or any HTTP status other than 200: fail, naming the status.
- Otherwise: write the ticket to
.ai/tracker/fetch-item-<key>.jsonand print a pass with its type and status.
## Result verdict: pass summary: Fetched item ABC-123 (type=Story status=To Do) and wrote its fields to disk. artifacts: - .ai/tracker/fetch-item-ABC-123.json next_action: none
The shape of a pass, filled with an example key. The type and status are read from the response. The script does not look at the description, the acceptance criteria, or anything else in the ticket.
Intake reads that file next. A separate script on its side decides which design keywords and headings matched. That is the first point where the ticket's content counts for anything.
What it doesn't solve
A ticket that arrives fine
A clean fetch proves the ticket exists and the call was safe. It says nothing about whether anyone can build from it.
The gap
A ticket can come back with a pass and still be missing what the work needs: no acceptance criteria, no steps to reproduce a bug.
Where it gets caught
In the next stage, readiness. It checks the ticket against fixed criteria for its type, with a script and no model: a Story needs a description and acceptance criteria, a Bug needs a reproduction URL and steps.
Next
Whether the ticket is clear enough to work on.