From grimoire
Converts incompatible class interfaces so they work together, wrapping legacy or third-party code without modifying it. Useful when integrating code with mismatched APIs.
How this skill is triggered — by the user, by Claude, or both
Slash command
/grimoire:apply-adapter-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Convert the interface of a class into the interface clients expect, enabling classes with incompatible interfaces to work together.
Convert the interface of a class into the interface clients expect, enabling classes with incompatible interfaces to work together.
Adopted by: Java's InputStreamReader (adapts byte-stream InputStream to
character-stream Reader — in every JVM), Python's io.TextIOWrapper (same
adaptation in the standard library), Django REST Framework's Serializer (adapts ORM
models to JSON-serializable dicts), and every database driver layer (JDBC, ODBC) which
adapts vendor-specific protocols to a standard interface.
Impact: GoF documents that the Adapter is the primary mechanism for integrating
legacy or third-party code into a new architecture without modifying either side.
Every major language's standard library uses it to bridge abstraction layers — evidence
of universal adoption across all major ecosystems.
Why best: The alternative — modifying the existing class — creates coupling to the
consumer and may be impossible (third-party code, compiled libraries). The alternative
of modifying the client breaks encapsulation. Adapter wraps without touching either side.
Sources: Gamma et al. (1994) pp. 139–150; Java I/O class hierarchy documentation;
Python io module documentation
from abc import ABC, abstractmethod
class JSONLogger(ABC):
@abstractmethod
def log(self, event: dict) -> None: ...
class LegacyLogger:
def write_line(self, timestamp: str, level: str, message: str) -> None:
print(f"[{timestamp}] {level}: {message}")
from datetime import datetime
class LegacyLoggerAdapter(JSONLogger):
def __init__(self, legacy: LegacyLogger):
self._legacy = legacy
def log(self, event: dict) -> None:
self._legacy.write_line(
timestamp=event.get("ts", datetime.now().isoformat()),
level=event.get("level", "INFO"),
message=event.get("message", ""),
)
legacy = LegacyLogger()
logger: JSONLogger = LegacyLoggerAdapter(legacy)
# Client uses only the target interface — unaware of LegacyLogger
logger.log({"level": "ERROR", "message": "payment failed", "ts": "2026-06-10T12:00:00"})
If both sides need to call each other, write two adapters — one for each direction. A single class implementing both interfaces creates hidden coupling and is hard to test.
apply-facade-pattern instead.Adapting too much. An adapter that translates complex business logic is a Facade or a service, not an adapter. Keep adapters thin — only interface translation, no logic.
Modifying the adaptee to make the adapter simpler. If you can modify the adaptee, there may be no need for an adapter at all. If you can't, don't.
Forgetting to handle adapter errors. When the adaptee throws an exception using its own error types, the adapter should either translate them to the target interface's error types or let them propagate with clear context.
npx claudepluginhub jeffreytse/grimoire --plugin grimoireWraps incompatible interfaces (Object Adapter via composition, async/promise adaptation, two-way adaptation) to make them work together without modifying source code. Useful when integrating third-party libraries or legacy components.
Generates Adapter pattern for PHP 8.4 to convert incompatible interfaces, wrap legacy code or external libraries like Stripe/AWS SDKs. Includes target interfaces, adapters, and unit tests.
Adds runtime object responsibilities via wrapping (Decorator pattern). Applies to OOP codebases, especially Java I/O streams, Python decorators, and Django middleware.