-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add improve-architecture plugin #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ba530a3
1987d06
f85806c
5112af3
3299420
d7f6218
dae2f83
10903a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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"] | ||
| } |
| 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. |
| 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: | ||
|
|
||
| ```markdown | ||
| ## <candidate title> | ||
|
|
||
| - status: proposed | selected | agreed-shape | rejected | ||
| - files: <comma-separated paths> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
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. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 👍 / 👎.