Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
*.tgz
.DS_Store

# Generated skill targets — source of truth is skill/; regenerated by npm run build
.agents/skills/lustra/
Expand Down
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,38 @@ All notable changes to this project are documented in this file. The format is b
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.2] - 2026-05-17

### Added

- `design` command: paradigm-aware module/package design review — SOLID for OO stacks,
cohesion/coupling/composition for Go, Rust, and functional ones. Module-scoped, distinct
from diff-scoped `review` and layout-scoped `structure`.
- `observability` command: logging and instrumentation quality — swallowed errors,
secrets/PII in logs, missing error context, absent metrics on critical paths.
- `migrate` command: guided one-major-at-a-time dependency migration with changelog
reading, codemods, and isolated verification.
- `SKILL.md` gains a shared Stack detection section; reference files point to it instead
of assuming a Node project.
- `LUSTRA_BUILD_ROOT` override in `scripts/build.js` to direct generated provider
directories elsewhere.

### Changed

- Renamed `lint` → `analyze`, `prettier` → `format`, `libs` → `deps` (the last with a
sharpened scope: health and upgrades only — deletion is `deadcode`, vulnerability
remediation is `security`, major upgrades are `migrate`).
- Decoupled the skill from the JS/npm ecosystem: every tool-running command now carries a
per-ecosystem tool table (Node/Python/Go/Rust) with an explicit fallback, instead of
hardcoding `eslint`/`prettier`/`npm`/`knip`. Now 18 commands.
- Normalized every reference file to the same structure (Purpose / Detect / Triage /
Fix policy / Report) and updated `README.md`, `SKILL.md`, and the package description.

### Fixed

- Smoke tests no longer write provider directories into the repository working tree;
builds under test target a temporary directory.

## [0.1.1] - 2026-05-17

### Changed
Expand Down
47 changes: 27 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Lustra

The code-hygiene skill that makes your AI harness clean up its own slop. 1 skill,
15 commands wrapping real tooling, from first commit to technical due diligence.
18 commands wrapping real tooling, from first commit to technical due diligence.

> Install with `npx skills add breim/lustra`, or `npm i -g lustra-cli` for a global skill.

Expand All @@ -11,31 +11,35 @@ AI writes code that runs and looks fine and is quietly wrong: dead abstractions,
error handling, tests that assert nothing, dependencies nobody uses, a green pipeline that
gates nothing. Linters catch a slice of it. The rest needs judgment on top of real tools.

Lustra runs the actual tooling — `npm audit`, `knip`, `eslint`, `tsc`, your test runner,
`prettier`, `license-checker` — then triages the output: filters false positives, ranks by
real risk, fixes only what is mechanically safe, and proposes the rest as a diff. It does
not guess where a tool would. It runs the tool and applies judgment.
Lustra detects your stack and runs its actual tooling — the dependency auditor, linter,
type checker, test runner, formatter, dead-code and license scanners — then triages the
output: filters false positives, ranks by real risk, fixes only what is mechanically
safe, and proposes the rest as a diff. It does not guess where a tool would. It runs the
tool and applies judgment.

## What's Included

15 commands under one skill, mapped to a project lifecycle. `audit` runs the diagnostic
18 commands under one skill, mapped to a project lifecycle. `audit` runs the diagnostic
ones together for a one-shot health report.

| Phase | Command | What it does |
| --- | --- | --- |
| start | `audit` | One graded health report across every dimension (due diligence) |
| start | `baseline` | Scaffold the guardrail configs for the detected stack |
| iterate | `review` | Structured correctness / design / slop review of a diff or path |
| iterate | `types` | Type-checker triage; catch `any`/`@ts-ignore` evasion |
| iterate | `types` | Type-checker triage; catch `any`/`@ts-ignore`-style evasion |
| iterate | `tests` | Run the suite, coverage on the diff, catch fake/empty tests |
| iterate | `lint` | ESLint plus AI-slop smells no rule catches |
| iterate | `prettier`| Formatting drift, fixed mechanically |
| iterate | `analyze` | The linter's findings plus AI-slop smells no rule catches |
| iterate | `format` | Formatting drift, fixed mechanically |
| polish | `security` | Exploitable defects: secrets, injection, authz, vulnerable deps |
| polish | `license` | Dependency license compatibility and IP risk |
| polish | `deadcode` | Unused files, exports, dependencies — confirmed before deletion |
| polish | `libs` | Dependency health: outdated, deprecated, duplicated, unused |
| polish | `deps` | Dependency health and upgrades: outdated, deprecated, duplicated |
| polish | `design` | Module/package design: SOLID, or cohesion/coupling for non-OO stacks |
| polish | `observability` | Logging and instrumentation quality so failures are diagnosable |
| polish | `perf` | Performance smells: N+1, blocking IO, unbounded growth, bundle weight |
| polish | `docs` | Documentation drift and undocumented public surface |
| maintain | `migrate` | Guided one-major-at-a-time dependency migration with codemods |
| maintain | `ci` | Pipeline soundness: real gates, CI security, reproducibility |
| maintain | `structure` | Detect the stack, then advise or reorganize project structure |

Expand All @@ -50,11 +54,11 @@ maintain.**

- **Start** — `audit` an inherited codebase to see what you really have; `baseline` a
fresh one so it has guardrails from day one.
- **Iterate** — while building, `review` the diff, then `types`, `tests`, `lint`,
`prettier` to keep the loop honest.
- **Polish** — before shipping, harden it: `security`, `license`, `deadcode`, `libs`,
`perf`, `docs`.
- **Maintain** — over time, `ci` and `structure` keep the project from rotting.
- **Iterate** — while building, `review` the diff, then `types`, `tests`, `analyze`,
`format` to keep the loop honest.
- **Polish** — before shipping, harden it: `security`, `license`, `deadcode`, `deps`,
`design`, `observability`, `perf`, `docs`.
- **Maintain** — over time, `migrate`, `ci` and `structure` keep the project from rotting.

For technical due diligence, `audit` is the answer: it runs security, license, supply
chain, reliability, maintainability and bus-factor checks and grades each — without
Expand Down Expand Up @@ -117,11 +121,14 @@ lustra build # regenerate the per-harness skill directorie

## Supported Tools

Lustra orchestrates tools you already use and stays out of the way when one is absent
(it says so rather than guessing): `npm audit`, `knip`, `eslint`, `tsc`, the project's
test runner (jest/vitest/mocha/pytest/…), `prettier`, `npm outdated`, `license-checker`,
and `semgrep` when present. Non-JS stacks are detected and handled with their own tooling
where available.
Lustra detects the stack first, then orchestrates the tools you already use for it and
stays out of the way when one is absent (it says so rather than guessing): the
dependency-vulnerability scanner (`npm audit`/`pip-audit`/`govulncheck`/`cargo audit`),
linter (ESLint/Ruff/`go vet`/Clippy), type checker (`tsc`/mypy/`go vet`/`cargo check`),
test runner (jest/vitest/pytest/`go test`/`cargo test`), formatter
(Prettier/Black/`gofmt`/`rustfmt`), dead-code and license scanners, and `semgrep` when
present. Each command's reference file carries its own per-ecosystem tool table; an
unknown stack falls back to static reading, flagged as lower-confidence.

## Contributing

Expand Down
33 changes: 18 additions & 15 deletions bin/lustra.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,21 +113,24 @@ Usage:
Clients: ${providers.map(p => p.provider).join(', ')}

