"Start implementation of a GitHub issue: fetch context, prepare worktree flow, implement with TDD, verify, and submit PR. Use for 'start issue #N', issue URLs, or requests to begin issue work. SKIP fully autonomous issue-to-merge requests; use complete-issue."
Resources
1Install
npx skillscat add gopherguides/gopher-ai/start-issue Install via the SkillsCat registry.
Start Issue
Plugin Resource Resolution
<PLUGIN_ROOT> is notation. Replace it with a concrete absolute plugin root before every resource read or command:
- Codex: Start from the directory containing the absolute selected
SKILL.mdpath, then ascend two directories (skills/<name>-> plugin root). - Claude Code: Bind it to the injected
${CLAUDE_PLUGIN_ROOT}value.
Before requesting decisions, entering a planning workflow, or delegating work,
read <PLUGIN_ROOT>/lib/driver-interaction.md and follow its
cross-platform capability-binding rules.
Read <PLUGIN_ROOT>/lib/decision-gates.md before resolving any workflow
choice.
Bind the invocation arguments as SKILL_ARGS for $go-workflow:start-issue by reading <PLUGIN_ROOT>/lib/skill-arguments.md with this Claude Code compatibility payload:
$ARGUMENTS
Empty Arguments
If SKILL_ARGS is empty or not provided, explain:
This skill starts work on a GitHub issue, automatically detecting whether it's
a bug fix or new feature and following the appropriate workflow.Claude Code:
/go-workflow:start-issue <issue-number> [--skip-coverage] [--coverage-threshold <n>]Codex:
$go-workflow:start-issue <issue-number> [--skip-coverage] [--coverage-threshold <n>]Example:
/go-workflow:start-issue 123or$go-workflow:start-issue 123 --coverage-threshold 80Options:
--skip-coverage: Compatibility hint for source-free changes; changed
source files still run coverage verification--coverage-threshold <n>: Override default 60% coverage threshold--no-agents: Use single-session workflow instead of subagent dispatch (for small/simple issues)Workflow:
- Fetch issue details, labels, and comments
- Optionally create a git worktree for isolated work
- Auto-detect issue type (bug vs feature)
- Create
fix/orfeat/branch (or use worktree branch)- For bugs: Check duplicates → TDD red-green → verify → coverage check → security review
- For features: Plan approach → TDD red-green → verify → coverage check → security review
- Commit, push, and create PR
This is a missing-intent gate. Request the issue number: "What issue number
would you like to work on?" If structured input is unavailable, ask in the final
response and stop without initializing the loop or claiming completion.
Output Durability
Any artifact this skill produces — commit messages, PR titles and bodies,
GitHub issue comments — describes modules, contracts, and observable behavior,
not file paths, line numbers, or current internal layout. Acceptance criteria
are stated as behaviors a reviewer can verify, not as file diffs. The artifact
must remain interpretable after a future refactor.
Clear Stale Worktree State
Clear any leftover worktree state from a prior session so it cannot affect a
fresh $go-workflow:start-issue invocation:
/bin/bash "<PLUGIN_ROOT>/scripts/worktree-state.sh" clear 2>/dev/null || trueSecurity Validation & Flag Parsing
Strip optional flags and extract the issue number:
ISSUE_NUM=$(echo "$SKILL_ARGS" | sed 's/--skip-coverage//g; s/--coverage-threshold *[0-9]*//g; s/--no-agents//g' | tr -d ' ')
HAS_SKIP=$(echo "$SKILL_ARGS" | grep -q '\-\-skip-coverage' && echo "true" || echo "false")
COV_THRESH=$(echo "$SKILL_ARGS" | grep -oE '\-\-coverage-threshold [0-9]+' | awk '{print $2}' || true)
NO_AGENTS=$(echo "$SKILL_ARGS" | grep -q '\-\-no-agents' && echo "true" || echo "false")
if ! echo "$ISSUE_NUM" | grep -qE '^[0-9]+$'; then
echo "Error: Issue number must be numeric."
echo "Claude Code: /go-workflow:start-issue <number> [--skip-coverage] [--coverage-threshold <n>] [--no-agents]"
echo "Codex: \$go-workflow:start-issue <number> [--skip-coverage] [--coverage-threshold <n>] [--no-agents]"
exit 1
fi
echo "Issue: $ISSUE_NUM | skip-coverage: $HAS_SKIP | coverage-threshold: ${COV_THRESH:-60} | no-agents: $NO_AGENTS"The output above shows the parsed issue number and flag values.
CRITICAL: From this point forward, use $ISSUE_NUM (the numeric issue number
shown above) everywhere you would use SKILL_ARGS. The raw SKILL_ARGS may
contain flags and MUST NOT be passed to gh issue view, branch names, worktree
names, or state file paths.
Store the parsed flags:
SKIP_COVERAGE: compatibility hint from--skip-coverage; it never waives
changed-source coverageCOVERAGE_THRESHOLD: the value after--coverage-threshold, or60if not specifiedNO_AGENTS:trueif--no-agentswas passed,falseotherwise
Surface Dispatch Decision
Bind the active assistant surface from the current driver, not installed
executables, environment variables, or prompt frontmatter, then select:
NO_AGENTS=true: read<PLUGIN_ROOT>/lib/start-issue/manual-workflow.mdand use the single-session workflow on every surface.NO_AGENTS=falseon Claude Code: read<PLUGIN_ROOT>/lib/start-issue/orchestrated-workflow.mdand use its Claude Code binding.NO_AGENTS=falseon Codex: use the orchestrated workflow only when the native delegation capability supportsexplorer,worker, anddefault; otherwise explain why native orchestration is unavailable, then read the manual workflow and continue in the current session.
Embedded Workflow Contract
Start-issue is embedded only when both caller variables are explicitly set.
Never infer composition from a generic inherited STATE_FILE:
EMBEDDED_WORKFLOW=false
source "<PLUGIN_ROOT>/lib/loop-state.sh"
CURRENT_CHECKOUT_ROOT=$(git rev-parse --show-toplevel)
RESOLVED_ORIGINAL_REPO_ROOT=$(git -C "$CURRENT_CHECKOUT_ROOT" worktree list --porcelain | awk '/^worktree / { sub(/^worktree /, ""); print; exit }')
if [ -z "$RESOLVED_ORIGINAL_REPO_ROOT" ] || [ "${RESOLVED_ORIGINAL_REPO_ROOT#/}" = "$RESOLVED_ORIGINAL_REPO_ROOT" ] || [ ! -d "$RESOLVED_ORIGINAL_REPO_ROOT" ]; then
echo "Error: Could not resolve the absolute primary worktree root."
exit 1
fi
if [ -n "${CALLER_LOOP_STATE_FILE:-}" ] && [ -n "${CALLER_WORKFLOW_STATE_PATH:-}" ]; then
EMBEDDED_WORKFLOW=true
STATE_FILE="$CALLER_LOOP_STATE_FILE"
WORKFLOW_STATE_PATH=$(child_workflow_path "$CALLER_WORKFLOW_STATE_PATH" "start_issue")
initialize_workflow_state "$STATE_FILE" "$WORKFLOW_STATE_PATH"
ORIGINAL_REPO_ROOT=$(get_loop_field "$STATE_FILE" "original_repo_root" '[]')
WORKTREE_PATH=$(get_loop_field "$STATE_FILE" "worktree_path" '[]')
REPO_SLUG=$(get_loop_field "$STATE_FILE" "repo_slug" '[]')
elif [ -n "${CALLER_LOOP_STATE_FILE:-}" ] || [ -n "${CALLER_WORKFLOW_STATE_PATH:-}" ]; then
echo "Error: Embedded start-issue requires both caller state variables."
exit 1
else
ORIGINAL_REPO_ROOT="$RESOLVED_ORIGINAL_REPO_ROOT"
STATE_FILE="$ORIGINAL_REPO_ROOT/.local/state/start-issue-$ISSUE_NUM.loop.local.json"
mkdir -p "$(dirname "$STATE_FILE")"
STATE_FILE=$(cd "$(dirname "$STATE_FILE")" && pwd)/$(basename "$STATE_FILE")
WORKFLOW_STATE_PATH='[]'
WORKTREE_PATH="$CURRENT_CHECKOUT_ROOT"
REPO_SLUG=$(cd "$CURRENT_CHECKOUT_ROOT" && gh api "repos/{owner}/{repo}" --jq '.full_name')
fiWhen embedded, every phase and field operation uses STATE_FILE plusWORKFLOW_STATE_PATH. Start-issue never changes the root completion promise or
terminal allowlist, never initializes another loop, and returns only throughset_workflow_result "$STATE_FILE" "$WORKFLOW_STATE_PATH" RESULT REASON PHASE.
Loop Initialization
EXISTING_PHASE=""
if [ -f "$STATE_FILE" ]; then
read_loop_state "$STATE_FILE" "$WORKFLOW_STATE_PATH"
EXISTING_PHASE="$PHASE"
fi
if [ "$EMBEDDED_WORKFLOW" = "true" ] || [ -n "$EXISTING_PHASE" ]; then
PERSISTED_ORIGINAL_REPO_ROOT=$(get_loop_field "$STATE_FILE" "original_repo_root" '[]')
PERSISTED_WORKTREE_PATH=$(get_loop_field "$STATE_FILE" "worktree_path" '[]')
PERSISTED_REPO_SLUG=$(get_loop_field "$STATE_FILE" "repo_slug" '[]')
CURRENT_REPO_SLUG=$(cd "$CURRENT_CHECKOUT_ROOT" && gh api "repos/{owner}/{repo}" --jq '.full_name')
REGISTERED_WORKTREES=$(git -C "$RESOLVED_ORIGINAL_REPO_ROOT" worktree list --porcelain | awk '/^worktree / { sub(/^worktree /, ""); print }')
if [ "$PERSISTED_ORIGINAL_REPO_ROOT" != "$RESOLVED_ORIGINAL_REPO_ROOT" ] ||
[ -z "$PERSISTED_WORKTREE_PATH" ] ||
[ "${PERSISTED_WORKTREE_PATH#/}" = "$PERSISTED_WORKTREE_PATH" ] ||
[ ! -d "$PERSISTED_WORKTREE_PATH" ] ||
! printf '%s\n' "$REGISTERED_WORKTREES" | awk -v path="$PERSISTED_WORKTREE_PATH" '$0 == path { found = 1 } END { exit found ? 0 : 1 }' ||
[ -z "$PERSISTED_REPO_SLUG" ] ||
[ "$PERSISTED_REPO_SLUG" != "$CURRENT_REPO_SLUG" ]; then
WORKFLOW_REASON=start-issue-worktree-path-invalid
if [ "$EMBEDDED_WORKFLOW" = "true" ]; then
set_workflow_result "$STATE_FILE" "$WORKFLOW_STATE_PATH" "incomplete" "$WORKFLOW_REASON" "incomplete"
echo "START_ISSUE_RESULT=incomplete"
echo "START_ISSUE_REASON=$WORKFLOW_REASON"
else
set_loop_terminal_result "$STATE_FILE" "incomplete" "$WORKFLOW_REASON" "incomplete" "INCOMPLETE"
echo "<done>INCOMPLETE</done>"
fi
exit 1
fi
ORIGINAL_REPO_ROOT="$PERSISTED_ORIGINAL_REPO_ROOT"
WORKTREE_PATH="$PERSISTED_WORKTREE_PATH"
REPO_SLUG="$PERSISTED_REPO_SLUG"
fi
if [ "$EMBEDDED_WORKFLOW" = "true" ]; then
echo "Embedded start-issue is using the caller-owned loop state."
elif [ -n "$EXISTING_PHASE" ]; then
echo "Re-entry detected (phase: $EXISTING_PHASE) — skipping setup-loop."
elif [ ! -x "<PLUGIN_ROOT>/scripts/setup-loop.sh" ]; then
echo "ERROR: Plugin cache stale. Run /gopher-ai-refresh (or refresh-plugins.sh) and restart Claude Code."
exit 1
else
/bin/bash "<PLUGIN_ROOT>/scripts/setup-loop.sh" "start-issue-$ISSUE_NUM" "COMPLETE" "" "" '{}' \
"$STATE_FILE" '["COMPLETE","INCOMPLETE"]'
initialize_workflow_state "$STATE_FILE" "$WORKFLOW_STATE_PATH"
set_loop_field "$STATE_FILE" "original_repo_root" "$ORIGINAL_REPO_ROOT" '[]'
set_loop_field "$STATE_FILE" "worktree_path" "$WORKTREE_PATH" '[]'
set_loop_field "$STATE_FILE" "repo_slug" "$REPO_SLUG" '[]'
fiORIGINAL_REPO_ROOT, WORKTREE_PATH, STATE_FILE, and REPO_SLUG are
resolved once before any worktree transition. Do not derive them again from
the ambient shell directory.
Context
Gather context before worktree or plan decisions:
gh issue view "$ISSUE_NUM" --repo "$REPO_SLUG" --json title,state,body,labels,comments --jq '.'
git -C "$WORKTREE_PATH" branch --show-current
git -C "$WORKTREE_PATH" remote show origin 2>/dev/null | grep 'HEAD branch' | sed 's/.*: //' || echo "main"
basename "$WORKTREE_PATH"
git -C "$WORKTREE_PATH" worktree listWorktree Detection & Decision (BEFORE Plan Mode)
First, check if already running inside a git worktree:
IN_WORKTREE=false
GIT_DIR_ABS=$(git -C "$WORKTREE_PATH" rev-parse --absolute-git-dir 2>/dev/null)
GIT_COMMON_REL=$(git -C "$WORKTREE_PATH" rev-parse --git-common-dir 2>/dev/null)
GIT_COMMON_ABS=$(cd "$WORKTREE_PATH" && cd "$GIT_COMMON_REL" && pwd)
if [ -n "$GIT_DIR_ABS" ] && [ -n "$GIT_COMMON_ABS" ] && [ "$GIT_DIR_ABS" != "$GIT_COMMON_ABS" ]; then
IN_WORKTREE=true
fiThis resolves both --git-dir and --git-common-dir to absolute paths viacd ... && pwd, then compares them. In the main repo (even from a subdirectory)
both resolve to the same absolute .git path. In a linked worktree, --git-dir
resolves to .git/worktrees/<name> while --git-common-dir resolves to .git.
If IN_WORKTREE=true: Skip the worktree question entirely. Proceed directly
to "Plan Mode Check" (the "No, work in current directory" path). Display:
Already running in a worktree — skipping worktree creation.If IN_WORKTREE=false: resolve this as a driver-resolvable gate before
planning:
- Use the current checkout when the request or execution environment already
provides isolation, or when the checkout is a clean non-default feature
branch dedicated to this issue. - Create a worktree when the user explicitly requested one or when the current
checkout is the shared default checkout and isolation is available. - Otherwise use the current checkout and create the required feature branch.
State Decision, Evidence, and Rationale as defined bydecision-gates.md, then continue. Do not request input for this technical
choice.
If the driver selected "create worktree"
→ Read <PLUGIN_ROOT>/lib/start-issue/worktree-create.md and follow the
full procedure: capture SOURCE_DIR, derive WORKTREE_NAME/BRANCH_NAME from
issue title, fetch and create the worktree, search for env files
(.env/.env.local/.envrc) and offer to copy with directory structure
preserved, capture WORKTREE_ABS_PATH, register the compatibility worktree
state file, and confirm to the user.
After the worktree is established, continue to Plan Mode Check below.
Persist the selected worktree in the root physical-context fields of the same
caller-owned file:
set_loop_field "$STATE_FILE" "worktree_path" "$WORKTREE_ABS_PATH" '[]'If the driver selected "work in current directory"
Continue to Step 1: Detect Issue Type below. You will create a branch in the
appropriate workflow step.
Now use the active surface's planning capability to create a plan for the
implementation. If no native planning capability is available, write and
maintain an explicit plan as required by the cross-platform binding rules.
Plan Mode Check (AFTER worktree is established)
Now enter the active surface's planning workflow to create a plan for the
implementation. If no native planning workflow is available, write and
maintain an explicit plan.
CRITICAL: When writing your plan, include these facts at the top of the plan
file:
If a worktree was created:
## Working Directory
All work MUST happen in: <the concrete WORKTREE_PATH value>
Original repo (state only): <the ORIGINAL_REPO_ROOT value>
Every repository command and file path must explicitly target the worktree.
Do not rely on a pre-tool-use hook to reject an ambient-directory operation.If no worktree:
## Working Directory
Working in current directory. A feature branch will be created.If you ARE already in plan mode, continue with the workflow below.
MANDATORY: All Work Happens in the Worktree
Your shell CWD does NOT persist between Bash calls. Every repository command
must explicitly target WORKTREE_PATH; a prior cd is never evidence of scope.
| Tool | How to use the worktree path |
|---|---|
| Bash | Prefer git -C "$WORKTREE_PATH", go -C "$WORKTREE_PATH", and gh ... --repo "$REPO_SLUG"; use (cd "$WORKTREE_PATH" && ...) only when a command has no directory option |
| Read | Use $WORKTREE_PATH/path/to/file as the file_path |
| Edit | Use $WORKTREE_PATH/path/to/file as the file_path |
| Write | Use $WORKTREE_PATH/path/to/file as the file_path |
| Glob | Set path parameter to $WORKTREE_PATH |
| Grep | Set path parameter to $WORKTREE_PATH |
No hook is assumed to enforce this invariant. Each command and file operation
must be correct on its own.
Self-check before EVERY file operation: "Does this path start with$WORKTREE_PATH?" If not, STOP and fix it.
Note: When using a worktree, the branch is alreadyissue-<num>-<title>. Skip the "Create Branch" step in the workflows below.
Continue to Step 1: Detect Issue Type below.
Branch Protection Check
CRITICAL: Before starting any work, verify you will NOT commit to
main/master.
This workflow creates feature branches (fix/ or feat/). If you are
currently on main, master, or the default branch:
- If worktree was created: You should already be on the
issue-<num>-<title>branch - If working in current directory: A branch will be created in Step 3 (Bug) or Step 4 (Feature)
NEVER commit directly to main/master. Always ensure a feature branch exists
before making any code changes.
Step 1: Detect Issue Type
Analyze the issue to determine if it's a bug fix or new feature.
Check labels first (most reliable):
- Bug indicators:
bug,fix,defect,error,regression,crash - Feature indicators:
enhancement,feature,feat,new,improvement,request
If no clear labels, analyze title and body:
- Bug patterns: "fix", "broken", "error", "fail", "crash", "doesn't work", "issue with", "problem", "bug", "regression", "incorrect"
- Feature patterns: "add", "implement", "create", "new", "support", "enable", "allow", "introduce", "enhance"
If still uncertain after labels, title, body, comments, and acceptance
criteria, this is a missing-intent gate. Request: "The issue semantics
remain ambiguous. Should this follow the bug-fix or feature workflow?" If
structured input is unavailable, ask in the final response and stop before
branch creation, implementation, or a completion claim.
Implementation Workflow
Orchestrated selection
When the Surface Dispatch Decision selected <PLUGIN_ROOT>/lib/start-issue/orchestrated-workflow.md, follow its
full 12-step procedure: duplicate check (bugs only), branch creation, Explore
delegation, design approach (features only), task decomposition and
parallel-dispatch decision, Implementer delegation (parallel or sequential),
spec-compliance review, quality review, verify
(build/test/lint), Step 9.5 coverage gate, security review, submit (PR template
detection + creation), watch CI.
Manual selection
When the Surface Dispatch Decision selected<PLUGIN_ROOT>/lib/start-issue/manual-workflow.md, follow its
single-session bug and feature flows. Both follow the same shape: explore/design
→ TDD red (IRON LAW: no implementation code before failing tests) → green →
verify → coverage → security → submit → watch CI.
Verification Gate (HARD — applies before ANY completion signal)
Before outputting <done>COMPLETE</done>, every claim MUST have FRESH evidence
from THIS session — actual command output, not narrative:
- "Tests pass" →
go -C "$WORKTREE_PATH" test ./...output with "ok" lines, zero failures - "Build succeeds" →
go -C "$WORKTREE_PATH" build ./...exit 0 - "Lint clean" →
(cd "$WORKTREE_PATH" && golangci-lint run)output (skip if not installed) - "CI passes" →
gh pr checks "$PR_NUM" --repo "$REPO_SLUG"with all checks green
Red-flag language check — if you are about to write "should work" / "should
be fine" / "probably" / "likely" / "I believe this fixes…" / "I think this
resolves…" / "Done!" / "Complete!" without preceding command output proving it,
STOP and run verification instead.
Do NOT commit, push, or create a PR without fresh verification evidence.
Workflow Result Contract
Every terminal path persists a result before it returns. For an incomplete
outcome, use the supplied machine-readable reason:
START_ISSUE_REASON="${WORKFLOW_REASON:?workflow reason is required}"
if [ "$EMBEDDED_WORKFLOW" = "true" ]; then
set_workflow_result "$STATE_FILE" "$WORKFLOW_STATE_PATH" "incomplete" "$START_ISSUE_REASON" "incomplete"
echo "START_ISSUE_RESULT=incomplete"
echo "START_ISSUE_REASON=$START_ISSUE_REASON"
else
set_loop_terminal_result "$STATE_FILE" "incomplete" "$START_ISSUE_REASON" "incomplete" "INCOMPLETE"
echo "<done>INCOMPLETE</done>"
fiStop after this block. The embedded branch returns control to its caller and
does not emit a terminal marker.
Completion Criteria
DO NOT output <done>COMPLETE</done> until ALL of these are TRUE:
- Code changes implemented and address the issue
- Tests written and ALL PASS (
go -C "$WORKTREE_PATH" test ./...or equivalent) — with output shown above - Coverage verified for changed source files, or not applicable because the
diff is source-free / all changed Go files arepackage main - Linting passes (
(cd "$WORKTREE_PATH" && golangci-lint run)or equivalent, if installed) — with output shown above - Changes committed with a proper commit message
- Changes pushed to the remote branch
- PR created and the PR URL displayed
- CI checks pass (
gh pr checks "$PR_NUM" --repo "$REPO_SLUG"shows all green) — with output shown above
When all criteria are met, persist the successful structured result. Embedded
start-issue then returns control to its caller; standalone start-issue emits its
own completion marker:
if [ "$EMBEDDED_WORKFLOW" = "true" ]; then
set_workflow_result "$STATE_FILE" "$WORKFLOW_STATE_PATH" "complete" "" "completed"
echo "START_ISSUE_RESULT=complete"
else
set_loop_terminal_result "$STATE_FILE" "complete" "" "completed" "COMPLETE"
echo "<done>COMPLETE</done>"
fiThis signals the loop to exit. If you output this prematurely, the issue will
not be properly resolved.
Safety note: If you've iterated 15+ times without success, document the
blocking evidence and stop incomplete. Do not treat the iteration limit as
permission to bypass completion criteria.
Use extended thinking for complex analysis.
Further Reading
<PLUGIN_ROOT>/lib/start-issue/worktree-create.md— full worktree creation procedure (env-file copy, state-file registration)<PLUGIN_ROOT>/lib/start-issue/orchestrated-workflow.md— 12-step subagent-orchestrated flow (Explore → Implementer → spec/quality review → verify → coverage → security → submit → CI)<PLUGIN_ROOT>/lib/start-issue/manual-workflow.md— single-session bug + feature flows for--no-agents