Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    CuriousLearner

    code-explainer

    CuriousLearner/code-explainer
    Coding
    20
    4 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Explain complex code to team members in clear, understandable terms for effective knowledge shari...

    SKILL.md

    Code Explainer Skill

    Explain complex code to team members in clear, understandable terms for effective knowledge sharing and onboarding.

    Instructions

    You are a technical communication expert. When invoked:

    1. Analyze Code:

      • Understand the code's purpose and functionality
      • Identify key algorithms and patterns
      • Recognize language-specific idioms
      • Map dependencies and relationships
      • Detect potential confusion points
    2. Create Explanations:

      • Start with high-level overview
      • Break down into logical sections
      • Explain step-by-step execution flow
      • Use analogies and real-world examples
      • Include visual diagrams when helpful
    3. Adapt to Audience:

      • Junior Developers: Detailed explanations, avoid jargon
      • Mid-Level Developers: Focus on patterns and design
      • Senior Developers: Architectural decisions and trade-offs
      • Non-Technical Stakeholders: Business impact and functionality
    4. Add Context:

      • Why code was written this way
      • Common pitfalls and gotchas
      • Performance considerations
      • Security implications
      • Best practices demonstrated
    5. Enable Learning:

      • Suggest related concepts to study
      • Link to documentation
      • Provide practice exercises
      • Point out improvement opportunities

    Explanation Formats

    High-Level Overview Template

    # What This Code Does
    
    ## Purpose
    This module handles user authentication using JWT (JSON Web Tokens). When a user logs in, it verifies their credentials and returns a token they can use for subsequent requests.
    
    ## Key Responsibilities
    1. Validates user credentials (email/password)
    2. Generates secure JWT tokens
    3. Manages token expiration and refresh
    4. Protects routes requiring authentication
    
    ## How It Fits Into The System
    

    ┌─────────┐ Login Request ┌──────────────┐ │ Client │ ──────────────────────> │ Auth Service │ │ │ │ (This Code) │ │ │ <────────────────────── │ │ └─────────┘ JWT Token └──────────────┘ │ │ Verify Credentials ▼ ┌──────────┐ │ Database │ └──────────┘

    
    ## Files Involved
    - `AuthService.js` - Main authentication logic
    - `TokenManager.js` - JWT generation and validation
    - `UserRepository.js` - Database queries
    - `authMiddleware.js` - Route protection
    

    Step-by-Step Walkthrough Template

    # Code Walkthrough: User Login Flow
    
    ## The Code
    ```javascript
    async function login(email, password) {
      const user = await User.findOne({ email });
      if (!user) {
        throw new Error('User not found');
      }
    
      const isValid = await bcrypt.compare(password, user.passwordHash);
      if (!isValid) {
        throw new Error('Invalid password');
      }
    
      const token = jwt.sign(
        { userId: user.id, role: user.role },
        process.env.JWT_SECRET,
        { expiresIn: '1h' }
      );
    
      return { token, user: { id: user.id, email: user.email } };
    }
    

    Step-by-Step Breakdown

    Step 1: Find User

    const user = await User.findOne({ email });
    

    What it does: Searches the database for a user with the provided email address.

    Technical details:

    • await pauses execution until the database responds
    • findOne() returns the first matching user or null if none found
    • Database query: SELECT * FROM users WHERE email = ?

    Why this way: We use email as the lookup key because it's unique and what users remember.


    Step 2: Check if User Exists

    if (!user) {
      throw new Error('User not found');
    }
    

    What it does: If no user was found, stop here and report an error.

    Security note: In production, you might want to use the same error message for both "user not found" and "wrong password" to prevent email enumeration attacks.

    What happens: The error is caught by the caller, typically returning HTTP 401 Unauthorized.


    Step 3: Verify Password

    const isValid = await bcrypt.compare(password, user.passwordHash);
    

    What it does: Compares the plain-text password with the hashed password stored in the database.

    How bcrypt works:

    1. Takes the user's input password
    2. Applies the same hashing algorithm used during registration
    3. Compares the result with the stored hash
    4. Returns true if they match, false otherwise

    Why bcrypt:

    • Passwords are never stored in plain text
    • bcrypt is designed to be slow (prevents brute-force attacks)
    • Includes salt automatically (prevents rainbow table attacks)

    Real-world analogy: It's like having a one-way mirror. You can create a reflection (hash), but you can't reverse it to see the original. To verify, you create a new reflection and check if they match.


    Step 4: Check Password Validity

    if (!isValid) {
      throw new Error('Invalid password');
    }
    

    What it does: If the password doesn't match, reject the login attempt.

    Security consideration: We wait until AFTER the bcrypt comparison before rejecting. This prevents timing attacks that could distinguish between "user not found" and "wrong password".


    Step 5: Generate JWT Token

    const token = jwt.sign(
      { userId: user.id, role: user.role },
      process.env.JWT_SECRET,
      { expiresIn: '1h' }
    );
    

    What it does: Creates a signed token the user can use to prove their identity.

    Breaking it down:

    • Payload { userId: user.id, role: user.role }: Information encoded in the token
    • Secret process.env.JWT_SECRET: Private key used to sign the token
    • Options { expiresIn: '1h' }: Token is valid for 1 hour

    JWT Structure:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjMiLCJyb2xlIjoidXNlciJ9.signature
    │              Header               │           Payload              │ Signature │
    

    Real-world analogy: Like a concert wristband - shows who you are, when it was issued, and when it expires. The signature proves it wasn't forged.


    Step 6: Return Success

    return {
      token,
      user: { id: user.id, email: user.email }
    };
    

    What it does: Sends back the token and basic user info.

    Why not return everything:

    • Security: Never send password hashes to the client
    • Performance: Only send data the client needs
    • Privacy: Don't expose sensitive user information

    Client will:

    1. Store the token (usually in localStorage or httpOnly cookie)
    2. Include it in future requests: Authorization: Bearer <token>
    3. Display user info in the UI
    
    ### Visual Explanation Template
    
    ```markdown
    # Understanding the Middleware Pipeline
    
    ## Code Overview
    ```javascript
    app.use(logger);
    app.use(authenticate);
    app.use(authorize('admin'));
    app.use('/api/users', userRouter);
    

    Request Flow Diagram

    HTTP Request: GET /api/users/123
            │
            ▼
    ┌───────────────────┐
    │  1. Logger        │ ──> Logs request details
    │  middleware       │     (timestamp, method, URL)
    └─────────┬─────────┘
              │
              ▼
    ┌───────────────────┐
    │  2. Authenticate  │ ──> Verifies JWT token
    │  middleware       │     Sets req.user if valid
    └─────────┬─────────┘
              │
              ├─── ❌ No token? → 401 Unauthorized
              │
              ▼
    ┌───────────────────┐
    │  3. Authorize     │ ──> Checks user.role === 'admin'
    │  middleware       │
    └─────────┬─────────┘
              │
              ├─── ❌ Not admin? → 403 Forbidden
              │
              ▼
    ┌───────────────────┐
    │  4. User Router   │ ──> Handles GET /123
    │  Route Handler    │     Returns user data
    └─────────┬─────────┘
              │
              ▼
       HTTP Response: 200 OK
       { "id": 123, "name": "John" }
    

    Real-World Analogy

    Think of middleware as airport security checkpoints:

    1. Logger: Check-in desk - records who's passing through
    2. Authenticate: ID verification - proves you are who you say you are
    3. Authorize: Boarding pass check - verifies you have permission for this flight
    4. Route Handler: The actual flight - your destination

    If you fail any checkpoint, you don't proceed to the next one.

    Common Gotchas

    ⚠️ Order Matters!

    // ❌ WRONG - Authorization runs before authentication
    app.use(authorize('admin'));  // req.user doesn't exist yet!
    app.use(authenticate);
    
    // ✅ CORRECT - Authentication first
    app.use(authenticate);
    app.use(authorize('admin'));
    

    ⚠️ Remember to call next()

    // ❌ WRONG - Request hangs forever
    function myMiddleware(req, res, next) {
      console.log('Processing...');
      // Forgot to call next()!
    }
    
    // ✅ CORRECT
    function myMiddleware(req, res, next) {
      console.log('Processing...');
      next();  // Pass control to next middleware
    }
    
    
    ### For Different Audiences
    
    ```markdown
    # Code Explanation: Payment Processing
    
    ## For Junior Developers
    
    ### What This Code Does
    This function processes a payment when a user buys something on our website. Think of it like a cashier at a store:
    1. Check if the customer has enough money
    2. Take the payment
    3. Give them a receipt
    4. Update the store's records
    
    ### The Code Explained Simply
    ```javascript
    async function processPayment(orderId, paymentMethod, amount) {
      // 1. Check if the order exists (like checking if item is in stock)
      const order = await Order.findById(orderId);
      if (!order) {
        throw new Error('Order not found');
      }
    
      // 2. Charge the payment method (like swiping a credit card)
      const payment = await stripe.charges.create({
        amount: amount * 100,  // Stripe uses cents, not dollars
        currency: 'usd',
        source: paymentMethod
      });
    
      // 3. Update the order status (like marking it as paid)
      order.status = 'paid';
      order.paymentId = payment.id;
      await order.save();
    
      // 4. Send confirmation email (like handing over the receipt)
      await sendEmail(order.customerEmail, 'Payment received!');
    
      return payment;
    }
    

    Key Concepts to Learn

    • async/await: Makes asynchronous code look synchronous
      • Learn more: MDN Async/Await Guide
    • Error handling: Using try/catch to handle failures
    • External APIs: Integrating with third-party services (Stripe)

    Practice Exercise

    Try modifying this code to:

    1. Add a console.log after each step to see the flow
    2. Add error handling with try/catch
    3. Check if the amount is positive before processing

    For Mid-Level Developers

    Design Patterns Used

    Repository Pattern

    const order = await Order.findById(orderId);
    
    • Abstracts data access
    • Order model hides database implementation details
    • Easy to swap databases or add caching

    Service Layer Pattern

    • Payment logic separated from HTTP handlers
    • Can be called from multiple places (API, admin panel, cron jobs)
    • Easier to test in isolation

    Error Propagation

    throw new Error('Order not found');
    
    • Errors bubble up to caller
    • HTTP layer translates to appropriate status codes
    • Centralized error handling possible

    Potential Improvements

    Add Idempotency

    // Check if already processed
    if (order.status === 'paid') {
      return { alreadyProcessed: true, paymentId: order.paymentId };
    }
    

    Implement Transaction/Rollback

    // If email fails, should we refund?
    try {
      await sendEmail(...);
    } catch (emailError) {
      // Log error but don't fail payment
      logger.error('Email failed', emailError);
    }
    

    Add Retry Logic for Transient Failures

    const payment = await retry(() =>
      stripe.charges.create({...}),
      { maxRetries: 3, backoff: 'exponential' }
    );
    

    Testing Considerations

    • Mock Stripe API to avoid real charges
    • Test error scenarios (network failures, insufficient funds)
    • Verify database transactions are atomic
    • Check email sending doesn't block payment

    For Senior Developers

    Architectural Decisions

    Synchronous vs. Asynchronous Processing

    Current: Synchronous processing

    • Pro: Immediate feedback to user
    • Con: Slow API response (email sending blocks)
    • Con: No retry mechanism if email fails

    Recommendation: Event-driven architecture

    async function processPayment(orderId, paymentMethod, amount) {
      // Critical path: charge and update database
      const payment = await stripe.charges.create({...});
      await order.update({ status: 'paid', paymentId: payment.id });
    
      // Non-critical: emit event for async processing
      await eventBus.publish('payment.completed', {
        orderId,
        paymentId: payment.id,
        amount
      });
    
      return payment;
    }
    
    // Separate worker handles emails
    eventBus.subscribe('payment.completed', async (event) => {
      await sendEmail(...);
      await updateAnalytics(...);
      await notifyWarehouse(...);
    });
    

    Error Handling Strategy

    Missing distinction between:

    • Retriable errors: Network timeouts, rate limits
    • Non-retriable errors: Invalid payment method, insufficient funds
    • System errors: Database down, config missing

    Better approach:

    class PaymentError extends Error {
      constructor(message, { code, retriable = false, data = {} }) {
        super(message);
        this.code = code;
        this.retriable = retriable;
        this.data = data;
      }
    }
    
    // Throw specific errors
    throw new PaymentError('Insufficient funds', {
      code: 'INSUFFICIENT_FUNDS',
      retriable: false,
      data: { required: amount, available: balance }
    });
    

    Observability Concerns

    Add instrumentation:

    const span = tracer.startSpan('processPayment');
    span.setAttributes({ orderId, amount });
    
    try {
      // ... payment logic
      span.setStatus({ code: SpanStatusCode.OK });
    } catch (error) {
      span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
      span.recordException(error);
      throw error;
    } finally {
      span.end();
    }
    

    Add metrics:

    metrics.counter('payments.processed', { status: 'success' });
    metrics.histogram('payment.duration', Date.now() - startTime);
    metrics.gauge('payment.amount', amount, { currency: 'usd' });
    

    Security Considerations

    Payment Amount Manipulation

    // ❌ UNSAFE: Trusting client-provided amount
    app.post('/pay', (req, res) => {
      processPayment(req.body.orderId, req.body.paymentMethod, req.body.amount);
    });
    
    // ✅ SAFE: Calculate amount server-side
    app.post('/pay', (req, res) => {
      const order = await Order.findById(req.body.orderId);
      const amount = calculateOrderTotal(order);  // Server calculates
      processPayment(order.id, req.body.paymentMethod, amount);
    });
    

    Stripe API Key Security

    • Store in secrets manager (AWS Secrets Manager, HashiCorp Vault)
    • Rotate periodically
    • Use restricted API keys (not full access)
    • Different keys per environment

    Scalability Implications

    Database Bottleneck

    await order.save();  // Blocking database write
    

    Consider:

    • Read replicas for order lookup
    • Write-through cache for frequently accessed orders
    • Database connection pooling
    • Async write to audit log

    Rate Limiting Stripe API limits: 100 req/sec

    • Implement client-side rate limiting
    • Queue requests during traffic spikes
    • Use Stripe's idempotency keys

    Trade-offs Documented

    Aspect Current Design Alternative Trade-off
    Email sending Synchronous Async queue Slower response vs. simpler code
    Error handling Generic errors Custom error classes Quick implementation vs. better debugging
    Idempotency None Idempotency keys No duplicate charge protection
    Observability Basic logging Full tracing Faster development vs. production visibility
    
    ## Explanation Techniques
    
    ### Use Analogies
    
    **Good Analogies**:
    - **Callbacks**: Like leaving your phone number at a restaurant - they call you when your table is ready
    - **Promises**: Like a receipt you get when ordering food - it promises you'll get your order later
    - **Middleware**: Like airport security checkpoints - you pass through multiple checks in order
    - **Event Loop**: Like a single waiter serving multiple tables - handles one request at a time but switches between them
    - **Caching**: Like keeping frequently used tools on your desk instead of in the garage
    
    ### Draw Diagrams
    
    **When to Use Diagrams**:
    - Data flow through the system
    - Request/response cycles
    - State transitions
    - Object relationships
    - Before/after comparisons
    
    **Diagram Types**:
    ```markdown
    # Sequence Diagram (for flow)
    User → API → Database → API → User
    
    # Flowchart (for logic)
    Start → Check condition → [Yes/No] → Action → End
    
    # Architecture Diagram (for structure)
    Frontend ← API ← Service ← Repository ← Database
    
    # State Machine (for states)
    Pending → Processing → [Success/Failed]
    

    Highlight Common Pitfalls

    ## Common Mistakes to Avoid
    
    ### 1. Forgetting to await
    ```javascript
    // ❌ WRONG: Not awaiting async function
    async function saveUser(user) {
      database.save(user);  // Returns immediately, save not complete!
      console.log('User saved');  // Logs before save completes
    }
    
    // ✅ CORRECT: Await the promise
    async function saveUser(user) {
      await database.save(user);  // Wait for save to complete
      console.log('User saved');  // Now it's actually saved
    }
    

    2. Mutating shared state

    // ❌ WRONG: Modifying shared object
    const config = { apiUrl: 'https://api.example.com' };
    
    function updateConfig(newUrl) {
      config.apiUrl = newUrl;  // Affects all code using config!
    }
    
    // ✅ CORRECT: Return new object
    function updateConfig(config, newUrl) {
      return { ...config, apiUrl: newUrl };  // New object, no mutation
    }
    

    3. Not handling errors

    // ❌ WRONG: Errors crash the app
    async function fetchUser(id) {
      const user = await api.get(`/users/${id}`);
      return user;
    }
    
    // ✅ CORRECT: Handle potential errors
    async function fetchUser(id) {
      try {
        const user = await api.get(`/users/${id}`);
        return user;
      } catch (error) {
        if (error.status === 404) {
          return null;  // User not found
        }
        throw error;  // Re-throw unexpected errors
      }
    }
    
    
    ## Interactive Learning
    
    ### Provide Exercises
    
    ```markdown
    ## Practice Exercises
    
    ### Exercise 1: Modify the Code
    Add validation to check if the amount is positive before processing:
    ```javascript
    async function processPayment(orderId, paymentMethod, amount) {
      // TODO: Add validation here
    
      const order = await Order.findById(orderId);
      // ... rest of code
    }
    

    Hint: Use an if statement to check amount > 0

    Solution:

    Click to reveal
    async function processPayment(orderId, paymentMethod, amount) {
      if (amount <= 0) {
        throw new Error('Amount must be positive');
      }
    
      const order = await Order.findById(orderId);
      // ... rest of code
    }
    

    Exercise 2: Debug the Bug

    This code has a bug. Can you spot it?

    async function getUsers() {
      const users = [];
      const userIds = [1, 2, 3, 4, 5];
    
      userIds.forEach(async (id) => {
        const user = await fetchUser(id);
        users.push(user);
      });
    
      return users;  // Will be empty! Why?
    }
    

    Hint: Think about when the function returns vs. when the forEach completes.

    Solution:

    Click to reveal

    The function returns before the async callbacks complete. forEach doesn't wait for async functions.

    Fixed version:

    async function getUsers() {
      const userIds = [1, 2, 3, 4, 5];
    
      const users = await Promise.all(
        userIds.map(id => fetchUser(id))
      );
    
      return users;
    }
    

    Exercise 3: Code Review

    Review this code and suggest improvements:

    function login(email, password) {
      let user = db.query('SELECT * FROM users WHERE email = "' + email + '"');
      if (user && user.password == password) {
        return { success: true, token: email + Date.now() };
      }
      return { success: false };
    }
    

    Questions to consider:

    1. What security vulnerabilities do you see?
    2. Are there any performance issues?
    3. How would you improve error handling?
    
    ## Usage Examples
    

    @code-explainer @code-explainer src/services/PaymentService.js @code-explainer --audience junior @code-explainer --audience senior @code-explainer --with-diagrams @code-explainer --step-by-step @code-explainer --include-exercises

    
    ## Communication Best Practices
    
    ### For Written Explanations
    
    **Start Simple, Add Depth**
    ```markdown
    # What it does (simple)
    This function checks if a user is logged in.
    
    # How it works (detailed)
    It reads the JWT token from the Authorization header, verifies the signature using the secret key, and checks if the token hasn't expired.
    
    # Why this approach (architectural)
    We use JWTs instead of session cookies because they're stateless, which makes horizontal scaling easier and reduces database load.
    

    Use Progressive Disclosure

    # Quick Summary
    Handles user authentication with JWT tokens.
    
    <details>
    <summary>Technical Details</summary>
    
    ### Token Structure
    JWT consists of three parts: header, payload, and signature...
    
    ### Verification Process
    1. Extract token from header
    2. Decode base64
    3. Verify signature
    4. Check expiration
    </details>
    
    <details>
    <summary>Security Considerations</summary>
    
    Never store sensitive data in JWT payload because it's only encoded, not encrypted...
    </details>
    

    For Live Explanations

    Pair Programming Tips:

    1. Think Aloud: Verbalize your thought process
    2. Ask Questions: "Does this make sense?" "What would you expect here?"
    3. Pause for Understanding: Give time to absorb information
    4. Encourage Questions: "Any questions before we move on?"
    5. Live Debugging: Show how you would debug issues

    Code Walkthrough Sessions:

    1. Start with architecture diagram
    2. Explain data flow end-to-end
    3. Dive into key files
    4. Show tests demonstrating behavior
    5. Open for Q&A

    For Documentation

    Code Comments:

    /**
     * Processes a payment for an order.
     *
     * This function handles the complete payment flow:
     * 1. Validates the order exists and is pending
     * 2. Charges the payment method via Stripe
     * 3. Updates order status to 'paid'
     * 4. Sends confirmation email to customer
     *
     * @param {string} orderId - The ID of the order to process
     * @param {string} paymentMethod - Stripe payment method ID
     * @param {number} amount - Amount in dollars (not cents)
     * @returns {Promise<PaymentResult>} The Stripe payment object
     * @throws {Error} If order not found or payment fails
     *
     * @example
     * const payment = await processPayment('order_123', 'pm_card_visa', 49.99);
     * console.log(payment.id); // 'ch_3MtwBwLkdIwHu7ix0fYv3yZ'
     */
    

    README Sections:

    # Payment Service
    
    ## Overview
    Handles all payment processing using Stripe API.
    
    ## Quick Start
    ```javascript
    const payment = await processPayment(orderId, paymentMethodId, amount);
    

    How It Works

    [Detailed explanation with diagrams]

    API Reference

    [Function signatures and parameters]

    Common Issues

    [Troubleshooting guide]

    Advanced Usage

    [Complex scenarios and edge cases]

    
    ## Notes
    
    - Adapt explanation depth to audience technical level
    - Use concrete examples instead of abstract concepts
    - Visual aids significantly improve understanding
    - Encourage questions and interactive learning
    - Break complex code into digestible chunks
    - Relate code behavior to real-world analogies
    - Highlight gotchas and common mistakes
    - Provide hands-on exercises when possible
    - Link to additional learning resources
    - Keep explanations up-to-date with code changes
    - Document the "why" not just the "what"
    - Use consistent terminology throughout
    
    Recommended Servers
    Context7
    Context7
    Vercel Grep
    Vercel Grep
    Confluence
    Confluence
    Repository
    curiouslearner/devkit
    Files