Skip to content
6 changes: 6 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
"source": "./plugins/diagnose",
"category": "debugging",
"tags": ["debug", "diagnose", "troubleshooting", "root-cause", "regression", "skill"]
},
{
"name": "improve-architecture",
"source": "./plugins/improve-architecture",
"category": "architecture",
"tags": ["architecture", "refactoring", "deep-modules", "ousterhout", "module-design", "testability", "skill"]
}
]
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Browse and manage with `/plugin`. To refresh after updates: `/plugin marketplace
| [`guardrails`](plugins/guardrails) | Hook | Bundles four independently-toggleable PreToolUse safety guards: secret-pattern detection, hardcoded machine-path check, git hook-bypass blocking (`--no-verify`, `core.hooksPath`, `LEFTHOOK=0`), and advisory CLI-flag verification. |
| [`bug-report`](plugins/bug-report) | Skill | Turns an informal defect description into a structured five-field bug report (title, repro, expected vs actual, severity, fix location). Read-only — it captures, never fixes or files on its own. |
| [`diagnose`](plugins/diagnose) | Skill | Debugs observed failures via a disciplined six-phase loop — build a fast deterministic reproduction signal, reproduce, rank falsifiable hypotheses, instrument, fix with a regression test, then clean up and post-mortem. |
| [`improve-architecture`](plugins/improve-architecture) | Skill | Scans an existing codebase for module-level architecture friction — shallow modules, seam leaks, locality gaps — using Ousterhout's deep-module lens, presents candidates as a self-contained HTML report, and interviews the selected candidate before handing off for planning. |

Install one: `/plugin install <plugin-name>@melodic-software`.

Expand Down
11 changes: 11 additions & 0 deletions plugins/improve-architecture/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "improve-architecture",
"version": "0.1.0",
"description": "Scans an existing codebase for module-level architecture friction — shallow modules, seam leaks, and locality gaps — using Ousterhout's deep-module lens, presents candidates as a self-contained HTML report, and runs an interview loop on the selected candidate before handing off for planning.",
"author": {
"name": "Melodic Software",
"email": "info@melodicsoftware.com"
},
"keywords": ["architecture", "refactoring", "deep-modules", "ousterhout", "module-design", "testability", "skill"]
}
65 changes: 65 additions & 0 deletions plugins/improve-architecture/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# improve-architecture

A Claude Code plugin that scans an existing codebase for **module-level
architecture friction** and proposes concrete improvements. It is proactive
discovery, distinct from reviewing a diff or planning new work: it hunts for
shallow modules, seam leaks, and locality gaps in code that already exists.

The first (and default) lens implements John Ousterhout's **deep-module**
concept from *A Philosophy of Software Design* — a module is *shallow* when its
interface is nearly as complex as its implementation, and *deep* when a small
interface hides large behavior. Deepening shallow modules improves both
testability and AI/agent-navigability: a small interface lets a reader grasp a
module's purpose without traversing the whole import graph.

## What it does

1. **Explore for friction.** Walks the codebase (via a read-only exploration
subagent), reads the project's glossary and architecture decision records if
present, and applies the *deletion test* to anything suspected shallow —
would deleting it concentrate complexity, or merely move it?
2. **Present candidates.** Writes a self-contained HTML report (inline styles and
inline SVG only, no remote fetch) to the OS temp directory, one card per
candidate with a before/after diagram, a recommendation badge, and a
dependency-category badge. Alongside it, writes a durable machine-readable
candidate list that survives the session.
3. **Interview the selected candidate.** Once you pick one, walks the design tree
— constraints, dependencies, the shape of the deepened module, what sits
behind the seam, which tests survive — and records the agreed shape for a
planning step to consume.

## Invoke

```shell
/improve-architecture:improve-architecture # defaults to the deepening lens
/improve-architecture:improve-architecture deepening # explicit
```

Trigger phrases (Claude may also invoke it automatically): "improve
architecture", "find deepening opportunities", "shallow modules", "architecture
scan", "make this more testable", "module seams", "locality".

## Persistence

The durable candidate list is written to `${CLAUDE_PLUGIN_DATA}` by default. If
your project maintains its own per-task work-artifact convention (a tracked
working directory documented in your `CLAUDE.md` or rules), the skill honors that
location instead and reports the path either way.

## Configuration

This plugin has no `userConfig`. It adapts to your project through your
project's own context: its glossary (if any), its architecture decision records,
and its work-artifact convention. There is nothing to hand-edit in the plugin.

## Install

```shell
/plugin marketplace add melodic-software/claude-code-plugins
/plugin install improve-architecture@melodic-software
```

## License

MIT (SPDX-License-Identifier: MIT). See the `LICENSE` file at the root of the
`melodic-software/claude-code-plugins` repository.
62 changes: 62 additions & 0 deletions plugins/improve-architecture/skills/improve-architecture/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
name: improve-architecture
description: "Scan an existing codebase for module-level friction and architecture improvement opportunities. Explores for shallow modules (interface nearly as complex as implementation), seam leaks, and locality gaps; presents candidates as a self-contained HTML report; runs an interview loop on the selected candidate; hands off an agreed candidate shape for planning. Use when: 'improve architecture', 'find deepening opportunities', 'shallow modules', 'architecture improvement', 'Ousterhout deepening', 'make code more testable', 'make code more AI-navigable', 'find refactoring opportunities', 'what should we improve', 'architecture scan', 'codebase friction', 'module seams', 'locality'. Skip when: applying mechanical code-level tidyings (this operates at module level), reviewing a diff before merge, enforcing architecture rules on a change, or root-cause debugging a specific failure."
argument-hint: "[action] (e.g., deepening)"
user-invocable: true
disable-model-invocation: true
---

## Pre-computed context

Current branch: !`git branch --show-current 2>/dev/null || echo "unknown"`
Recent commits: !`git log --oneline -10 2>/dev/null || echo "no commits"`
Working tree status: !`git status --porcelain 2>/dev/null | head -10 || echo "clean"`

## Variables

Arguments: `$ARGUMENTS`

## Purpose

Improvement is distinct from review and planning. Review evaluates a DIFF against criteria (reactive). Planning designs NEW work (forward-looking). This skill scans EXISTING code for friction and proposes candidates for improvement (proactive).

The scan-present-pick process generalizes across improvement **lenses**. Each lens (action) brings its own analysis method and vocabulary via an `actions/<lens>.md` playbook plus a `research/<lens>/` reference set, loaded only when that lens runs. The first lens, `deepening`, implements Ousterhout's deep-module concept — finding shallow modules (interface nearly as complex as implementation) and proposing how to deepen them. The aim is **testability and AI/agent-navigability (AX)**: a deep module's small interface lets a reader — human or agent — grasp its purpose without traversing the whole import graph.

This finds existing friction — it does not plan new work, apply mechanical code-level tidyings, enforce rules on a diff, or review changes before a PR. Those are separate concerns handled by planning, tidying, rule-enforcement, and review tools respectively (see "Composition").

## Actions

| Argument | Action | What it does |
|----------|--------|-------------|
| *(empty)* | Defaults to `deepening` | Runs the deepening lens |
| `deepening` | **Deepening (Ousterhout)** | Shallow→deep module scan → HTML report → interview loop → hand off an agreed candidate for planning. Full process: `actions/deepening.md` |

One lens per invocation — lenses don't chain implicitly. Read the action's playbook for its full process.

### Adding a lens

A new improvement lens (e.g. `coupling`, `testability`, dependency-direction review) is a pure ADD — never edit an existing lens's contract to add one (open for extension, closed for modification):

- `actions/<lens>.md` — the lens playbook (phases, gates, output shape)
- `research/<lens>/` — reference for that lens, loaded only when its action runs (per-action progressive disclosure)
- one row in the Actions table above

## What this skill does NOT do

- **Does not plan implementation** — produces candidates + agreed shape; a planning step plans the work
- **Does not enforce rules** — a rule-enforcement reviewer does that reactively on a diff
- **Does not apply mechanical tidyings** — code-level tidyings (rename, extract, inline) are a separate, smaller-grained concern
- **Does not review a diff** — pre-merge review tools do that
- **Does not write code** — discovery and design skill only
- **Does not brainstorm a rough problem** — this skill hunts architecture friction on its own lenses; open-ended "how could we approach X" divergence is a brainstorming concern

## Composition

Graceful degradation — where a named step below is not available in the consuming project, inline the equivalent work in this session instead of blocking on it.

| When | Then | How |
|------|------|-----|
| A debugging pass finds an architectural root cause | Run this skill's deepening lens | Structured deepening review of the affected module |
| A candidate shape is agreed | Hand off to a planning skill if the project has one; else summarize the agreed shape for planning | Consumes the `agreed-shape` entry from the candidate artifact (see `actions/deepening.md`) |
| During the interview loop | Update the project's ubiquitous-language glossary if it maintains one | Inline term additions/sharpening as decisions crystallize |
| Post-improvement | Review the implemented changes with the project's review tool | Standard diff review |
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Deepening lens (Ousterhout)

The `deepening` action implements Ousterhout's "deepening" concept — finding shallow modules (interface nearly as complex as implementation) and proposing how to deepen them (small interface, large behavior behind it).

Three phases. Each has a hard gate before the next.

## Phase 1 — Explore for friction

Read the project's domain glossary if it maintains one — the nearest `UBIQUITOUS-LANGUAGE.md` (or equivalent), found by walking UP from the directory being examined toward the repo root and stopping at the first match (the same way `.editorconfig` / `.gitignore` resolve). Also read any architecture decision records in the area being examined.

Use the Agent tool with `subagent_type=Explore` (or any read-only exploration subagent available) to walk the codebase. Explore organically — note where friction appears:

- Where does understanding one concept require bouncing between many small modules?
- Where are modules **shallow** — interface nearly as complex as implementation?
- Where have pure functions been extracted for testability, but real bugs hide in how they're called (no **locality**)?
- Where do tightly-coupled modules leak across their **seams**?
- Where do bugs recur *at the seams between* several owned subsystems (e.g. frontend ↔ API ↔ CLI ↔ store) rather than inside any one — a signal to wrap them behind a single **deep** interface so one integration test exercises the whole flow instead of debugging each boundary?
- Which parts of the codebase are untested, or hard to test through their current **interface**?

Apply the **deletion test** to anything suspected shallow: would deleting it concentrate complexity, or move it? "Concentrates" is the signal. Full vocabulary in [../research/deepening/vocabulary.md](../research/deepening/vocabulary.md).

Classify each candidate's dependencies per [../research/deepening/dependencies.md](../research/deepening/dependencies.md) — the category determines testing strategy.

## Phase 2 — Present candidates as HTML report

Write a self-contained HTML file via a secure temp-file primitive so the path is unpredictable and permissions are restrictive. On Unix/Linux, create it with `mktemp` (e.g. `mktemp --tmpdir deepening-review-XXXXXX.html` or `mktemp -t deepening-review.XXXXXX.html`); on Windows, use a user-scoped temp under `%LOCALAPPDATA%\Temp` or equivalent. Open for user: `start <path>` on Windows, `open <path>` on macOS, `xdg-open <path>` on Linux. Report the absolute path.

Report is **self-contained — inline `<style>` + inline SVG only, no CDN or remote runtime** (a report that fetches remote assets is both a privacy and a supply-chain hazard, and breaks when opened offline). Build layout from an inline `<style>` block; draw diagrams as inline SVG or hand-built HTML/CSS — inline SVG node-and-edge for graph-shaped relationships, hand-built divs for editorial visuals (mass diagrams, cross-sections).

Each candidate gets a card with: files involved, problem (one sentence), solution (one sentence), before/after diagram, benefits in terms of **leverage** and **locality**, recommendation badge (`Strong` / `Worth exploring` / `Speculative`), dependency category badge.

End with a **Top recommendation** section. Full scaffold and diagram patterns in [../research/deepening/html-report.md](../research/deepening/html-report.md).

Use the project's domain glossary vocabulary for the domain, and [../research/deepening/vocabulary.md](../research/deepening/vocabulary.md) vocabulary for architecture.

**Durable candidate artifact.** Alongside the HTML (the human-readable companion, ephemeral in the temp dir), write a machine-readable candidate list that survives the session. Default location: `${CLAUDE_PLUGIN_DATA}/deepening-candidates-<timestamp>.md`. If the consuming project maintains its own per-task work-artifact convention (e.g. a tracked slice/working directory documented in its `CLAUDE.md` or rules), honor that instead and write the file there. Tell the user the path. This file — not the HTML — is the durable handoff a planning step consumes. One entry per candidate:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep candidate artifacts scoped to the project

When this plugin is used in more than one repository, this default writes every repo’s architecture candidate list into the same plugin-level data directory; the Claude Code reference says ${CLAUDE_PLUGIN_DATA} resolves to ~/.claude/plugins/data/{id}/, so it is keyed by plugin rather than by project (https://code.claude.com/docs/en/plugins-reference#environment-variables). These artifacts contain repo paths and design notes, so a later planning handoff or cleanup in another project can see or stale-use unrelated candidates; put them under a ${CLAUDE_PROJECT_DIR}-derived slug, or require a project-local convention before writing.

Useful? React with 👍 / 👎.


```markdown
## <candidate title>

