AIBites: AI Skills

skill library, anatomy of a skill, composing tools

1.0 - Introduction

AI Skills pdf
YouTube video
A skill is a reusable, named tool definition - a packaged set of domain-specific instructions, reference documentation, and scripts that extends an AI's capabilities by teaching it specialized workflows and best practices for specific tasks, like expert knowledge modules that load on-demand when relevant to a query. The Anthropic platform includes a skill system that stores prompt and resource information in a sandboxed directory. OpenAI and Gemini do not provide those services directly. You can simulate AI Skills for those platforms by creating an agent that reads prompt and reference information stored in a local directory and injects it into a connected LLM via the platform's messaging API. Building a skill library means you write a tool once and reuse it across many agents and sessions. A library of composable skills lets you assemble new agents quickly from existing parts.
Why build a skill library?
  1. Copy-pasting tool definitions into every script creates maintenance debt. A shared library means a fix reaches every agent at once.
  2. Named, well-described skills are self-documenting - the model reads the description and knows what the tool does without explanation in the prompt.
  3. A library of composable skills lets you assemble new agents quickly from existing parts.

2.0 - Skill File Structure

Fig 1. Claude Sandbox File System
Claude.ai maintains a local sandboxed file system shown in Fig 1. The user-data folder holds user files uploaded by pasting into chat prompts or sent as message payloads by agents or Claude Code. It also holds output files generated by Claude, returned as a message payload from a remote LLM. A sibling directory is reserved for skills: The skills/public directory is populated by Anthropic and updated with platform releases. It includes general-purpose skills for document editing, spreadsheet analysis, and product self-knowledge that are available to all users automatically. The skills/examples directory contains demonstration skills that show how to structure Skill.md files, reference catalogs, and helper scripts. These are a good starting point for understanding skill anatomy before writing your own. The skills/user directory is where developer-defined skills live. A skill placed here is automatically considered by claude.ai when a user prompt matches its purpose - no explicit invocation needed. Skills in this directory persist across all chat sessions and accumulate as domain knowledge grows.
Fig 2. Claude Skill Structure
A skill file, e.g., implementation_smells.skill, is a zip file with a "skill" extension. Its structure is shown in Fig 2. The Skills.md file embedded in the .skill zip acts like a prompt to the LLM that governs the activities and results of applying this skill. This "prompt" is a permanent, reusable module. The skills prompt is automatically passed to the LLM if the user prompt has words that match its purpose. All of the skill's resources persist across all chats. scripts/helper.py in Fig 2 acts as an agent if it uses the Anthropic API to send messages to the LLM. Scripts that do not use the message API are like helper functions for the LLM. references/api_docs.md provides domain-specific information. assets/template.pptx provides formatting for responses. This is a powerful mechanism. It allows a developer or organization to build in domain knowledge for chats and console operations - a continuing process that progressively enhances AI functionality for a specific domain.

3.0 - Anatomy of a Skill

Each skill is a Python function paired with a tool definition dict. The function is the implementation; the dict is the contract the model reads to decide when and how to call it.
def skill_code_metrics(path: str) -> dict:
    """Count lines, functions, and blank lines in a Python source file.
    Returns {"lines": int, "functions": int, "blanks": int}.
    """
    import ast, pathlib
    src = pathlib.Path(path).read_text()
    tree = ast.parse(src)
    functions = sum(1 for n in ast.walk(tree) if isinstance(n, ast.FunctionDef))
    lines = src.count("\n")
    blanks = sum(1 for ln in src.splitlines() if not ln.strip())
    return {"lines": lines, "functions": functions, "blanks": blanks}

SKILL_CODE_METRICS = {
    "name": "code_metrics",
    "description": skill_code_metrics.__doc__,
    "input_schema": {
        "type": "object",
        "properties": {"path": {"type": "string"}},
        "required": ["path"]
    }
}

4.0 - Composing Skills

Pass a list of skill definitions to a single agent call. The model chooses which tools to invoke and in what order. Keep each skill focused on one action - composition happens at the agent level, not inside a skill.
all_skills = [SKILL_READ_FILE, SKILL_CODE_METRICS, SKILL_LIST_DIR]

