Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Capture Issue

BSecurity

Use when asked to capture or create an issue from conversation or natural language.

6 stars
0 votes
0 copies
0 views
Added 10/6/2026
ai-agentsgoshellbashgitapisecuritydocumentation

Works with

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 10/6/2026

$npx -y skills add BrennonTWilliams/little-loops --skill capture-issue --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Capture Issue?

Add the live security badge to your README — it updates automatically with every re-scan.

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

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

Download with Pro
Files
SKILL.md
---
name: capture-issue
description: Use when asked to capture or create an issue from conversation or natural language.
args: "[description] [--quick] [--parent EPIC-NNN]"
argument-hint: "[description]"
allowed-tools:
  - Read
  - Glob
  - Grep
  - Write
  - Bash(ll-issues:*, git:*)
  - Bash(ll-session:*)
arguments:
  - name: input
    description: Natural language description of the issue (optional - analyzes conversation if omitted)
    required: false
  - name: flags
    description: Optional flags (--quick for minimal template, --parent EPIC-NNN to link as child)
    required: false
metadata:
trigger_fixtures:
  should_fire:
    - "capture this bug as a new issue from our conversation"
    - "create an issue from this natural language description"
  should_not_fire:
    - "fix this issue's template structure"
    - "detect conflicting requirements across open issues"
---

# Capture Issue

You are tasked with capturing issues from either a natural language description or the current conversation context, with automatic duplicate detection and support for reopening completed issues.

## Configuration

This command uses project configuration from `.ll/ll-config.json`:
- **Issues base**: `{{config.issues.base_dir}}`
- **Template style**: `{{config.issues.capture_template}}` (full or minimal)
- **Exact duplicate threshold**: `{{config.issues.duplicate_detection.exact_threshold}}` (default: 0.8)
- **Similar issue threshold**: `{{config.issues.duplicate_detection.similar_threshold}}` (default: 0.5)
- **Status enum**: `open`, `in_progress`, `blocked`, `deferred`, `done`, `cancelled` — see `.claude/CLAUDE.md` § Issue File Format for full enum and forbidden synonyms.

## Arguments

$ARGUMENTS

- **input** (optional): Natural language description of the issue
  - If provided, parse and create single issue
  - If omitted, analyze conversation for potential issues
- **flags** (optional): Modify command behavior
  - `--quick` - Use minimal template regardless of config setting
  - `--parent EPIC-NNN` - Link the new issue as a child of the given EPIC: sets `parent:` in child frontmatter and updates the EPIC's `relates_to:` list and `## Children` section

## Process

### Phase 1: Determine Mode and Extract Issues

**Parse flags:**

```bash
FLAGS="${flags:-}"
QUICK_MODE=false
if [[ "$FLAGS" == *"--quick"* ]]; then QUICK_MODE=true; fi

PARENT_ID=""
if [[ "$FLAGS" =~ --parent[[:space:]]+([A-Z]+-[0-9]+) ]]; then
  PARENT_ID="${BASH_REMATCH[1]}"
fi
```

**If `--parent` was given, validate it before proceeding:**

1. Search `{{config.issues.base_dir}}/epics/` for a file whose frontmatter `id:` matches `PARENT_ID`.
2. If no matching EPIC file is found, abort with:
   ```
   ❌ Parent EPIC not found: [PARENT_ID]. Check the ID and try again.
   ```
3. Store the resolved EPIC file path as `PARENT_EPIC_PATH` for use in Phase 4c.

**Check the arguments to determine mode:**

```
IF input argument is provided:
  MODE = "direct"
ELSE:
  MODE = "conversation"
```

#### Direct Mode (description provided)

Parse the natural language description to extract:

1. **Issue Title**: Create a concise summary (5-10 words max)
2. **Issue Type**: Infer from keywords:
   - **BUG**: "broken", "error", "crash", "fails", "doesn't work", "wrong", "bug", "issue with", "problem"
   - **FEAT**: "add", "new feature", "implement", "create", "support for", "need", "want", "should have"
   - **ENH**: "improve", "enhance", "better", "optimize", "refactor", "cleanup", "update", "upgrade"
   - **EPIC**: "epic", "initiative", "milestone", "large effort", "multi-issue", "decompose into", "rollup of", "umbrella"
   - Default to **ENH** if unclear. Use **EPIC** only when the user explicitly signals coordination scope (a container that will be decomposed into child BUG/FEAT/ENH issues).
