Skip to content

Latest commit

 

History

History
759 lines (613 loc) · 17.4 KB

File metadata and controls

759 lines (613 loc) · 17.4 KB

Example Output: Generated Coding Style Skill

This document shows what a generated coding style skill looks like after analyzing a developer's repositories.

Generated Structure

~/.openclaw/workspace/skills/your-coding-style/
├── SKILL.md              (This document, but as skill doc)
├── RULES.md              (Detailed rules)
├── PROMPTS.md            (Claude prompts)
├── EXAMPLES.md           (Code examples)
├── style-guide.json      (Machine-readable)
└── metadata.json         (Analysis metadata)

Example: RULES.md

# Your Coding Style Rules

## Naming Conventions

**Rule:** Use camelCase for variables and functions, PascalCase for classes and components, UPPER_SNAKE_CASE for constants

### ✓ Good Examples

```typescript
const userName = "John";
const userEmail = "john@example.com";
const isActive = true;
const hasPermission = user.permissions.includes('admin');
const shouldRender = condition && anotherCondition;

function getUserData(userId) { }
function calculateTotal(items) { }

class UserManager { }
class DataRepository { }

const MAX_RETRIES = 3;
const DEFAULT_TIMEOUT = 5000;

✗ Bad Examples

const user_name = "John";
const UserEmail = "john@example.com";
const Active = true;
const permission = false;

function get_user_data(user_id) { }
function CalculateTotal(items) { }

const maxRetries = 3;  // Should be UPPER_CASE
const defaultTimeout = 5000;  // Should be UPPER_CASE

const u = "John";  // Too short, non-descriptive

Confidence: 94%


Function Structure

Rule: Keep functions small (target: 30 LOC, max 50 LOC). Use early returns to minimize nesting. Single responsibility principle.

✓ Good Examples

function validateUser(user) {
  if (!user) return null;
  if (!user.email) return null;
  if (!isEmailValid(user.email)) return null;
  
  return user;
}

function processOrderItems(order) {
  const validItems = order.items.filter(item => item.quantity > 0);
  if (validItems.length === 0) return [];
  
  return validItems.map(item => ({
    ...item,
    total: item.price * item.quantity
  }));
}

✗ Bad Examples

// Too long, too nested
function processUser(user) {
  if (user) {
    if (user.active) {
      if (user.verified) {
        if (user.permissions) {
          if (user.permissions.includes('admin')) {
            // Way too deep
          }
        }
      }
    }
  }
}

// Multiple responsibilities
function getUserAndCalculateTax(userId) {
  // Fetch user
  const user = database.getUser(userId);
  // Calculate tax
  const tax = user.income * 0.25;
  // Format for display
  const formatted = `$${tax.toFixed(2)}`;
  return { user, tax, formatted };
}

Confidence: 88%


Error Handling

Rule: Explicitly return error values or throw descriptive errors. Never silently fail.

✓ Good Examples

// Using explicit returns
function parseJson(str) {
  try {
    return { success: true, data: JSON.parse(str) };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

// Using throws with context
function getUserById(id) {
  if (!id || typeof id !== 'string') {
    throw new Error(`getUserById: invalid id "${id}". Expected non-empty string`);
  }
  const user = database.findById(id);
  if (!user) {
    throw new Error(`getUserById: user not found with id "${id}"`);
  }
  return user;
}

// Using Result type pattern
function validateEmail(email) {
  if (!email.includes('@')) {
    return { ok: false, error: 'Email must contain @' };
  }
  return { ok: true, data: email.toLowerCase() };
}

✗ Bad Examples

// Silent failure
function parseJson(str) {
  try {
    return JSON.parse(str);
  } catch {
    return null;  // What went wrong? No idea.
  }
}

// No error context
function getUserById(id) {
  const user = database.findById(id);
  return user;  // What if null? Calling code has no idea
}

// Hidden errors
function processItems(items) {
  items.forEach(item => {
    item.status = 'processed';  // What if item is null? Crashes silently
  });
}

Confidence: 86%


Comments & Documentation

Rule: Explain WHY, not WHAT. Code should be self-documenting. Comments only for non-obvious logic.

✓ Good Examples

// Why: Validate before expensive operation to avoid wasted cycles
if (!isValidUser(user)) return null;

// Why: Map to internal schema. DB uses different naming conventions
const normalized = rows.map(row => ({
  id: row.user_id,
  name: row.full_name,
  email: row.email_address
}));

// Why: Users expect feedback immediately, process async
const saveUserAsync = (user) => {
  database.save(user);  // Not awaited, runs in background
  return { status: 'saving' };
};

✗ Bad Examples

// What, not why
const user = database.getUser(id);  // Get user from database
const isValid = validateUser(user);  // Check if user is valid

// Obvious comments are noise
for (let i = 0; i < items.length; i++) {  // Loop through items
  console.log(items[i]);  // Print item
}

// Too many comments = unreadable code
function calc(a, b) {  // Calculate
  const c = a + b;  // Add a and b
  const d = c * 2;  // Multiply by 2
  const e = d / 4;  // Divide by 4
  return e;  // Return result
}

Confidence: 81%


Testing & Test Colocation

Rule: Tests colocated with source code (same directory, .test.ts extension). 70%+ coverage target.

File Structure

src/
├── utils/
│   ├── formatDate.ts
│   ├── formatDate.test.ts        ← colocated
│   ├── calculateTax.ts
│   └── calculateTax.test.ts       ← colocated
├── hooks/
│   ├── useAuth.ts
│   ├── useAuth.test.ts            ← colocated
│   └── useLocalStorage.ts

✓ Good Testing

// formatDate.ts
export function formatDate(date) {
  if (!date) return '';
  return new Intl.DateTimeFormat('en-US').format(date);
}

// formatDate.test.ts
import { formatDate } from './formatDate';

describe('formatDate', () => {
  it('formats dates correctly', () => {
    expect(formatDate(new Date('2024-01-15'))).toBe('1/15/2024');
  });

  it('returns empty string for null', () => {
    expect(formatDate(null)).toBe('');
  });

  it('handles invalid dates', () => {
    expect(formatDate(new Date('invalid'))).toBe('');
  });
});

✗ Bad Testing

// tests/utils/formatDate.test.ts (separate folder)
// Hard to navigate, easy to ignore

// Missing edge cases
describe('formatDate', () => {
  it('works', () => {
    expect(formatDate(new Date('2024-01-15'))).toBe('1/15/2024');
  });
});

// Too integrated
describe('Date utils', () => {
  it('formats and validates and parses dates', () => {
    // Testing too much in one test
  });
});

Confidence: 92%


Code Organization

Rule: Organize by feature/domain, not by type. Clear separation of concerns.

✓ Good Structure

src/
├── features/
│   ├── auth/
│   │   ├── components/
│   │   │   ├── LoginForm.tsx
│   │   │   └── LoginForm.test.tsx
│   │   ├── hooks/
│   │   │   ├── useAuth.ts
│   │   │   └── useAuth.test.ts
│   │   ├── services/
│   │   │   ├── authService.ts
│   │   │   └── authService.test.ts
│   │   └── types.ts
│   ├── users/
│   │   ├── components/
│   │   ├── hooks/
│   │   ├── services/
│   │   └── types.ts
│   └── products/
├── shared/
│   ├── components/
│   ├── hooks/
│   └── utils/
└── app.tsx

✗ Bad Structure

src/
├── components/
│   ├── LoginForm.tsx
│   ├── UserList.tsx
│   └── ProductCard.tsx
├── services/
│   ├── authService.ts
│   ├── userService.ts
│   └── productService.ts
├── hooks/
│   ├── useAuth.ts
│   ├── useUser.ts
│   └── useProduct.ts
├── types/
│   └── types.ts
├── utils/
│   └── helpers.ts

Confidence: 89%


Imports & Dependency Management

Rule: Prefer ES modules. Group imports logically (standard lib, packages, local). Use relative paths for local imports.

✓ Good Imports

// Standard library
import { readFile } from 'fs';
import path from 'path';

// Third-party packages
import React from 'react';
import { useQuery } from '@tanstack/react-query';

// Local modules (grouped by feature)
import { UserForm } from '../components/UserForm';
import { useUserData } from '../hooks/useUserData';
import { userService } from '../services/userService';
import { type User } from '../types';

✗ Bad Imports

// Mixed import styles
const React = require('react');
import { Component } from 'react';

// Chaotic order
import { calculateTax } from './utils/tax';
import axios from 'axios';
import { UserForm } from './components';
import React from 'react';
import path from 'path';
import { useState } from 'react';

// Deep relative paths
import { Helper } from '../../../../utils/helpers';

// Unused imports
import { unused } from './module';

Confidence: 91%


Summary

Category Rule Confidence
Naming camelCase/PascalCase/UPPER_SNAKE 94%
Functions 30 LOC target, early returns 88%
Errors Explicit handling, never silent 86%
Comments Why not what 81%
Testing Colocated, 70%+ coverage 92%
Organization By feature, clear structure 89%
Imports ES modules, grouped, local 91%

Overall Confidence: 89% (based on 8 repositories, 340 files)

Generated: 2024-01-15T10:30:00Z


---

## Example: PROMPTS.md

```markdown
# Claude Prompts for Your Coding Style