resp = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=2048,
    tools=all_skills,
    messages=[{
        "role": "user",
        "content": "Report metrics for every .py file in src/."
    }]
)

5.0 - Example: Code Smells Skill

The following is an example of a useful skill uploaded to a /mnt/skills/user sandbox folder. It was built using claude.ai with the prompt:
"can you create a skill for detecting implementation smells"
Here are the results extracted from implementation_smells.skill:
Skill.md contains a sequence of prompts that define the analysis activities and flow. It looks like documentation for the skill, but in fact is the heart of the skill.
Skill.md

Implementation Smells Detection

Systematically identify code quality issues, anti-patterns, and implementation smells across multiple programming languages to improve maintainability, readability, and robustness.

Detection Workflow

Follow this process when analyzing code for implementation smells:

1. Determine Analysis Scope

For single files/snippets:

  • Analyze the provided code directly
  • Focus on localized smells (naming, nesting, function length)

For multi-file codebases:

  • Ask user if they want automated scanning or manual review
  • For automated: Use scripts/smell_detector.py on individual files
  • For manual: Review files systematically, consulting reference catalog

For specific languages:

  • Consult language-specific sections in references/smell-catalog.md
  • Apply both universal and language-specific smell patterns

2. Load Reference Documentation

Read references/smell-catalog.md to access the comprehensive smell catalog when needed:

  • For general review: Scan all categories
  • For focused analysis: Jump to relevant category (e.g., Error Handling, Performance)
  • For language-specific: Review language-specific sections

3. Systematic Analysis

Analyze code in this order for comprehensive coverage:

a) Code Organization (5 minutes)

  • Long methods/functions (>50-100 lines)
  • God classes (>500 lines, excessive responsibilities)
  • Feature envy (methods using other classes more than own)
  • Primitive obsession (primitives instead of domain objects)

b) Naming and Documentation (3 minutes)

  • Unclear variable/function names (x, temp, data)
  • Inconsistent naming conventions
  • Missing documentation on public APIs
  • Dead code (unused functions, commented blocks)

c) Control Flow (5 minutes)

  • Deep nesting (>3-4 levels)
  • Complex conditionals (>3 boolean operators)
  • Duplicated code blocks
  • Magic numbers/strings

d) Error Handling (3 minutes)

  • Silent failures (empty catch blocks)
  • Exception swallowing
  • Unchecked return codes

e) Language-Specific (3 minutes)

  • C++: Raw pointers, manual memory, missing virtual destructors
  • Python: Mutable defaults, bare except, no context managers
  • Rust: Excessive .clone(), unwrap proliferation
  • C#: Missing IDisposable, async overuse

4. Report Generation

Structure findings clearly:

=== Implementation Smells Analysis ===

  HIGH SEVERITY (requires immediate attention):
  - [Smell Type] at Line X: [Description]
    โ†’ Impact: [Why it matters]
    ๐Ÿ’ก Suggestion: [How to fix]

  MEDIUM SEVERITY (should address soon):
  - [Similar format]

  LOW SEVERITY (nice to have):
  - [Similar format]

  === Summary ===
  Total: X smell(s) detected
  Prioritized recommendations: [Top 3 fixes]

5. Provide Actionable Recommendations

For each detected smell:

  • Explain WHY it's problematic (not just WHAT)
  • Show concrete refactoring example when helpful
  • Prioritize fixes by impact and effort
  • Suggest tools (linters, static analyzers) for ongoing detection

Automated Detection

Use the provided script for quick automated scanning:

python scripts/smell_detector.py <source_file> [language]

The script detects:

  • Long functions (>50 lines)
  • Deep nesting (>4 levels)
  • Magic numbers (hardcoded literals)
  • Unclear naming (generic names like temp, data)
Limitations: Automated detection catches obvious smells but misses context-dependent issues. Always combine with manual review for comprehensive analysis.

Common Analysis Requests

"Review this code for quality issues"

  1. Read references/smell-catalog.md for smell categories
  2. Systematically check each category
  3. Provide structured report with severity levels

"Find refactoring opportunities"

  1. Focus on Code Organization and Control Flow sections
  2. Identify extraction opportunities (long methods, duplicated code)
  3. Suggest specific refactorings with before/after examples