3. **Priority**: Infer from severity language:
   - **P0-P1**: "critical", "urgent", "blocking", "security", "data loss", "production down"
   - **P2**: "important", "high priority", "significant"
   - **P3**: Default for most issues
   - **P4-P5**: "minor", "low priority", "nice to have", "someday"
4. **Description**: The full description text

#### Conversation Mode (no description)

Analyze the current conversation session to identify potential issues:

1. **Problems discussed but not resolved** - bugs, errors, failures mentioned
2. **Improvements mentioned but deferred** - "we should...", "it would be better if..."
3. **Feature ideas that came up** - "we could add...", "what if we..."
4. **TODOs or action items mentioned** - explicit tasks identified

For each potential issue found, extract:
- Source context (brief quote or summary of what prompted it)
- Issue title
- Issue type (BUG/FEAT/ENH)
- Priority suggestion
- Brief description

**Present all identified issues to the user:**

```markdown
## Issues Identified from Conversation

| # | Type | Priority | Title |
|---|------|----------|-------|
| 1 | BUG  | P2       | [title] |
| 2 | ENH  | P3       | [title] |
| 3 | FEAT | P3       | [title] |
| 4 | EPIC | P2       | [title] |

### Issue 1: [Title]
- **Type**: BUG (inferred from: "this keeps failing...")
- **Context**: [Brief quote from conversation]

### Issue 2: [Title]
- **Type**: ENH (inferred from: "we should improve...")
- **Context**: [Brief quote from conversation]
```

**Use AskUserQuestion to let user select which issues to capture (multi-select):**

```yaml
questions:
  - question: "Which issues would you like to capture?"
    header: "Select issues"
    options:
      - label: "Issue 1: [title]"
        description: "[type] - [brief context]"
      - label: "Issue 2: [title]"
        description: "[type] - [brief context]"
    multiSelect: true
```

If no issues are identified, inform the user:
```
No actionable issues found in this conversation. You can run this command with an input argument:
/ll:capture-issue "description of the issue"
```

### Phase 2: Duplicate Detection

For each issue to capture, search for existing duplicates. This phase performs two checks: (1) title word-overlap scoring against active and completed/cancelled issues via `ll-issues find-similar`, and (2) an FTS5 near-duplicate check against the session history DB using `ll-session search --fts "<keywords>" --kind issue --limit 5 2>/dev/null || true`. If `.ll/history.db` is absent or the query returns no results, proceed silently without warning.

#### Word-Overlap Scoring (Active + Completed Issues)

`find-similar` scores the candidate title against every issue's title using the canonical Jaccard implementation in `text_utils.py`. `--against all` includes `done`/`cancelled` issues alongside active ones, so one call replaces the separate active/completed passes:

```bash
ll-issues find-similar "<new issue title>" --against all
```