## Short System Prompt

Use this when asking Claude to generate code:

**Prompt:**

You are an expert code generator familiar with this developer's personal coding style.

Rules:

  • Use camelCase for variables/functions, PascalCase for classes/components
  • Keep functions under 50 LOC (target 30), use early returns
  • Always handle errors explicitly, never fail silently
  • Comments explain WHY, not WHAT
  • Colocate tests with source code, target 70%+ coverage
  • Organize by feature/domain, not by type
  • Prefer ES modules, group imports logically

When writing code, follow these rules consistently.

Full System Prompt

Use for complex code generation tasks:

Prompt:

You are an expert code generator who understands this developer's coding philosophy and style.

**Developer's Philosophy:**
- Priorities: Readability and maintainability above performance
- Code quality: Explicit > implicit, obvious > clever
- Testing: Unit-focused, colocated with source
- Error handling: Always explicit, never silent failures

**Coding Standards:**

1. **Naming Conventions**
   - Variables/functions: camelCase
   - Classes/components: PascalCase
   - Constants: UPPER_SNAKE_CASE
   - Booleans start with: is, has, should, can
   - No single letters except in loops (i, j, k)

2. **Function Structure**
   - Target: 30 lines of code
   - Maximum: 50 lines of code
   - Maximum parameters: 3 (use object for 4+)
   - Use early returns to minimize nesting
   - Maximum nesting depth: 2 levels
   - One responsibility per function

