Skip to content
Back to skills

Issue Refine

BSecurity

Analyze a raw GitHub issue and rewrite it with structured sections,

  • 8 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 5, 2026
developmenttypescriptpythonrustgoshellbashgitapi

Works with

  • claude code
  • cursor
  • vscode
  • terminal
  • cli
  • api

Security analysis

B88/100
  • criticalSends environment variables or credentials to an external URL

Pro scans all 2 files and shows the line behind each finding

Scanned November 5, 2026

npx -y skills add nightgauge/nightgauge --skill issue-refine --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Issue Refine?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Issue Refine
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/nightgauge-issue-refine/badge)](https://www.skillsdirectory.com/skills/nightgauge-issue-refine)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: issue-refine
description: Analyze a raw GitHub issue and rewrite it with structured sections,
  acceptance criteria, and implementation guidance — making it immediately
  pipeline-ready. Use before /nightgauge-issue-pickup on sparse or unstructured
  issues.
license: Apache-2.0
metadata:
  author: nightgauge
  version: "1.0.3"
  source: https://github.com/nightgauge/nightgauge
allowed-tools: Read Glob Grep Bash
disable-model-invocation: true
---

# Issue Refine

> Enrich a raw GitHub issue with structured sections and codebase context

## Description

This skill transforms a sparse or unstructured GitHub issue into a
pipeline-ready issue by:

1. Fetching the raw issue from GitHub
2. Detecting the issue type (bug or feature) from labels and body content
3. Performing codebase-aware analysis using `Glob`/`Grep` to find relevant files
4. Constructing a structured body with all required pipeline sections
5. Updating the issue on GitHub with the enriched content
6. Optionally calling `nightgauge issue mark-refined` (depends on #2533)

## Invocation

| Tool           | Command                                     |
| -------------- | ------------------------------------------- |
| Claude Code    | `/nightgauge:issue-refine <N>` (via plugin) |
| OpenAI Codex   | `$nightgauge-issue-refine <N>`              |
| GitHub Copilot | Invoke via Agent Skills                     |
| Cursor         | Invoke via Agent Skills                     |

## Arguments

```bash
# Refine a specific issue
/nightgauge:issue-refine 42

# Auto-detect from current branch
/nightgauge:issue-refine
```

The skill arguments (the text after the skill name) are the issue
number. If omitted, the issue number is inferred from the current branch.

## Philosophy

- **Preserve original content** — the original body is always saved in a
  `<details>` block at the bottom
- **Codebase-grounded** — all file references come from actual `Glob`/`Grep`
  results, never hallucinated
- **Non-destructive** — if required sections already exist, they are not
  duplicated
- **Title-preserving** — the issue title is never modified

---

## Workflow

### Phase Marker Protocol

<!-- phase-registry: standalone-skill -->

This skill is standalone (not a pipeline execution stage), so its `stage="issue-refine"`
emits intentionally do not appear in `PHASE_REGISTRY`. The annotation above opts
the skill out of `scripts/validate-phase-markers.ts`.

At the start of each phase, emit a structured phase marker as an HTML comment on
its own line. Format:

`<!-- phase:start name="{phase-name}" index={N} total={T} stage="issue-refine" -->`

### Phase 0: Environment Preflight

### Phase 0: Environment Preflight

**PURPOSE**: Verify the nightgauge binary is available and the environment
is healthy before executing any pipeline stage. Skills halt immediately with
actionable instructions when this check fails.

Three-layer check:

1. **Binary discovery** — shell-level, runs before invoking the binary
2. **Doctor check** — binary-level, full environment health via `doctor --json`
3. **Project environment** — the checks the project declares under
   `preflight.environment` (#101); opt-in, silent when none are declared

The binary discovery cascade below is **provider-neutral** (issue 4029): it works
identically under every adapter (Claude, Codex, Gemini, …) and references no
VSCode-extension-specific path. The host that spawns the skill (the VSCode
extension's `skillRunner`, or the Go `nightgauge` binary in auto/CLI mode)
resolves the binary authoritatively and exports `NIGHTGAUGE_BIN`, which
this cascade honors first. The remaining steps (PATH, the development-only repo
`bin/` and worktree canonical-repo `bin/`, `~/go/bin`) are fallbacks for direct
or terminal invocation.

This intentionally **diverges** from
`claude-plugins/nightgauge/hooks/lib/guard.sh` (issue 3262 → issue 4029): guard.sh is
Claude-Code-only and retains a trailing `~/.vscode/extensions/...` glob to serve
the standalone-terminal-Claude case (where no host exports `NIGHTGAUGE_BIN`).
Skills must stay portable Markdown and cannot reference that VSCode-only path —
so the shared resolution order (`NIGHTGAUGE_BIN` → PATH → gated repo → gated
canonical → `~/go/bin`) stays in sync, and only guard.sh carries the extra Claude-only
fallback. The `nightgauge preflight skill-portability` gate enforces that
no skill reintroduces a `.vscode/extensions` path, and that every cascade keeps
the `NIGHTGAUGE_DEV_REPO_BIN` gate (#2758): a foreign repository's
`bin/nightgauge` must never run.

After the cascade resolves `$BINARY`, the preflight prepends
`dirname($BINARY)` to `PATH` so subsequent bare `nightgauge ...`
invocations later in the same skill body resolve through PATH rather than
failing with "command not found" (issue 3262).

```bash
# Layer 1: provider-neutral binary discovery (NIGHTGAUGE_BIN → PATH → gated repo
# bin → gated canonical-repo bin → ~/go/bin). No VSCode-extension path — see issue 4029.
# Repo bins need NIGHTGAUGE_DEV_REPO_BIN=1 and a verified core checkout (#2758).
BINARY="${NIGHTGAUGE_BIN:-}"
[ -n "$BINARY" ] && [ ! -x "$BINARY" ] && BINARY=""
[ -z "$BINARY" ] && BINARY=$(command -v nightgauge 2>/dev/null || echo "")
if [ -z "$BINARY" ] && [ "${NIGHTGAUGE_DEV_REPO_BIN:-}" = "1" ]; then
  for NG_ROOT in "$(git rev-parse --show-toplevel 2>/dev/null)" \
    "$(cd "$(git rev-parse --git-common-dir 2>/dev/null)/.." 2>/dev/null && pwd)"; do
    [ -x "$NG_ROOT/bin/nightgauge" ] || continue
    grep -qx 'module github.com/nightgauge/nightgauge' "$NG_ROOT/go.mod" 2>/dev/null || continue
    NG_ORIGIN="$(git -C "$NG_ROOT" config --get remote.origin.url 2>/dev/null)"
    case "${NG_ORIGIN%.git}" in
      git@github.com:nightgauge/nightgauge | https://github.com/nightgauge/nightgauge | \
        ssh://git@github.com/nightgauge/nightgauge) BINARY="$NG_ROOT/bin/nightgauge"; break ;;
    esac
  done
fi
[ -z "$BINARY" ] && [ -x "$HOME/go/bin/nightgauge" ] && BINARY="$HOME/go/bin/nightgauge"
if [ -z "$BINARY" ]; then
  echo "ERROR: nightgauge binary not found via NIGHTGAUGE_BIN, PATH or ~/go/bin" >&2
  echo "" >&2
  echo "Install via: go install github.com/nightgauge/nightgauge/cmd/nightgauge@latest" >&2
  echo "Or download from: https://github.com/nightgauge/nightgauge/releases" >&2
  echo "Run \`nightgauge doctor\` after installing to verify your environment." >&2
  exit 1
fi
# Make the resolved binary callable via bare `nightgauge ...` later in this skill body (issue 3262).
export PATH="$(dirname "$BINARY"):$PATH"

# Per-repo GitHub token: export GH_TOKEN so every `gh` call in this skill
# authenticates as the *current repo's* configured user instead of the machine-
# global `gh auth` active account. `forge auth token` resolves per-repo (config
# github_user/token → GITHUB_TOKEN → `gh auth token --user <github_user>`), so
# concurrent sessions/workspaces owned by different GitHub users each use their
# own token. GH_TOKEN outranks GITHUB_TOKEN and the gh keyring. Only resolve when
# unset (an upstream env value — e.g. the VSCode extension's terminal env —
# wins); never fail preflight over it. Mirrors hooks/lib/guard.sh (sync, issue 3262).
if [ -z "${GH_TOKEN:-}" ]; then
  IB_REPO_TOKEN="$("$BINARY" forge auth token 2>/dev/null || true)"
  if [ -n "$IB_REPO_TOKEN" ]; then
    export GH_TOKEN="$IB_REPO_TOKEN"
    export GITHUB_TOKEN="${GITHUB_TOKEN:-$IB_REPO_TOKEN}"
  fi
  unset IB_REPO_TOKEN
fi

# Layer 2: full environment health check via doctor --json
DOCTOR_RESULT=$("$BINARY" doctor --json 2>/dev/null)
DOCTOR_EXIT=$?
if [ "$DOCTOR_EXIT" -eq 2 ]; then
  echo "ERROR: Environment check failed — nightgauge doctor reports broken environment." >&2
  FAILED_CHECKS=$(printf '%s\n' "$DOCTOR_RESULT" | jq -r '.failed_checks[]? // empty' 2>/dev/null)
  if [ -n "$FAILED_CHECKS" ]; then
    echo "Failing check(s): $(echo "$FAILED_CHECKS" | tr '\n' ',' | sed 's/,$//')" >&2
  fi
  printf '%s\n' "$DOCTOR_RESULT" | jq -r '.errors[]' >&2 2>/dev/null || true
  INSTALL_MSG=$(printf '%s\n' "$DOCTOR_RESULT" | jq -r '.install_instructions // empty' 2>/dev/null)
  [ -n "$INSTALL_MSG" ] && echo "$INSTALL_MSG" >&2
  exit 1
fi
if [ "$DOCTOR_EXIT" -eq 1 ]; then
  echo "WARNING: Environment has non-critical issues:" >&2
  printf '%s\n' "$DOCTOR_RESULT" | jq -r '.warnings[]' >&2 2>/dev/null || true
  # Continue — warnings do not block skill execution
fi

# Layer 3: project-declared environment checks (preflight.environment, #101).
# Opt-in: with none declared this prints nothing and continues. The verb
# writes one `[environment-halt]` line per failed check, with its remedy.
if ! "$BINARY" preflight environment >/dev/null; then
  echo "[environment-halt] Project environment check failed — fix the environment, not the code." >&2
  exit 1
fi
```

**Exit codes from `nightgauge doctor`**:

| Code | Meaning                         | Skill behavior                          |
| ---- | ------------------------------- | --------------------------------------- |
| 0    | Healthy                         | Continue                                |
| 1    | Degraded (warnings only)        | Continue with warning printed to stderr |
| 2    | Broken (required checks failed) | Halt immediately with error details     |

**Layer 3** halts the stage when any check declared under
`preflight.environment` in the workspace's `.nightgauge/config.yaml` fails
(exit 1) or the declaration is invalid (exit 2). The failure is in the
operator's environment, not the code: do not edit code to work around it, do
not run the remedy yourself, and end the stage. The pipeline records it as
`environment_halt` and holds the issue for an operator.

Do not theorize about the cause beyond what is printed here — the failing
check name (`failed_checks`) and its `.errors[]` message are the complete
diagnosis (#277).


---

### Phase 1: Validate Prerequisites and Resolve Issue Number

```bash
printf '<!-- phase:start name="validate-prerequisites" index=1 total=6 stage="issue-refine" -->\n'
```

#### Step 1.1: Verify GitHub Authentication

```bash
nightgauge forge auth status || { echo "ERROR: Forge auth not configured. Run: nightgauge forge auth login"; exit 1; }
```

#### Step 1.2: Resolve Issue Number

```bash
# Use argument if provided, otherwise infer from current branch
ISSUE_NUMBER="${ARGUMENTS:-$(git branch --show-current 2>/dev/null | grep -oE '[0-9]+' | head -1)}"

if [ -z "$ISSUE_NUMBER" ]; then
  echo "ERROR: No issue number provided and could not infer from branch."
  echo "Usage: /nightgauge:issue-refine <issue-number>"
  echo "Example: /nightgauge:issue-refine 42"
  exit 1
fi

echo "Refining issue #${ISSUE_NUMBER}..."
```

#### Step 1.3: Fetch Issue Details

```bash
REPO="${NIGHTGAUGE_REPO:-$(nightgauge git repo-slug)}"
: "${REPO:?set NIGHTGAUGE_REPO or run inside a clone with an origin remote}"
ISSUE_NUMBER="${NIGHTGAUGE_ISSUE_NUMBER:-$(git branch --show-current | sed -n 's#^[^/]*/\([0-9]*\)-.*#\1#p')}"
: "${ISSUE_NUMBER:?set NIGHTGAUGE_ISSUE_NUMBER or check out the issue branch}"
# --comments returns only comments by users with write access (or a trusted
# bot); the rest never reach this skill (#2130).
ISSUE_JSON=$(nightgauge forge issue view "$ISSUE_NUMBER" --repo "$REPO" \
  --json --comments 2>/dev/null)

if [ -z "$ISSUE_JSON" ] || [ "$(printf '%s\n' "$ISSUE_JSON" | jq -r '.number // empty')" = "" ]; then
  echo "ERROR: Issue #${ISSUE_NUMBER} not found or not accessible."
  exit 1
fi

ISSUE_TITLE=$(printf '%s\n' "$ISSUE_JSON" | jq -r '.title')
ISSUE_BODY=$(printf '%s\n' "$ISSUE_JSON" | jq -r '.body // ""')
ISSUE_STATE=$(printf '%s\n' "$ISSUE_JSON" | jq -r '.state')
ISSUE_LABELS=$(printf '%s\n' "$ISSUE_JSON" | jq -r '[.labels[].name] | join(",")')

echo "Issue: #${ISSUE_NUMBER} — ${ISSUE_TITLE}"
echo "State: ${ISSUE_STATE}"
echo "Labels: ${ISSUE_LABELS:-none}"
```

---

### Phase 2: Detect Issue Type and Analyze Existing Content

```bash
printf '<!-- phase:start name="detect-issue-type" index=2 total=6 stage="issue-refine" -->\n'
```

#### Step 2.1: Determine Issue Type

```bash
# Prefer explicit type label
if printf '%s\n' "$ISSUE_LABELS" | grep -q "type:bug"; then
  ISSUE_TYPE="bug"
elif printf '%s\n' "$ISSUE_LABELS" | grep -q "type:feature"; then
  ISSUE_TYPE="feature"
elif printf '%s\n' "$ISSUE_LABELS" | grep -q "type:chore"; then
  ISSUE_TYPE="chore"
elif printf '%s\n' "$ISSUE_LABELS" | grep -q "type:docs"; then
  ISSUE_TYPE="docs"
else
  # Infer from body keywords
  BODY_LOWER=$(echo "$ISSUE_BODY" | tr '[:upper:]' '[:lower:]')
  if printf '%s\n' "$BODY_LOWER" | grep -qE '\b(bug|error|exception|crash|broken|fail|wrong|incorrect|regression|stack trace)\b'; then
    ISSUE_TYPE="bug"
  elif printf '%s\n' "$BODY_LOWER" | grep -qE '\b(add|implement|create|build|feature|enhancement|support|allow)\b'; then
    ISSUE_TYPE="feature"
  else
    ISSUE_TYPE="feature"  # safe default
  fi
  echo "No type label found — inferred type: ${ISSUE_TYPE}"
fi

echo "Issue type: ${ISSUE_TYPE}"
```

#### Step 2.2: Detect Existing Structured Sections

```bash
# Check which pipeline sections already exist to avoid duplication
HAS_SUMMARY=false
HAS_USER_STORY=false
HAS_ACCEPTANCE_CRITERIA=false
HAS_TECHNICAL_NOTES=false
HAS_ROOT_CAUSE=false
HAS_COMPLEXITY=false

printf '%s\n' "$ISSUE_BODY" | grep -q "^## Summary" && HAS_SUMMARY=true
printf '%s\n' "$ISSUE_BODY" | grep -q "^## User Story" && HAS_USER_STORY=true
printf '%s\n' "$ISSUE_BODY" | grep -qE "^## Acceptance Criteria" && HAS_ACCEPTANCE_CRITERIA=true
printf '%s\n' "$ISSUE_BODY" | grep -q "^## Technical Notes" && HAS_TECHNICAL_NOTES=true
printf '%s\n' "$ISSUE_BODY" | grep -q "^## Root Cause" && HAS_ROOT_CAUSE=true
printf '%s\n' "$ISSUE_BODY" | grep -q "^## Complexity" && HAS_COMPLEXITY=true

echo "Existing sections — Summary:${HAS_SUMMARY} AC:${HAS_ACCEPTANCE_CRITERIA} Technical:${HAS_TECHNICAL_NOTES}"
```

---

### Phase 3: Codebase-Aware Analysis

```bash
printf '<!-- phase:start name="codebase-analysis" index=3 total=6 stage="issue-refine" -->\n'
```

**PURPOSE**: Ground the refined issue in actual codebase files. All file
references in the output MUST come from this phase — never from model
generation.

#### Step 3.1: Extract Keywords from Issue

Extract component names, class names, file paths, and error terms mentioned in
the issue title and body:

```bash
# Extract PascalCase component/class names (likely TypeScript/Go identifiers)
COMPONENT_KEYWORDS=$(echo "${ISSUE_TITLE} ${ISSUE_BODY}" | \
  grep -oE '[A-Z][a-zA-Z]{3,}(Service|Manager|Controller|Handler|Provider|View|Panel|Tree|Dashboard|Orchestrator|Selector|Config|Schema|Parser|Client|Router)' | \
  sort -u | head -10)

# Extract file paths or module names explicitly mentioned
EXPLICIT_PATHS=$(echo "${ISSUE_TITLE} ${ISSUE_BODY}" | \
  grep -oE '[a-zA-Z0-9_/.-]+\.(ts|go|tsx|json|yaml|md)' | \
  sort -u | head -10)

# For bugs: extract error message keywords
if [ "$ISSUE_TYPE" = "bug" ]; then
  ERROR_KEYWORDS=$(echo "$ISSUE_BODY" | \
    grep -oE '"[^"]{5,50}"|\`[^`]{5,50}\`|Error: [^\n.]{5,50}' | \
    head -5)
fi

echo "Component keywords: ${COMPONENT_KEYWORDS:-none}"
echo "Explicit paths: ${EXPLICIT_PATHS:-none}"
```

#### Step 3.2: Search Codebase for Related Files

```bash
RELATED_FILES=""

# Use the Grep tool (or rg if available) to find files containing each keyword.
# When executing in a bash block, rg provides the same capability as the Grep tool.
for KW in $COMPONENT_KEYWORDS; do
  MATCHES=$(rg "$KW" \
    --glob "*.ts" --glob "*.tsx" --glob "*.go" \
    -l 2>/dev/null | head -3)
  if [ -z "$MATCHES" ]; then
    # Fallback to grep if rg not available
    MATCHES=$(grep -r "$KW" \
      --include="*.ts" --include="*.tsx" --include="*.go" \
      -l 2>/dev/null | head -3)
  fi
  if [ -n "$MATCHES" ]; then
    RELATED_FILES="${RELATED_FILES}
${MATCHES}"
  fi
done

# Verify explicitly mentioned file paths exist
for PATH_REF in $EXPLICIT_PATHS; do
  if [ -f "$PATH_REF" ]; then
    RELATED_FILES="${RELATED_FILES}
${PATH_REF}"
  fi
done

# Deduplicate and limit
RELATED_FILES=$(echo "$RELATED_FILES" | sort -u | grep -v '^$' | head -10)

echo "Related files found:"
echo "${RELATED_FILES:-  (none — keyword search returned no results)}"
```

#### Step 3.3: Read Key File Context (Bug Path Only)

For bug issues, read the first 1-2 most relevant related files to understand the
code path. This improves the quality of the Root Cause Analysis section.

```bash
if [ "$ISSUE_TYPE" = "bug" ] && [ -n "$RELATED_FILES" ]; then
  FIRST_FILE=$(echo "$RELATED_FILES" | head -1)
  if [ -f "$FIRST_FILE" ]; then
    echo "=== Reading key file: $FIRST_FILE ==="
    # Read first 50 lines for context without overwhelming the agent
    head -50 "$FIRST_FILE"
    echo "=== (truncated) ==="
  fi
fi
```

---

### Phase 4: Construct Refined Issue Body

```bash
printf '<!-- phase:start name="construct-body" index=4 total=6 stage="issue-refine" -->\n'
```

**PURPOSE**: Build the structured body using analysis from phases 2 and 3.

Using the original issue content, inferred type, and codebase file list from
Phase 3, construct a new issue body with the following structure. Reuse existing
sections if they were already present (do not duplicate them).

#### Required Sections

Build the body with these sections in order:

**1. Summary** (always include — expand the title into a clear description):

```markdown
## Summary

{2-4 sentence description of the problem or feature. For bugs: what behavior is
observed vs. expected. For features: what capability is being added and why.
Expand on the original title — do not just repeat it verbatim.}
```

**2. User Story** (features only):

```markdown
## User Story

As a {user persona — developer, user, admin, etc.},
I want {specific action or capability},
So that {business or user value delivered}.
```

**3. Acceptance Criteria** (always include):

```markdown
## Acceptance Criteria

- [ ] {concrete, testable outcome 1}
- [ ] {concrete, testable outcome 2}
- [ ] {concrete, testable outcome 3}
```

Each criterion must be observable and testable. Avoid vague criteria like "works
correctly" — instead: "When X happens, Y is displayed" or "Calling Z returns
status 200 with field F present."

**4. Technical Notes** (always include):

```markdown
## Technical Notes

**Affected files:**
{For each file in RELATED_FILES from Phase 3.2:}

- `{file_path}` — {one line: why this file is relevant}

{If RELATED_FILES is empty:}
**Note:** No files were identified by automated codebase search. Implementation
agent should investigate relevant files during pickup.

**Implementation approach:**
{1-3 sentences of implementation guidance. For bugs: how to reproduce and where
to look. For features: what approach to take and what patterns to follow.}
```

**5. Root Cause Analysis** (bugs only):

```markdown
## Root Cause Analysis

**Observed behavior:** {what the user sees happening}

**Expected behavior:** {what should happen instead}

**Suspected location:** {file or module where the bug likely originates, from
Phase 3.3 analysis — or "Unknown, requires investigation" if no files found}

**Reproduction steps:**

1. {step 1}
2. {step 2}
   (Extract from issue body if present; otherwise note "Not provided — add before
   implementation")
```

**6. Complexity Estimate** (always include):

```markdown
## Complexity Estimate

Size: {XS|S|M|L|XL} — {1-sentence rationale based on number of affected files
and scope of change}
```

Size heuristics:

- **XS**: Single file, <20 lines changed
- **S**: 1-2 files, focused change
- **M**: 3-5 files, moderate scope
- **L**: 5-10 files or cross-cutting concern
- **XL**: 10+ files or architectural change

**7. Related Issues** (include only when dependencies are discovered):

```markdown
## Related Issues

- Depends on #{N} — {reason}
- Part of #{N} — {relationship}
```

**8. Original Issue** (always append — preservation block):

```markdown
<details>
<summary>Original Issue (before refinement)</summary>

{ISSUE_BODY verbatim — even if empty, include the block}

</details>
```

#### Body Construction Rule

- Sections that **already exist** in `ISSUE_BODY` (detected in Phase 2.2) are
  NOT added again. Instead, the existing section content is preserved as-is.
- The `<details>` preservation block is always appended, even if the issue body
  was already structured.
- Do NOT modify the issue title.

---

### Phase 5: Apply Updates to GitHub

```bash
printf '<!-- phase:start name="apply-updates" index=5 total=6 stage="issue-refine" -->\n'
```

#### Step 5.1: Write Body to Temp File

Write the constructed body to a temp file to avoid shell argument escaping issues
with `nightgauge forge issue edit`:

```bash
BODY_FILE=$(mktemp /tmp/issue-refine-body-XXXXXX.md)
# Agent writes NEW_BODY content to $BODY_FILE here
cat > "$BODY_FILE" << 'BODYEOF'
{constructed body from Phase 4}
BODYEOF
```

#### Step 5.2: Update Issue Body

```bash
REPO="${NIGHTGAUGE_REPO:-$(nightgauge git repo-slug)}"
: "${REPO:?set NIGHTGAUGE_REPO or run inside a clone with an origin remote}"
ISSUE_NUMBER="${NIGHTGAUGE_ISSUE_NUMBER:-$(git branch --show-current | sed -n 's#^[^/]*/\([0-9]*\)-.*#\1#p')}"
: "${ISSUE_NUMBER:?set NIGHTGAUGE_ISSUE_NUMBER or check out the issue branch}"
nightgauge issue edit "$ISSUE_NUMBER" --repo "$REPO" --body "$(cat "$BODY_FILE")"

if [ $? -ne 0 ]; then
  echo "ERROR: Failed to update issue #${ISSUE_NUMBER} body."
  rm -f "$BODY_FILE"
  exit 1
fi

rm -f "$BODY_FILE"
echo "Issue #${ISSUE_NUMBER} body updated."
```

#### Step 5.3: Add Type Label if Missing

```bash
ISSUE_NUMBER="${NIGHTGAUGE_ISSUE_NUMBER:-$(git branch --show-current | sed -n 's#^[^/]*/\([0-9]*\)-.*#\1#p')}"
: "${ISSUE_NUMBER:?set NIGHTGAUGE_ISSUE_NUMBER or check out the issue branch}"
if ! printf '%s\n' "$ISSUE_LABELS" | grep -qE '(^|,)type:'; then
  nightgauge forge graphql -f query="mutation{addLabelsToLabelable(input:{labelableId:\"$ISSUE_NUMBER\",labelIds:[\"type:${ISSUE_TYPE}\"]}){clientMutationId}}" 2>/dev/null || \
    echo "WARNING: Could not add type:${ISSUE_TYPE} label (may not exist in repo)."
fi
```

#### Step 5.4: Mark as Refined (Graceful Fallback)

Call the Go binary's `mark-refined` command if available. This depends on
issue #2533. If the command does not exist, skip silently.

```bash
ISSUE_NUMBER="${NIGHTGAUGE_ISSUE_NUMBER:-$(git branch --show-current | sed -n 's#^[^/]*/\([0-9]*\)-.*#\1#p')}"
: "${ISSUE_NUMBER:?set NIGHTGAUGE_ISSUE_NUMBER or check out the issue branch}"
BINARY="${NIGHTGAUGE_BIN:-}"
[ -n "$BINARY" ] && [ ! -x "$BINARY" ] && BINARY=""
[ -z "$BINARY" ] && BINARY=$(command -v nightgauge 2>/dev/null || echo "")
if [ -z "$BINARY" ] && [ "${NIGHTGAUGE_DEV_REPO_BIN:-}" = "1" ]; then
  for NG_ROOT in "$(git rev-parse --show-toplevel 2>/dev/null)" \
    "$(cd "$(git rev-parse --git-common-dir 2>/dev/null)/.." 2>/dev/null && pwd)"; do
    [ -x "$NG_ROOT/bin/nightgauge" ] || continue
    grep -qx 'module github.com/nightgauge/nightgauge' "$NG_ROOT/go.mod" 2>/dev/null || continue
    NG_ORIGIN="$(git -C "$NG_ROOT" config --get remote.origin.url 2>/dev/null)"
    case "${NG_ORIGIN%.git}" in
      git@github.com:nightgauge/nightgauge | https://github.com/nightgauge/nightgauge | \
        ssh://git@github.com/nightgauge/nightgauge) BINARY="$NG_ROOT/bin/nightgauge"; break ;;
    esac
  done
fi
[ -z "$BINARY" ] && [ -x "$HOME/go/bin/nightgauge" ] && BINARY="$HOME/go/bin/nightgauge"
[ -n "$BINARY" ] && export PATH="$(dirname "$BINARY"):$PATH"

if [ -n "$BINARY" ]; then
  "$BINARY" issue mark-refined "$ISSUE_NUMBER" 2>/dev/null || true
fi
```

#### Step 5.5: Report Success

```bash
REPO="${NIGHTGAUGE_REPO:-$(nightgauge git repo-slug)}"
: "${REPO:?set NIGHTGAUGE_REPO or run inside a clone with an origin remote}"
ISSUE_NUMBER="${NIGHTGAUGE_ISSUE_NUMBER:-$(git branch --show-current | sed -n 's#^[^/]*/\([0-9]*\)-.*#\1#p')}"
: "${ISSUE_NUMBER:?set NIGHTGAUGE_ISSUE_NUMBER or check out the issue branch}"
ISSUE_URL=$(nightgauge forge issue view "$ISSUE_NUMBER" --repo "$REPO" --json 2>/dev/null | jq -r '.url // empty')
[ -n "$ISSUE_URL" ] || ISSUE_URL="https://github.com/${REPO}/issues/${ISSUE_NUMBER}"

echo ""
echo "✓ Issue #${ISSUE_NUMBER} refined successfully"
echo "  URL: ${ISSUE_URL}"
echo "  Type: ${ISSUE_TYPE}"
echo "  Files referenced: $(printf '%s\n' "${RELATED_FILES}" | grep -c . 2>/dev/null || echo 0)"
echo ""
echo "Next step: /nightgauge-issue-pickup ${ISSUE_NUMBER}"
```

---

### Phase 6: Self-Assessment Epilogue

```bash
printf '<!-- phase:start name="self-assessment" index=6 total=6 stage="issue-refine" -->\n'
```

### Self-Assessment Epilogue

**PURPOSE**: Evaluate whether this skill's instructions matched reality during
this execution. This phase is **non-blocking** — skip entirely if any main phase
failed. A perfectly working skill produces **no output** from this phase.

> See [docs/SKILL_SELF_ASSESSMENT.md](https://github.com/nightgauge/nightgauge/blob/main/docs/SKILL_SELF_ASSESSMENT.md) for
> the full strategy, synthesis algorithm, and integration architecture.

#### When to Skip

- Any prior phase exited with an error before completing
- The skill was cancelled or timed out
- Running in `--dry-run` mode

#### Step 1: Evaluate Execution Friction

Review the execution that just completed. Answer these questions honestly:

1. **Command failures**: Did any command, script, or binary call in the skill
   instructions fail? (e.g., script not found, wrong flags, missing binary)
2. **Workarounds**: Did you have to deviate from the skill instructions to
   accomplish the goal? (e.g., used `gh` directly because a referenced script
   didn't exist, skipped a step that referenced a nonexistent file)
3. **Stale references**: Did any file path, function name, API endpoint, or tool
   referenced in the instructions not exist in the current codebase?
4. **Unclear instructions**: Were any instructions ambiguous enough that you had
   to guess at the intended behavior?
5. **Missing instructions**: Was there a significant step you had to figure out
   on your own that should have been documented in this skill?

**If ALL answers are "no" — write nothing and complete the skill normally.** The
goal is silence when everything works.

#### Step 2: Write Assessment Record

Only if friction was detected in Step 1. Write a single JSON file,
`assessments/{STAGE_NAME}-${ISSUE_NUMBER}.json` in the clone's pipeline state
directory, through the binary (JSON on stdin; never a direct file write):

```bash
ISSUE_NUMBER="${NIGHTGAUGE_ISSUE_NUMBER:-$(git branch --show-current | sed -n 's#^[^/]*/\([0-9]*\)-.*#\1#p')}"
: "${ISSUE_NUMBER:?set NIGHTGAUGE_ISSUE_NUMBER or check out the issue branch}"
nightgauge layout write pipeline "assessments/{STAGE_NAME}-${ISSUE_NUMBER}.json" <<'JSON'
{ ... the record below ... }
JSON
```

The assessment record MUST follow this schema:

```json
{
  "schema_version": "1",
  "skill": "{STAGE_NAME}",
  "skill_file": "skills/nightgauge-{STAGE_NAME}/SKILL.md",
  "issue_number": 42,
  "timestamp": "2026-03-10T14:30:00Z",
  "friction": [
    {
      "type": "command_failure",
      "severity": "high",
      "description": "hooks/lib/add-to-project.sh not found — script was deleted",
      "skill_line_hint": "claude-plugins/nightgauge/hooks/lib/add-to-project.sh <issue-number>",
      "actual_resolution": "Used gh api graphql to add issue to project board directly",
      "suggested_fix": "Replace with: nightgauge project add <issue-number>"
    }
  ]
}
```

**Friction types**: `command_failure`, `workaround`, `stale_reference`,
`unclear_instruction`, `missing_instruction`

**Severity levels**:

- `high` — instruction is **broken**. Required manual workaround to complete.
- `medium` — instruction is **misleading**. Agent adapted without user help.
- `low` — instruction is **suboptimal**. No functional impact.

**Rules**:

- **One record per execution** — multiple friction items go in the `friction`
  array, not separate files.
- **Be specific** — quote the exact instruction text that was wrong. Not "some
  commands didn't work" but "Step 5.2 calls `hooks/lib/add-to-project.sh` but
  this script was deleted in commit 65915701."
- **Suggest the fix** — every finding MUST include `suggested_fix` with the
  concrete SKILL.md change needed. Not "update the docs" but "replace
  `hooks/lib/add-to-project.sh <N>` with `nightgauge project add <N>`."
- **Don't invent friction** — only report issues you actually encountered during
  this execution. Do not speculate about potential problems.

#### Step 3: Validate and Complete

```bash
# Validate JSON if written
ISSUE_NUMBER="${NIGHTGAUGE_ISSUE_NUMBER:-$(git branch --show-current | sed -n 's#^[^/]*/\([0-9]*\)-.*#\1#p')}"
: "${ISSUE_NUMBER:?set NIGHTGAUGE_ISSUE_NUMBER or check out the issue branch}"
ASSESSMENT_FILE="$(nightgauge layout path pipeline "assessments/{STAGE_NAME}-${ISSUE_NUMBER}.json")"
if [ -f "$ASSESSMENT_FILE" ]; then
  python3 -m json.tool "$ASSESSMENT_FILE" > /dev/null 2>&1 || \
    echo "WARNING: Assessment record is not valid JSON" >&2
fi
```


---

## Error Handling

| Condition                           | Action                                                       |
| ----------------------------------- | ------------------------------------------------------------ |
| Forge auth not configured           | Exit 1 with `nightgauge forge auth login` remediation        |
| Issue not found                     | Exit 1 with clear message                                    |
| Issue already fully structured      | Detect existing sections, append only missing ones           |
| No related files found              | Include note in Technical Notes; do not fabricate file paths |
| `nightgauge forge issue edit` fails | Exit 1 with error output                                     |
| `mark-refined` binary missing       | Skip silently (graceful fallback) — depends on #2533         |

## Completion Checklist

- [ ] Issue body updated with structured sections
- [ ] Original content preserved in `<details>` block
- [ ] Type label added if it was missing
- [ ] `mark-refined` called (or gracefully skipped if #2533 not merged)
- [ ] Issue title unchanged
- [ ] All file references come from actual `Glob`/`Grep` results
- [ ] Next step (`/nightgauge-issue-pickup`) displayed

Files in this skill

  • CHANGELOG.md2.3 KB
  • SKILL.md29.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.