library-api-design

Enforces API design rules for Solidity contracts in openzeppelin-contracts.

Updated Aug 10, 2026
One-click install
npx skills add https://github.com/isreal916/pistis --skill library-api-design-isreal916
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: library-api-design
Source: https://github.com/isreal916/pistis/tree/main/contracts/lib/openzeppelin-contracts/.claude/skills/library-api-design
Command: npx skills add https://github.com/isreal916/pistis --skill library-api-design-isreal916

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Solidity library contracts are inherited downstream, so API design mistakes (missing virtual, wrong calldata usage, reverts instead of no-ops) break inheritors and cannot be caught by linters. This Skill codifies the openzeppelin-contracts conventions so new or modified contracts preserve inheritability. ## Core Features & Use Cases - Virtual and override rules: Defines when functions must be virtual, why alias functions and convenience overloads are not, and why external cannot be an override point. - Data location and visibility guidance: Specifies memory vs calldata for reference types, public vs external defaults, and the internal/external split pattern using _msgSender(). - State machine and storage patterns: Covers the _update single-override pattern, no-op over revert philosophy, super calls in extensions, immutable tagging for the upgrades transpiler, and ERC-7201 namespaced storage. - Use Case: When adding a new ERC extension contract, apply these rules to decide which functions are virtual, where _update is overridden, and whether ERC-7201 storage is justified. ## Quick Start Review my new contract under contracts/ against the library API design rules and flag any violations.

Frequently Asked Questions about library-api-design

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
When should a Solidity function be marked virtual in OpenZeppelin contracts?

Mark every public and internal function virtual except alias functions that only forward to another function and convenience overloads that fill in a default argument. The canonical full-argument form is the virtual override point.

Should I use memory or calldata for function arguments in Solidity libraries?

Use memory for strings, bytes, arrays, and structs, including in public functions, because calldata forces every inheritor to match. Calldata is only valid for msg.data slices, narrowly scoped internal decoding helpers, or explicit Calldata-suffixed utility variants.

Why can't an external function be an override point in Solidity?

An override of an external function cannot call super, so functions designed to be overridden must be public. Solhint's no-external-virtual rule catches this, and the fix is public virtual rather than silencing the rule.

When should I use ERC-7201 namespaced storage in upgradeable contracts?

ERC-7201 is opt-in, not the default, since OpenZeppelin upgradeable variants are auto-generated by the transpiler. Use it only when namespacing is genuinely necessary, such as Initializable.sol, and justify new uses in NatSpec.

Should a function revert or no-op on vacuous input in library contracts?

Prefer no-ops over reverts when doing nothing creates no security concern, such as skipping zero-size batches or returning false for already-revoked roles. Overrides can add requirements on a no-op base but cannot remove requirements the base enforces.