- status: proposed | selected | agreed-shape | rejected
- files: <comma-separated paths>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Quote paths in the durable handoff

When the scanned repo contains a path with a comma or newline (valid Git filenames), this machine-readable handoff can be parsed as extra paths or even extra Markdown fields/candidates by the later planning step, because paths are emitted as one raw comma-separated scalar. The HTML report now has escaping rules, but this durable artifact is the one subsequent automation consumes; require a structured representation such as a JSON/YAML array, or explicit escaping/quoting of every codebase-derived scalar before writing it.

Useful? React with 👍 / 👎.

- dependency-category: in-process | local-substitutable | ports-and-adapters | mock
- recommendation: Strong | Worth exploring | Speculative
- problem: <one sentence>
- deepening: <one sentence — the shallow-module friction signal, not an interface proposal>
- agreed-shape: <empty until Phase 3 — filled when the user picks and the shape is grilled: interface entry points, what sits behind the seam, tests that survive>
- rejected-reason: <only if status is rejected and the reason is load-bearing>
```

End the file with `top-recommendation: <candidate title>`.

**ADR conflicts**: if a candidate contradicts an existing architecture decision record, surface only when friction is real enough to warrant revisiting. Mark clearly in the card.

Do NOT propose interfaces yet. After the report is written, ask: "Which of these would you like to explore?"

## Phase 3 — Interview loop on selected candidate

Once the user picks a candidate, walk the design tree: constraints, dependencies, shape of the deepened module, what sits behind the seam, what tests survive.

Side effects inline as decisions crystallize:

- **New concept not in the project glossary?** If the project maintains a ubiquitous-language glossary, add the term immediately rather than batching it to the end.
- **Sharpening a fuzzy term?** Update the glossary right there.
- **User rejects a candidate with a load-bearing reason?** Offer to record it as an architecture decision — only when the reason would help a future explorer avoid re-suggesting it.
- **Want to explore alternative interfaces?** See [../research/deepening/interface-design.md](../research/deepening/interface-design.md) — "Design It Twice" via parallel subagents.

When the candidate's shape is agreed, update its entry in the candidate artifact to `status: agreed-shape` and fill `agreed-shape` (interface entry points, what sits behind the seam, tests that survive). Hand off to a planning step, which consumes the `agreed-shape` entry to plan the implementation. If no dedicated planning tool is available in the project, summarize the agreed shape directly so implementation can proceed.
Loading
Loading