Create an atomic PR closing a GitHub issue end-to-end via a 6-step pipeline. Use to resolve, fix, or implement issue #N. Don't use for analysis without fixing (/issue-analysis), reviewing a PR (/issue-pr-review), or bulk backlog work (/auto-pilot).
Create an atomic PR closing a GitHub issue end-to-end via a 6-step pipeline. Use to resolve, fix, or implement issue #N. Don't use for analysis without fixing (/issue-analysis), reviewing a PR (/issue-pr-review), or bulk backlog work (/auto-pilot).
license
MIT
compatibility
Requires git and GitHub CLI (gh) with authentication and push access. Self-contained — uses shared agents from shared/agents/.
Resolve a GitHub issue end-to-end — from issue to atomic PR in 6 steps.
Invocation
Invocation
Mode
What happens
/issue-resolver <N>
interactive
Resolve issue #N, ask user to pick plan
/issue-resolver <N> --auto
auto-pilot
Resolve fully autonomously, no user prompts
/issue-resolver <N> --no-run-log
(modifier)
Suppress the .gitissue/runs.jsonl append; return telemetry to the caller instead
The argument must be a GitHub issue number. --auto is set automatically when invoked by /auto-pilot.
The --no-run-log flag is orthogonal to --auto and is passed only by /auto-pilot — see Step 5 — Deliver → Run-log entry for the rationale.
Prerequisites
Verify before any operation — git repository (git rev-parse --git-dir), gh installed (which gh), authenticated (gh auth status), GitHub remote exists (git remote -v). On failure, print the exact error from references/error-messages.md and stop.
Repo Sync Before Edits (mandatory)
Applies to the in-place path only (ordinary auto mode, or interactive after
declining Step 0e). Accepted interactive and validated caller-managed worktrees
start from the fetched base; an invalid IDD_CALLER_WORKTREE=1 is a stop, never
a sync bypass or in-place fallback. Sync in-place with the stash-first pattern:
(including untracked) → fetch → rebase-pull the current branch → pop the stash,
aborting with the recovery hint if the pop conflicts. Copy the exact snippet and
the full recovery procedure from references/docs/sync-conventions.md (Quick Reference
(Copy-Paste Snippet)) — canonical; never improvise a bare rebase on a dirty
tree. If origin is missing or rebase conflicts occur, stop and ask the user
(interactive) or abort with a clear error (auto).
Configuration
Load config once at skill start: run python3 references/scripts/gi-config.py — two independent requirements, both mandatory. Working directory: the repo root, because the script resolves .gitissue.yml against the working directory; run it from anywhere else and it exits 0 reporting config_file: null/first_run: true, silently discarding the repo's real config. Script path: relative to this SKILL.md's own directory, not to the working directory — resolve it to an absolute path exactly as the Bundled dependency precheck resolves its list, and pass that absolute path to python3. It prints {"config": {…dotted keys…}, "config_file": …, "first_run": …} as JSON on stdout, merging the defaults below with .gitissue.yml. Exit 0: use config, and print the ○ First run line below when first_run is true. Exit 3: .gitissue.yml is invalid — print the validation error from references/error-messages.md (Invalid config) and stop. Script file absent: a bundled dependency is missing, which is a broken install and not a degrade — stop and print the ✗ Missing bundled dependency block the Bundled dependency precheck names. Any other outcome (no python3, non-zero exit, unparsable stdout): print ⚠ gi-config unavailable — using the inline defaults below and instead follow the manual fallback procedure that makes up the rest of this section. That procedure is the alternative to this script, never an extra step to run alongside it: on exit 0 the script's config is the whole answer and the rest of this section is reference material only. Never re-read the config after this step.
Otherwise, load .gitissue.yml from the repo root once at skill start. If the file does not exist, use defaults and print:
○ First run — using default config. Run /init-gitissue to customize.
Defaults (full field reference in references/docs/config-schema.md):
issue.auto_normalize: true
resolve.approval_gate: auto (ignored in auto mode — always auto)
resolve.branch_prefix: "auto"
resolve.auto_test: true
resolve.test_timeout: 300
resolve.max_commits: 10
resolve.qa_max_cycles: 5
resolve.adaptive_effort: true — scale the pipeline to the issue's complexity (see Step 0g — Complexity gate). When false, every issue runs the full pipeline (profile pinned to full).
resolve.ui_review.browser_review: "ask" — gates only the optional browser/screenshot review; the code-level UI review (Step 4 — UI/UX review) is auto-detected and always runs.
The resolve pipeline delegates heavy work to subagents (shared/agents/) to keep the main agent's context window clean and token budget predictable. Main agent stays in Step 0, Step 4 (orchestrates review-fix), and Step 5 (deliver); Steps 1-3 each spawn one subagent. Full diagram in references/pipeline-steps.md (Subagent Architecture Diagram).
Each subagent's prompt file is listed under Additional Resources below. Every
agent opens with a role header and a compact I/O contract; the conventions they share (spawn note, tool posture, injection boundary,
confidence scale, gh --json, autonomous operation) live once in
references/docs/shared-agent-conventions.md.
Spawning a subagent (canonical pattern)
Every step below spawns with the same shape — only role, description, and prompt file change. Do NOT set subagent_type — always use the default general-purpose agent (never the agent's own name — none are registered agent types):
Agent(
description="{role} — {action} issue #N",
prompt=<{agent-file}.md prompt with {variables} replaced>,
# do NOT set subagent_type — default general-purpose agent, never a custom type (e.g. NOT "code-reviewer")
)
Orchestrating the agents (model/effort, monitoring, audit)
As the orchestrator, for each spawned step:
Name the role in the spawn description (e.g. "researcher — research issue #N").
Size the model/effort per references/docs/agent-model-effort.md from the most-recent
complexity signal, falling back to the agent's default tier — advisory, never blocks.
Monitor before advancing — verify the agent returned its contract's required
shape (researcher: status+complexity; synthesizer: one recommended option;
implementer: commits+tests+repro for bugs; reviewer/fixer: result+counts). A
missing/blocking return is the signal to stop (interactive) or follow auto behavior.
Audit — record the per-step signal the run log folds in (complexity, qa_cycles, outcome, duration_s) plus the [N/5] tracker line.
Environment check
If the Agent tool is available, use subagents as described above; if not (e.g. Claude.ai), execute each step inline via the fallback instructions.
Bundled dependency precheck
Verify this skill's bundled subagent prompts and reference files are present. Before execution, verify every path in the list below exists relative to the skill's directory (the dirname of this SKILL.md). This list is the authoritative guard — keep it complete and independent of the Additional Resources navigation index, which exists for human navigation and may list files with source-relative group prefixes. If any path is missing, stop immediately and print the ✗ Missing bundled dependency block from references/error-messages.md (Bundled dependencies); do not continue with an inline or guessed subagent prompt:
The resolve pipeline has 6 steps (0-5) — Preflight, Research, Plan, Implement,
QA, Deliver. Display progress with the [N/5] step counter: each step prints a
new line on start (●), updating to ✓/✗ on success/failure. Static
sequential output — no animation. Worked example of the full tracker in
references/report-templates.md (Expected Inline Pipeline Output).
Step completion reports
Each step closes with a completion report — √/× per check plus a
Result: PASS | PARTIAL | FAIL line — so "step done" is checkable rather than
asserted. The per-step check names, the Result semantics, and the block
format are in references/report-templates.md (Step Completion Reports) —
read it now, before Step 0. A step is not complete until its Result:
line is printed.
Step 0 — Preflight
Check whether this issue should be worked on. Open with ● Preflight check for issue #N....
0a — Fetch issue
The GitHub-backed helpers share the bundled subprocess boundary in references/scripts/gi-gh.py. First classify any framed caller payload per Step 0i; then run python3 references/scripts/gi-issue.py {N} --fields number,title,body,labels,assignees,state,comments,updatedAt and read .issue only when the payload is absent/partial. Capture updatedAt here — 0d's gh issue edit bumps it, so 0h must compare against this pre-normalization value or it reports stale on every first-normalized issue. The same issue is read again in 0d, Step 1, and Step 5; the script serves those repeats from .gitissue/cache/ rather than the network, and the field list is this skill's choice. Resolve the script path as the Bundled dependency precheck resolves its list. Exit 3 is a stop. No python3, exit 2 (an unresolved script path), or exit 4 degrades: run gh issue view {N} --json number,title,body,labels,assignees,state,comments,updatedAt directly — the cache is an optimization, never a dependency. 0d rewrites the body, so it MUST end with python3 references/scripts/gi-issue.py {N} --invalidate; the cache is repo-wide and outlives this skill, so without it Step 1 and Step 5 read the pre-normalization body. Caller payload: when the spawn prompt carries a correctly nonce-framed, complete issue_payload for this issue (/auto-pilot captured it in mode-neutral Step 1.2b), use it in place of this read only — issue_payload = supplied | partial | absent, updatedAt required, missing/mismatched framing or any doubt is absent and this fetch runs; 0d still rewrites and still invalidates, and no safety check is ever gated on it (Step 0i — Caller payload gate in references/pipeline-steps.md). A payload carries every field above except comments, and its state and updatedAt are only as fresh as the caller's fetch, so under suppliedrun one live read before 0b: gh issue view N --json state,comments,updatedAt — not through the cache — and decide the two stops below from that state, never the payload. Before 0d, parse and require an exact match between retained and live updatedAt; mismatch, missing, or unparsable discards the payload and runs the complete 0a fetch with --refresh (or direct full-field gh fallback), whose record then feeds normalization and 0h condition 5. This per-issue fallback applies identically to individual, array, and keyed-map payloads.
If not found: output error and stop. If closed: output warning and stop.
0b — Check for existing work
git branch -a | grep -i "{N}"# existing branches
gh pr list --state open --json number,title,body,headRefName --limit 20
Scan PR bodies for Closes #N, Fixes #N, Resolves #N. If an open PR already exists, print the ⚠ PR already targets issue block from references/error-messages.md (Guards) and stop — return status: pr_in_progress with that pr_number and branch_name, and never close the issue: an unreviewed, unmerged PR is not a resolution (references/pipeline-steps.md → Early exit). Only a merged PR or a closing commit on the default branch is already_resolved.
0c — Guards
Interactive: warn and ask if assigned to someone else or wontfix/blocked/do-not-merge labels exist. Auto: skip the assignment guard; log blocking labels, don't stop.
0d — Auto-normalize
If issue.auto_normalize is true and not already normalized (no <!-- gitissue:normalized v1 --> marker):
Security label check (SPEC §1.4) — before any rewrite, scan issue labels for security, CVE, or vulnerability (case-insensitive). If any match:
Auto mode (--auto / IDD_AUTO_MODE=1): print the ⚠ … Skipping auto-normalization warning from references/error-messages.md (Security-labeled issue (skip)) — using the first matching label name for {label} — and continue preflight without rewriting the issue body.
Interactive mode: print the same warning and ask for explicit operator confirmation. Default is no — do not rewrite unless the operator clearly confirms (e.g. y / yes). If declined, continue without normalization.
Normalize inline — when no security label blocks (or interactive operator confirmed): classify issue type, generate normalized body, add marker, post a backup comment with the original body, update the issue via gh issue edit, invalidate the cached entry (python3 references/scripts/gi-issue.py {N} --invalidate), then re-fetch. This is the same structure-only flow as /issue-creator Normalize mode (references/modes.md in the issue-creator skill); the resolver does not invoke /issue-creator as a subprocess — it performs Step 0d inline. If normalization fails, warn and continue with the original body (see references/error-messages.md).
0e — Workspace (interactive only)
Before Step 0e or 0f selects a workspace, derive one {branch_name} with python3 references/scripts/gi-branch.py {N} --from-issue --type {type} and read .branch. --from-issue is mandatory — never put the issue title or the configured prefix on the command line. A title is written by whoever filed the issue, so interpolating it into a shell word is a command injection that /auto-pilot would run unattended; --from-issue makes the script read both values itself. {type} is one of the six literals this skill classified, never free text. Exit 3 is a stop; no python3, exit 2 (an unresolved script path), or exit 4 degrades to deriving the name by hand per references/docs/naming-conventions.md. Both workspace paths use this one name — full contract in references/pipeline-steps.md (Step 0e).
Then decide where the resolution work happens.
Auto mode (--auto / IDD_AUTO_MODE=1): skip this offer entirely. A set
IDD_CALLER_WORKTREE=1 uses the validated caller-managed path in
references/pipeline-steps.md; otherwise go to 0f (legacy in-place). Neither
auto path shows the prompt.
Interactive mode: offer to run the resolution in a dedicated git worktree
— an isolated checkout in a separate directory — so branch creation,
implementation, and testing never touch the user's current working tree. State
plainly what will be set up and the workspace/branch naming the user can expect:
◆ Workspace for issue #N
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
This resolution can run in an isolated git worktree instead of your
current working tree.
Branch: {branch_name}
Worktree: ../{repo}-worktrees/{branch_name with / → -}
Setup: copies your gitignored local config (.env*, and similar),
then runs this project's detected install/bootstrap so the
workspace is ready to run without manual reconfiguration.
Accepting keeps your current working tree untouched. Declining uses the current working tree with the existing sync and branch behavior.
Resolve in a new worktree? [Y/n]
Accept replaces 0f — Create branch and the mandatory Repo Sync; decline runs the
mandatory Repo Sync then 0f — Create branch as today. Creation commands,
setup-artifact propagation, cleanup guidance, and fallback-on-failure behavior are
in references/pipeline-steps.md (Step 0e — Workspace) — never leave the user
without a working resolution.
0f — Create branch
The in-place path — ordinary auto mode, or interactive after declining the
offer. Accepted interactive and validated caller-managed paths already checked
out the branch and skip this sub-step.
Use the {branch_name} already derived before Step 0e/0f (see 0e — Workspace,
references/docs/config-schema.md, references/docs/naming-conventions.md) — never re-derive it here.
If branch already exists:
Interactive mode: ask continue or fresh
Auto mode: continue (checkout existing branch)
0g — Complexity gate (select the pipeline profile)
Decide before Step 1 how much pipeline this issue earns, so a trivial edit
does not pay the full orchestration cost. The mechanism, the shared XS … XL
scale it reuses, and the safety rules are defined once in
references/docs/agent-model-effort.md (Complexity → pipeline profile) — apply that
document here; this sub-step is only the resolver's entry point into it.
When resolve.adaptive_effort is false, skip the gate entirely: set
profile = full and continue exactly as before. Otherwise select the profile
from the issue's pre-work Effort band (the XS … XL value in the issue's
## Metadata, written by /issue-creator) — never from a later agent output, so
the saving is real:
EffortXS/S but low-confidence, or absent/unparseable → profile = full (ambiguous → fuller)
What light collapses — the single home for this rule.full leaves every
step exactly as it is today. Each step below points back to this table; the full
per-step mechanics live in references/pipeline-steps.md (Step N → light
profile).
Step
light behavior
1 — Research
Lighter pass: the already-resolved safety check and a focused scan of the obviously-affected file(s) still run; skip the broad dependency trace and external solution research.
2 — Plan
Skip the 3-option synthesis entirely — do not spawn the synthesizer. Derive a direct minimal plan inline and record it as the selected option, so the Decision Record still has a real Selected option; the design-confirm checkpoint does not apply — unless 0h set analysis_reuse = fresh, in which case Step 2 — Plan → reuse governs instead: options are lifted from the analysis, not derived, and the design-confirm checkpoint does apply.
3 — Propose relevant skills
Skip the propose/install — set selected_skills = [] and go straight to the implementer, mirroring auto-mode behavior. Leftover teardown still runs (references/pipeline-steps.md → Step 3 — Propose relevant skills): a light run must still release skills a crashed earlier run borrowed — the one path where even teardown is off is a parallel lane (IDD_CALLER_WORKTREE=1), which disables borrowing outright (Parallel lanes there).
4 — QA
Cap the review-fix loop at 1 cycle (a single review pass; fix once if blocking issues are found, then deliver) instead of resolve.qa_max_cycles. One reviewer spawn still runs — the fast path reduces depth, it does not skip review. UI review remains auto-detected as usual.
5 — Deliver
Unchanged — always emits the Decision Record and Acceptance Criteria Verification table. The profile never removes durable memory.
The profile may only be revised upward later (e.g. Step 1 research reports
high/complex on what the band called S → switch to full for the remaining
steps); never downgrade a full run to light mid-pipeline.
After preflight, surface the chosen profile so the effort decision is
transparent. {workspace_note} is (worktree) in a worktree, empty otherwise;
{profile} is light or full — when resolve.adaptive_effort is false,
still print effort: full (the pinned profile) so the line is uniform:
Set analysis_reuse to fresh, stale, or absent by the five-condition predicate in references/pipeline-steps.md (Step 0h — Analysis reuse gate) — its single home; never define "fresh" anywhere else. fresh seeds Step 1's research and skips Step 2's synthesizer; stale/absent run today's full pipeline unchanged. Any doubt — missing key, short SHA, unparsable timestamp, failed git call — is stale (fail-safe). Skipped, like 0g, when resolve.adaptive_effort is false; no new config key.
Step 1 — Research
Deeply understand the issue, affected codebase, and possible solutions; also verifies the issue hasn't already been fixed (early-exit path closes it in auto mode). Spawn the researcher (references/agents/codebase-researcher.md) with the canonical pattern — full delegation payload, phases, early-exit behavior, and inline fallback are in references/pipeline-steps.md (Step 1 — Research).
light profile: run a lighter research pass — see the profile table in
Step 0g for what it collapses, and references/pipeline-steps.md (Step 1 —
Research → light profile) for the mechanics. On a high/complex signal,
revise the profile upward to full (never downward). analysis_reuse = fresh (0h): pass prior_analysis and run the seeded verify-first pass — hints to confirm or refute, never to trust; the already-resolved check still runs in full (Step 1 — Research → reuse). Also pass the optional sibling key triage_context (this issue's triage row, from the caller or from the triage graph): unlike prior_analysis it carries no commit pin, so it may only reorder a scan, never authorise skipping a phase (Step 1 — Research → triage_context).
After research:
[1/5] Research ✓ read {N} files, complexity: {level}
Step 2 — Plan
Generate implementation options and select one. Spawn the synthesizer (references/agents/synthesizer.md) with the canonical pattern. It returns 3 options — minimal / balanced / comprehensive — with the balanced option usually recommended.
Selection behavior (interactive auto, interactive comment-and-wait, auto-pilot) and inline fallback are in references/pipeline-steps.md (Step 2 — Plan).
light profile: skip the 3-option synthesis — see the profile table in
Step 0g; full procedure in references/pipeline-steps.md (Step 2 — Plan →
light profile). analysis_reuse = fresh (0h) skips the same spawn but wins Step 2 when both apply — not an addition to the light skip, a replacement for it: lift options[], recommended_option, overall_complexity and overall_risk from the analysis instead of deriving a minimal plan, deriving each rejection_reason from decision_record.options_rejected[] (Step 2 — Plan → reuse).
High-risk work earns exactly one extra agreement point before code is written —
no new phase, artifact, or config key. Fires only when both hold: synthesizer
reports overall_complexity: L/XL or overall_risk: High (trivial/low/medium
skip it), and interactive mode (--auto/IDD_AUTO_MODE=1 never pauses).
Accept (default) → Step 3 unchanged; decline → stop before implementing and
suggest re-running or picking a different option. Record the decision in the PR
Decision Record. Full procedure in references/pipeline-steps.md (Step 2 —
Plan → Design-confirm checkpoint).
Step 3 — Implement
Propose relevant skills
Before spawning the implementer, optionally augment it with external skills from
references/skill-index.md. Detect (installed vs available-to-borrow when
resolve.borrow_skills is true), propose, accept into selected_skills;
internal agents remain the fallback. Borrow/install, {name, origin} records
via references/scripts/gi-state.py, teardown of origin: borrowed only, the
◆/○ block, leftover cleanup, and auto-mode are in
references/pipeline-steps.md (Step 3 — Propose relevant skills).
light profile: skip the propose/install — see the profile table in Step 0g — but still run the leftover teardown in references/pipeline-steps.md.
Write code and tests based on the selected plan. Spawn the implementer (references/agents/implementer.md) with the canonical pattern, passing the plan, branch name, naming conventions, and selected_skills.
For bug issues, the implementer first runs the red-capable reproduction checkpoint — reproduce the symptom, confirm it fails red, fix, then convert to a regression test. Surfaced as evidence in the PR Decision Record and acceptance table. Non-bug issues skip it; auto mode never blocks. See references/bug-verification.md.
Full payload, commit guardrails, and inline fallback are in references/pipeline-steps.md (Step 3 — Implement).
Automated review-fix loop: review → test → fix → repeat until clean or max cycles reached.
Spawning the code reviewer
For each QA cycle, spawn a fresh reviewer (references/agents/code-reviewer.md) with the canonical pattern — fresh each cycle for unbiased review.
When the reviewer or test/build run returns blocking issues, spawn or re-message the fixer (references/agents/fixer.md) the same way. Pass issue context, branch/base branch, reviewer findings, failing test/build output, commit message fix({scope}): address review feedback (#N), and the pre-commit security gate it MUST run before committing — security_convention (references/docs/pre-commit-security.md), secscan_script (references/scripts/gi-secscan.py) and secscan_policy_ref (origin/${base}) as spawn variables, because an emitted agent prompt cannot resolve a skill-relative path on its own. Paths and a ref name only — the script reads security.* from that ref itself, so the branch being fixed never supplies the policy that scans it. Collect the fixer's JSON result and decide whether to start another cycle — never apply fixes inline when the Agent tool is available.
UI/UX review (auto-detected)
UI review is auto-detected per issue — no config flag enables it. Scan the issue body/diff for UI work before the QA cycles, then run only what can and should run: the code UI review reads the diff, is environment-independent, and runs anywhere including headless (never gated on a GUI/browser); the browser UI review takes optional screenshots from a running app and runs only when reachable and opted in, else skips with a warning while the code UI review still runs — fail-soft.
Detection rules, the ui-reviewer spawn, the ui_review.browser_review gate, and skip/success messages are in references/docs/ui-review.md; the resolver's own deltas (diff command, variables, resolve.ui_review.browser_review as the gate key, findings flow) are in references/pipeline-steps.md (Step 4 — UI/UX review). Cycle mechanics and loop controls (resolve.qa_max_cycles, exit-on-clean, exit-on-stagnation) are in the same file (Step 4 — QA).
light profile: cap the review-fix loop at 1 cycle instead of
resolve.qa_max_cycles — see the profile table in Step 0g. Class policy:
light=1; full+low/medium=2; full+high=qa_max_cycles. Record ceiling/breach_reason.
Step 5 — Deliver
Push, create PR, and report.
Verify all tests pass
When resolve.auto_test is true (default), run the full test suite one final time to confirm everything is clean after QA fixes. When false, skip this suite (QA Step 4 may still have run tests during the loop). Under auto_test, not over it: when tests_state's SHA equals git rev-parse HEADand git status --porcelain=v1 --untracked-files=all is empty at this moment, a clean QA cycle already ran this exact suite on this exact tree — skip it and print ○ Test suite: skipped (last green {count}@{sha_short} == HEAD). Nothing recorded, or any doubt, runs it (references/pipeline-steps.md, Step 4 — QA → Last-green test state, the single home of the variable and both consumers).
If tests fail at this point, print ✗ Final test run failed — PR not created with the failure details and stop — even in auto mode, a failing PR is worse than no PR.
Update documentation
If the changes affect documented behavior, update README, inline docs, and CHANGELOG as applicable.
Push branch and create PR
Before pushing, run a final pre-push pass over the whole branch diff — it catches secrets that slipped in during QA fixes. Export IDD_AUTO_MODE=1 first in auto mode, then run python3 references/scripts/gi-secscan.py --range "origin/${base}" --policy-ref "origin/${base}" from the repo root. It reads this repo's security.allow_pattern, security.extra_secret_file_pattern, security.extra_secret_value_pattern, and security.max_file_size_mb from .gitissue.yml itself — never pass a config value on the command line, because .gitissue.yml is repo-controlled and a crafted value would escape its quoting. --policy-ref takes that policy from the base ref rather than this branch: the issue body that drove the implementation is untrusted, so a branch that grew a permissive security.allow_pattern must not be the branch that decides how it is scanned. Treat exit 0 as a pass only when policy_source is the ref:origin/… you asked for, verdict is not block, and scanned is not 0 while skipped is above 0 — a scan that examined nothing is not a clean scan, and an allow pattern suppresses scanning rather than findings. Exit 1 is the block verdict: stop, do not push, and report the path from blocking[] — never fall through to the prose scan hoping for a pass. Exit 3 (an uncompilable security.* regex) is also a stop. A missing python3, exit 2 (the script path did not resolve, or the invocation was malformed — a scan that never ran is never a scan that passed), or exit 4 degrades: print ⚠ gi-secscan unavailable — running the documented scan and run the Primary Pattern in references/docs/pre-commit-security.md over git diff --name-only "origin/${base}"...HEAD instead. Exit 1 with no parsable JSON on stdout is a crash rather than a verdict — treat it as exit 2 and degrade. Do not improvise a weaker check, and never read any non-zero exit as a pass. Only after the scan passes (or warnings are accepted):
PR title:{type}({scope}): {description} (#{issue_number}) (see references/docs/naming-conventions.md)
PR body: Fill the template in references/report-templates.md (PR Body Template) — Summary, Approach, Decision Record (from .gitissue/analysis-<N>.json if present, else synthesized), Changes table, Test Results, Acceptance Criteria Verification table. The last two are the durable analysis signal surviving squash-merge; never omit them (see references/docs/idd-methodology.md). That template's last line is the <!-- gitissue:qa v1 … --> handoff marker: fill it in only when QA exited clean, and otherwise drop the line — never append a second copy, because two markers make the consumer fall back to the full pipeline. Field derivation, the omit-on-a-non-clean-exit rule, and the no-secret-scan-field rule are in references/report-templates.md (QA handoff marker); head= is git rev-parse HEAD taken after the last commit and immediately before git push.
Project board sync
If projects.sync_enabled is true, update status to status_map.done (see references/docs/github-projects-sync.md). After delivery:
[5/5] Deliver ✓ PR #{pr_number} created
Run-log entry (monitoring)
At every terminal outcome — delivered PR (success), early exit because
already fixed (already_resolved), or a failed step (failed) — append exactly
one JSON line to .gitissue/runs.jsonl, unless invoked with --no-run-log,
in which case append nothing and return the telemetry to the caller instead.
--no-run-log enforces the single writer rule under /auto-pilot and is
independent of --auto — a standalone /issue-resolver <N> --auto is not
suppressed and still writes. Field derivation (the object's keys, the researcher
complexity collapse, when to omit profile) and the full suppression rationale
are in references/report-templates.md (Run-log entry — field derivation and
suppression), which follows the schema in references/docs/config-schema.md
(.gitissue/runs.jsonl — run log).
# Exactly one of these runs. --echo validates the telemetry you return and writes nothing.if [ -n "$no_run_log" ]; thenprintf'%s'"$run_json" | python3 references/scripts/gi-runlog.py --echo; elseprintf'%s'"$run_json" | python3 references/scripts/gi-runlog.py --append; fi# Fallback when `python3` is unavailable or the script exits 4: mkdir -p .gitissue && printf '%s\n' "$run_json" >> .gitissue/runs.jsonl
Exit 3: the record itself is invalid — the script printed the reason on stderr and wrote nothing. This is a stop, not a degrade: never append $run_json raw, because that writes the malformed line the script exists to reject. Correct the record and re-run, or drop the line.
Only the write is best-effort and non-fatal — a write that cannot happen (no python3, exit 2 for an unresolved script path or a malformed invocation, exit 4) never blocks the reported run result; use the fallback append above for any of them, never for exit 3. A rejected record is never written by any path. Only append; never rewrite or reorder existing lines.
Closing Summary
After the pipeline completes, print one closing block carrying only what the
live [N/5] tracker never printed: the outcome line, the risk_rating, and the
single PR reference (number, title, URL, Closes #N). Repeating any tracker
metric — per-step pass/fail, files read, complexity, option, files changed, test
counts, QA cycles — is the duplication issue #165 removed. Use the matching
variant in references/report-templates.md (Closing Summary): Successful
Resolution (every step passed), Resolution With Warnings (QA left residual
issues or another step warned), or Already Resolved (Step 0/1 found the issue
already closed — no PR reference). The Expected Inline Pipeline Output example
in the same file shows the tracker and closing block together.
Auto-Pilot Mode
When invoked with --auto (or by /auto-pilot), the entire pipeline runs without user interaction. Each step above already states its own auto behavior; these are the cross-cutting invariants:
Environment: Export IDD_AUTO_MODE=1 before any shell snippet that consults it (references/docs/pre-commit-security.md).
Workspace: The default resolution path is in-place. Skip Step 0e and allow no git worktree add on the default resolution path; ordinary standalone auto mode and auto-pilot's default single-lane path run mandatory Repo Sync, then 0f, exactly as before. A resolver launched by auto-pilot with max_parallel > 1 may receive IDD_CALLER_WORKTREE=1; after the linked-worktree/branch validation in references/pipeline-steps.md, it uses that already-current workspace without creating, falling back from, or cleaning it up. The prompt never appears on either path.
Never blocks:0c skips the assignment guard and logs blocking labels as warnings; 0g still runs (reads the pre-work Effort band, no prompt); Step 1 closes an already-resolved issue with a comment and exits cleanly; Step 2 auto-selects the recommended option and design-confirm never appears; Step 3 continues past the max-commits guard with a warning and never prompts for skills (internal agents only unless resolve.borrow_skills is true — then auto-selects/borrows); Step 4 runs its cycles autonomously and delivers with known issues on stagnation. Every terminal outcome still runs borrow teardown.
Deliver: Create PR. Do NOT merge — merging is /auto-pilot or /issue-pr-review's job. Under /auto-pilot the selected profile is returned in the telemetry (with --no-run-log) and folded into auto-pilot's single run-log line; a standalone --auto run writes profile itself.
No [y/N] prompts, no Choose: prompts, no Continue? prompts. Every decision point has a defined auto behavior.
Edge Cases
No acceptance criteria, empty issue body, large issues (20+ files), test failure/timeout, and branch-already-exists are all handled — full behavior for each is in references/pipeline-steps.md (Edge Cases).
Platform Driver and Output Conventions
All tracker access follows the GitHub driver — --json with explicit field selection, never parsed text output. The full operation catalog and driver rules live in references/docs/platform-github.md.
Terminal output follows the references/docs/terminal-style.md contract — symbols ● ✓ ✗ ◆ ⚡ ⚠ ○, two-space indent, ┄ separators, URLs on their own line, ≤80 chars, one blank line between sections, static sequential output (no animation), plus the [N/5] pipeline step counter. Errors use the rich format from references/error-messages.md: ✗ what failed, then To fix: <command>, then a docs link when applicable.
Additional Resources
Navigation index for the Bundled dependency precheck list above (that list, not this one, is the authoritative guard).
Docs (docs/): sync-conventions.md · naming-conventions.md · pre-commit-security.md · idd-methodology.md · github-projects-sync.md · config-schema.md · run-log-schema.md · agent-model-effort.md · shared-agent-conventions.md · platform-github.md · terminal-style.md · ui-review.md — the repo-root DESIGN.md is the human-facing companion to the last of these (color palette, per-command mockups) and is not bundled.