Skip to main content

skill-cite

Verify citation claims against Literature/ index and Zotero library. Invoke for /cite command.

설치로 이동

소스 정보

저장소
benbrastmckie/nvim
최근 소스 활동
2026년 8월 24일 22:21
감지된 SKILL.md 언어
영어
스타
444
포크
459

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
skill-cite
description
Verify citation claims against Literature/ index and Zotero library. Invoke for /cite command.
allowed-tools
Bash, Read, Write, Edit, AskUserQuestion
# Cite Skill (Direct Execution) Direct execution skill for verifying citation claims in task artifacts against the Literature/ index and Zotero library. Extracts citations, searches for source matches, scores confidence, presents findings interactively, and creates tasks for unverified claims. **Key behavior**: Users always see citation findings BEFORE any tasks are created. Users select which unverified/gap claims to address via interactive prompts. ## Context References Reference (do not load eagerly): - Path: `@specs/state.json` - Machine state - Path: `@specs/TODO.md` - Current task list - Path: `@specs/literature/index.json` - Literature index for keyword matching --- ## Execution ### Step 1: Parse Arguments Extract task number, optional description text, and flags from command input: ```bash # Parse from command input args="$ARGUMENTS" # Extract task number (first numeric argument) task_num=$(echo "$args" | grep -oP '^\s*\K\d+' | head -1) # Check for --gaps flag (also show gap items separately) show_gaps=false if echo "$args" | grep -q -- '--gaps'; then show_gaps=true fi # Check for optional description text (everything after flags/number) description_override=$(echo "$args" | sed 's/--[a-z-]*//g' | sed "s/$task_num//" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//') ``` If no task number is provided and no direct file path is given, report and exit: ``` ## Error: No Task Specified Usage: /cite N [--gaps] N Task number to verify citations for --gaps Also flag citations found but with no PDF source Example: /cite 42 /cite 42 --gaps ``` ### Step 2: Generate Session ID Generate session ID for tracking: ```bash source .claude/scripts/lib/common.sh session_id="$(common_session_id)" ``` ### Step 3: Locate Task Artifacts Read state.json to find the task slug and locate artifacts: ```bash project_root="$(pwd)" state_file="$project_root/specs/state.json" # Find task slug from state.json task_slug=$(jq -r --argjson num "$task_num" \ '.active_projects[] | select(.project_number == $num) | .project_name' \ "$state_file") # Also check archive if [ -z "$task_slug" ] || [ "$task_slug" = "null" ]; then task_slug=$(jq -r --argjson num "$task_num" \ '.archive[]? | select(.project_number == $num) | .project_name' \ "$state_file" 2>/dev/null) fi # Construct task directory path (zero-padded 3 digits) task_dir=$(printf "specs/%03d_%s" "$task_num" "$task_slug") if [ ! -d "$project_root/$task_dir" ]; then echo "Error: Task directory not found: $task_dir" exit 1 fi # Glob all artifact files (reports, plans, summaries) artifact_files=() while IFS= read -r -d '' f; do artifact_files+=("$f") done < <(find "$project_root/$task_dir" -name "*.md" -print0 2>/dev/null) if [ ${#artifact_files[@]} -eq 0 ]; then echo "No artifact files found in $task_dir" echo "Nothing to verify." exit 0 fi ``` ### Step 4: Extract Citations For each artifact file, run `cite-extract.sh` and aggregate results: ```bash script_dir="$project_root/.claude/extensions/literature/scripts" all_citations=() # JSON objects as strings total_found=0 for artifact_file in "${artifact_files[@]}"; do rel_path="${artifact_file#$project_root/}" # Run cite-extract.sh on the file raw_output=$("$script_dir/cite-extract.sh" --format=json "$artifact_file" 2>/dev/null) || { exit_code=$? # exit code 2 = no citations found (normal), anything else = error if [ $exit_code -ne 2 ]; then echo "Warning: cite-extract.sh failed for $rel_path (exit $exit_code)" >&2 fi continue } # Add source_file field to each result and accumulate # cite-extract.sh output schema: [{claim, source_text, line_number, confidence, pattern_type}] enriched=$(echo "$raw_output" | jq --arg file "$rel_path" \ '[.[] | . + {source_file: $file}]' 2>/dev/null) || continue count=$(echo "$enriched" | jq 'length' 2>/dev/null || echo 0) total_found=$((total_found + count)) # Append to all_citations (collect as JSON array strings to merge later) all_citations+=("$enriched") done # Merge all citation arrays into one if [ ${#all_citations[@]} -eq 0 ]; then combined_citations="[]" else combined_citations=$(printf '%s\n' "${all_citations[@]}" | jq -s 'add // []') fi ``` ### Step 5: Handle No Citations Found If no citations were extracted: ``` ## No Citations Found **Task**: #{N} — {task_slug} **Artifacts Scanned**: {count} files in {task_dir} No citation patterns detected across task artifacts. Patterns searched: author_year, parenthetical, phrase_attribution, theorem_attr, direct_quote, numeric_bracket, alpha_num_bracket, latex_cite ``` Exit gracefully without prompts. ### Step 6: Search Literature/ Index For each unique citation claim, extract query terms and search `specs/literature/index.json`: ```bash if [ -n "${LITERATURE_DIR:-}" ] && [ -d "$LITERATURE_DIR" ]; then lit_index="$LITERATURE_DIR/index.json" else lit_index="$project_root/specs/literature/index.json" fi index_available=false if [ -f "$lit_index" ]; then index_available=true fi # For each citation, extract key terms from source_text and match against index # index.json entry schema: {id, title, keywords[], file, summary} # Match strategy: count how many query terms appear in (title + keywords joined) score_against_index() { local source_text="$1" local query_terms # Extract significant words (strip common stop words, lowercase, split) query_terms=$(echo "$source_text" | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9 ]/ /g' \ | tr ' ' '\n' \ | grep -vE '^(a|an|the|in|on|at|of|to|for|and|or|by|as|is|are|was|were|be|that|this|from|with|it|its|et|al|pp|vol|no|doi)$' \ | grep -v '^[0-9]\{1,4\}$' \ | sort -u | tr '\n' ' ') if [ -z "$query_terms" ] || [ "$index_available" = "false" ]; then echo "0" return fi # Count term overlaps in title + keywords fields jq -r --arg terms "$query_terms" ' .entries // [] | map( (.title + " " + ((.keywords // []) | join(" "))) | ascii_downcase | . as $haystack | ($terms | split(" ") | map(select(length > 2)) | map(if (($haystack | test(.; "i")) // false) then 1 else 0 end) | add // 0) ) | max // 0 ' "$lit_index" 2>/dev/null || echo "0" } ``` ### Step 7: Search Zotero For each unique citation claim, search via `zotero-search.sh`: ```bash # Check if Zotero is configured (zotero-search.sh exits 1 if library not found) zotero_available=false if "$script_dir/zotero-search.sh" --limit=1 --format=json "test" &>/dev/null; then zotero_available=true elif [ $? -eq 2 ]; then # exit 2 = no results (library exists, query returned nothing) zotero_available=true fi search_zotero() { local source_text="$1" if [ "$zotero_available" = "false" ]; then echo "[]" return fi # zotero-search.sh accepts query terms as positional args # Output schema: [{citation_key, title, authors, year, score, pdf_paths, abstract_snippet}] local query_words query_words=$(echo "$source_text" | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9 ]/ /g' \ | tr ' ' '\n' \ | grep -vE '^(a|an|the|in|on|at|of|to|for|and|or|by|as|is|et|al|pp)$' \ | grep -v '^[0-9]\{1,4\}$' \ | sort -u | head -8 | tr '\n' ' ') if [ -z "$query_words" ]; then echo "[]" return fi # shellcheck disable=SC2086 "$script_dir/zotero-search.sh" --limit=5 --format=json $query_words 2>/dev/null \ || echo "[]" } ``` ### Step 8: Score Confidence Apply scoring to each extracted citation and classify it: **Scoring thresholds** (based on search results): - **confirmed**: Zotero top result score >= 3 OR index keyword overlap >= 2 - **partial**: Zotero top result score 1–2 OR index keyword overlap == 1 - **unconfirmed**: No match in either Zotero or Literature/ index - **gap**: Citation pattern found but source text suggests a specific work that exists in index/Zotero yet has no associated PDF ```bash score_citation() { local source_text="$1" local pattern_type="$2" local extract_confidence="$3" # from cite-extract.sh (0.5–0.9) # Get index overlap score local index_overlap index_overlap=$(score_against_index "$source_text") # Get Zotero results local zotero_results zotero_top_score zotero_results=$(search_zotero "$source_text") zotero_top_score=$(echo "$zotero_results" | jq '.[0].score // 0' 2>/dev/null || echo 0) # Classify local status best_match if [ "$zotero_top_score" -ge 3 ] 2>/dev/null || [ "$index_overlap" -ge 2 ] 2>/dev/null; then status="confirmed" best_match=$(echo "$zotero_results" | jq -r '.[0] | "\(.authors[0] // "Unknown") (\(.year // "n.d.")). \(.title)"' 2>/dev/null \ || echo "Literature index match (overlap: $index_overlap)") elif [ "$zotero_top_score" -ge 1 ] 2>/dev/null || [ "$index_overlap" -ge 1 ] 2>/dev/null; then status="partial" best_match=$(echo "$zotero_results" | jq -r '.[0] | "\(.authors[0] // "Unknown") (\(.year // "n.d.")). \(.title)"' 2>/dev/null \ || echo "Weak literature index match (overlap: $index_overlap)") else status="unconfirmed" best_match="No match found" fi # Check for gap: pattern found but PDF unavailable if [ "$status" != "unconfirmed" ] && [ "$show_gaps" = "true" ]; then local pdf_count pdf_count=$(echo "$zotero_results" | jq '.[0].pdf_paths // [] | length' 2>/dev/null || echo 0) if [ "$pdf_count" -eq 0 ] && [ "$zotero_top_score" -ge 1 ] 2>/dev/null; then status="gap" fi fi
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기