"What's wrong with this code?"

  1. Quick scan for high-severity smells first
  2. Explain impact of each issue found
  3. Provide concrete improvement suggestions

"Make this more maintainable"

  1. Detect smells hurting maintainability (naming, documentation, complexity)
  2. Prioritize changes by ROI (impact vs effort)
  3. Show step-by-step refactoring path

Language-Specific Guidance

When analyzing language-specific code:

C++ Code:

  • Check for RAII violations, raw pointer ownership
  • Look for missing const-correctness
  • Verify virtual destructors in base classes
  • Review for modern C++ idioms (smart pointers, auto, range-based loops)

Python Code:

  • Check for mutable default arguments
  • Verify proper use of context managers
  • Look for bare except clauses
  • Review for PEP 8 compliance

Rust Code:

  • Identify excessive .clone() calls (often indicates design issues)
  • Check for unwrap()/expect() in production code
  • Review lifetime annotations for over-specification
  • Verify idiomatic error handling with Result<T>

C# Code:

  • Check IDisposable implementation for resources
  • Review async/await patterns for appropriateness
  • Verify proper disposal patterns
  • Check for exceptions used in control flow

Best Practices

When analyzing:

  • Start broad (automated scan), then deep-dive manually
  • Consider context (teaching code vs production code has different standards)
  • Balance perfectionism with pragmatism (not every smell needs fixing)
  • Prioritize smells that impact actual problems (bugs, performance, security)

