Guide for creating optimized Claude Code agents. Use to design a new specialized agent, a swarm sub-agent, or a multi-agent workflow. Follows the Skill → Agent (preloaded skills) → Skill orchestration pattern.
日本語の概要は準備中です。原文の説明を表示しています。
SOLID Principles from Clean Architecture (Robert C. Martin). Use for code review, refactoring decisions, or when designing new modules/components.
日本語の概要は準備中です。原文の説明を表示しています。
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Based on "Clean Architecture" by Robert C. Martin, Chapter 7-11 (pages 57-90)
Read .claude/roles/architect.md — adopt this profile and follow all its rules.
This skill activates for:
"A module should have one, and only one, reason to change." — Clean Architecture, p.62
A module should be responsible to one, and only one, actor (stakeholder/user group).
// ❌ Bad: one class, three actors driving change
// - the developer (trigger flow)
// - the platform integration (GitLab/GitHub API)
// - the dashboard (stats persistence)
class ReviewService {
async triggerReview(mr: TrackedMr): Promise<void> {
/* developer concern: enqueue a review job */
}
async fetchThreads(mrId: MergeRequestId): Promise<Thread[]> {
/* platform concern: hit GitLab/GitHub API */
}
async saveStats(stats: ReviewStats): Promise<void> {
/* dashboard concern: persist aggregated metrics */
}
}
// ✅ Good: one module per actor
export class TriggerReviewUseCase implements UseCase<TriggerReviewInput, void> {
constructor(private readonly queue: QueueGateway) {}
async execute(input: TriggerReviewInput): Promise<void> {
await this.queue.enqueue(input);
}
}
export interface ThreadFetchGateway {
fetch(mrId: MergeRequestId): Promise<Thread[]>;
}
export class ReviewStatsPresenter {
present(stats: ReviewStats): ReviewStatsViewModel {
return { average: stats.averageScore, total: stats.totalReviews };
}
}
"A software artifact should be open for extension but closed for modification." — Clean Architecture, p.70
You should be able to change the behavior of a module by adding new code, not changing existing code.
// ❌ Bad: every new platform forces editing the use case
async function fetchThreads(
mrId: MergeRequestId,
platform: Platform
): Promise<Thread[]> {
if (platform === 'gitlab') return glabCli.fetchThreads(mrId);
if (platform === 'github') return ghCli.fetchThreads(mrId);
// Adding Bitbucket means editing this function...
throw new Error(`Unknown platform: ${platform}`);
}
// ✅ Good: use case depends on an abstraction, new platforms add new classes
export interface ThreadFetchGateway {
fetch(mrId: MergeRequestId): Promise<Thread[]>;
}
export class GitLabThreadFetchGateway implements ThreadFetchGateway {
async fetch(mrId: MergeRequestId): Promise<Thread[]> { /* glab CLI */ }
}
export class GitHubThreadFetchGateway implements ThreadFetchGateway {
async fetch(mrId: MergeRequestId): Promise<Thread[]> { /* gh CLI */ }
}
// Adding Bitbucket = a new class, zero changes to existing use cases
export class BitbucketThreadFetchGateway implements ThreadFetchGateway {
async fetch(mrId: MergeRequestId): Promise<Thread[]> { /* bb CLI */ }
}
"Subtypes must be substitutable for their base types." — Clean Architecture, p.78
If S is a subtype of T, objects of type T may be replaced with objects of type S without altering any desirable properties.
Gateway contracts are the most common LSP carrier in this codebase. Every implementation must honor the documented behavior — including the null-return convention for intentional absence (undefined is banned in domain types).
// Contract: returns null when no review context exists for the MR
export interface ReviewContextGateway {
findByMr(mrId: MergeRequestId): Promise<ReviewContext | null>;
}
// ❌ Bad: throws on absence — callers written against the contract break
class FileReviewContextGateway implements ReviewContextGateway {
async findByMr(mrId: MergeRequestId): Promise<ReviewContext | null> {
const path = this.pathFor(mrId);
if (!existsSync(path)) {
throw new Error('Context not found'); // violates the null-return contract
}
return JSON.parse(readFileSync(path, 'utf-8'));
}
}
// ✅ Good: every implementation honors the contract
class FileReviewContextGateway implements ReviewContextGateway {
async findByMr(mrId: MergeRequestId): Promise<ReviewContext | null> {
const path = this.pathFor(mrId);
if (!existsSync(path)) return null;
return JSON.parse(readFileSync(path, 'utf-8'));
}
}
class MemoryReviewContextGateway implements ReviewContextGateway {
constructor(private readonly contexts = new Map<MergeRequestId, ReviewContext>()) {}
async findByMr(mrId: MergeRequestId): Promise<ReviewContext | null> {
return this.contexts.get(mrId) ?? null;
}
}
"Don't depend on things you don't need." — Clean Architecture, p.84
Clients should not be forced to depend on methods they don't use. Many client-specific interfaces are better than one general-purpose interface.
// ❌ Bad: one fat platform interface, every consumer carries unused capabilities
export interface ReviewPlatformGateway {
fetchThreads(mrId: MergeRequestId): Promise<Thread[]>;
fetchDiff(mrId: MergeRequestId): Promise<DiffMetadata>;
postComment(mrId: MergeRequestId, body: string): Promise<void>;
resolveThread(threadId: ThreadId): Promise<void>;
searchOpenMrs(): Promise<TrackedMr[]>;
}
// A presenter that only reads threads still depends transitively on write capabilities
export class ThreadListPresenter {
constructor(private readonly platform: ReviewPlatformGateway) {}
async present(mrId: MergeRequestId): Promise<ThreadListViewModel> {
const threads = await this.platform.fetchThreads(mrId);
return { items: threads.map(toViewModel) };
}
}
// ✅ Good: focused gateways, each client depends only on what it actually uses
export interface ThreadFetchGateway {
fetch(mrId: MergeRequestId): Promise<Thread[]>;
}
export interface DiffMetadataFetchGateway {
fetch(mrId: MergeRequestId): Promise<DiffMetadata>;
}
export interface ReviewActionGateway {
postComment(mrId: MergeRequestId, body: string): Promise<void>;
resolveThread(threadId: ThreadId): Promise<void>;
}
// The presenter depends only on the read capability it needs
export class ThreadListPresenter {
constructor(private readonly threadFetch: ThreadFetchGateway) {}
async present(mrId: MergeRequestId): Promise<ThreadListViewModel> {
const threads = await this.threadFetch.fetch(mrId);
return { items: threads.map(toViewModel) };
}
}
"Depend on abstractions, not concretions." — Clean Architecture, p.87
High-level modules should not depend on low-level modules. Both should depend on abstractions.
"The source code dependencies point in the opposite direction to the flow of control." — Clean Architecture, p.89
Flow of control: Controller → Gateway → glab/gh CLI
Source dependency: Controller → Interface ← Gateway implementation
The composition root (src/main/routes.ts) is the only place that instantiates concrete gateways. Controllers and use cases depend exclusively on abstractions injected through a typed Dependencies interface.
// ❌ Bad: controller depends on a concrete implementation
import { GitLabThreadFetchGateway } from '@/interface-adapters/gateways/threadFetch.gitlab.gateway.js';
export async function handleGitLabWebhook(
request: FastifyRequest,
reply: FastifyReply
): Promise<void> {
const threadFetch = new GitLabThreadFetchGateway(executor); // direct instantiation!
const threads = await threadFetch.fetch(mrId);
// ...
}
// ✅ Good: depend on the abstraction, inject from the composition root
// 1. Abstraction lives in the entities (domain) layer
// src/entities/thread/threadFetch.gateway.ts
export interface ThreadFetchGateway {
fetch(mrId: MergeRequestId): Promise<Thread[]>;
}
// 2. Controller receives the abstraction via typed Dependencies
export interface GitLabWebhookDependencies {
threadFetch: ThreadFetchGateway;
}
export async function handleGitLabWebhook(
request: FastifyRequest,
reply: FastifyReply,
deps: GitLabWebhookDependencies
): Promise<void> {
const threads = await deps.threadFetch.fetch(mrId);
// ...
}
// 3. Composition root wires the concrete implementation
// src/main/routes.ts
app.post('/webhooks/gitlab', async (request, reply) => {
await handleGitLabWebhook(request, reply, {
threadFetch: new GitLabThreadFetchGateway(executor),
});
});
┌─────────────────────────────────────────────────────┐
│ Frameworks │
│ (Fastify, Claude CLI, p-queue) │
├──────────────────────────┬──────────────────────────┤
│ │ │
│ ┌──────────────────────▼──────────────────────┐ │
│ │ Interface Adapters │ │
│ │ (Webhook controllers, Presenters, │ │
│ │ platform Gateway implementations) │ │
│ └──────────────────────┬──────────────────────┘ │
│ │ │
│ ┌──────────────────────▼──────────────────────┐ │
│ │ Application Layer │ │
│ │ (Use Cases, Gateway interfaces) │ │
│ └──────────────────────┬──────────────────────┘ │
│ │ │
│ ┌──────────────────────▼──────────────────────┐ │
│ │ Domain Layer │ │
│ │ (TrackedMr, ReviewContext, ReviewScore) │ │
│ └─────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────┘
↑ Source code dependencies point INWARD
↓ Control flow can point either direction
"The SOLID principles tell us how to arrange our functions and data structures into classes, and how those classes should be interconnected." — p.58
"The goal of the principles is the creation of mid-level software structures that: tolerate change, are easy to understand, and are the basis of components that can be used in many software systems." — p.58
"Violating OCP is the most common way of creating fragile designs." — p.71
まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
Guide for creating optimized Claude Code agents. Use to design a new specialized agent, a swarm sub-agent, or a multi-agent workflow. Follows the Skill → Agent (preloaded skills) → Skill orchestration pattern.
日本語の概要は準備中です。原文の説明を表示しています。
Anti-overengineering guide based on YAGNI. Use before adding an architectural pattern, during code review, or to challenge an overly complex implementation.
日本語の概要は準備中です。原文の説明を表示しています。
Clean Architecture (Uncle Bob) guide for this project. Use when creating modules, entities, use cases, presenters, controllers, gateways, guards, services. Contains tactical patterns and structure conventions.
日本語の概要は準備中です。原文の説明を表示しています。
Audit documentation for duplication, staleness, language issues, and verbosity. Read-only — produces an actionable report.
日本語の概要は準備中です。原文の説明を表示しています。
Local auto-review of modified code (no GitLab/GitHub). Runs 5 sequential audits and generates a local report. Ideal for validating code before creating a MR/PR.
日本語の概要は準備中です。原文の説明を表示しています。
Clean Code (Robert C. Martin) guide to produce and challenge code that is readable, durable, simple, and consistent. Covers naming, functions, comments, smells, and refactor heuristics. Complements `/solid` (SOLID principles) and `/anti-overengineering` (YAGNI/KISS). Activate during the REFACTOR phase of the TDD cycle and during implementation self-review.
日本語の概要は準備中です。原文の説明を表示しています。