Skill commands (inside your agent):
/lustra audit One graded health report (due diligence)
/lustra baseline Scaffold guardrail configs for the stack
/lustra review Structured review of a diff or path
/lustra types Type-checker triage, catch evasion
/lustra tests Run suite, diff coverage, catch fake tests
/lustra lint ESLint + AI-slop smells
/lustra prettier Fix formatting drift
/lustra security Find exploitable security defects
/lustra license Dependency license / IP risk
/lustra deadcode Remove unused files, exports, dependencies
/lustra libs Audit dependency health
/lustra perf Performance smells
/lustra docs Documentation drift and gaps
/lustra ci Pipeline soundness
/lustra structure Detect the stack, advise or reorganize`)
/lustra audit One graded health report (due diligence)
/lustra baseline Scaffold guardrail configs for the stack
/lustra review Structured review of a diff or path
/lustra types Type-checker triage, catch evasion
/lustra tests Run suite, diff coverage, catch fake tests
/lustra analyze Linter findings + AI-slop smells
/lustra format Fix formatting drift
/lustra security Find exploitable security defects
/lustra license Dependency license / IP risk
/lustra deadcode Remove unused files, exports, dependencies
/lustra deps Dependency health and upgrades
/lustra design Design quality: SOLID / cohesion / coupling
/lustra observability Logging and instrumentation quality
/lustra perf Performance smells
/lustra docs Documentation drift and gaps
/lustra migrate Guided one-major dependency migration
/lustra ci Pipeline soundness
/lustra structure Detect the stack, advise or reorganize`)
}
}

Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lustra-cli",
"version": "0.1.1",
"description": "Code-hygiene skill for AI coding agents: clean AI slop, find security flaws, dead code, dependency rot, lint, format, review, and project structure.",
"version": "0.1.2",
"description": "Stack-agnostic code-hygiene skill for AI coding agents: clean AI slop, find security flaws, dead code, dependency rot, design and logging issues; lint, format, type-check, test, review, migrate dependencies, and fix project structure.",
"license": "MIT",
"author": "Henrique Breim <henrique@breim.com.br>",
"repository": {
Expand Down
3 changes: 2 additions & 1 deletion scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ const providers = require('./providers')

const root = path.join(__dirname, '..')
const source = path.join(root, 'skill')
const outRoot = process.env.LUSTRA_BUILD_ROOT || root

if (!fs.existsSync(path.join(source, 'SKILL.md'))) {
console.error('skill/SKILL.md not found — nothing to build')
process.exit(1)
}

for (const { configDir, displayName } of providers) {
const dest = path.join(root, configDir, 'skills', 'lustra')
const dest = path.join(outRoot, configDir, 'skills', 'lustra')
fs.rmSync(dest, { recursive: true, force: true })
fs.mkdirSync(dest, { recursive: true })
fs.cpSync(source, dest, { recursive: true })
Expand Down
33 changes: 26 additions & 7 deletions skill/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
name: lustra
description: "Use when the user wants to clean up AI slop, harden a codebase, or run technical due diligence: review code for security flaws and vulnerable or wrongly-licensed dependencies, find and remove dead code, audit dependency health, run and triage linters, type checkers, test suites and Prettier, find performance smells, check documentation and CI health, scaffold baseline configs for the detected stack, do a structured code review, fix project structure, or produce one aggregated health report across all of these. Triggers on phrases like clean this up, find security issues, remove dead code, check dependencies, lint, typecheck, run the tests, format, review my code, check licenses, is this slow, fix the project structure, set up the project, audit everything, due diligence, or this looks like AI slop. Wraps real tools (npm audit, knip, eslint, tsc, the test runner, prettier, npm outdated, license-checker) and triages their output. Not for UI/visual design work."
description: "Use when the user wants to clean up AI slop, harden a codebase, or run technical due diligence: review code for security flaws and vulnerable or wrongly-licensed dependencies, find and remove dead code, audit dependency health, run and triage linters, type checkers, test suites and formatters, evaluate design principles (SOLID and the cohesion/coupling equivalents for non-OO stacks), audit logging and observability, find performance smells, check documentation and CI health, scaffold baseline configs for the detected stack, do a structured code review, guide a one-major-at-a-time dependency migration, fix project structure, or produce one aggregated health report across all of these. Triggers on phrases like clean this up, find security issues, remove dead code, check dependencies, lint, typecheck, run the tests, format, review my code, check the design, check logging, is this slow, migrate a dependency, fix the project structure, set up the project, audit everything, due diligence, or this looks like AI slop. Wraps the detected stack's real tooling — dependency auditor, linter, type checker, test runner, formatter, dead-code and license scanners — and triages its output. Not for UI/visual design work."
user-invocable: true
argument-hint: "[audit|security|license|libs|types|tests|deadcode|lint|review|perf|structure|docs|ci|prettier|baseline] [target]"
argument-hint: "[audit|baseline|review|types|tests|analyze|format|security|license|deadcode|deps|design|observability|perf|docs|migrate|ci|structure] [target]"
allowed-tools: Bash Read Edit Grep Glob
---

Expand Down Expand Up @@ -31,20 +31,25 @@ Grouped by lifecycle phase. `audit` runs the diagnostic ones together.

**Iterate**
- `review` — structured correctness / design / slop review of a diff or path.
- `types` — type-checker triage; catch `any`/`@ts-ignore` evasion.
- `types` — type-checker triage; catch `any`/`@ts-ignore`-style evasion.
- `tests` — run the suite, coverage on the diff, catch fake/empty tests.
- `lint` — ESLint plus AI-slop smells that no rule catches.
- `prettier` — formatting drift.
- `analyze` — the linter's findings plus AI-slop smells that no rule catches.
- `format` — formatting drift, fixed mechanically.

**Polish**
- `security` — vulnerabilities: secrets, injection, broken authorization, vulnerable deps.
- `license` — dependency license compatibility and IP risk.
- `deadcode` — unused files, exports, and dependencies (knip).
- `libs` — dependency health: outdated, deprecated, duplicated, unused.
- `deadcode` — unused files, exports, and dependencies; deletes only what is confirmed.
- `deps` — dependency health and upgrades: outdated, deprecated, duplicated. Reports
unused deps and advisories but defers deletion to `deadcode` and vuln fixes to `security`.
- `design` — module/package design quality: SOLID, or cohesion/coupling/composition for
non-OO stacks. Module-scoped, unlike diff-scoped `review` or layout-scoped `structure`.
- `observability` — logging and instrumentation quality so failures are diagnosable.
- `perf` — performance smells: N+1, blocking IO, unbounded growth, bundle weight.
- `docs` — documentation drift and undocumented public surface.

**Maintain**
- `migrate` — guided one-major-at-a-time dependency migration: changelog, codemods, suite.
- `ci` — pipeline soundness: real gates, CI security, reproducibility.
- `structure` — detect the stack, then report or reorganize project structure.

Expand Down Expand Up @@ -77,3 +82,17 @@ redefine it:
skipped, and why.

Read-only detection is exempt. Changing files or dependencies is not.

## Stack detection

Every command that runs a tool first identifies the stack. Reference files point here and
do not redefine this:

1. Read the manifests at the target root to identify language and framework:
`package.json` (and the framework), `pyproject.toml`/`setup.py`, `go.mod`,
`Cargo.toml`, `pom.xml`/`build.gradle`, `Gemfile`, `composer.json`.
2. State the detected stack explicitly before running anything. If detection is ambiguous
or the repo is polyglot, ask rather than assume.
3. Pick the tool from the reference file's per-ecosystem table. If no tool exists for the
detected stack, say so and fall back to static reading — mark that result
lower-confidence. Never run a stack's tool against a project that is not that stack.
27 changes: 19 additions & 8 deletions skill/reference/lint.md → skill/reference/analyze.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
# lint
# analyze

**Purpose:** the linter's findings, plus the slop a linter structurally cannot see.
**Purpose:** the linter / static analyzer's findings, plus the slop a linter structurally
cannot see.

## Detect

1. If an ESLint config exists, `npx -y eslint . --format json` scoped to the target.
2. If none exists, do **not** silently add one. Run with a minimal recommended config and
say the result is advisory; offer to add a real config as a separate, confirmed step.
Detect the stack (SKILL.md § Stack detection), then run its linter scoped to the target:

| Stack | Linter |
| --- | --- |
| JS/TS | `npx -y eslint . --format json` |
| Python | `ruff check --output-format json` (or `flake8`/`pylint`) |
| Go | `go vet ./...` and `staticcheck ./...` if present |
| Rust | `cargo clippy --message-format json` |

1. If a linter config exists for the stack, use it.
2. If none exists, do **not** silently add one. Run with the tool's recommended config,
say the result is advisory, and offer to add a real config as a separate confirmed step.
3. Read the target for AI-slop smells no rule catches:
- Abstractions with exactly one caller; indirection that only forwards.
- `try/catch` that logs and rethrows, swallows, or re-wraps with no added meaning.
Expand All @@ -17,18 +27,19 @@

## Triage

ESLint errors before warnings. For slop smells, only raise ones you can justify concretely
Linter errors before warnings. For slop smells, only raise ones you can justify concretely
— name the caller count, the impossible condition, the comment that adds nothing. Skip
stylistic preferences the repo's own config does not enforce.

## Fix policy

- Present the autofixable set as a checklist (rule + `file:line` per item). On approval,
run `eslint --fix` scoped to the approved files, then re-run to confirm zero regressions.
run the linter's autofix scoped to the approved files, then re-run to confirm zero
regressions. Confirmation flow per SKILL.md.
- Propose (diff + ask): every slop-smell change — these are semantic. Match existing
style; do not reformat untouched lines.

## Report

Two sections: ESLint (counts + remaining manual items) and slop smells (`file:line`,
Two sections: linter (counts + remaining manual items) and slop smells (`file:line`,
the smell, the concrete justification, the proposed change).
Loading
Loading