diff --git a/.github/actions/dart_package/action.yaml b/.github/actions/dart_package/action.yaml
new file mode 100644
index 000000000..69fcdffe9
--- /dev/null
+++ b/.github/actions/dart_package/action.yaml
@@ -0,0 +1,100 @@
+name: Dart Package Workflow
+description: Build and test Dart packages.
+
+inputs:
+ collect_coverage:
+ required: false
+ default: "true"
+ description: Whether to collect code coverage
+ collect_score:
+ required: false
+ default: "true"
+ description: Whether to collect the pana score
+ concurrency:
+ required: false
+ default: "4"
+ description: The value of the concurrency flag (-j) used when running tests
+ coverage_excludes:
+ required: false
+ default: ""
+ description: Globs to exclude from coverage
+ dart_sdk:
+ required: false
+ default: "stable"
+ description: "The dart sdk version to use"
+ working_directory:
+ required: false
+ default: "."
+ description: The working directory for this workflow
+ min_coverage:
+ required: false
+ default: "100"
+ description: The minimum coverage percentage value
+ min_score:
+ required: false
+ default: "120"
+ description: The minimum pana score value
+ analyze_directories:
+ required: false
+ default: "lib test"
+ description: Directories to analyze
+ report_on:
+ required: false
+ default: "lib"
+ description: Directories to report on when collecting coverage
+ run_tests:
+ required: false
+ default: "true"
+ description: Whether to run tests for the package.
+
+runs:
+ using: "composite"
+ steps:
+ - name: ๐ฏ Setup Dart
+ uses: dart-lang/setup-dart@v1
+ with:
+ sdk: ${{inputs.dart_sdk}}
+
+ - name: ๐ฆ Install Dependencies
+ working-directory: ${{ inputs.working_directory }}
+ shell: ${{ inputs.shell }}
+ run: dart pub get
+
+ - name: โจ Format
+ working-directory: ${{ inputs.working_directory }}
+ shell: ${{ inputs.shell }}
+ run: dart format --set-exit-if-changed .
+
+ - name: ๐ Analyze
+ working-directory: ${{ inputs.working_directory }}
+ shell: ${{ inputs.shell }}
+ run: dart analyze --fatal-warnings ${{inputs.analyze_directories}}
+
+ - name: ๐งช Test
+ if: inputs.run_tests == 'true'
+ working-directory: ${{ inputs.working_directory }}
+ shell: ${{ inputs.shell }}
+ run: |
+ dart pub global activate coverage
+ dart test -j ${{inputs.concurrency}} --coverage=coverage && dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=${{inputs.report_on}} --check-ignore
+
+ - name: ๐ Verify Coverage
+ if: inputs.run_tests == 'true' && inputs.collect_coverage == 'true'
+ uses: VeryGoodOpenSource/very_good_coverage@v3
+ with:
+ path: ${{inputs.working_directory}}/coverage/lcov.info
+ exclude: ${{inputs.coverage_excludes}}
+ min_coverage: ${{inputs.min_coverage}}
+
+ - name: ๐ฏ Verify Pub Score
+ if: inputs.collect_score == 'true'
+ working-directory: ${{ inputs.working_directory }}
+ shell: ${{ inputs.shell }}
+ run: |
+ dart pub global activate pana 0.22.21
+ sudo apt-get install webp
+ PANA=$(pana . --no-warning); PANA_SCORE=$(echo $PANA | sed -n "s/.*Points: \([0-9]*\)\/\([0-9]*\)./\1\/\2/p")
+ echo "score: $PANA_SCORE"
+ IFS='/'; read -a SCORE_ARR <<< "$PANA_SCORE"; SCORE=SCORE_ARR[0]; TOTAL=SCORE_ARR[1]
+ if [ -z "$1" ]; then MINIMUM_SCORE=TOTAL; else MINIMUM_SCORE=$1; fi
+ if (( $SCORE < $MINIMUM_SCORE )); then echo "minimum score $MINIMUM_SCORE was not met!"; exit 1; fi
diff --git a/.github/workflows/dart_frog_lint.yaml b/.github/workflows/dart_frog_lint.yaml
new file mode 100644
index 000000000..bfcb03941
--- /dev/null
+++ b/.github/workflows/dart_frog_lint.yaml
@@ -0,0 +1,30 @@
+name: dart_frog_lint
+
+on:
+ pull_request:
+ paths:
+ - ".github/workflows/dart_frog_lint.yaml"
+ - "packages/dart_frog_lint/lib/**"
+ - "packages/dart_frog_lint/pubspec.yaml"
+ push:
+ branches:
+ - main
+ paths:
+ - ".github/workflows/dart_frog_lint.yaml"
+ - "packages/dart_frog_lint/lib/**"
+ - "packages/dart_frog_lint/pubspec.yaml"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: ๐ Git Checkout
+ uses: actions/checkout@v4
+
+ - name: ๐ฏ Build
+ uses: ./.github/actions/dart_package
+ with:
+ analyze_directories: lib
+ run_tests: false # there aren't any tests since this is just a single yaml file.
+ working_directory: packages/dart_frog_lint
diff --git a/.github/workflows/publish_dart_frog_lint.yaml b/.github/workflows/publish_dart_frog_lint.yaml
new file mode 100644
index 000000000..913143671
--- /dev/null
+++ b/.github/workflows/publish_dart_frog_lint.yaml
@@ -0,0 +1,22 @@
+name: publish/dart_frog_lint
+
+on:
+ push:
+ tags:
+ - "dart_frog_lint-v[0-9]+.[0-9]+.[0-9]+*"
+
+jobs:
+ publish:
+ environment: pub.dev
+ runs-on: ubuntu-latest
+ permissions:
+ id-token: write # Required for authentication using OIDC
+
+ steps:
+ - name: ๐ Git Checkout
+ uses: actions/checkout@v4
+
+ - name: ๐ฆ Publish
+ uses: ./.github/actions/pub_publish
+ with:
+ working_directory: packages/dart_frog_lint
diff --git a/packages/dart_frog_lint/.gitignore b/packages/dart_frog_lint/.gitignore
new file mode 100644
index 000000000..cc063e820
--- /dev/null
+++ b/packages/dart_frog_lint/.gitignore
@@ -0,0 +1,10 @@
+# See https://www.dartlang.org/guides/libraries/private-files
+
+# Files and directories created by pub
+.dart_tool/
+.packages
+build/
+pubspec.lock
+
+# Test related files
+coverage/
\ No newline at end of file
diff --git a/packages/dart_frog_lint/CHANGELOG.md b/packages/dart_frog_lint/CHANGELOG.md
new file mode 100644
index 000000000..2d5599a50
--- /dev/null
+++ b/packages/dart_frog_lint/CHANGELOG.md
@@ -0,0 +1,3 @@
+# 0.1.0
+
+- feat: initial release ๐
diff --git a/packages/dart_frog_lint/LICENSE b/packages/dart_frog_lint/LICENSE
new file mode 100644
index 000000000..32bc63089
--- /dev/null
+++ b/packages/dart_frog_lint/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Dart Frog Dev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/packages/dart_frog_lint/README.md b/packages/dart_frog_lint/README.md
new file mode 100644
index 000000000..d6eba6319
--- /dev/null
+++ b/packages/dart_frog_lint/README.md
@@ -0,0 +1,49 @@
+[
](https://dart-frog.dev/)
+
+### Dart Frog Lint
+
+
+
+[![discord][discord_badge]][discord_link]
+[![dart][dart_badge]][dart_link]
+
+[![ci][ci_badge]][ci_link]
+[![coverage][coverage_badge]][ci_link]
+[![pub package][pub_badge]][pub_link]
+[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link]
+[![License: MIT][license_badge]][license_link]
+
+A collection of lint rules built specifically for [Dart Frog][docs_link].
+
+## Documentation ๐
+
+For official documentation, please visit [dart-frog.dev][docs_link].
+
+## Quick Start ๐
+
+1. Install `dart_frog_lint`
+
+ `dart pub add --dev dart_frog_lint`
+
+1. Add an `analysis_options.yaml` to the root of your project with the recommended rules
+
+ ```yaml
+ include: package:dart_frog_lint/recommended.yaml
+ ```
+
+[ci_badge]: https://github.com/dart-frog-dev/dart_frog/actions/workflows/dart_frog_lint.yaml/badge.svg?branch=main
+[ci_link]: https://github.com/dart-frog-dev/dart_frog/actions/workflows/dart_frog_lint.yaml
+[coverage_badge]: https://raw.githubusercontent.com/dart-frog-dev/dart_frog/main/packages/dart_frog_lint/coverage_badge.svg
+[dart_badge]: https://img.shields.io/badge/Dart-%230175C2.svg?style=for-the-badge&logo=dart&logoColor=5BB4F0&color=1E2833
+[dart_link]: https://dart.dev
+[discord_badge]: https://img.shields.io/discord/1394707782271238184?style=for-the-badge&logo=discord&color=1C2A2E&logoColor=1DF9D2
+[discord_link]: https://discord.gg/dart-frog
+[docs_link]: https://dart-frog.dev
+[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg
+[license_link]: https://opensource.org/licenses/MIT
+[logo_black]: https://raw.githubusercontent.com/dart-frog-dev/dart_frog/main/assets/dart_frog_logo_black.png#gh-light-mode-only
+[logo_white]: https://raw.githubusercontent.com/dart-frog-dev/dart_frog/main/assets/dart_frog_logo_white.png#gh-dark-mode-only
+[pub_badge]: https://img.shields.io/pub/v/dart_frog.svg
+[pub_link]: https://pub.dartlang.org/packages/dart_frog
+[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg
+[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis
diff --git a/packages/dart_frog_lint/analysis_options.yaml b/packages/dart_frog_lint/analysis_options.yaml
new file mode 100644
index 000000000..45d2e04e3
--- /dev/null
+++ b/packages/dart_frog_lint/analysis_options.yaml
@@ -0,0 +1 @@
+include: ./lib/recommended.yaml
diff --git a/packages/dart_frog_lint/assets/logo.png b/packages/dart_frog_lint/assets/logo.png
new file mode 100644
index 000000000..a64380703
Binary files /dev/null and b/packages/dart_frog_lint/assets/logo.png differ
diff --git a/packages/dart_frog_lint/coverage_badge.svg b/packages/dart_frog_lint/coverage_badge.svg
new file mode 100644
index 000000000..499e98ce2
--- /dev/null
+++ b/packages/dart_frog_lint/coverage_badge.svg
@@ -0,0 +1,20 @@
+
diff --git a/packages/dart_frog_lint/example/README.md b/packages/dart_frog_lint/example/README.md
new file mode 100644
index 000000000..12bb7e135
--- /dev/null
+++ b/packages/dart_frog_lint/example/README.md
@@ -0,0 +1,11 @@
+# Dart Frog Lint
+
+1. Install `dart_frog_lint`
+
+ `dart pub add --dev dart_frog_lint`
+
+1. Add an `analysis_options.yaml` to the root of your project with the recommended rules
+
+ ```yaml
+ include: package:dart_frog_lint/recommended.yaml
+ ```
diff --git a/packages/dart_frog_lint/lib/dart_frog_lint.dart b/packages/dart_frog_lint/lib/dart_frog_lint.dart
new file mode 100644
index 000000000..df4696c26
--- /dev/null
+++ b/packages/dart_frog_lint/lib/dart_frog_lint.dart
@@ -0,0 +1,3 @@
+/// A collection of lint rules built specifically for Dart Frog.
+/// Learn more at https://dart-frog.dev
+library;
diff --git a/packages/dart_frog_lint/lib/recommended.yaml b/packages/dart_frog_lint/lib/recommended.yaml
new file mode 100644
index 000000000..6afbc1a7f
--- /dev/null
+++ b/packages/dart_frog_lint/lib/recommended.yaml
@@ -0,0 +1,10 @@
+include: package:very_good_analysis/analysis_options.yaml
+analyzer:
+ exclude:
+ - build/**
+linter:
+ rules:
+ # Route names are derived from the respective file names
+ file_names: false
+ # Experimental and there are lots of false positives
+ specify_nonobvious_property_types: false
diff --git a/packages/dart_frog_lint/pubspec.yaml b/packages/dart_frog_lint/pubspec.yaml
new file mode 100644
index 000000000..4023dc0eb
--- /dev/null
+++ b/packages/dart_frog_lint/pubspec.yaml
@@ -0,0 +1,18 @@
+name: dart_frog_lint
+description: A collection of lint rules built specifically for the Dart Frog backend framework.
+version: 0.1.0
+homepage: https://dart-frog.dev
+repository: https://github.com/dart-frog-dev/dart_frog
+issue_tracker: https://github.com/dart-frog-dev/dart_frog/issues
+documentation: https://dart-frog.dev/getting-started
+topics: [lint, server, backend, shelf, dart-frog]
+
+screenshots:
+ - description: Dart Frog logo.
+ path: assets/logo.png
+
+environment:
+ sdk: ">=3.0.0 <4.0.0"
+
+dependencies:
+ very_good_analysis: ^9.0.0