Skip to content
Open
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
21 changes: 21 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "scopelint",
"owner": {
"name": "ScopeLift"
},
"metadata": {
"description": "ScopeLint and ScopeLift skills for Foundry/Solidity: lint workflows and structure reviews.",
"version": "1.0.0"
},
"plugins": [
{
"name": "scopelint",
"source": "./plugins/scopelint",
"description": "ScopeLint lint workflow and ScopeLift review: run scopelint check, list findings by priority, fix or review with the 'why' behind conventions.",
"version": "1.0.0",
"author": { "name": "ScopeLift" },
"repository": "https://github.com/ScopeLift/scopelint",
"keywords": ["solidity", "foundry", "lint", "code-review", "scopelint"]
}
]
}
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
categories = ["development-tools"]
description = "An opinionated formatting and linting tool for foundry projects"
edition = "2021"
# Exclude plugin/marketplace dirs from package; when include is set they're already omitted.
# cargo test and clippy only run on Rust sources (src/, tests/) so they never see these dirs.
exclude = ["plugins", ".claude-plugin"]
include = ["/src"]
keywords = ["foundry", "linting", "formatting"]
license = "MIT"
Expand Down
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ A simple and opinionated tool designed for basic formatting/linting of Solidity
- [`scopelint check`](#scopelint-check)
- [`scopelint fix`](#scopelint-fix)
- [`scopelint spec`](#scopelint-spec)
- [Claude Code plugin](#claude-code-plugin)
- [Development](#development)

## Installation
Expand Down Expand Up @@ -125,6 +126,38 @@ Right now it's focused on specifications for unit tests, which are very useful f
As a result, it does not yet include information about protocol invariants or integration test / user-story types of specifications.
If you have any thoughts or ideas, please open an issue [here](https://github.com/ScopeLift/scopelint/issues/new).

## Claude Code plugin

`ScopeLint` ships as a [Claude Code](https://code.claude.com) plugin so you can run lint workflows and structure reviews from inside Claude. The plugin adds two skills:

| Skill | What it does |
|-------|----------------|
| **lint** | Runs `scopelint check`, lists findings in priority order, and can fix them (or ask you). By default offers to address all findings. |
| **review** | Reviews your Foundry/Solidity project for structure and quality using ScopeLint’s conventions, and explains the “why” behind each finding. |

### Install the plugin

In [Claude Code](https://code.claude.com), run:

1. **Add the marketplace** (this repo):
```text
/plugin marketplace add ScopeLift/scopelint
```

2. **Install the plugin**:
```text
/plugin install scopelint@scopelint
```

3. Restart Claude Code if prompted. Run `/help` to see the skills under the `scopelint` namespace.

### Use the skills

- **Lint and fix**: Run `/scopelint:lint` or ask in natural language, e.g. *“Run scopelint and fix the findings”* or *“Lint this project and list issues by priority.”*
- **Structure review**: Run `/scopelint:review` or ask e.g. *“Review this Solidity project’s structure and quality.”*

Claude can also use these skills automatically when you talk about linting, fixing conventions, or code/structure review in a Foundry project. You need `ScopeLint` installed locally (`cargo install scopelint`) and a Foundry layout (`src/`, `test/`, `script/`).

## Development

For developers interested in contributing to `scopelint`, please see our [Development Guide](DEV.md) for detailed information about:
Expand Down
7 changes: 7 additions & 0 deletions plugins/scopelint/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "scopelint",
"description": "ScopeLint lint workflow and ScopeLift review: run scopelint check, list findings by priority, fix or review with the 'why' behind conventions.",
"version": "1.0.0",
"author": { "name": "ScopeLift" },
"repository": "https://github.com/ScopeLift/scopelint"
}
37 changes: 37 additions & 0 deletions plugins/scopelint/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ScopeLint Claude Code Plugin

This plugin adds two [Claude Code](https://code.claude.com) skills for Foundry/Solidity workflows:

| Skill | Command | Description |
|-------|----------|-------------|
| **lint** | `/scopelint:lint` | Run `scopelint check`, list findings in priority order, and fix them (or ask). By default, offer to address all findings. |
| **review** | `/scopelint:review` | Code structure and quality review using ScopeLint’s philosophy; outputs findings with the “why” behind each convention. |

Skills are also **model-invoked**: Claude can use them automatically when you ask to lint the project, fix convention issues, or request a code/structure review of a Solidity/Foundry codebase.

## Installation

1. Add the ScopeLint marketplace (this repo):
```bash
/plugin marketplace add ScopeLift/scopelint
```
2. Install the plugin:
```bash
/plugin install scopelint@scopelint
```
3. Restart Claude Code if needed. Run `/help` to see the skills under the `scopelint` namespace.

## Requirements

- [ScopeLint](https://github.com/ScopeLift/scopelint) installed: `cargo install scopelint`
- A Foundry project layout (`src/`, `test/`, `script/`, and optionally `foundry.toml`)

## Local development

Load the plugin without installing from the marketplace:

```bash
claude --plugin-dir ./plugins/scopelint
```

Then run e.g. `/scopelint:lint` or ask Claude to “run scopelint and fix the findings.”
84 changes: 84 additions & 0 deletions plugins/scopelint/skills/lint/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
name: lint
description: Run scopelint check on Foundry projects, list findings in priority order, and address them (or ask the user). Use when the user wants to lint a Solidity/Foundry project, fix convention issues, or when reviewing code for ScopeLint-style best practices.
---

# ScopeLint Lint Workflow

Choose a reason for hiding this comment

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

Have you tested these skills out? How have they performed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup yup. It does make it easier to fix
It's basically like a :fix command and so far i've got 100% success rate (tried it on a 2 personal projects )


Use the ScopeLint CLI to find convention and formatting issues in a Foundry project, present them in priority order, and either fix them or ask the user how to proceed. By default, offer to address all findings unless the user prefers to triage manually.

## When to use

- User asks to lint the project, run scopelint, or fix convention issues.
- User wants findings listed so they can address them or have the agent fix them.
- Working in a repo with Solidity/Foundry and you want to enforce test naming, constants, script entrypoints, internal prefixes, etc.

## Prerequisites

- Project has a Foundry layout (e.g. `src/`, `test/`, `script/`) and optionally `foundry.toml`.
- ScopeLint is installed: `cargo install scopelint` (or already on PATH).

## Workflow

1. **Run check**
From the project root (or the directory containing `foundry.toml`):
```bash
scopelint check
```
Capture stdout/stderr. Exit code is non-zero if there are findings.

2. **List findings in priority order**
Parse the output and present findings in this order (structural first, then naming, then cleanup):
- **Script** – multiple public `run` methods or wrong script interface (blocks deployment clarity).
- **Src** – internal/private functions not prefixed with `_` (consistency and readability).
- **Test** – test names not matching `test(Fork)?(Fuzz)?(_Revert(If|When|On))?_(\w+)*` (tests as spec).
- **Constant** – constants/immutables not `ALL_CAPS`.
- **Error** – custom errors not following project convention (e.g. prefix).
- **Variable** – variable naming issues.
- **Import** – unused imports (can be auto-fixed with `scopelint fix`).
- **Directive / Eip712** – directive or EIP-712 typehash issues.

For each finding, show: **rule**, **file**, **line** (if any), and **message**. Group by file if there are many findings.

3. **Propose next step**
- **Default**: Offer to address all findings (apply fixes and/or edits as appropriate).
- If the user prefers to fix themselves, list the prioritized list and stop.
- If they want only some categories fixed (e.g. "fix imports and constants only"), do that.

4. **Applying fixes**
- **Unused imports**: Run `scopelint fix`; it removes unused imports and re-runs `scopelint check`. Prefer this over hand-editing.
- **Other rules**: Apply edits in code (rename tests, constants, internal functions, script entrypoints, etc.) so that `scopelint check` passes. Optionally run `scopelint fmt` after edits to keep formatting consistent.

5. **Re-check**
After edits, run `scopelint check` again and report any remaining or new findings.

## Output format (for the user)

When listing findings, use a clear, scannable format, for example:

```markdown
## ScopeLint findings (by priority)

### Script
- `script/Deploy.s.sol`: multiple public run methods, only one is allowed.

### Src
- `src/Counter.sol` (line 42): internal function name should start with `_`.

### Test
- `test/Counter.t.sol` (line 18): Invalid test name `testCounter` — use convention like `test_RevertWhen_Zero()`.

### Constant
- `src/Token.sol` (line 12): constant/immutable should be ALL_CAPS.

### Import (auto-fixable)
- `src/Helper.sol` (line 5): unused import `Foo`.
```

Then state: "I can fix these (including running `scopelint fix` for imports). Proceed?" or follow the user's preference.

## Notes

- Paths are read from `foundry.toml` (e.g. `src`, `test`, `script`); optional `[check]` section can override. No need to change config if the layout is standard.
- Ignored findings (inline `// scopelint: ...` or `.scopelint` file) are not reported by `scopelint check`; only non-ignored items need to be listed and fixed.
- If `scopelint` is not installed, tell the user to run `cargo install scopelint` and then re-run the workflow.
86 changes: 86 additions & 0 deletions plugins/scopelint/skills/review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
name: review
description: Review Foundry/Solidity projects for code structure and quality using ScopeLint's philosophy (conventions over config, tests as spec, clear script entrypoints). Use when the user asks for a code review, structure review, or quality review of a Solidity/Foundry codebase.
---

# ScopeLift Review

Review code structure and quality in Foundry/Solidity projects using the same principles behind ScopeLint: conventions over config, tests as spec, and clear boundaries so protocol logic stays easy to reason about. Combine `scopelint check` output with brief, actionable findings that explain the "why."

## When to use

- User asks for a code review, structure review, or quality review of a Solidity/Foundry project.
- User wants to understand how their project aligns with Foundry best practices and ScopeLint's conventions.
- Reviewing a PR or a directory of contracts/tests/scripts and you want to surface both tool findings and higher-level structure issues.

## ScopeLint "why" (feed this into findings)

- **Foundry gives great primitives**, but projects easily drift into inconsistent naming, test layouts, and scripts that are hard to reason about. The review should call out where that drift shows up.
- **Solidity-aware checks**: Rules are tailored to Foundry (tests, scripts, sources), not generic linting. Findings should reference these contexts (e.g. "script," "test," "src").
- **Conventions over config**: A small set of opinionated practices (test naming, internal prefixes, single script `run`, ALL_CAPS constants) so teams converge quickly. Findings should tie issues to these conventions.
- **Tests as spec**: Test layout and naming should read like a spec; `scopelint spec` can generate a human-readable spec from them. The review can note when test names or structure don't support that.
- **Fits the workflow**: Same paths as Forge via `foundry.toml`; no custom config required. Mention if path or layout quirks might affect tooling or CI.

## Workflow

1. **Run scopelint check**
From project root:
```bash
scopelint check
```
Capture all findings (file, rule, line, message). These are your **tool findings**.

2. **Optional: run scopelint spec**
If tests exist:
```bash
scopelint spec
```
Use the output to see whether test structure already reads like a spec or where it's vague/inconsistent. Reference this in the review when discussing test quality.

3. **Inspect structure**
Quickly check:
- **Scripts**: One public `run` per script? Helpers in a separate contract/file?
- **Tests**: Naming like `test_RevertWhen_*` / `testFork_*` / `testFuzz_*`? Grouped by behavior?
- **Src**: Internal/private functions prefixed with `_`? Constants/immutables in ALL_CAPS?
- **Layout**: `src` / `test` / `script` (or custom paths in `foundry.toml`) used consistently?

4. **Produce the review**
Output a short review that:
- **Summarizes** overall structure and alignment with the conventions above.
- **Lists findings** in two groups:
- **ScopeLint findings**: Each item from `scopelint check` with a one-line "why" (e.g. "Internal functions should be prefixed with `_` so they're visually distinct and match Foundry conventions").
- **Structure / quality**: Any extra observations (e.g. "Test file has many unrelated tests; consider splitting by contract or behavior," "Script has two public entrypoints; only one `run` is recommended").
- **Suggests next steps**: Run `scopelint fix` for auto-fixable items, then fix the rest by hand; optionally run `scopelint fmt` and `scopelint spec` to tidy format and regenerate the spec.

## Review output format

Use a structure like:

```markdown
## ScopeLift review

### Summary
[2–4 sentences on structure, test/script/source layout, and alignment with conventions.]

### ScopeLint findings (with rationale)
| Rule | File / location | Issue | Why it matters |
|--------|------------------|-------|----------------|
| script | script/Deploy.s.sol | … | Single public `run` keeps deployment and tooling predictable. |
| src | src/Counter.sol (L42) | … | `_` prefix for internal/private avoids confusion with external API. |
| test | test/Counter.t.sol (L18) | … | Convention names (e.g. test_RevertWhen_*) let tests double as a spec. |
| constant | src/Token.sol (L12) | … | ALL_CAPS makes constants easy to spot. |

### Structure / quality
- [Bullet points for anything not covered by ScopeLint but relevant to structure or readability.]

### Next steps
1. Run `scopelint fix` to remove unused imports and re-check.
2. Address remaining findings (rename tests, constants, internal functions, or script entrypoints).
3. Optionally run `scopelint fmt` and `scopelint spec` and commit the updated spec.
```

## Notes

- Keep the "why" column short: one sentence per rule type is enough. Reuse the same rationale for the same rule across findings.
- If `scopelint check` passes, the review can be brief: "No ScopeLint findings; structure looks aligned with conventions," plus any optional structure/quality notes.
- If the project isn't Foundry or doesn't use the usual layout, say so and focus on whatever structure and tooling they do use; you can still apply the same philosophy (conventions, tests as spec, clear entrypoints) where relevant.
12 changes: 5 additions & 7 deletions src/check/validators/src_names_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,11 @@ pub fn validate(parsed: &Parsed) -> Vec<InvalidItem> {
invalid_items.push(invalid_item);
}
}
SourceUnitPart::ContractDefinition(c) => {
if !matches!(c.ty, ContractTy::Library(_)) {
for el in &c.parts {
if let ContractPart::FunctionDefinition(f) = el {
if let Some(invalid_item) = validate_name(parsed, f) {
invalid_items.push(invalid_item);
}
SourceUnitPart::ContractDefinition(c) if !matches!(c.ty, ContractTy::Library(_)) => {

Choose a reason for hiding this comment

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

Why make this change?

Copy link
Contributor Author

@thelostone-mc thelostone-mc Mar 12, 2026

Choose a reason for hiding this comment

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

lint error :P
dcecb42

for el in &c.parts {
if let ContractPart::FunctionDefinition(f) = el {
if let Some(invalid_item) = validate_name(parsed, f) {
invalid_items.push(invalid_item);
}
}
}
Expand Down
Loading