Claude Code Plugins

Community-maintained marketplace

Feedback

meta-library-dev

@aRustyDev/ai
0
0

Develop reusable library code across languages. Use when designing public APIs, organizing modules, managing versioning, or creating utility libraries. Provides foundational patterns that language-specific *-lib-* skills extend.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name meta-library-dev
description Develop reusable library code across languages. Use when designing public APIs, organizing modules, managing versioning, or creating utility libraries. Provides foundational patterns that language-specific *-lib-* skills extend.

Library Development Patterns

Foundational patterns for developing reusable library code across programming languages. This meta-skill provides guidance that language-specific library skills (e.g., rust-lib-dev, python-lib-dev) extend.

When to Use This Skill

  • Designing library public APIs
  • Organizing modules and package structure
  • Managing semantic versioning and compatibility
  • Creating utility libraries, frameworks, or toolkits
  • Establishing documentation and testing standards for libraries
  • Publishing and distributing packages

This Skill Does NOT Cover

  • SDK development (wrapping APIs/services) - see meta-sdk-patterns-eng
  • Application architecture - see architecture-patterns
  • Language-specific implementation details - see *-lib-* skills
  • CLI tool development - see *-cli-* skills

Library vs SDK: Key Distinctions

Aspect Library SDK
Purpose Reusable functionality API/service wrapper
Dependencies Minimal, self-contained Tied to external service
Versioning Independent semver Often tracks API version
Examples lodash, requests, serde AWS SDK, Stripe SDK
Testing Unit/integration tests Mocks external service

Public API Design

Principle: Minimal Surface Area

Expose only what users need. Everything public becomes a maintenance commitment.

Good: 3-5 primary exports that compose
Bad: 50 exports that users must navigate

Export Patterns

Layered Exports:

library/
├── mod.rs (or index.ts, __init__.py)  # Primary public API
├── types.rs                            # Public types/interfaces
├── errors.rs                           # Error types
└── internal/                           # Private implementation
    └── ...

Explicit vs Glob Exports:

# Preferred: Explicit exports
from .core import parse, validate, transform
__all__ = ["parse", "validate", "transform"]

# Avoid: Glob re-exports (hides what's public)
from .core import *

Naming Conventions

Element Convention Example
Functions Verb-first, descriptive parse_json, validateInput
Types/Classes Noun, singular Parser, ValidationResult
Constants SCREAMING_SNAKE DEFAULT_TIMEOUT, MAX_RETRIES
Modules Lowercase, descriptive parser, validators

Function Signatures

Prefer Specific Over Generic:

// Good: Clear intent
fn parse_config(path: &Path) -> Result<Config, ParseError>

// Avoid: Too generic, unclear
fn parse(input: &str) -> Result<Value, Error>

Parameter Guidelines:

  • 0-3 parameters: Use positional
  • 4+ parameters: Use options object/struct
  • Required first, optional last
  • Sensible defaults for optional parameters
// Good: Options object for many parameters
interface ParseOptions {
  encoding?: string;
  strict?: boolean;
  maxDepth?: number;
}
function parse(input: string, options?: ParseOptions): Result

// Avoid: Too many positional parameters
function parse(input: string, encoding: string, strict: boolean, maxDepth: number): Result

Module Organization

Standard Structure

library/
├── src/
│   ├── lib.rs           # Rust: Library root
│   ├── index.ts         # TS: Package entry
│   ├── __init__.py      # Python: Package init
│   │
│   ├── core/            # Core functionality
│   │   ├── mod.rs
│   │   ├── parser.rs
│   │   └── validator.rs
│   │
│   ├── types/           # Type definitions
│   │   ├── mod.rs
│   │   └── config.rs
│   │
│   ├── errors/          # Error types
│   │   ├── mod.rs
│   │   └── parse_error.rs
│   │
│   └── utils/           # Internal utilities
│       └── ...
│
├── tests/               # Integration tests
├── examples/            # Usage examples
├── benches/             # Benchmarks (if applicable)
└── docs/                # Additional documentation

Module Cohesion Principles

High Cohesion:

  • Modules should do one thing well
  • Related functionality stays together
  • Clear boundaries between modules

Low Coupling:

  • Modules should be independently testable
  • Minimize cross-module dependencies
  • Use dependency injection for flexibility

Re-export Patterns

Facade Pattern for Complex Libraries:

// lib.rs - Clean public interface
pub use crate::core::{parse, validate};
pub use crate::types::{Config, Result};
pub use crate::errors::ParseError;

// Internal modules hidden
mod core;
mod types;
mod errors;
mod utils;  // Not re-exported

Versioning Strategy

Semantic Versioning (SemVer)

MAJOR.MINOR.PATCH

MAJOR: Breaking changes
MINOR: New features (backward compatible)
PATCH: Bug fixes (backward compatible)

What Constitutes Breaking Changes?

Change Type Breaking? Version Bump
Remove public function Yes MAJOR
Change function signature Yes MAJOR
Add required parameter Yes MAJOR
Add optional parameter No MINOR
Add new function No MINOR
Fix bug in existing behavior No PATCH
Performance improvement No PATCH

Pre-release Versions

0.x.y  - Initial development (breaking changes allowed in minor)
1.0.0-alpha.1 - Alpha release
1.0.0-beta.1  - Beta release
1.0.0-rc.1    - Release candidate
1.0.0         - Stable release

Deprecation Process

  1. Announce deprecation with @deprecated annotation
  2. Document migration path in deprecation notice
  3. Maintain deprecated API for at least one minor version
  4. Remove in next major version
import warnings

def old_function():
    """
    .. deprecated:: 2.0.0
       Use :func:`new_function` instead.
    """
    warnings.warn(
        "old_function is deprecated, use new_function instead",
        DeprecationWarning,
        stacklevel=2
    )
    return new_function()

Error Handling

Error Type Design

Hierarchical Error Types:

#[derive(Debug, thiserror::Error)]
pub enum LibraryError {
    #[error("Parse error: {0}")]
    Parse(#[from] ParseError),

    #[error("Validation error: {0}")]
    Validation(#[from] ValidationError),

    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
}

#[derive(Debug, thiserror::Error)]
pub enum ParseError {
    #[error("Invalid syntax at line {line}: {message}")]
    InvalidSyntax { line: usize, message: String },

    #[error("Unexpected token: {0}")]
    UnexpectedToken(String),
}

Error Messages

Good Error Messages Include:

  • What happened
  • Where it happened (context)
  • How to fix it (when possible)
# Good
ParseError: Invalid JSON at line 42: expected ',' or '}' after object property

# Bad
Error: Parse failed

Result Types

Prefer Result Types Over Exceptions (where language supports):

// Rust: Result type
pub fn parse(input: &str) -> Result<Document, ParseError>

// TypeScript: Discriminated union
type ParseResult =
  | { success: true; data: Document }
  | { success: false; error: ParseError };

Configuration Patterns

Configuration Hierarchy

1. Defaults (in code)
2. Config file
3. Environment variables
4. Explicit parameters

Builder Pattern for Configuration

let config = ConfigBuilder::new()
    .timeout(Duration::from_secs(30))
    .max_retries(3)
    .strict_mode(true)
    .build()?;

Validation at Construction

@dataclass
class Config:
    timeout: int
    max_retries: int

    def __post_init__(self):
        if self.timeout <= 0:
            raise ValueError("timeout must be positive")
        if self.max_retries < 0:
            raise ValueError("max_retries cannot be negative")

Testing Strategies

Test Pyramid for Libraries

         /\
        /  \     E2E (examples work)
       /----\
      /      \   Integration (modules work together)
     /--------\
    /          \ Unit (individual functions work)
   --------------

Testing Patterns

Property-Based Testing:

#[quickcheck]
fn parse_roundtrip(input: ValidJson) -> bool {
    let parsed = parse(&input.0)?;
    let serialized = serialize(&parsed);
    input.0 == serialized
}

Snapshot Testing:

test('parser output', () => {
  const result = parse(complexInput);
  expect(result).toMatchSnapshot();
});

Fuzz Testing:

#[fuzz]
fn fuzz_parser(data: &[u8]) {
    // Should not panic on any input
    let _ = parse(data);
}

Example-Driven Testing

def parse_date(s: str) -> date:
    """Parse a date string.

    Examples:
        >>> parse_date("2024-01-15")
        date(2024, 1, 15)

        >>> parse_date("invalid")
        Traceback (most recent call last):
            ...
        ValueError: Invalid date format
    """

Documentation Standards

Documentation Hierarchy

README.md          # Quick start, installation
docs/
├── guide/         # Tutorials, how-tos
├── reference/     # API documentation
└── examples/      # Runnable examples

API Documentation Requirements

Every public item needs:

  1. Summary - One-line description
  2. Description - Detailed explanation (if needed)
  3. Parameters - Each parameter documented
  4. Returns - Return value documented
  5. Errors - Possible errors documented
  6. Examples - At least one usage example
/// Parses a configuration file into a Config struct.
///
/// Reads the file at the given path and parses it as TOML format.
/// The file must exist and be valid UTF-8.
///
/// # Arguments
///
/// * `path` - Path to the configuration file
///
/// # Returns
///
/// A `Config` struct containing the parsed configuration.
///
/// # Errors
///
/// Returns `ParseError::Io` if the file cannot be read.
/// Returns `ParseError::InvalidSyntax` if the TOML is malformed.
///
/// # Examples
///
/// ```
/// let config = parse_config("config.toml")?;
/// assert_eq!(config.timeout, 30);
/// ```
pub fn parse_config(path: &Path) -> Result<Config, ParseError> {
    // ...
}

README Template

# Library Name

Brief description of what the library does.

## Installation

\`\`\`bash
# Package manager command
\`\`\`

## Quick Start

\`\`\`language
// Minimal working example
\`\`\`

## Features

- Feature 1
- Feature 2
- Feature 3

## Documentation

- [Guide](docs/guide/)
- [API Reference](docs/reference/)
- [Examples](examples/)

## License

[License type]

Compatibility Considerations

Minimum Supported Version

Document and test against minimum versions:

# Cargo.toml
rust-version = "1.70"

# pyproject.toml
requires-python = ">=3.9"

# package.json
"engines": {
  "node": ">=18.0.0"
}

Feature Flags

Use feature flags for optional functionality:

# Cargo.toml
[features]
default = ["json"]
json = ["serde_json"]
yaml = ["serde_yaml"]
async = ["tokio"]

Backward Compatibility Strategies

  1. Additive changes only in minor versions
  2. Feature flags for optional new features
  3. Type aliases to rename types without breaking
  4. Default parameters instead of signature changes

Publishing and Distribution

Pre-publish Checklist

  • Version bumped appropriately
  • CHANGELOG updated
  • All tests passing
  • Documentation updated
  • Examples work with new version
  • No accidental breaking changes
  • License file present
  • README accurate

Registry-Specific Guidelines

Registry Key Requirements
crates.io Cargo.toml metadata complete, license
npm package.json fields, TypeScript types
PyPI pyproject.toml, classifiers, requires-python
Maven pom.xml, GPG signing, Javadoc

Changelog Format

Follow Keep a Changelog:

# Changelog

## [Unreleased]

## [2.1.0] - 2024-01-15

### Added
- New `parse_strict` function for strict parsing

### Changed
- Improved error messages for parse failures

### Deprecated
- `parse_loose` is deprecated, use `parse` with `strict: false`

## [2.0.0] - 2024-01-01

### Changed
- **BREAKING**: Renamed `Config` to `Settings`
- **BREAKING**: `parse` now returns `Result` instead of panicking

Performance Considerations

Avoid Premature Optimization

  1. Correctness first - Make it work
  2. Clarity second - Make it readable
  3. Performance third - Make it fast (if needed)

Common Performance Patterns

Zero-Copy Where Possible:

// Good: Borrow instead of clone
fn process(data: &str) -> Result<&str, Error>

// Avoid: Unnecessary allocation
fn process(data: &str) -> Result<String, Error>

Lazy Evaluation:

// Good: Iterator (lazy)
fn items(&self) -> impl Iterator<Item = &Item>

// Avoid: Collect everything (eager)
fn items(&self) -> Vec<Item>

Benchmark Before Optimizing:

#[bench]
fn bench_parse(b: &mut Bencher) {
    let input = include_str!("../fixtures/large.json");
    b.iter(|| parse(input));
}

Extension Points

Plugin Architecture

pub trait Plugin {
    fn name(&self) -> &str;
    fn process(&self, input: &Document) -> Result<Document, Error>;
}

pub struct Library {
    plugins: Vec<Box<dyn Plugin>>,
}

impl Library {
    pub fn register_plugin(&mut self, plugin: impl Plugin + 'static) {
        self.plugins.push(Box::new(plugin));
    }
}

Callback Hooks

interface Hooks {
  beforeParse?: (input: string) => string;
  afterParse?: (result: Document) => Document;
  onError?: (error: Error) => void;
}

function parse(input: string, hooks?: Hooks): Document {
  const processed = hooks?.beforeParse?.(input) ?? input;
  // ...
}

Anti-Patterns to Avoid

1. God Module

Problem: Single module with too many responsibilities Solution: Split by domain/functionality

2. Leaky Abstractions

Problem: Internal implementation details exposed in public API Solution: Clear public/private boundaries

3. Unstable Dependencies

Problem: Depending on unstable/pre-1.0 libraries in public API Solution: Wrap or re-export with stable types

4. Breaking Changes in Patches

Problem: Changing behavior in patch releases Solution: Strict semver adherence

5. Missing Error Context

Problem: Generic errors that don't help debugging Solution: Rich error types with context

6. Documentation Drift

Problem: Docs out of sync with code Solution: Doc tests, examples in tests


References