3. **Error Handling**
   - Never silently fail
   - Either throw with context or return { success, error }
   - Validate inputs at function boundaries
   - Always explain what went wrong

4. **Comments**
   - Explain WHY, not WHAT
   - Code should be self-documenting
   - Only comment non-obvious logic
   - Use JSDoc for public APIs only

5. **Testing**
   - Colocate tests with source (.test.ts files)
   - Target 70%+ code coverage
   - Unit tests (fast, isolated) > integration tests
   - Mock external dependencies
   - Test naming: describe + it("should...")

6. **Code Organization**
   - Group by feature/domain, not by type
   - Clear separation of concerns
   - One component/module per file (mostly)
   - Shared code in shared/ directory

7. **Imports**
   - Use ES modules (import/export)
   - Group logically: stdlib, packages, local
   - Use relative paths for local imports
   - Remove unused imports

**When Generating Code:**
1. Analyze the context and existing patterns
2. Follow the rules above strictly
3. If there's ambiguity, ask the developer
4. Explain deviations from the style if necessary
5. Ensure consistency with the project

**Key Principles:**
- Readability first
- Make the right thing obvious
- Explicit is better than implicit
- Fast feedback (tests, types)

Example: style-guide.json

{
  "language": "typescript",
  "confidence": 0.89,
  "generatedAt": "2024-01-15T10:30:00Z",
  "philosophy": {
    "priorities": "Readability and maintainability",
    "style-approach": "Explicit > implicit",
    "solution-preference": "Obvious over clever",
    "naming-philosophy": "Descriptive, consistent camelCase",
    "ideal-function-length": "30 LOC target, 50 max",
    "error-handling": "Explicit throws or error returns",
    "test-coverage-target": "70%+",
    "unit-integration-ratio": "80/20",
    "test-location": "Colocated (.test.ts)",
    "folder-structure": "By feature/domain"
  },
  "rules": [
    {
      "category": "Naming Conventions",
      "rule": "camelCase for variables/functions, PascalCase for classes, UPPER_SNAKE_CASE for constants",
      "confidence": 0.94
    },
    {
      "category": "Function Structure",
      "rule": "Keep under 50 LOC, target 30. Use early returns. Max 2 nesting levels.",
      "confidence": 0.88
    },
    {
      "category": "Error Handling",
      "rule": "Explicit error handling. Never fail silently.",
      "confidence": 0.86
    },
    {
      "category": "Comments",
      "rule": "Explain WHY, not WHAT. Code is self-documenting.",
      "confidence": 0.81
    },
    {
      "category": "Testing",
      "rule": "Colocate tests. 70%+ coverage. Unit > integration.",
      "confidence": 0.92
    },
    {
      "category": "Organization",
      "rule": "Group by feature/domain, not by type.",
      "confidence": 0.89
    }
  ],
  "baselinePatterns": {
    "typescript": {
      "naming": {
        "camelCase": 0.95,
        "snake_case": 0.03,
        "PascalCase": 0.01,
        "UPPER_SNAKE_CASE": 0.01
      },
      "functions": {
        "avgLength": 32,
        "maxLength": 89,
        "minLength": 3
      },
      "testing": {
        "colocated": 0.92,
        "separateFolder": 0.08
      }
    }
  }
}

