Skip to content
Back to skills

Nightgauge Assess Epic

ASecurity

Analyze an epic's sub-issues and recommend batch vs sequential pipeline

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

Works with

  • claude code
  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned November 5, 2026

npx -y skills add nightgauge/nightgauge --skill nightgauge-assess-epic --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Nightgauge Assess Epic?

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

Security grade badge for Nightgauge Assess Epic
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nightgauge-nightgauge-assess-epic/badge)](https://www.skillsdirectory.com/skills/nightgauge-nightgauge-assess-epic)

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: nightgauge-assess-epic
description: Analyze an epic's sub-issues and recommend batch vs sequential pipeline
  processing strategy. Use before starting work on an epic to determine optimal
  execution approach.
license: Apache-2.0
metadata:
  author: nightgauge
  version: "1.0.2"
  source: https://github.com/nightgauge/nightgauge
  chainable: true
allowed-tools: Read Bash Glob Grep
---

# Nightgauge Assess Epic

## Description

Analyzes an epic's sub-issues to determine whether they should be processed via
batch, sequential, or hybrid pipeline execution. Extracts file overlap, size
variance, and dependency signals from sub-issues, then computes a deterministic
strategy recommendation with confidence scoring and estimated savings.

The recommendation is advisory: every sub-issue still runs its own pipeline and
PR into the epic branch, and `epic-complete` opens the single epic PR. There is
no multi-issue pipeline run (#366).

**Use Cases:**

- Planning pipeline execution strategy before starting an epic
- Evaluating whether sub-issues have sufficient file overlap for batching
- Estimating token and cost savings from parallel batch execution
- Identifying dependency chains that require sequential processing

**When to Use:**

- Before queuing an epic for pipeline processing
- When an epic has 3+ sub-issues and you want to optimize execution
- After sub-issues change (new issues added, scope changes) to refresh strategy
- When deciding the order in which to queue an epic's sub-issues

## Invocation

| Tool        | Command                                 |
| ----------- | --------------------------------------- |
| Claude Code | `/nightgauge:assess-epic <epic-number>` |
| Copilot     | Invoke via Agent Skills extension       |
| Cursor      | Run via Agent Skills or direct SKILL.md |
| Headless    | `claude -p "/nightgauge:assess-epic"`   |

## Arguments

| Argument        | Description                     | Required | Default |
| --------------- | ------------------------------- | -------- | ------- |
| `<epic-number>` | GitHub issue number of the epic | Yes      | -       |

### Examples

```bash
# Assess epic #799's execution strategy
/nightgauge:assess-epic 799

# Assess a different epic
/nightgauge:assess-epic 1672
```

---

## Prerequisites

- `gh` CLI installed and authenticated (`gh auth login`)
- `jq` installed for JSON processing
- Epic issue must exist with the `type:epic` label
- Sub-issues must be linked via GitHub's native sub-issue feature (GraphQL
  `subIssues` API)
- Git repository with GitHub remote

**CRITICAL**: This skill runs headless. Do NOT use AskUserQuestion. Make
autonomous decisions or fail with clear error.

---

## Workflow

### Phase 0: Environment Preflight

<!-- include: ../_shared/PREFLIGHT.md -->

---

### Phase 1: Validate Input and Fetch Epic

#### Step 1.1: Validate Epic Number

```bash
EPIC_NUMBER="${1:?ERROR: Epic number is required. Usage: /nightgauge:assess-epic <epic-number>}"

# Validate numeric input
if ! printf '%s\n' "$EPIC_NUMBER" | grep -qE '^[0-9]+$'; then
  echo "ERROR: Epic number must be a positive integer (got: $EPIC_NUMBER)"
  exit 1
fi
```

#### Step 1.2: Fetch Epic Issue

```bash
EPIC_JSON=$(gh issue view "$EPIC_NUMBER" --json number,title,labels,state,body 2>&1)
if [ $? -ne 0 ]; then
  echo "ERROR: Could not fetch issue #$EPIC_NUMBER. Verify the issue exists."
  echo "  Try: gh issue view $EPIC_NUMBER"
  exit 1
fi

# Verify it has the type:epic label
IS_EPIC=$(printf '%s\n' "$EPIC_JSON" | jq -r '.labels[]?.name' | grep -c '^type:epic$' || echo "0")
if [ "$IS_EPIC" -eq 0 ]; then
  echo "ERROR: Issue #$EPIC_NUMBER does not have the 'type:epic' label."
  echo "  This command only works on epic issues."
  exit 1
fi

EPIC_TITLE=$(printf '%s\n' "$EPIC_JSON" | jq -r '.title')
echo "Epic #$EPIC_NUMBER: $EPIC_TITLE"
```

#### Step 1.3: Fetch Sub-Issues

The shared epic-handling reference, `skills/_shared/EPIC_HANDLING.md`, covers
sub-issue detection (read it directly — `assess-epic` is not a pipeline stage,
so the composer does not expand the directive below).

<!-- include: ../_shared/EPIC_HANDLING.md -->

The binary reads every sub-issue, page by page, or exits non-zero; it never
returns part of the list as the whole of it (#1701).

```bash
# Detect owner/repo from git remote
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
OWNER=$(echo "$REMOTE_URL" | sed -E 's|.*[:/]([^/]+)/([^/.]+)(\.git)?$|\1|')
REPO=$(echo "$REMOTE_URL" | sed -E 's|.*[:/]([^/]+)/([^/.]+)(\.git)?$|\2|')

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 [ -z "$BINARY" ]; then
  echo "ERROR: nightgauge binary not found via NIGHTGAUGE_BIN, PATH or ~/go/bin"
  echo "Install via: go install github.com/nightgauge/nightgauge/cmd/nightgauge@latest"
  exit 1
fi

# stdout only: a warning on stderr must not land in the JSON.
if ! SUB_ISSUES_JSON=$("$BINARY" issue list --epic "$EPIC_NUMBER" \
    --owner "$OWNER" --repo "$REPO" --json); then
  echo "ERROR: Failed to fetch sub-issues for epic #$EPIC_NUMBER (the error is above)"
  exit 1
fi

# The binary writes subIssues as null when there are none.
SUB_COUNT=$(printf '%s\n' "$SUB_ISSUES_JSON" | jq '.subIssues // [] | length')
if [ "$SUB_COUNT" -eq 0 ]; then
  echo "ERROR: Epic #$EPIC_NUMBER has no sub-issues linked via GitHub's sub-issue feature."
  echo "  Sub-issues must be linked using the addSubIssue GraphQL mutation."
  echo "  Body text references (e.g., '- [ ] #123') do NOT count."
  exit 1
fi

echo "Found $SUB_COUNT sub-issues"
printf '%s\n' "$SUB_ISSUES_JSON" | jq -r '.subIssues[] |
  "  #\(.number) - \(.title) [\(.state)]"'
```

---

### Phase 2: Assess with Go Binary (Deterministic)

`$BINARY` is the binary Step 1.3 resolved.

```bash
ASSESS_JSON=$("$BINARY" epic assess "$EPIC_NUMBER" \
  --owner "$OWNER" --repo "$REPO" --json 2>/dev/null)

if [ $? -ne 0 ] || [ -z "$ASSESS_JSON" ]; then
  echo "ERROR: nightgauge epic assess failed for epic #$EPIC_NUMBER"
  exit 1
fi

STRATEGY=$(printf '%s\n' "$ASSESS_JSON" | jq -r '.strategy')
REASONING=$(printf '%s\n' "$ASSESS_JSON" | jq -r '.reasoning')
EST_COST=$(printf '%s\n' "$ASSESS_JSON" | jq -r '.estimatedCostUsd')
EST_MINUTES=$(printf '%s\n' "$ASSESS_JSON" | jq -r '.estimatedMinutes')
OPEN_COUNT=$(printf '%s\n' "$ASSESS_JSON" | jq '.issues | length')

echo "Strategy: $(echo "$STRATEGY" | tr '[:lower:]' '[:upper:]')"
echo "Reasoning: $REASONING"
```

---

### Phase 4: Generate Report

#### Step 4.1: Format Assessment Output

```bash
echo ""
echo "Epic #$EPIC_NUMBER Assessment"
echo "===================="
echo ""
echo "Strategy: $(echo "$STRATEGY" | tr '[:lower:]' '[:upper:]')"
echo "Reasoning: $REASONING"
echo ""
echo "Sub-Issues: $OPEN_COUNT open / $SUB_COUNT total"
echo ""
echo "Estimates:"
echo "  Cost: \$$EST_COST"
echo "  Time: $EST_MINUTES min"
echo ""
echo "Per-Issue Breakdown:"
printf '%s\n' "$ASSESS_JSON" | jq -r '.issues[] |
  "  #\(.issueNumber) complexity=\(.complexityScore) model=\(.recommendedModel)\(if .hasDependencies then " [blocked]" else "" end)"'
echo ""
echo "Recommendation:"
case "$STRATEGY" in
  parallel)
    echo "  All $OPEN_COUNT sub-issues are independent — queue them concurrently."
    ;;
  mixed)
    echo "  Queue independent sub-issues concurrently."
    echo "  Run dependency-blocked issues sequentially after their blockers."
    ;;
  sequential)
    echo "  Process sub-issues one at a time in dependency order."
    echo "  High dependency complexity makes batching counterproductive."
    ;;
esac
```

#### Step 4.2: Write JSON Report

```bash
REPORT_FILE=$(printf '%s\n' "$ASSESS_JSON" | jq \
  --arg epic_number "$EPIC_NUMBER" \
  --arg epic_title "$(echo "$EPIC_TITLE" | sed 's/"/\\"/g')" \
  --argjson sub_total "$SUB_COUNT" \
  --arg assessed_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  '. + {
    "schema_version": "2",
    "epic_number": ($epic_number | tonumber),
    "epic_title": $epic_title,
    "sub_issues": { "total": $sub_total, "open": (.issues | length) },
    "assessed_at": $assessed_at
  }' | nightgauge layout write pipeline "epic-assessment-${EPIC_NUMBER}.json")

echo ""
echo "Report written to: $REPORT_FILE"
```

---

### Self-Assessment Epilogue

<!-- include: ../_shared/SELF_ASSESSMENT_EPILOGUE.md -->

---

## Error Handling

| Condition                     | Action                                       |
| ----------------------------- | -------------------------------------------- |
| Missing epic number argument  | Error with usage hint                        |
| Invalid epic number (non-int) | Error with validation message                |
| Epic issue not found          | Error with GitHub issue link suggestion      |
| Issue lacks `type:epic` label | Error explaining epic requirement            |
| No sub-issues linked          | Error explaining GraphQL linking requirement |
| All sub-issues closed         | Exit 0 with "no assessment needed" message   |
| `gh` CLI not authenticated    | Error with `gh auth login` instructions      |
| GraphQL query failure         | Error with raw response for debugging        |
| `bc` not available            | Fall back to integer arithmetic              |
| Sub-issue body fetch failure  | Continue with partial data, warn user        |

---

## Pipeline Position

```
UTILITIES (not part of main pipeline)

/nightgauge:assess-epic <epic-number>
       |
  Standalone analysis tool for epic batch planning
  Reads: GitHub API (epic + sub-issues + blocking)
  Writes: pipeline/epic-assessment-{N}.json (nightgauge layout write)
```

This is a standalone utility skill. It does not affect pipeline state and can be
run at any time without interfering with active pipeline runs. The queue command
(`/nightgauge:queue`) automatically invokes this assessment when an epic
issue number is queued.

---

## Related Skills

- **`/nightgauge:queue`** - Queue management; auto-invokes assess-epic when
  epic issues are queued
- **`skills/_shared/EPIC_HANDLING.md`** - Shared epic detection and handling
  patterns
- **`skills/_shared/DEPENDENCY_CHECKING.md`** - Shared dependency checking logic

---

**Author:** nightgauge **License:** Apache-2.0

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.