When reporting:

  • Group related smells (don't list every magic number separately)
  • Show impact, not just detection ("This causes X problem" not "This violates Y rule")
  • Provide actionable fixes, not just criticism
  • Celebrate good patterns found alongside smells

When recommending:

  • Suggest incremental improvements (not "rewrite everything")
  • Link smells to actual pain points (maintenance costs, bugs)
  • Consider team expertise level in recommendations
  • Recommend preventive tools (linters, IDE plugins, pre-commit hooks)
The smell-detector.py script consists of a set of methods that automate scanning of the domain files. The developer may use it directly, or the LLM may run a quick scan before embarking on a deeper analysis.
scripts/smell-detector.py Figure 1. smell-detector.py
  1 #!/usr/bin/env python3
    2 """
    3 Automated implementation smell detector.
    4 Analyzes source code files for common code smells.
    5 """
    6
    7 import re
    8 import sys
    9 from pathlib import Path
    10 from typing import List, Dict, Tuple
    11 from dataclasses import dataclass
    12
    13
    14 @dataclass
    15 class SmellReport:
    16     """Represents a detected code smell."""
    17     smell_type: str
    18     severity: str  # 'high', 'medium', 'low'
    19     line_number: int
    20     description: str
    21     suggestion: str
    22
    23
    24 class SmellDetector:
    25     """Detects implementation smells in source code."""
    26
    27     def __init__(self, language: str):
    28         self.language = language.lower()
    29         self.reports: List[SmellReport] = []
    30
    31     def detect_long_function(self, lines: List[str], threshold: int = 50) -> List[SmellReport]:
    32         """Detect functions exceeding line count threshold."""
    33         smells = []
    34
    35         # Language-specific function patterns
    36         patterns = {
    37             'python': r'^\s*def\s+(\w+)',
    38             'c++': r'^\s*\w+[\s\*&]+(\w+)\s*\([^)]*\)\s*{?',
    39             'rust': r'^\s*fn\s+(\w+)',
    40             'c#': r'^\s*\w+\s+(\w+)\s*\([^)]*\)\s*{',
    41         }
    42
    43         pattern = patterns.get(self.language)
    44         if not pattern:
    45             return smells
    46
    47         in_function = False
    48         func_start = 0
    49         func_name = ""
    50
    51         for i, line in enumerate(lines, 1):
    52             match = re.search(pattern, line)
    53             if match:
    54                 # If we were in a function, check its length
    55                 if in_function and (i - func_start) > threshold:
    56                     smells.append(SmellReport(
    57                         smell_type="Long Function",
    58                         severity="high",
    59                         line_number=func_start,
    60                         description=f"Function '{func_name}' is {i - func_start} lines long",
    61                         suggestion=f"Consider breaking down '{func_name}' into smaller, focused functions"
    62                     ))
    63
    64                 in_function = True
    65                 func_start = i
    66                 func_name = match.group(1)
    67
    68         return smells
    69
    70     def detect_deep_nesting(self, lines: List[str], max_depth: int = 4) -> List[SmellReport]:
    71         """Detect deeply nested control structures."""
    72         smells = []
    73
    74         for i, line in enumerate(lines, 1):
    75             # Count leading whitespace
    76             stripped = line.lstrip()
    77             if not stripped or stripped.startswith('#') or stripped.startswith('//'):
    78                 continue
    79
    80             indent = len(line) - len(stripped)
    81
    82             # Assume 4 spaces per level (adjust based on detected style)
    83             depth = indent // 4
    84
    85             if depth > max_depth:
    86                 smells.append(SmellReport(
    87                     smell_type="Deep Nesting",
    88                     severity="medium",
    89                     line_number=i,
    90                     description=f"Nesting level {depth} exceeds recommended maximum",
    91                     suggestion="Consider extracting nested logic into separate functions or use early returns"
    92                 ))
    93
    94         return smells
    95
    96     def detect_magic_numbers(self, lines: List[str]) -> List[SmellReport]:
    97         """Detect hardcoded numeric literals (excluding 0, 1, -1)."""
    98         smells = []
    99
    100         # Numbers to ignore (common constants)
    101         ignore = {0, 1, -1, 2}
    102
    103         for i, line in enumerate(lines, 1):
    104             # Skip comments and strings
    105             if re.search(r'^\s*[#//]', line) or '"' in line or "'" in line:
    106                 continue
    107
    108             # Find numeric literals
    109             numbers = re.findall(r'\b(\d+\.?\d*)\b', line)
    110             for num_str in numbers:
    111                 try:
    112                     num = float(num_str)
    113                     if num not in ignore and num > 1:
    114                         smells.append(SmellReport(
    115                             smell_type="Magic Number",
    116                             severity="low",
    117                             line_number=i,
    118                             description=f"Magic number '{num_str}' used without named constant",
    119                             suggestion=f"Consider extracting '{num_str}' to a named constant"
    120                         ))
    121                 except ValueError:
    122                     pass
    123
    124         return smells
    125
    126     def detect_unclear_naming(self, lines: List[str]) -> List[SmellReport]:
    127         """Detect unclear variable/function names."""
    128         smells = []
    129
    130         # Problematic name patterns
    131         unclear_patterns = [
    132             r'\b(x|y|z|i|j|k)\s*=',  # Single letter vars (except in loops)
    133             r'\b(temp|tmp|data|info|val|var)\d*\s*=',
    134             r'\b(foo|bar|baz)\s*=',
    135         ]
    136
    137         for i, line in enumerate(lines, 1):
    138             # Skip for loops (i, j, k are acceptable)
    139             if 'for' in line and any(x in line for x in ['i', 'j', 'k']):
    140                 continue
    141
    142             for pattern in unclear_patterns:
    143                 if re.search(pattern, line):
    144                     smells.append(SmellReport(
    145                         smell_type="Unclear Naming",
    146                         severity="medium",
    147                         line_number=i,
    148                         description="Variable has unclear or generic name",
    149                         suggestion="Use descriptive names that reveal intent"
    150                     ))
    151                     break
    152
    153         return smells
    154
    155     def detect_all(self, code: str) -> List[SmellReport]:
    156         """Run all smell detectors on the code."""
    157         lines = code.split('\n')
    158
    159         all_smells = []
    160         all_smells.extend(self.detect_long_function(lines))
    161         all_smells.extend(self.detect_deep_nesting(lines))
    162         all_smells.extend(self.detect_magic_numbers(lines))
    163         all_smells.extend(self.detect_unclear_naming(lines))
    164
    165         # Sort by line number
    166         all_smells.sort(key=lambda s: s.line_number)
    167
    168         return all_smells
    169
    170
    171 def analyze_file(filepath: Path, language: str = None) -> List[SmellReport]:
    172     """Analyze a source file for implementation smells."""
    173
    174     # Auto-detect language from extension if not provided
    175     if not language:
    176         ext_to_lang = {
    177             '.py': 'python',
    178             '.cpp': 'c++',
    179             '.cc': 'c++',
    180             '.cxx': 'c++',
    181             '.rs': 'rust',
    182             '.cs': 'c#',
    183         }
    184         language = ext_to_lang.get(filepath.suffix.lower(), 'unknown')
    185
    186     with open(filepath, 'r', encoding='utf-8') as f:
    187         code = f.read()
    188
    189     detector = SmellDetector(language)
    190     return detector.detect_all(code)
    191
    192
    193 def format_report(smells: List[SmellReport], filepath: Path) -> str:
    194     """Format smell reports for display."""
    195     if not smells:
    196         return f"โˆš No implementation smells detected in {filepath.name}"
    197
    198     output = [f"\n=== Implementation Smells in {filepath.name} ===\n"]
    199
    200     # Group by severity
    201     by_severity = {'high': [], 'medium': [], 'low': []}
    202     for smell in smells:
    203         by_severity[smell.severity].append(smell)
    204
    205     for severity in ['high', 'medium', 'low']:
    206         items = by_severity[severity]
    207         if not items:
    208             continue
    209
    210         output.append(f"\n{severity.upper()} SEVERITY ({len(items)} found):")
    211         for smell in items:
    212             output.append(f"\n  Line {smell.line_number}: {smell.smell_type}")
    213             output.append(f"  โฆ {smell.description}")
    214             output.append(f"  ?? {smell.suggestion}")

    215     output.append(f"\n\nTotal: {len(smells)} smell(s) detected")
    216     return '\n'.join(output)
    217
    218
    219 if __name__ == '__main__':
    220     if len(sys.argv) < 2:
    221         print("Usage: python smell_detector.py <source_file> [language]")
    222         sys.exit(1)
    223
    224     filepath = Path(sys.argv[1])
    225     language = sys.argv[2] if len(sys.argv) > 2 else None
    226
    227     if not filepath.exists():
    228         print(f"Error: File '{filepath}' not found")
    229         sys.exit(1)
    230
    231     smells = analyze_file(filepath, language)
    232     print(format_report(smells, filepath))
          
smell-catalog.md, like Skill.md, is essentially a multi-part prompt uploaded once and used across all chats whenever user prompts indicate an analysis of code quality. The content of the "references" dropdown is a list of prompts that define each code smell this skill can identify. A developer may add more definitions as the domain evolves.
references/smell-catalog.md

Implementation Smells Reference

This document catalogs common implementation smells across multiple programming languages, organized by category.

Code Organization Smells

Long Method

  • Symptom: Functions/methods exceeding 50-100 lines
  • Impact: Difficult to understand, test, and maintain
  • Detection: Count lines of code per function
  • Languages: All

God Class/Object

  • Symptom: Classes with excessive responsibilities (>500 lines, >10 methods)
  • Impact: High coupling, low cohesion, difficult to modify
  • Detection: Class size, method count, dependency count
  • Languages: OOP languages (C++, C#, Java, Python, Rust)

Feature Envy

  • Symptom: Method uses more features of another class than its own
  • Impact: Poor encapsulation, misplaced responsibility
  • Detection: Count external vs internal member access
  • Languages: OOP languages

Primitive Obsession

  • Symptom: Using primitives instead of small objects for domain concepts (e.g., string for phone number)
  • Impact: Scattered validation logic, unclear semantics
  • Detection: Frequent primitive parameters, validation spread across code
  • Languages: All

Naming and Documentation Smells

Unclear Naming

  • Symptom: Variables like x, temp, data, info, single letters (except loop counters)
  • Impact: Difficult to understand purpose
  • Detection: Short names, generic terms, abbreviations without context
  • Languages: All

Inconsistent Naming

  • Symptom: Mixed conventions (camelCase + snake_case, inconsistent prefixes)
  • Impact: Confusion, harder navigation
  • Detection: Pattern analysis across identifiers
  • Languages: All

Missing Documentation

  • Symptom: Public APIs, complex algorithms without comments/docstrings
  • Impact: Maintenance difficulty, incorrect usage
  • Detection: Check for doc comments on public interfaces
  • Languages: All (especially API-heavy code)

Dead Code

  • Symptom: Unused functions, variables, imports, commented-out blocks
  • Impact: Cluttered codebase, maintenance burden
  • Detection: Static analysis for unreachable/unused code
  • Languages: All

Control Flow Smells

Deep Nesting

  • Symptom: >3-4 levels of indentation (nested ifs, loops)
  • Impact: Cognitive overload, hard to follow logic
  • Detection: Maximum nesting depth
  • Languages: All

Complex Conditionals

  • Symptom: Boolean expressions with >3 conditions, nested ternaries
  • Impact: Error-prone, hard to test
  • Detection: Count operators in conditionals
  • Languages: All

Duplicated Code

  • Symptom: Identical or very similar code blocks in multiple places
  • Impact: Maintenance burden, inconsistent changes
  • Detection: Clone detection algorithms
  • Languages: All

Magic Numbers/Strings

  • Symptom: Hardcoded literals without named constants
  • Impact: Unclear meaning, difficult to update
  • Detection: Literal values not in constant declarations
  • Languages: All

Error Handling Smells

Silent Failures

  • Symptom: Empty catch blocks, ignored return codes
  • Impact: Hidden bugs, difficult debugging
  • Detection: Empty exception handlers, unchecked results
  • Languages: C++, C#, Python, Rust (via Result<T>)

Exception Swallowing

  • Symptom: Catching general exceptions without re-throw or logging
  • Impact: Masked errors, debugging difficulty
  • Detection: Catch-all handlers without action
  • Languages: Exception-based languages

Error Code Soup

  • Symptom: Functions returning multiple error codes, deeply nested error checks
  • Impact: Complex control flow, missed error cases
  • Detection: Multiple return paths for errors, >3 error checks per function
  • Languages: C, C++ (pre-C++17)

Performance and Resource Smells

Premature Optimization

  • Symptom: Complex micro-optimizations without profiling data
  • Impact: Reduced readability for negligible gains
  • Detection: Unusual patterns, complex bit manipulations without justification
  • Languages: All

Resource Leaks

  • Symptom: Missing cleanup, no RAII/using/with patterns
  • Impact: Memory leaks, file handle exhaustion
  • Detection: Missing destructors, no scope guards, manual memory management
  • Languages: C++ (raw pointers), C, Python (file handles)

Inefficient Algorithms

  • Symptom: O(nยฒ) when O(n log n) possible, repeated computation
  • Impact: Poor scalability
  • Detection: Nested loops over same data, repeated expensive calls
  • Languages: All

Language-Specific Smells

C++

  • Raw Pointer Ownership: Use of new/delete instead of smart pointers
  • Non-const References: Output parameters via non-const ref instead of return values
  • Manual Memory Management: Lack of RAII idiom
  • Missing Virtual Destructors: Base classes without virtual destructors

Python

  • Mutable Default Arguments: Using lists/dicts as default parameters
  • Bare Except: except: without exception type
  • Global State: Excessive use of global variables
  • Not Using Context Managers: Manual file handling instead of with

Rust

  • Excessive Cloning: .clone() everywhere to satisfy borrow checker
  • Unwrap Proliferation: .unwrap() instead of proper error handling
  • String Confusion: Mixing String/&str/OsString without clarity
  • Manual Lifetime Annotations: Over-specifying lifetimes

C#

  • IDisposable Not Implemented: Resources without proper disposal
  • Async Over Sync: Using async for non-I/O operations
  • Finalize Without Dispose: Finalizers without IDisposable pattern
  • Exception for Control Flow: Using exceptions for normal program flow

Anti-Patterns

Shotgun Surgery

  • Symptom: Single change requires modifications across many files
  • Impact: High coupling, error-prone changes
  • Detection: Change impact analysis
  • Languages: All

Inappropriate Intimacy

  • Symptom: Classes accessing each other's internals excessively
  • Impact: Tight coupling, fragile code
  • Detection: Friend classes, protected member usage, excessive getters/setters
  • Languages: OOP languages

Refused Bequest

  • Symptom: Subclass doesn't use inherited methods
  • Impact: Broken Liskov Substitution Principle
  • Detection: Overridden methods that throw exceptions or do nothing
  • Languages: OOP languages
Skills have slightly different setup for the claude.ai chatbot and the Claude Code CLI:
  • claude.ai chatbot
    Setup: click on profile → Settings → Capabilities → Skills → Add → Upload a skill
  • claude code CLI
    Setup: create a folder C:\Users\[user name]\.claude\skills\[skill_folder_name]\
    then extract the .skill zip file into that folder.
Run Analysis in Claude Code
Figure 2. Implementation-smells Output
  1
    2     ?
    3     |
    4    ?โ–ˆ?     Claude Code v2.1.45
    5  โ–?โ–ˆโ–ˆโ–ˆ?โ–Œ   Sonnet 4.6 ยท Claude Pro
    6 ??โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ??  C:\github\Jimfawcett\NewSite\code\AI
    7   ?? ??
    8
    9 ? analyze code smells for /DemoAgent-Claude2/Test/RustDirNav
   10
   11 ? Skill(implementation-smells)
   12   ?  Successfully loaded skill
   13
   14 ? Searched for 1 pattern, read 3 files (ctrl+o to expand)
   15
   16 ? Now let me run the automated detector on both source files in parallel.
   17
   18 ? 2 Bash agents finished (ctrl+o to expand)
   19    โ”œโ”€ Run smell detector on lib.rs ยท 1 tool use ยท 5.6k tokens
   20    โ”‚  ?  Done
   21    โ””โ”€ Run smell detector on test1.rs ยท 1 tool use ยท 5.6k tokens
   22       ?  Done
   23
   24 ? Now I have everything needed for a thorough manual + automated analysis.
   25
   26   ---
   27   Implementation Smells Analysis - RustDirNav
   28
   29   Files analyzed: src/lib.rs (259 lines), examples/test1.rs (77 lines)
   30
   31   ---
   32   HIGH SEVERITY
   33
   34   1. Bitwise OR instead of logical OR - lib.rs:136
   35   if self.in_patterns(&entry) | self.pats.is_empty()
   36   Uses | (bitwise/non-short-circuit) instead of || (logical, short-circuit). For bool both produce the
   37   same result, but | always evaluates both sides - pats.is_empty() is called even when in_patterns is
   38   already true. This is a readability and correctness risk: future maintainers may read | as intentional
   39   non-short-circuit and be confused, or a side-effecting predicate added later would behave unexpectedly.
   40
   41   Fix: if self.in_patterns(&entry) || self.pats.is_empty()
   42
   43   ---
   44   MEDIUM SEVERITY
   45
   46   2. Redundant where clauses - lib.rs:65-67, lib.rs:118-119
   47
   48   The impl<App: DirEvent + Default> block already declares the bounds. Both new() and visit() repeat them
   49    redundantly:
   50   pub fn new() -> Self where App: DirEvent + Default { ... }  // redundant
   51   pub fn visit(&mut self, dir: &Path) -> io::Result<()> where App: DirEvent { ... }  // redundant
   52   Fix: Remove the where clauses on both methods.
   53
   54   3. #[allow(dead_code)] / #[allow(unused_imports)] suppressing warnings - lib.rs:18,47
   55
   56   #[allow(unused_imports)] on use std::path::{Path, PathBuf} and #[allow(dead_code)] on DirNav hide real
   57   signals. PathBuf is used internally but the allow attribute suggests it was added hastily. Suppressing
   58   instead of resolving makes it easy to miss genuine dead code added later.
   59
   60   Fix: Remove the allow attributes; verify each import/field is needed, remove what isn't.
   61
   62   4. Test ordering dependency - lib.rs:182-183
   63   // test_setup() should run first. To ensure that:
   64   //   use cargo -- --test-threads=1
   65   Tests requiring a specific execution order and single-threaded mode is a brittle design. test_walk
   66   silently passes if test_setup hasn't run (it may find pre-existing files from a prior run), and fails
   67   on a clean checkout with no indication why.
   68
   69   Fix: Make test_walk call setup logic directly, or use a #[test] fixture pattern (std::sync::Once +
   70   OnceLock) to guarantee initialization before dependent tests.
   71
   72   5. num_file counts ALL files, not just matching ones - lib.rs:135
   73   self.num_file += 1;               // incremented for every file
   74   if self.in_patterns(&entry) | ... {
   75       files.push(entry.file_name()); // only matching files added
   76   }
   77   get_files() returns a count that includes non-matching files, while the user typically expects "files
   78   found/matched." The field name and doc comment say "number of files processed" - ambiguous, and callers
   79    comparing get_files() to app results will be confused.
   80
   81   Fix: Either rename to num_files_seen and add a separate num_files_matched, or increment only when the
   82   file matches a pattern.
   83
   84   6. _-prefixed variables that are actively used - test1.rs:33,34
   85   let _pat1: String = "rs".to_string();
   86   let _pat4: String = "rlib".to_string();
   87   // ...
   88   dn.add_pat(&_pat1);   // _pat1 IS used
   89   dn.add_pat(_pat4);    // _pat4 IS used
   90   The _ prefix idiomatically signals "intentionally unused." These variables are clearly used. This
   91   misleads readers and masks future real unused-variable warnings.
   92
   93   Fix: Rename to pat1, pat4.
   94
   95   ---
   96   LOW SEVERITY
   97
   98   7. Explicit return Ok(()) in non-tail position - lib.rs:157
   99
  100           return Ok(());  // normal return
  101       }
  102       Err(Error::new(...))
  103   Idiomatic Rust uses Ok(()) as the implicit expression of the last statement in an if branch rather than
  104    an explicit return. Minor style issue but inconsistent with Rust conventions.
  105
  106   8. Double string conversion - lib.rs:123, lib.rs:146
  107   self.replace_sep(dir).to_string_lossy().to_string()
  108   replace_sep already returns an OsString, calling .to_string_lossy() yields a Cow<str>, then
  109   .to_string() allocates again. This is a minor allocation smell on a hot path (called per directory).
  110
  111   9. /// doc-comment syntax used for regular comments - test1.rs:67-71
  112   ///////////////////////////////////////////////
  113   // uncomment lines below to see error return
  114   The leading /// line is a doc comment. While it doesn't cause a bug here, doc comment syntax should be
  115   reserved for API documentation, not inline banners/notes.
  116
  117   10. Manual Default impl for unit struct - test1.rs:21-25
  118   impl Default for Appl {
  119       fn default() -> Self { Appl }
  120   }
  121   Appl is a unit struct; #[derive(Default)] would express the same intent with less code.
  122
  123   ---
  124   Automated Detector Notes
  125
  126   The script flagged a false positive: do_file appearing as "168 lines long" - this is a measurement
  127   error (the tool measured from the trait definition line to end of file rather than the method body,
  128   which is 2 lines). The deep-nesting flags at lines 132-154 are real but borderline; the 4-level nesting
  129    in visit is typical for filesystem traversal code.
  130
  131   ---
  132   Summary
  133
  134   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  135   โ”‚ Severity โ”‚ Count โ”‚                      Top Priority                      โ”‚
  136   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
  137   โ”‚ High     โ”‚ 1     โ”‚ Bitwise | instead of || (line 136)                     โ”‚
  138   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
  139   โ”‚ Medium   โ”‚ 5     โ”‚ Test ordering, file count semantics, _ variable naming โ”‚
  140   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
  141   โ”‚ Low      โ”‚ 4     โ”‚ Style and minor allocation issues                      โ”‚
  142   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  143
  144   Top 3 fixes by impact:
  145   1. Line 136 - Change | to || (correctness risk)
  146   2. num_file semantics - Clarify what the counter actually counts
  147   3. Test ordering - Eliminate the --test-threads=1 requirement
  148
  149 ? Ran for 2m 29s
  150
  151 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  152 ? fix the bitwise OR smell on line 136
  153 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  154   ? for shortcuts
            
Note that agents are local applications that can't use the sandboxed skill files held by Claude.ai in its browser local storage. Agents could be configured to use the same local skill files that Claude Code uses, but there is little added benefit since Claude Code with skills is easy to use directly.

6.0 - References

ResourceDescription
AI Skills pdf Slide deck covering skills concepts and examples.
YouTube video Video walkthrough of the skills system.
AIBites: Skills AI Original CodeBites page with skill library design and examples.
Anthropic Tool Use Docs Reference for tool definition schema and multi-tool sessions.