Agent skill
software-architect
Install this agent skill to your Project
npx add-skill https://github.com/ravigummadi/software-architect-plugin/tree/main/skills/software-architect
SKILL.md
Software Architect
Expert architecture analysis based on John Ousterhout's "A Philosophy of Software Design" (2nd Edition) and Jeff Dean's Performance Hints.
Core Principle
Complexity is the enemy. It manifests as:
- Change amplification - small changes touch many places
- Cognitive load - too much to know to make a change
- Unknown unknowns - not knowing what you don't know
Root causes: Dependencies (can't understand in isolation) and Obscurity (important info not obvious).
Sub-Agent Execution Strategy
When running as a sub-agent, follow this efficient pattern:
1. STRUCTURE SCAN (single Glob)
→ Glob **/*.{py,ts,js,go,rs,java} to map codebase
2. ENTRY POINT READ (1-2 files)
→ Read main entry files (main.*, index.*, app.*)
3. TARGETED ANALYSIS (mode-specific)
→ Use grep patterns below for the requested mode
→ Read only flagged files
4. REPORT
→ Use output template for mode
→ Cite file:line for every finding
Token Budget: Aim for <20 file reads per analysis. Quality over quantity.
The 9 Red Flags
| Flag | Symptom | Fix | Detection Pattern |
|---|---|---|---|
| Shallow Module | Interface ~ implementation complexity | Combine modules or rethink abstraction | Classes <50 lines with many public methods |
| Information Leakage | Same knowledge in multiple modules | Centralize in one module | Same constant/format in multiple files |
| Temporal Decomposition | Structure follows execution order | Structure by information hiding | Files named step1, step2, phase1, etc. |
| Overexposure | Must know rare features for common case | Hide behind sensible defaults | Functions with >5 parameters |
| Pass-Through Method | Just delegates to similar method | Merge layers or add value | return self.x.method() patterns |
| Repetition | Same pattern in multiple places | Extract to single location | Duplicate code blocks |
| Special-General Mixture | Special-case code in general mechanism | Push special code to higher layer | if type == "special" in generic code |
| Conjoined Methods | Can't understand one without the other | Make methods self-contained | Methods always called together |
| Hard to Name | Difficulty naming = unclear purpose | Rethink responsibilities | Names: Manager, Handler, Processor, Utils |
Grep Patterns for Red Flag Detection
# Shallow Module - many public, little implementation
Grep: "^(export |public )" → count per file, flag if ratio > 0.3
# Information Leakage - same magic values
Grep: "(0x[0-9A-F]+|[A-Z_]{4,}.*=.*[0-9]+)" → find duplicates across files
# Pass-Through Methods
Grep: "return (self|this)\.[a-z]+\.[a-z]+\("
# Overexposure - too many parameters
Grep: "def |function |fn |func " → Read and count params, flag if >5
# Hard to Name
Grep: "(Manager|Handler|Processor|Helper|Utils|Misc|Common|Base)(\.|::|\(|$)"
Deep Module Principle
Deep: Simple interface, significant hidden functionality (good). Shallow: Interface complexity ~ implementation complexity (bad).
DEEP SHALLOW
┌────────┐ ┌──────────────────┐
│interface│ │ interface │
├────────┤ ├──────────────────┤
│ │ │ implementation │
│ impl │ └──────────────────┘
│ │
└────────┘
Functional Core / Imperative Shell (FCIS)
| Layer | Contains | Characteristics |
|---|---|---|
| Core | Business logic, rules, transformations | Pure functions, no I/O, easily tested |
| Shell | I/O, DB, network, external services | Thin, orchestrates core, hard to test |
Verify: Core has no imports from shell. Shell calls core, not vice versa.
Performance Red Flags
| Pattern | Problem | Fix |
|---|---|---|
| Allocation in hot loop | Memory pressure | Reuse buffers, pre-size |
| Lock per operation | Contention | Batch under single lock |
| O(N) where O(1) works | Algorithmic waste | Hash tables, precompute |
| Logging in hot path | Cost even disabled | Remove or sample 1-in-N |
| Creating clients per request | Connection overhead | Reuse/pool clients |
| Sequential I/O | Latency stacking | Parallelize independent calls |
Quick Reference Numbers
| Operation | Latency |
|---|---|
| L1 cache | 0.5 ns |
| L2 cache | 7 ns |
| Main memory | 100 ns |
| SSD read | 150 us |
| Network (same DC) | 0.5 ms |
Strategic vs Tactical Programming
| Approach | Mindset | Result |
|---|---|---|
| Tactical | "Just get it working" | Accumulates complexity, creates debt |
| Strategic | "Invest 10-20% in design" | Pays dividends, faster long-term |
Tactical Red Flags
- Features added without refactoring
- "We'll fix it later" comments
- Copy-paste with minor changes
- No abstractions, just raw implementation
- Growing functions instead of extracting
The Tactical Tornado: Prolific coder who ships fast but leaves complexity. Management sees hero; codebase sees villain.
# Detect tactical patterns
Grep: "TODO|FIXME|HACK|XXX|TEMPORARY|WORKAROUND"
Grep: "# fix later|// fix later|fix this later"
Comments & Documentation (Ch 12-16)
What Comments Should Capture
- Intent - Why, not what
- Design decisions - Rationale for choices
- Non-obvious behavior - Edge cases, gotchas
- Cross-module concerns - How pieces fit together
Comment Red Flags
| Bad | Why | Better |
|---|---|---|
// increment i |
Repeats code | Don't write it |
// loop through users |
Obvious | State the purpose |
// returns the value |
No information | State what value means |
Good Comment Patterns
# Low-level: Add precision
timeout = 30 # seconds, chosen to exceed max DB query time
# High-level: Add intuition
# This module handles all authentication flows. External callers
# should only use authenticate() - internal methods handle OAuth,
# SAML, and password flows transparently.
# Interface: Contract documentation
def process(data: bytes) -> Result:
"""Transform raw sensor data into calibrated measurements.
Args:
data: Raw bytes from sensor, must be exactly 64 bytes
Returns:
Result with .values (list of floats) or .error (string)
Note:
Thread-safe. Calibration loaded once at module init.
"""
Detection Patterns
# Missing interface docs
Grep: "^(def |function |class |interface )" → check for docstring/JSDoc
# Useless comments (repeats code)
Grep: "// (get|set|return|increment|decrement|loop|iterate)"
# Good: Design rationale
Grep: "(because|reason|tradeoff|alternative|chose|decision)"
Naming Conventions (Ch 14)
Properties of Good Names
- Precise - Says exactly what it is
- Consistent - Same concept = same name everywhere
Naming Red Flags
| Bad | Problem | Better |
|---|---|---|
data, info, item |
Too vague | userProfile, orderData |
temp, tmp, x |
Meaningless (unless tiny scope) | Describe the value |
processData() |
What kind of processing? | validateUserInput() |
handleStuff() |
Stuff? | routeIncomingRequest() |
doWork() |
What work? | calculateTaxes() |
Loop Variable Rule
i, j, k- OK for tiny loops (< 10 lines)- Larger loops need descriptive names:
userIndex,rowNum
Consistency Rule
Pick one name per concept and use it everywhere:
uservscustomervsclient- pick ONEfetchvsgetvsretrieve- pick ONEcreatevsmakevsbuild- pick ONE
# Detect naming issues
Grep: "\b(data|info|temp|tmp|result|value|item|obj|thing)\b" -i
# Detect inconsistency - look for synonyms
Grep: "(get|fetch|retrieve|load|read)[A-Z]" → should be consistent
Grep: "(user|customer|client|account)" → should be consistent
Consistency (Ch 17)
Why Consistency Matters
- Reduces cognitive load (learn once, apply everywhere)
- Enables safe assumptions
- Makes code predictable
What to Keep Consistent
| Area | Example |
|---|---|
| Naming | Always userId, never user_id or uid |
| Error handling | Always throw, or always return errors |
| Async patterns | Always promises, or always callbacks |
| File structure | components/Foo/Foo.tsx, Foo.test.tsx, Foo.styles.ts |
The "Better Idea" Trap
"Having a better idea is NOT a sufficient excuse to introduce inconsistency."
If changing convention, change it everywhere or don't change it.
# Detect inconsistency
Grep: "(snake_case|camelCase)" → mixing styles
Grep: "Promise|callback|async.*await" → mixing async patterns
Grep: "(throw|return.*error|return.*null)" → mixing error patterns
Design It Twice
Before implementing, design at least two different approaches:
- Compare tradeoffs explicitly
- Pick best fit for requirements
- Even a quick comparison improves design
When to Apply
- New subsystems
- Complex algorithms
- Public interfaces
- Architectural decisions
Define Errors Out of Existence (Ch 10)
Instead of adding error handling, redefine the operation so errors can't occur:
| Problem | Bad | Good |
|---|---|---|
| Delete non-existent key | Throw KeyNotFound | No-op (success) |
| Substring past end | Throw OutOfBounds | Return partial |
| Divide by zero | Throw DivideByZero | Define as 0 or ∞ |
# Detect overactive error handling
Grep: "throw|raise|panic" → count, high ratio may indicate opportunity
Grep: "try.*catch|except|rescue" → same analysis
Analysis Modes
| Mode | Command | Focus |
|---|---|---|
red-flags |
/software-architect red-flags |
Scan for 9 red flags |
depth |
/software-architect depth |
Module depth analysis |
complexity |
/software-architect complexity |
3 complexity metrics |
fcis |
/software-architect fcis |
Core/shell separation |
performance |
/software-architect performance |
Performance patterns |
split |
/software-architect split |
Split vs combine advice |
comments |
/software-architect comments |
Comment quality review |
naming |
/software-architect naming |
Naming convention check |
consistency |
/software-architect consistency |
Codebase consistency |
tactical |
/software-architect tactical |
Strategic vs tactical audit |
review <file> |
/software-architect review src/foo.py |
Review specific file |
| (none) | /software-architect |
General review |
Analysis Process
- Explore - Use
Globfor structure,Grepfor patterns,Readfor details - Identify - Match against red flags / principles above
- Assess - Rate severity: critical > high > medium > low
- Report - Cite
file:line, explain fix, prioritize by impact
Output Templates
General / Review Mode
## Summary
[1-2 sentences]
## Issues
| Issue | Location | Severity | Fix |
|-------|----------|----------|-----|
## Strengths
[What's done well]
## Recommendations
1. [Highest priority first]
Red Flags Mode
| Flag | Location | Severity | Evidence | Fix |
|---|
Depth Mode
| Module | Interface | Implementation | Rating | Notes |
|---|
Complexity Mode
| Metric | Score (1-5) | Evidence |
|---|---|---|
| Change Amplification | ||
| Cognitive Load | ||
| Unknown Unknowns |
FCIS Mode
Core Layer:
- [module] - Pure/Impure - Notes
Shell Layer:
- [module] - Notes
Violations: [Any core importing shell, I/O in core, etc.]
Performance Mode
| Pattern | Location | Severity | Current | Fix |
|---|
Split Mode
## Current State
[Description]
## Recommendation: [Split/Keep Combined]
**Rationale:** [Why]
**If splitting:**
- Component A: [responsibility]
- Component B: [responsibility]
Comments Mode
## Comment Quality Summary
| Category | Count | Assessment |
|----------|-------|------------|
| Interface docs | | |
| Design rationale | | |
| Useless (repeats code) | | |
| Missing (public APIs) | | |
## Issues
| Location | Problem | Suggestion |
|----------|---------|------------|
## Recommendations
1. [Priority-ordered fixes]
Naming Mode
## Naming Analysis
| Category | Finding |
|----------|---------|
| Vague names | [list] |
| Inconsistencies | [list] |
| Overly generic | [list] |
## Recommendations
| Current | Suggested | Reason |
|---------|-----------|--------|
Consistency Mode
## Consistency Audit
| Area | Convention A | Convention B | Files Affected |
|------|--------------|--------------|----------------|
## Recommendation
Pick [A/B] because [reason]. Update these files: [list]
Tactical Mode
## Technical Debt Indicators
| Pattern | Count | Locations |
|---------|-------|-----------|
| TODO/FIXME/HACK | | |
| "Fix later" comments | | |
| Copied code blocks | | |
| Giant functions | | |
## Assessment
Strategic score: [1-10]
## Recommendations
1. [How to reduce tactical debt]
Key Heuristics
Split if: Truly independent, different rates of change, general vs special-purpose.
Combine if: Share information, combining simplifies interface, hard to understand separately.
Pull complexity down: Module developer suffers so users don't.
Define errors out: Redefine semantics so errors become normal cases.
Different layer = different abstraction: Adjacent layers with similar abstractions = problem.
Language-Specific Patterns
Python
# Entry points
Glob: "**/main.py", "**/__main__.py", "**/app.py", "**/wsgi.py"
# Module structure
Glob: "**/__init__.py" → map package hierarchy
# Red flags
Grep: "from.*import \*" → star imports (information leakage)
Grep: "global " → global state
Grep: "except:" → bare except (overactive error handling)
TypeScript/JavaScript
# Entry points
Glob: "**/index.{ts,js}", "**/main.{ts,js}", "**/app.{ts,js}"
# Red flags
Grep: "any" → type: any (defeats type safety)
Grep: "as any" → type assertions (same)
Grep: "// @ts-ignore" → suppressed errors
Grep: "export \*" → barrel exports (information leakage)
Go
# Entry points
Glob: "**/main.go", "**/cmd/**/*.go"
# Red flags
Grep: "interface\{\}" → empty interface (no type safety)
Grep: "panic\(" → panic in library code
Grep: "_ =" → ignored errors
Rust
# Entry points
Glob: "**/main.rs", "**/lib.rs"
# Red flags
Grep: "unwrap\(\)" → panicking unwrap
Grep: "expect\(" → panicking expect
Grep: "unsafe " → unsafe blocks
Java
# Entry points
Glob: "**/Main.java", "**/Application.java", "**/*Application.java"
# Red flags
Grep: "catch.*Exception.*\{\s*\}" → empty catch
Grep: "public class.*\{" → check file line count (God class)
Grep: "@SuppressWarnings" → suppressed warnings
Quick Reference Checklists
Pre-Review Checklist (Run These Greps First)
1. Glob **/*.{ext} → understand file count and structure
2. Grep "TODO|FIXME|HACK" → find debt markers
3. Grep "Manager|Handler|Utils" → find naming smells
4. Grep "^(class|def|function|interface)" → map abstractions
5. Read entry point files → understand flow
Module Depth Checklist
For each major module, answer:
- Interface line count vs implementation line count?
- How many concepts must caller understand?
- What details are hidden from caller?
- Rating: Deep / Medium / Shallow
FCIS Verification Checklist
- Can I identify "core" (pure logic) modules?
- Can I identify "shell" (I/O) modules?
- Does core import from shell? (violation)
- Is business logic mixed with I/O? (violation)
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
git-guardrails-claude-code
Set up Claude Code hooks to block dangerous git commands (push, reset --hard, clean, branch -D, etc.) before they execute. Use when user wants to prevent destructive git operations, add git safety hooks, or block git push/reset in Claude Code.
edit-article
Edit and improve articles by restructuring sections, improving clarity, and tightening prose. Use when user wants to edit, revise, or improve an article draft.
migrate-to-shoehorn
Migrate test files from `as` type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace `as` in tests, or needs partial test data.
obsidian-vault
Search, create, and manage notes in the Obsidian vault with wikilinks and index notes. Use when user wants to find, create, or organize notes in Obsidian.
setup-pre-commit
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
scaffold-exercises
Create exercise directory structures with sections, problems, solutions, and explainers that pass linting. Use when user wants to scaffold exercises, create exercise stubs, or set up a new course section.
Didn't find tool you were looking for?