Task Lifecycle — Phase 2: Implement
Phase 2 of the task lifecycle, run by the jira-task-executor skill.
Triggered once per leaf issue, from inside its own worktree. Multiple
executors run in parallel against the worktrees the assigner set up.
The diagram surfaces the two systems the executor drives as their own
swimlanes — GIT (repo and PR state: merging the parent branch current,
committing, pushing, and the gh calls that list, comment on, or open the
PR) and
JIRA (issue state: the ownership check, fetching
the issue and its prior comments, the In Progress / In Review
transitions, any Task memory comments posted along the way, and the final
run-report comment) — so the full interaction reads
User ↔ Executor ↔ GIT ↔ JIRA left to right. The split is by what a call
is about, not by whether it writes: read-only calls sit on both lanes
(gh pr list, the issue fetch, the ownership probe). What is drawn as a
self-call instead is the executor's own tooling — ensure_local_env,
statuscheck and pr_base.sh, whose subject is the executor's own
context (is my config here, is my environment sound, which base do I
target) — and not because they stay local. Two of them reach the
network to answer it: the healthcheck probes both credentials
(GET /myself for Jira, GET /repos/… for GitHub), and pr_base.sh's
second source is the issue's own PR target branch: Jira comment — the
durable one, which survives a fresh clone where the git config it tries
first isn't there. ensure_local_env is the only genuinely local one, and
it does write: it copies .jst/jira-sdlc-tools.local.env in from the main
checkout when the worktree lacks it.
Sequence diagram
What the diagram shows
- Step labelling — every node carries the step number
jira-task-executor's ownSKILL.mdgives it (its steps are the bold01.–12.list, written here as 1–12 — the leading zero is a markdown-list artifact, not part of the step id). The credential block and Discovery & healthcheck run before step 1 and are unnumbered in the skill, so they are labelledPre-stephere. Phase 1 runs the same healthcheck but numbers it its step 1, so its diagram readsStep 1 — Discovery & healthcheck. The step name and thestatuscheck.shcall are identical across all three phases — only each skill's own numbering differs, and the diagrams follow the skill rather than renumbering it. - Three pre-flight steps, in a fixed order —
ensure_local_env.sh(sync the worktree's.jst/from the main checkout, and refuse to place the credentials file unless git ignores it there), thencheck_assignee.sh --role executor(the ownership gate), then thestatuscheck.shhealthcheck. The healthcheck is what turns the branch name into<KEY>, confirms this is a linked worktree on afeature//hotfix/issue branch, and readsgh_auth+gh_repo_accessup front — the whole point of running it before any work is that step 10 never discovers a logged-outghafter the implementation is already written and pushed. - Participant routing — the executor orchestrates between three
parties. GIT owns repo and PR state (merging the parent branch
current, the commit, the push, and the
ghcalls that list, comment on, or open the PR). JIRA owns issue state (thecheck_assigneeownership probe, the issue fetch that carries the parent family and prior comments, the In Progress and In Review transitions, anyTask memorycomments posted along the way, and the final run-report comment). Everything else stays off both lanes: the pre-flight scripts, the bootstrap hook,pr_base.sh, investigating, implementing and testing are the executor's own self-calls, while the two questions it asks — step 5's clarify and step 7a's install-a-runner — go to User. - The bootstrap hook (step 1a) — a worktree is a source tree, not a
running instance. When the healthcheck's
bootstraprow reads present, the executor runs the project's optional.jst/bootstrap.sh(or.jst/bootstrap.ps1) from the worktree root, automatically and with no confirmation prompt, passing theJST_*contract. It is fail-soft: a non-zero exit is reported in the final report and the run carries on, since a broken hook is the project's environment problem, not a reason to abandon work the executor can still do. Most projects ship no hook at all, which is why it is drawn as anopt. - Parallel lanes — the
par / and / endblock encodes the worktree-level parallelism the assigner's phase 1 setup makes possible. Every leaf has its own worktree and can run concurrently. - Two of the executor's questions are drawn as round-trips, because the
run continues down either arm — step 5, when the description or
acceptance criteria leaves an implementation choice that would change the
result (it asks rather than guesses, and step 3's transition deliberately
stands while it waits — someone has picked the issue up, so the issue is
not rolled back to To Do even if no answer comes); and step 7a, when the
repo has no test layer at all. Both are
optblocks with a realUserround-trip, the same way phase 1 draws its clarify loop and hotfix gate. The skill's other user-facing questions are drawn as notes rather than round-trips, because they gate the run instead of branching it: step 1b's confirmation when<KEY>turns out to have sub-tasks, and the stop-and-ask guards at step 2 (merge conflict), step 7c (a test that still fails when re-run individually) and step 10 (source=unresolved, or a prefix disagreeing with the resolved base). - Finding the test commands is its own step (7a) — which runner a
project uses, how it selects one test, and how it runs the suite vary too
much to ship a plugin default, so the executor reads
CLAUDE.md,AGENTS.mdor the README first, and recovers whatever is missing frompackage.jsonscripts,Makefiletargets or CI config when only half of it is written down. If the repo has no test layer at all, installing one is its own task and not the executor's call: it asks. Declining is a real path with a real consequence — the rest of step 7 is skipped, the report has to say testing was skipped and why, and the run commits untested. That is the only path here that reaches step 8 without 7b/7c. - Uniform path — the healthcheck confirms the worktree, then the executor brings its branch current, commits, pushes, opens (or updates) a PR (GIT), transitions to In Review (JIRA), and posts its run-report comment (JIRA). The PR is the thing phase 3 reviews.
- Step 10 has two arms, and the second one is the re-run — the executor
runs
gh pr list --head <branch> --state openbefore anything else at step 10. An existing open PR means this is the re-run after a rejection: step 9's push has already updated that PR, so the executor posts agh pr commentsaying what it fixed — for the reviewer's next pass — and creates nothing. It also does not re-resolve the base: an open PR's base is not this run's decision. Only the no-PR-yet arm resolves a base, and it does so withpr_base.sh, which tries git config → the JiraPR target branch:comment → a parent-branch search → the env default (top-level issues only, never a sub-task).source=unresolvedstops the run and asks, as does a prefix that disagrees with the resolved base — ahotfix/branch not targeting the production branch, or afeature/branch that is. That check is top-level-only (a sub-task is exempt — its base is its parent's branch), and the first case is the one that actually happens: a hotfix that fell through toenv-default, where retargeting a production fix at staging neither ships it nor gets it versioned. The two sources that do proceed still owe the report a sentence:branch-searchnames the branch it recovered,env-defaultsays that it fell through to the default. - Status transitions the executor owns — to In Progress on start,
to In Review on PR open (both JIRA). Each is skipped when the issue
already reads that status: workflows generally offer no transition into
the status an issue already occupies, so asking anyway exits 8, and a
non-zero
jira.shresult is a stop condition. That matters most on a re-run after a reject — the reviewer has already put the issue back to In Progress, and aborting there would end the run before it ever read the reviewer's findings. - Task memory is a first-class JIRA interaction, not a single comment
invariant — step 1b's fetch carries the issue's comments, and step 4
reads them in a fixed order of authority: a reviewer
CHANGES REQUESTED —verdict first (on a re-run it is the spec for that pass), then phase 1'sAssignment report, then priorTask memory (jira-task-executor)notes, then the previous run report. The executor may then post its own memory notes as investigation/implementation turns up findings worth preserving (theoptblock — zero or more per run, not fixed). These are expected companions to the one comprehensive run report posted after the In Review transition (PR URL, branch, final status) — the invariant is "one run report per run," not "one Jira comment per run." - Identity is per-request, and ownership is a gate — there is no login
step. Every Jira call carries
--role executorand authenticates on that credential for the one request, so every Jira write in the run — the In Progress and In Review transitions, the task-memory notes, the run report — is attributed to the executor account rather than to whoever happened to be logged in. Ownership is then confirmed, not assumed (check_assignee.sh):<KEY>must be assigned to that account. Anything else — unassigned, assigned to someone else, unreadable — stops the run before it has touched anything. The first two stop with thejira issue assign …command ready to paste; the unreadable case (no access to the project, or a Jira timeout) stops earlier than that message is built, so it reports the read failure instead. This is the counterpart to phase 1 assigning every issue to the executor on create: the assigner says who owns the work, and the executor refuses to work anything it doesn't own. (Ownership is compared byaccountId, not by email — Jira only exposes an assignee'semailAddressto that user themselves, so an email comparison cannot tell "someone else's" from "unassigned". Seeplugins/jira-sdlc/skills/_shared/jira-api-reference.md§10.) - Guards before work starts, and along the way — the worktree and
branch are validated by the healthcheck, not by a separate read: its
worktree,branchandissue_keyrows are what establish that this is<KEY>'s own linked worktree, andSKILL.md's step 2 leans on that ("Discovery already guaranteed you're on<KEY>'s own issue branch"). One ownership question survives into step 1b: if the fetched issue has sub-tasks,<KEY>is a multistep parent — a merge target, not an implementation surface — and the executor asks the user to confirm rather than silently implementing on it. Two more guards can stop the run before it commits anything: a merge conflict while bringing the branch current (GIT), and a test that still fails when re-run individually after the suite run (both leave the run stopped, with no commit/push/PR). Step 10 can stop it too —source=unresolved, or a prefix disagreeing with the resolved base — but by then the commit and the push have already landed, so what is missing there is the PR, not the work. - Phase 2 never sets Done — step 11 transitions to In Review and
stops there. A sub-task reaches
<STATUS_DONE>when its PR is merged into the parent branch, a single-step issue when its PR is merged into the base branch — by GitHub-for-Jira's merge automation where that is connected, or by hand. The other exit is a rejection, which sends the issue back to In Progress and re-runs this whole flow: step 4 reads the reviewer'sCHANGES REQUESTED —findings as the specification for that pass, and step 10's first arm updates the PR that already exists.