Example: metadata.json

{
  "name": "your-coding-style",
  "generatedAt": "2024-01-15T10:30:00Z",
  "confidence": 0.89,
  "language": "polyglot",
  "philosophy": {
    "priorities": "Readability and maintainability",
    "style-approach": "Explicit > implicit",
    "naming-philosophy": "Descriptive, consistent camelCase"
  },
  "statistics": {
    "repositoriesAnalyzed": 8,
    "totalFilesAnalyzed": 340,
    "languages": {
      "typescript": 280,
      "python": 45,
      "rust": 15
    },
    "frameworks": {
      "React": 6,
      "Next.js": 5,
      "Vitest": 7,
      "Drizzle": 4
    }
  }
}

Real Usage Example

After generating the skill, Claude uses it:

User: "Generate a user authentication service following my coding style"

Claude: "I'll create a user authentication service following your coding style guide.
[reads ~/.openclaw/workspace/skills/your-coding-style/RULES.md]

Here's a TypeScript auth service:

```typescript
// authService.ts
export interface AuthResult {
  success: boolean;
  error?: string;
  token?: string;
}

export async function authenticate(
  email: string,
  password: string
): Promise<AuthResult> {
  if (!email || !password) {
    return {
      success: false,
      error: 'Email and password are required'
    };
  }

  if (!isValidEmail(email)) {
    return {
      success: false,
      error: 'Invalid email format'
    };
  }

  try {
    const user = await database.findByEmail(email);
    
    if (!user) {
      return {
        success: false,
        error: 'User not found'
      };
    }

    const isValid = await verifyPassword(password, user.passwordHash);
    
    if (!isValid) {
      return {
        success: false,
        error: 'Invalid password'
      };
    }

    const token = generateToken(user.id);
    
    return {
      success: true,
      token
    };
  } catch (error) {
    return {
      success: false,
      error: 'Authentication failed: ' + error.message
    };
  }
}

// authService.test.ts
describe('authenticate', () => {
  it('should return token for valid credentials', async () => {
    const result = await authenticate('user@example.com', 'password');
    expect(result.success).toBe(true);
    expect(result.token).toBeDefined();
  });

  it('should return error for missing credentials', async () => {
    const result = await authenticate('', '');
    expect(result.success).toBe(false);
    expect(result.error).toContain('required');
  });

  it('should return error for invalid email', async () => {
    const result = await authenticate('invalid', 'password');
    expect(result.success).toBe(false);
    expect(result.error).toContain('Invalid email');
  });
});

Notice how the code follows all your rules:

  • ✓ camelCase naming
  • ✓ Small functions with early returns
  • ✓ Explicit error handling (no throwing)
  • ✓ Tests colocated and comprehensive
  • ✓ Comments explain WHY "

---

This is a realistic example of what gets generated and how it's used!