| name | architecture |
| user-invocable | true |
| description | Analyze software architecture — map current structure, identify gaps, and provide actionable suggestions. Also serves as a patterns reference for Clean Architecture, DDD, and entropy reduction. |
| version | 2.0.0 |
| status | active |
| packages | ["shared","app","extension","api"] |
| dependencies | [] |
| last_updated | 2026-04-03 |
| last_verified | 2026-04-03 |
Architecture Skill
Analyze the coop codebase architecture: map current state, identify structural gaps, and provide actionable improvement suggestions. Also a reference for design patterns and entropy reduction.
Invocation
/architecture # Full analysis (all packages)
/architecture shared # Scope to one package
/architecture --focus boundaries # Focus on a specific lens
/architecture --focus dependencies # Dependency health only
/architecture --focus complexity # Complexity hotspots only
Analysis Workflow
When invoked as /architecture, execute these phases in order. Output findings as chat — do NOT edit files (read-only session).
Phase 1: Structure Map
Build a current-state map of the codebase. For each package in scope:
- Module inventory — list top-level modules/directories with a one-line purpose
- Export surface — count public exports vs internal modules (barrel health)
- Dependency graph — map which packages import from which, flag circular deps
- Size profile — approximate line counts per module to spot bloat
Output as a table per package:
| Module | Purpose | Exports | Lines | Imports From |
|--------|---------|---------|-------|-------------|
Phase 2: Boundary Analysis
Check module boundaries against Coop architecture principles:
- Import discipline — flag any deep imports bypassing
@coop/shared barrels
- Layer violations — flag UI code in shared, business logic in components, framework code in domain
- Bounded context bleed — flag modules reaching into other modules' internals
- Shared surface health — are shared exports well-organized or becoming a junk drawer?
Severity: violation (must fix) | smell (should investigate) | note (worth knowing)
Phase 3: Gap Analysis
Identify structural gaps — things that are missing or misaligned:
- Missing abstractions — concrete dependencies where ports/adapters should exist
- Orphaned code — modules with no importers or unclear purpose
- Inconsistent patterns — same problem solved differently in different places
- Missing boundaries — logic that should be separated but isn't
- Test coverage gaps — modules with complex logic but no tests
- Documentation gaps — public APIs without clear contracts
Phase 4: Complexity Hotspots
Find the areas most likely to cause problems:
- High fan-in files — files imported by many others (fragile change points)
- High fan-out files — files importing many others (coupling magnets)
- Deep nesting — modules with deep directory trees or call chains
- God modules — files over 500 lines or modules doing too many things
- Churn candidates — areas where the same patterns repeat (abstraction opportunities)
Phase 5: Recommendations
Synthesize findings into prioritized, actionable suggestions:
| Priority | Category | Suggestion | Effort | Impact |
|---|
| P1 | ... | ... | S/M/L | ... |
Categories: boundary, abstraction, deletion, consistency, testing, performance
Effort: S (< 1 hour), M (half day), L (multi-day)
Group by theme. Lead with high-impact, low-effort wins. End with strategic suggestions that require planning.
Phase 6: Architecture Scorecard
Rate the overall architecture health (1-5) across these dimensions:
| Dimension | Score | Trend | Notes |
|---|
| Modularity | ?/5 | ↑↓→ | Are boundaries clean? |
| Cohesion | ?/5 | ↑↓→ | Do modules have single responsibilities? |
| Coupling | ?/5 | ↑↓→ | Can modules change independently? |
| Simplicity | ?/5 | ↑↓→ | Is complexity justified? |
| Consistency | ?/5 | ↑↓→ | Same patterns everywhere? |
| Testability | ?/5 | ↑↓→ | Can you test without infrastructure? |
Focus Modes
When --focus is specified, run only the relevant phase(s):
| Focus | Phases |
|---|
boundaries | Phase 2 + Phase 6 (modularity, cohesion, coupling) |
dependencies | Phase 1 (dependency graph) + Phase 2 (import discipline) |
complexity | Phase 4 + Phase 5 (hotspots → recommendations) |
gaps | Phase 3 + Phase 5 (gaps → recommendations) |
scorecard | Phase 6 only (quick health check) |
Execution Notes
- Read-only: This skill analyzes — it never edits files. Findings go to chat output.
- Use subagents: For full analysis across all packages, spawn Explore agents in parallel per package.
- Respect scope: When scoped to a package, only analyze that package and its immediate dependencies.
- Be specific: Every finding must reference a file path and line range. No vague observations.
- Coop context: Validate against the architecture defined in CLAUDE.md (local-first, passkey-first, browser-first, barrel imports, shared module location).
Part 1: Reducing Entropy
The Goal
Less total code in the final codebase - not less code to write right now.
- Writing 50 lines that delete 200 lines = net win
- Keeping 14 functions to avoid writing 2 = net loss
- "No churn" is not a goal. Less code is the goal.
Measure the end state, not the effort.
Three Questions
1. What's the smallest codebase that solves this?
Not "what's the smallest change" - what's the smallest result.
- Could this be 2 functions instead of 14?
- Could this be 0 functions (delete the feature)?
- What would we delete if we did this?
2. Does the proposed change result in less total code?
Before: X lines
After: Y lines
If Y > X -> Question the change
If Y < X -> Good direction
3. What can we delete?
Every change is an opportunity to delete:
- What does this make obsolete?
- What was only needed because of what we're replacing?
- What's the maximum we could remove?
Red Flags
| Red Flag | Reality |
|---|
| "Keep what exists" | Status quo bias. The question is total code, not churn. |
| "This adds flexibility" | Flexibility for what? YAGNI. |
| "Better separation of concerns" | More files/functions = more code. Separation isn't free. |
| "Type safety" | Worth how many lines? Sometimes runtime checks win. |
| "Easier to understand" | 14 things are not easier than 2 things. |
Prioritization
When trade-offs arise: Maintainability > Speed > Brevity
Protect the existing architecture over shipping fast.
Part 2: The Cathedral Test
Before writing code, run this mental checklist. Hold the "cathedral" (system architecture) in mind while laying this "brick" (specific change).
1. What Cathedral Am I Building?
Identify the system-level design this change supports:
| Domain | Coop Cathedral | Key Pattern |
|---|
| Local data | Dexie for structured persistence | useLiveQuery for reactive reads |
| Sync | Yjs CRDTs + y-webrtc | Y.Doc per coop, rooms per session |
| State management | Zustand with granular selectors | Never (s) => s, always specific fields |
| Auth | Passkey-first, Safe-based identity | useAuth from shared, never local |
| Module location | ALL shared logic in @coop/shared | Never define hooks in app/extension |
| Onchain | Safe + ERC-4337 via viem/permissionless | Mock/live mode via env var |
Ask: "Which cathedral does this change belong to?"
2. Does This Brick Fit?
Find the most similar existing file and verify alignment:
| Check | Example Reference |
|---|
| Naming conventions | useCoopMembers -> use[Domain][Action] |
| Error handling | Categorized errors, user-friendly messages |
| State updates | Dexie writes or Zustand actions |
| Sync handling | Yjs doc updates, room lifecycle |
| Import structure | import { x } from '@coop/shared' |
Reference file: [identify the closest existing implementation]
3. Hidden Global Costs?
Check architectural rules:
| Rule | Check | Fix |
|---|
| Timer Cleanup | Raw setTimeout/setInterval? | Use cleanup in useEffect |
| Event Listeners | Missing removeEventListener? | Use { once: true } or cleanup |
| Async Mount Guard | Async in useEffect without guard? | Use isMounted pattern |
| Zustand Selectors | (s) => s pattern? | Never (s) => s, use granular selectors |
| Dexie Reactivity | Manual polling for DB changes? | Use useLiveQuery |
| Chained useMemo | useMemo depending on useMemo? | Combine into single |
| Context Values | Inline object in Provider value? | Wrap in useMemo |
Additional checks:
4. Explain Non-Obvious Violations
When you spot a non-obvious violation:
- Explain the principle being violated
- Then suggest the fix
For obvious violations (missing cleanup, hardcoded addresses), the fix is self-explanatory.
Part 3: Design Patterns
Clean Architecture (Uncle Bob)
Layers (dependencies point inward):
+---------------------------------------------+
| Frameworks & Drivers | <- UI, Database, External
+---------------------------------------------+
| Interface Adapters | <- Controllers, Gateways
+---------------------------------------------+
| Use Cases | <- Application Logic
+---------------------------------------------+
| Entities | <- Business Rules
+---------------------------------------------+
Key Principles:
- Dependencies point inward only
- Inner layers independent of outer layers
- Business logic framework-agnostic
- Testable without external infrastructure
Hexagonal Architecture (Ports & Adapters)
interface ArchiveGateway {
upload(content: Uint8Array, meta: ArchiveMeta): Promise<ArchiveResult>;
}
class StorachaAdapter implements ArchiveGateway {
async upload(content: Uint8Array, meta: ArchiveMeta): Promise<ArchiveResult> {
return storachaClient.upload(content, meta);
}
}
class PublishService {
constructor(private archive: ArchiveGateway) {}
async publishDraft(draft: Draft): Promise<void> {
await this.archive.upload(draft.content, draft.meta);
}
}
Domain-Driven Design (DDD)
Tactical Patterns:
class InviteCode {
constructor(readonly code: string) {
if (code.length < 6) throw new Error("Invite code too short");
}
}
class Coop {
constructor(
readonly safeAddress: Address,
private name: string,
private members: Member[]
) {}
addMember(member: Member): void {
this.members.push(member);
}
}
class Draft {
publish(author: Member): void {
if (this.status !== DraftStatus.Ready) {
throw new Error("Can only publish ready drafts");
}
this.status = DraftStatus.Published;
}
}
Part 4: Coop Application
Current Architecture
| Pattern | Implementation |
|---|
| Ports | @coop/shared interfaces |
| Adapters | Package-specific implementations |
| Bounded Contexts | extension (browser experience), app (receiver/landing) |
| Persistence | Dexie tables + Yjs documents |
When Adding Features
- Define the domain entity in
shared/src/types/
- Create port interface in
shared/src/modules/ or shared/src/hooks/
- Implement adapter using existing infrastructure
- Keep business logic in domain, not UI
Directory Structure
Current structure (packages/shared/src/):
+-- flows/ # XState state machines
+-- hooks/ # React hooks
+-- modules/ # Business logic modules (auth, coop, storage, archive, onchain)
+-- providers/ # React context providers
+-- stores/ # Zustand state stores
+-- types/ # TypeScript type definitions
Note: Domain entities are defined in types/. Imports should use @coop/shared barrel exports.
Anti-Patterns
| Anti-Pattern | Problem |
|---|
| Anemic Domain | Entities with only data, no behavior |
| Framework Coupling | Business logic knows about browser APIs |
| Fat Controllers | Business logic in React components |
| Missing Abstractions | Concrete dependencies everywhere |
| Over-Engineering | DDD for simple CRUD operations |
Best Practices Summary
- Dependencies point inward — UI depends on domain, never reverse
- Small interfaces — Interface segregation
- Domain logic separate — No framework code in entities
- Test without infrastructure — Mock adapters, test domain
- Bounded contexts — Clear boundaries between domains
- Ubiquitous language — Same terms in code and conversation
- Bias toward deletion — Measure the end state
- Rich domain models — Behavior with data
Related Skills
react — Component composition and state management patterns
testing — TDD workflow that drives architectural decisions
performance — Bundle analysis and optimization that validate architecture
migration — Cross-package migration when architecture evolves