Returns ranked `{id, title, path, score}` candidates:
- Score >= {{config.issues.duplicate_detection.exact_threshold}} = exact duplicate
- Score {{config.issues.duplicate_detection.similar_threshold}}-{{config.issues.duplicate_detection.exact_threshold}} = similar issue
- No returned candidate = likely new issue (find-similar's own default threshold is {{config.issues.duplicate_detection.similar_threshold}}, so anything below that never appears in the results)

A match against a `done`/`cancelled` issue is a candidate for reopening rather than a fresh capture.

#### Search History DB for Near-Duplicates

Independently of word-overlap scoring, query the session history for recently closed or deferred issues matching the new issue's title keywords. This FTS5 query answers a different question (was something like this recently closed/deferred in conversation history?) against a different corpus (`.ll/history.db`, not `.issues/`), so it stays a separate call:

```bash
# NOTE: this stop-word regex is an FTS-query-keyword shim for ll-session --fts,
# not the similarity stop-word list — that list is text_utils._COMMON_WORDS,
# consumed via `ll-issues find-similar` above.
KEYWORDS=$(echo "<title>" | tr '[:upper:]' '[:lower:]' | grep -oE '\b[a-z]{3,}\b' | grep -vE '^(the|and|for|are|was|but|not|all|can|had|its|our|out|who|did|how|get|has|let|use|via|were|with|from|they|that|this|have|will|been|into|also|just|more|some|when|what|then|than|them|your|does|both|like)$' | tr '\n' ' ')
HIST_DUPES=$(ll-session search --fts "$KEYWORDS" --kind issue --limit 5 2>/dev/null || true)
```

If results include issues with `status: done` or `status: deferred` and >`{{config.history.capture_issue.dup_overlap_threshold}}` (default 0.7) title word overlap with the new issue title, surface a warning before writing the file:

```
Warning: Similar closed issue found: [ID] ([status]) — closed/deferred [N] days ago
   Title: [existing issue title]
   Proceed with new capture, or link to the existing issue instead?
```

Ask the user whether to proceed with capture or link to the existing issue. If `.ll/history.db` is absent or the query returns no results, proceed silently without warning.

### Phase 3: Handle Duplicates/Similar Issues

Based on duplicate detection results, take appropriate action. See [templates.md](templates.md) for detailed duplicate/similar handling flows including:
- Exact duplicate detection with user prompts
- Similar issue handling options
- Completed issue reopening flows
- "View Existing" / "View Completed" interaction patterns

#### If No Match Found (score < {{config.issues.duplicate_detection.similar_threshold}})

Proceed directly to issue creation without user confirmation.

### Phase 4: Execute Action

#### Action: Create New Issue

1. **Determine template style:**

   ```
   IF QUICK_MODE is true:
     TEMPLATE_STYLE = "minimal"
   ELSE IF config.issues.capture_template is set:
     TEMPLATE_STYLE = {{config.issues.capture_template}}
   ELSE:
     TEMPLATE_STYLE = "full"
   ```

2. **Infer `testable: false`** — scan the issue title and description for doc-only signal keywords before creating the file (ENH-2966: this mirrors `check_format_gaps`'s title + `## Summary` scan surface, word-boundary matched — not the pre-ENH-2966 whole-body substring scan):
   - **Signal keywords**: "doc", "docs", "documentation", "broken link"/"broken links", "broken anchor"/"broken anchors", "readme"/"readmes", "changelog"/"changelogs", "spelling", "typo"/"typos", "guide", "fix link"/"fix links" — word-boundary matches only (e.g. `doc` does not match inside `documentation` or `docs`)
   - **Threshold**: 2+ distinct keyword matches (case-insensitive) in the combined title + description text
   - If threshold met: after `ll-issues create` writes the file (step 4), use `Edit` to add `testable: false` to its frontmatter and log `ℹ️ Set testable: false (inferred: documentation-only issue)`
   - If threshold not met: leave `testable` unset (absence means testable)

3. **Verify quoted evidence against the cited artifact** (ENH-3283 — the write-time half of
   BUG-3282's verify-time gate). Before step 4's write, identify every quoted span in the drafted
   body (fenced block or inline backticks) that is attributed to a named file or issue ID — minus
   the non-trigger shapes below — and confirm each against that artifact.

   **Non-triggers — skip these without verifying:**
   - **Command output** and run-log excerpts (a pasted traceback, pytest summary, FSM state
     transition) — not a quotation *of* the file it mentions
   - **Reproduction steps** that name an artifact as an argument (e.g. `` `ll-issues show
     ENH-3277` ``) — cites the artifact as an input, not as a source of quoted text
   - **Proposed text** — a snippet the issue suggests be *written* (a new config key, a
     replacement line) — by definition absent from the artifact today
   - **Symbol and path names** in backticks (`` `create_issue` ``, `` `create.py:406` ``) —
     references, not spans
   - When it is ambiguous whether a span is a quotation at all, **leave it alone** — a missed
     fabrication is tolerable; deleting a true quote is not.

   **For each remaining triggered span**, confirm it appears in the cited artifact using the
   **`Grep` tool** — not shell `grep`, which this skill has no `Bash(grep:*)` grant for. If the
   span is attributed to an issue ID rather than a path, resolve the path first with `ll-issues
   show <ID> --json`. Check the current working-tree file only.

   **On a miss**: drop the quote and describe the evidence in prose, or re-read the artifact and
   quote it correctly — never write the unverified span. Evidence that genuinely came from
   uncommitted or transient state (a working-tree edit, a loop run directory) must be labeled as
   such explicitly, rather than attributed to the file.

4. **Create the issue file atomically** (FEAT-2947 — this single call replaces the old next-id/sections/slugify/Write dance, and wires `parent:` both directions when `PARENT_ID` is set):

   ```bash
   ll-issues create --type "$ISSUE_TYPE" --title "$ISSUE_TITLE" \
     --priority "$PRIORITY" --variant "$TEMPLATE_STYLE" \
     --body-file - --json \
     ${PARENT_ID:+--parent "$PARENT_ID"} <<< "$ISSUE_SUMMARY"
   ```

   Parse the JSON result for `{"id": ..., "path": ...}`. Note `--stage` is deliberately **not** passed here: later steps still mutate the file (the `testable: false` edit of step 2, the session-log append of step 5), so staging happens once at step 6 after those edits.

**New sections in v2.0** (auto-included based on template variant):
- **Motivation**: Why this matters (replaces Current Pain Point for ENH)
- **Implementation Steps**: High-level outline for agent guidance
- **Root Cause** (BUG): File + function anchor + explanation
- **API/Interface** (FEAT/ENH): Public contract changes
- **Use Case** (FEAT): Concrete scenario (renamed from User Story)

See [templates.md](templates.md) for the complete issue file template structure.

5. **Append session log entry** to the newly created issue file. Use the Bash tool:

```bash
ll-issues append-log <path-to-issue-file> /ll:capture-issue
```

If `ll-issues` is not available, fall back to manually appending with **exactly** this format (backticks required):

```
- `/ll:capture-issue` - YYYY-MM-DDTHH:MM:SS - `<absolute path to session JSONL>`
```

Append it under the existing `## Session Log` heading if one exists; create the
heading only when none does, immediately above the `---` / `## Status` footer.
Never add a second `## Session Log` heading (BUG-3424).

   For FEAT or EPIC captures, append a decision entry to the log (silent no-op when the decisions log is absent; skip entirely for BUG type). The log is hybrid storage — a legacy `.ll/decisions.yaml` flat file and/or `.ll/decisions.d/*.json` fragments — so gate on either (a fresh, never-compacted install has only the fragment dir):

   ```bash
   if [ "$ISSUE_TYPE" != "BUG" ] && { [ -f .ll/decisions.yaml ] || [ -d .ll/decisions.d ]; }; then
       ll-issues decisions add \
         --type=decision \
         --category="architecture" \
         --issue="$ISSUE_ID" \
         --rule="Captured: $ISSUE_TITLE" \
         --rationale="$ISSUE_SUMMARY" \
         --scope=issue \
         2>/dev/null || true
   fi
   ```

6. **Stage the new file** (last, so every edit above is included in the staged content):

```bash
git add "{{config.issues.base_dir}}/[category]/[filename]"
```

   If `PARENT_ID` was set, also stage the parent EPIC — `ll-issues create --parent` appended its
   `## Children` bullet but, without `--stage`, left it unstaged:

```bash
git add "PARENT_EPIC_PATH"
```

### Phase 4b: Link Relevant Documents (if documents.enabled)

See [templates.md](templates.md) for the complete document linking process including:
- Loading configured documents from `.ll/ll-config.json`
- Extracting key concepts and scoring relevance
- Selecting top matches (max 3 documents)
- Updating the "Related Key Documentation" section with a table format

**Skip this phase if**:
- `documents.enabled` is not `true` in `.ll/ll-config.json`
- OR no documents are configured in `documents.categories`

### Phase 4c: Wire Parent EPIC (if `--parent` was given)

**Skip this phase for the Create New Issue action** — `ll-issues create --parent` (Phase 4,
step 4) already writes `parent:` on the child and appends its `## Children` bullet on the EPIC,
both staged together (FEAT-2947). This phase applies only when reopening/updating an existing
issue under `PARENT_ID` outside the `create` path.

**Skip this phase if `PARENT_ID` is empty.**

After the child issue file is created and staged, update the EPIC at `PARENT_EPIC_PATH`:

#### 1. Add child ID to `relates_to:` frontmatter

Read the EPIC file's frontmatter. The `relates_to:` field may be:
- absent — insert `relates_to: [CHILD_ID]` after the last frontmatter field
- an empty list `relates_to: []` — replace with `relates_to: [CHILD_ID]`
- a populated list — append the new ID to the list

Use `Edit` to apply the change in-place. Example:

```
# Before
relates_to: [ENH-100, ENH-101]

# After
relates_to: [ENH-100, ENH-101, CHILD_ID]
```

#### 2. Append child to `## Children` section

If the EPIC body already contains a `## Children` section, append a new bullet at the end of it:

```markdown
- **CHILD_ID** — [one-sentence child title from the child's Summary]
```

If no `## Children` section exists, insert one before `## Status` (or at end of file if no Status footer):

```markdown
## Children

- **CHILD_ID** — [one-sentence child title]
```

Use `Edit` to apply the change. Do not rewrite the whole file.

#### 3. Stage the EPIC file

```bash
git add "PARENT_EPIC_PATH"
```

#### Action: Update Existing Issue

Append an "Additional Context" section to the existing issue:

```bash
cat >> "[path-to-existing-issue]" << 'EOF'

---

## Additional Context

- **Date**: [YYYY-MM-DD]
- **Source**: capture-issue

[New context/findings from the description or conversation]

EOF
```

Stage the updated file:
```bash
git add "[path-to-existing-issue]"
```

#### Action: Reopen Completed Issue

Issue status lives in frontmatter — reopening means flipping `status: done`
back to `status: open`. The file stays where it is in its type directory.

1. **Update the file's frontmatter and append a Reopened section:**

   - Find the closed issue file (in its type dir with `status: done`).
   - Run `ll-issues set-status ISSUE_ID open` to flip the status atomically.
     If the issue has no `id:` field (legacy file), fall back to `Edit` to insert
     `status: open` into the YAML frontmatter block.
   - Append a Reopened section to the body:

   ```markdown
   ---

   ## Reopened

   - **Date**: [YYYY-MM-DD]
   - **By**: capture-issue
   - **Reason**: Issue recurred or was not fully resolved

   ### New Findings

   [Context from the new description or conversation that prompted reopening]
   ```

2. **Stage the changes:**
```bash
git add "[path-to-issue]"
```

### Phase 5: Output Report

See [templates.md](templates.md) for complete output report templates including:
- Single issue report format
- Multiple issues summary table
- Next steps recommendations

---

## Examples

```bash
# Capture issue from explicit description (bug)
/ll:capture-issue "The login button doesn't respond on mobile Safari"

# Capture issue from explicit description (feature)
/ll:capture-issue "We should add dark mode support to the settings page"

# Capture issue from explicit description (enhancement)
/ll:capture-issue "The API response time could be improved with caching"

# Analyze current conversation for issues to capture
/ll:capture-issue

# Capture with minimal template (quick mode)
/ll:capture-issue "Quick note: cache is slow" --quick

# Analyze conversation and use minimal templates
/ll:capture-issue --quick

# Capture a child issue and link it to an existing EPIC
/ll:capture-issue "Add retry logic to sprint runner" --parent EPIC-1663

# Child with minimal template
/ll:capture-issue "Fix log output truncation" --parent EPIC-1626 --quick
```

---

## Integration

After capturing issues:
1. **Review**: `cat [issue-path]` to verify content
2. **Validate**: `/ll:ready-issue [ID]` to check accuracy
3. **Prioritize**: `/ll:prioritize-issues` if priority needs adjustment
4. **Link**: `/ll:link-epics` to assign parentless issues to open epics
5. **Commit**: `/ll:commit` to save new issues
6. **Process**: `/ll:manage-issue [type] [action] [ID]` to implement

Attribution

BrennonTWilliamsBrennonTWilliams
View sourceSee grades on GitHubMore from BrennonTWilliams →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

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 (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698621 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →