From 3f6f642f6bd7bf706041907c3f57cb19746968e6 Mon Sep 17 00:00:00 2001 From: Giancarmine Salucci Date: Tue, 23 Jun 2026 00:54:40 +0200 Subject: [PATCH] feat: portable cross-runtime code-simplification skill ast-grep-driven detection + ranking into a JSON ledger, two-track apply (deterministic autofix + model span-edits), configurable report/apply modes. Rule packs for JS/TS, Python, Go, Rust, Java; Svelte/SvelteKit support via project tooling + opt-in grammar. Runtime-neutral SKILL.md (Agent Skills spec). Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitattributes | 4 + .gitignore | 13 ++ README.md | 59 ++++++++ SKILL.md | 233 ++++++++++++++++++++++++++++++ assets/ledger.schema.json | 90 ++++++++++++ bin/README.md | 40 +++++ bin/VERSION | 1 + bin/checksums.txt | 1 + fixtures/EXAMPLE-findings.json | 146 +++++++++++++++++++ fixtures/go/messy.go | 23 +++ fixtures/java/Messy.java | 23 +++ fixtures/js/messy.js | 21 +++ fixtures/py/messy.py | 24 +++ fixtures/rust/messy.rs | 21 +++ fixtures/ts/messy.ts | 40 +++++ references/DETECTION.md | 95 ++++++++++++ references/OPTIMIZATION.md | 54 +++++++ references/PATTERNS.md | 107 ++++++++++++++ references/PORTABILITY.md | 77 ++++++++++ references/SVELTE.md | 102 +++++++++++++ rules/go/complexity.yml | 38 +++++ rules/go/simplify.yml | 19 +++ rules/java/complexity.yml | 38 +++++ rules/java/simplify.yml | 18 +++ rules/javascript/complexity.yml | 38 +++++ rules/javascript/simplify.yml | 41 ++++++ rules/manifest.json | 54 +++++++ rules/python/complexity.yml | 43 ++++++ rules/python/simplify.yml | 49 +++++++ rules/rust/complexity.yml | 39 +++++ rules/rust/simplify.yml | 18 +++ rules/svelte/runes.yml.example | 53 +++++++ rules/svelte/template.yml.example | 21 +++ rules/typescript/complexity.yml | 46 ++++++ rules/typescript/simplify.yml | 47 ++++++ sgconfig.yml | 40 +++++ 36 files changed, 1776 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 README.md create mode 100644 SKILL.md create mode 100644 assets/ledger.schema.json create mode 100644 bin/README.md create mode 100644 bin/VERSION create mode 100644 bin/checksums.txt create mode 100644 fixtures/EXAMPLE-findings.json create mode 100644 fixtures/go/messy.go create mode 100644 fixtures/java/Messy.java create mode 100644 fixtures/js/messy.js create mode 100644 fixtures/py/messy.py create mode 100644 fixtures/rust/messy.rs create mode 100644 fixtures/ts/messy.ts create mode 100644 references/DETECTION.md create mode 100644 references/OPTIMIZATION.md create mode 100644 references/PATTERNS.md create mode 100644 references/PORTABILITY.md create mode 100644 references/SVELTE.md create mode 100644 rules/go/complexity.yml create mode 100644 rules/go/simplify.yml create mode 100644 rules/java/complexity.yml create mode 100644 rules/java/simplify.yml create mode 100644 rules/javascript/complexity.yml create mode 100644 rules/javascript/simplify.yml create mode 100644 rules/manifest.json create mode 100644 rules/python/complexity.yml create mode 100644 rules/python/simplify.yml create mode 100644 rules/rust/complexity.yml create mode 100644 rules/rust/simplify.yml create mode 100644 rules/svelte/runes.yml.example create mode 100644 rules/svelte/template.yml.example create mode 100644 rules/typescript/complexity.yml create mode 100644 rules/typescript/simplify.yml create mode 100644 sgconfig.yml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ade629c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# Engine binaries are gitignored (see .gitignore). If you re-enable committing them +# and have git-lfs, uncomment to track them with LFS: +# bin/**/ast-grep filter=lfs diff=lfs merge=lfs -text +# bin/**/ast-grep.exe filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aacafc0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Bundled engine binaries are large (~50 MB) and platform-specific. They are NOT +# committed (no git-lfs here); they are fetched on first run or at packaging time. +# See bin/README.md. The local working tree keeps them so installed skills run offline. +bin/**/ast-grep +bin/**/ast-grep.exe +grammars/ + +# Skill runtime output (per-project ledger / reports), never part of the skill. +simplify/ + +# OS / editor noise +.DS_Store +*.swp diff --git a/README.md b/README.md new file mode 100644 index 0000000..2d6a3cd --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# simplify-code + +A portable [Agent Skill](https://agentskills.io/specification) that simplifies a +codebase **safely and incrementally** from any agent runtime — Claude Code, GitHub +Copilot (CLI / VS Code), pi, Codex CLI, Gemini CLI, Cursor. + +It reduces complexity, nesting, duplication, magic numbers, dead code, and long +functions **while preserving behavior** — detecting opportunities mechanically with a +bundled [`ast-grep`](https://ast-grep.github.io/) engine, ranking the biggest wins, +and applying fixes one at a time with build/test verification. + +## Why it stays fast and cheap + +- **Codebase out of context.** `ast-grep` finds + ranks candidates mechanically; the + model reads only the flagged spans, from a small JSON ledger on disk. +- **Two-track apply.** Mechanical fixes are applied by deterministic `ast-grep` + autofix rules (zero model tokens, zero hallucination); only genuinely semantic + refactors go to the model. +- **Resumable.** Progress is a `status` field in `simplify/findings.json`; reruns skip + finished work. + +## Design constraints (deliberate) + +- **No Python, no `.sh`/`.ps1`/`make`.** The engine is one cross-platform binary + (identical CLI on Win/macOS/Linux); the command *sequence* lives in `SKILL.md` and + the agent issues OS-appropriate invocations. Detection rules are declarative YAML. +- **Self-contained.** `ast-grep` is bundled per platform under `bin/` (see + `bin/README.md`); no install step, works offline. +- **JSON end-to-end** for the ledger (matches `ast-grep --json`); the only YAML is + ast-grep's own mandated rule/config format. +- **Framework-agnostic.** Build/test/lint commands are inferred by the model once and + cached in the ledger — never hardcoded. + +## Layout + +``` +SKILL.md entry point (read this first) +sgconfig.yml ast-grep project config → rules/ +bin/ bundled ast-grep binary per platform +rules// ast-grep rule packs (detect + autofix) +references/ PATTERNS · DETECTION · OPTIMIZATION · PORTABILITY +assets/ ledger.schema.json +fixtures/ messy sample code for validating the skill +``` + +## Install + +Copy or symlink this directory into your runtime's skills location — see +`references/PORTABILITY.md` for per-OS, per-runtime instructions. Then ask your agent +to "simplify this codebase" (preview) or "simplify and apply". + +## Languages + +JS/TS, Python, Go, Rust, Java today (ast-grep supports 20+; add a rule pack to extend). +**Svelte/SvelteKit** is supported specially (no built-in grammar): detection leans on the +project's own Svelte tooling + model-driven refactors with SvelteKit guardrails, with an +opt-in ast-grep grammar path — see `references/SVELTE.md`. + +License: MIT. diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..69ad3d7 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,233 @@ +--- +name: simplify-code +description: >- + Simplify and refactor a codebase safely and incrementally — reduce complexity, + nesting, duplication, magic numbers, dead code, and long functions while + preserving behavior. Detects opportunities mechanically with ast-grep, ranks + the biggest wins, and applies fixes one at a time with build/test verification. + Use when asked to simplify, clean up, refactor, reduce complexity, remove dead + code, or improve readability of code in any language (JS/TS, Python, Go, Rust, + Java, Svelte/SvelteKit, and more). +license: MIT +metadata: + author: simplify-code + version: "0.1.0" +allowed-tools: Read Edit Write Bash(git:*) Bash(ast-grep:*) Bash(sg:*) +--- + +# Simplify Code + +Systematic, behavior-preserving code simplification that runs the same way in any +agent runtime (Claude Code, GitHub Copilot CLI/VS Code, pi, Codex, Gemini CLI). + +The skill keeps the codebase **out of your context**: a bundled `ast-grep` binary +finds and ranks candidates mechanically, you assemble a small JSON **ledger** on +disk, and then you touch only the flagged spans — one fix at a time, verified. + +> Throughout, "run" means execute via your shell/terminal tool; "read the span" +> means read only the indicated line range; "edit" means your native file-edit +> tool. These map to whatever each runtime calls them. + +## When to use + +Activate when the user wants to simplify / clean up / refactor / de-duplicate / +reduce complexity / remove dead code / improve readability — for a file, a +directory, or a whole repository. + +## How it works (overview) + +``` +detect (ast-grep, 0 tokens) → assemble ledger (cheap) → infer build/test/lint (once) + → baseline gate → apply top findings (Track A: ast-grep autofix | Track B: span edit) + → verify each change → report +``` + +Two modes (default **report**): +- **report** — dry-run: produce proposed diffs + `simplification-report.md`, change nothing. +- **apply** — edit in place, re-running build/test after every change. + +Pick mode from the user's words ("dry run / preview / report" → report; "apply / do it +/ fix it" → apply). If unclear, do **report** first and offer to apply. + +--- + +## Step 0 — Locate the ast-grep engine + +`ast-grep` is the only required tool and is **bundled** with this skill — no install. +Detect platform and pick the binary; fall back gracefully. + +1. Determine `-`: + - OS: Linux→`linux`, macOS/Darwin→`darwin`, Windows→`win32`. + - Arch: x86_64/amd64→`x64`, arm64/aarch64→`arm64`. +2. Use `/bin/-/ast-grep` (`ast-grep.exe` on Windows). Make it + executable if needed (`chmod +x` on Unix). +3. **If that file is missing** (fresh clone — binaries aren't committed), fetch the pinned + release once into that dir, then verify against `bin/checksums.txt`: + the version is in `bin/VERSION`; releases are at + `https://github.com/ast-grep/ast-grep/releases/download//app-.zip` + (triples: `x86_64-unknown-linux-gnu`, `aarch64-unknown-linux-gnu`, + `x86_64-apple-darwin`, `aarch64-apple-darwin`, `x86_64-pc-windows-msvc`). Or just use a + PATH `ast-grep` / install it (next step). +5. Verify: run `ast-grep --version`. +6. **Fallbacks**, in order, if the bundled binary won't run (rare arch, or macOS + Gatekeeper / Windows SmartScreen blocking an unsigned binary): + a. an `ast-grep` (or `sg`) already on `PATH`; + b. if none, tell the user the one-line install for their OS + (`npm i -g @ast-grep/cli` · `brew install ast-grep` · `cargo install ast-grep` + · `scoop install ast-grep`) and offer to continue with **LLM-heuristic + detection** (grep + reading suspicious files) — slower, less precise. + +Refer to the binary below as `AST_GREP`. + +## Step 1 — Scope the candidate files + +Never touch files git ignores. + +- In a git repo: candidates = `git ls-files` plus + `git ls-files --others --exclude-standard` (tracked + untracked-but-unignored). +- Not a git repo: ask the user which paths to include before doing anything. +- Honor any path the user named (a file, dir, or glob) by intersecting with the above. + +## Step 2 — Detect (mechanical, ~0 tokens) + +Run ast-grep with this skill's bundled rules and emit JSON: + +``` +AST_GREP scan -c /sgconfig.yml --json +``` + +- `sgconfig.yml` points at `rules/` (per-language packs: detection + autofix). +- Rules cover: redundant boolean/ternary, magic numbers, dead/unreachable code, + deep nesting, long parameter lists, simplifiable APIs, duplicate-ish patterns. +- **Optional enrichment, only if already installed** (never install, never block on + absence): `scc`, `gocyclo`, `staticcheck`, `cargo clippy`, `knip`, `jscpd`, `pmd`. + Fold their output into the ledger as extra `signal`/findings. + +See `references/DETECTION.md` for rule authoring and the full enrichment matrix. + +**Svelte / SvelteKit (`.svelte`):** ast-grep has no built-in Svelte grammar, so handle +these specially (full guide: `references/SVELTE.md`): +- Detect primarily with the project's own Svelte tooling **if present** — run + `svelte-check` (machine output), the project's `eslint` (eslint-plugin-svelte) on + `**/*.svelte`, and/or `svelte/compiler` warnings; fold results into the ledger. +- Optionally, if a tree-sitter-svelte grammar has been built and enabled in + `sgconfig.yml`, the TS/JS packs apply to `' } +# injected: typescript +# - hostLanguage: svelte +# rule: { pattern: "" } +# injected: javascript +# --------------------------------------------------------------------------- +# +# Without the grammar, Svelte is still supported: detection falls back to the +# project's own Svelte tooling (svelte-check, eslint-plugin-svelte, svelte +# compiler warnings) as enrichment, and semantic refactors go to the model with +# the SvelteKit guardrails in references/SVELTE.md.