From 708160894d04d8293f9466b7c3601352d59b6040 Mon Sep 17 00:00:00 2001 From: roli-lpci Date: Thu, 17 Sep 2026 08:06:12 -0400 Subject: [PATCH 1/2] Add LintLang linter plugin --- README.md | 110 +++++++++--------- linters/lintlang/lintlang.test.ts | 3 + linters/lintlang/plugin.yaml | 27 +++++ linters/lintlang/test_data/clean.in.yaml | 16 +++ linters/lintlang/test_data/findings.in.yaml | 10 ++ .../lintlang_v0.6.0_clean.check.shot | 30 +++++ .../lintlang_v0.6.0_findings.check.shot | 64 ++++++++++ 7 files changed, 206 insertions(+), 54 deletions(-) create mode 100644 linters/lintlang/lintlang.test.ts create mode 100644 linters/lintlang/plugin.yaml create mode 100644 linters/lintlang/test_data/clean.in.yaml create mode 100644 linters/lintlang/test_data/findings.in.yaml create mode 100644 linters/lintlang/test_data/lintlang_v0.6.0_clean.check.shot create mode 100644 linters/lintlang/test_data/lintlang_v0.6.0_findings.check.shot diff --git a/README.md b/README.md index 068ee8384..27f1cad0a 100644 --- a/README.md +++ b/README.md @@ -38,60 +38,61 @@ Enable the following tools via: trunk check enable {linter} ``` -| Technology | Linters | -| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -| All | [codespell], [cspell], [gitleaks], [git-diff-check], [ls-lint], [pre-commit-hooks], [trunk-toolbox], [vale] | -| Ansible | [ansible-lint] | -| Apex | [pmd] | -| Bash | [shellcheck], [shfmt] | -| Bazel, Starlark | [buildifier] | -| C, C++ | [clang-format], [clang-tidy], [include-what-you-use], [pragma-once] | -| C# | [dotnet-format] | -| CircleCI Config | [circleci] | -| Cloudformation | [cfnlint], [checkov] | -| CMake | [cmake-format] | -| CSS, SCSS | [stylelint], [prettier] | -| Cue | [cue-fmt] | -| Dart | [dart] | -| Docker | [hadolint], [checkov] | -| Dotenv | [dotenv-linter] | -| GitHub | [actionlint], [pinact], [zizmor] | -| Go | [gofmt], [gofumpt], [goimports], [gokart], [golangci-lint], [golines], [semgrep] | -| GraphQL | [graphql-schema-linter], [prettier] | -| HAML | [haml-lint] | -| HTML Templates | [djlint] | -| Java | [google-java-format], [pmd], [semgrep] | -| Javascript | [biome], [deno], [eslint], [oxlint], [prettier], [rome], [semgrep] | -| JSON | [biome], [deno], [eslint], [prettier], [semgrep] | -| Kotlin | [detekt], [ktlint] | -| Kubernetes | [kube-linter] | -| Lua | [stylua] | -| Markdown | [deno], [markdownlint], [markdownlint-cli2], [markdown-link-check], [markdown-table-prettify], [prettier], [remark-lint], [rumdl] | -| Nix | [nixpkgs-fmt] | -| package.json | [sort-package-json] | -| Perl | [perlcritic], [perltidy] | -| PHP | [php-cs-fixer], [phpstan] | -| PNG | [oxipng] | -| PowerShell | [psscriptanalyzer] | -| Prisma | [prisma] | -| Protobuf | [buf] (breaking, lint, and format), [clang-format], [clang-tidy] | -| Python | [autopep8], [bandit], [black], [flake8], [isort], [mypy], [nbstripout], [pylint], [pyright], [semgrep], [yapf], [ruff], [sourcery], [ty] | -| Rego | [regal], [opa] | -| Renovate | [renovate] | -| Ruby | [brakeman], [rubocop], [rufo], [semgrep], [standardrb] | -| Rust | [clippy], [rustfmt] | -| Scala | [scalafmt] | -| Security | [checkov], [dustilock], [grype], [nancy], [osv-scanner], [pinact], [snyk], [tfsec], [trivy], [trufflehog], [terrascan], [zizmor] | -| SQL | [sqlfluff], [sqlfmt], [sql-formatter], [squawk] | -| SVG | [svgo] | -| Swift | [stringslint], [swiftlint], [swiftformat] | -| Terraform | [terraform] (validate and fmt), [checkov], [tflint], [tfsec], [terrascan], [tofu] | -| Terragrunt | [terragrunt] | -| Textproto | [txtpbfmt] | -| Typescript | [deno], [eslint], [oxlint], [prettier], [rome], [semgrep] | -| TOML | [taplo], [toml-tidy] | -| Typescript | [deno], [eslint], [prettier], [rome], [semgrep] | -| YAML | [prettier], [semgrep], [yamlfmt], [yamllint] | +| Technology | Linters | +| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| All | [codespell], [cspell], [gitleaks], [git-diff-check], [ls-lint], [pre-commit-hooks], [trunk-toolbox], [vale] | +| AI agent instructions and config | [lintlang] | +| Ansible | [ansible-lint] | +| Apex | [pmd] | +| Bash | [shellcheck], [shfmt] | +| Bazel, Starlark | [buildifier] | +| C, C++ | [clang-format], [clang-tidy], [include-what-you-use], [pragma-once] | +| C# | [dotnet-format] | +| CircleCI Config | [circleci] | +| Cloudformation | [cfnlint], [checkov] | +| CMake | [cmake-format] | +| CSS, SCSS | [stylelint], [prettier] | +| Cue | [cue-fmt] | +| Dart | [dart] | +| Docker | [hadolint], [checkov] | +| Dotenv | [dotenv-linter] | +| GitHub | [actionlint], [pinact], [zizmor] | +| Go | [gofmt], [gofumpt], [goimports], [gokart], [golangci-lint], [golines], [semgrep] | +| GraphQL | [graphql-schema-linter], [prettier] | +| HAML | [haml-lint] | +| HTML Templates | [djlint] | +| Java | [google-java-format], [pmd], [semgrep] | +| Javascript | [biome], [deno], [eslint], [oxlint], [prettier], [rome], [semgrep] | +| JSON | [biome], [deno], [eslint], [prettier], [semgrep] | +| Kotlin | [detekt], [ktlint] | +| Kubernetes | [kube-linter] | +| Lua | [stylua] | +| Markdown | [deno], [markdownlint], [markdownlint-cli2], [markdown-link-check], [markdown-table-prettify], [prettier], [remark-lint], [rumdl] | +| Nix | [nixpkgs-fmt] | +| package.json | [sort-package-json] | +| Perl | [perlcritic], [perltidy] | +| PHP | [php-cs-fixer], [phpstan] | +| PNG | [oxipng] | +| PowerShell | [psscriptanalyzer] | +| Prisma | [prisma] | +| Protobuf | [buf] (breaking, lint, and format), [clang-format], [clang-tidy] | +| Python | [autopep8], [bandit], [black], [flake8], [isort], [mypy], [nbstripout], [pylint], [pyright], [semgrep], [yapf], [ruff], [sourcery], [ty] | +| Rego | [regal], [opa] | +| Renovate | [renovate] | +| Ruby | [brakeman], [rubocop], [rufo], [semgrep], [standardrb] | +| Rust | [clippy], [rustfmt] | +| Scala | [scalafmt] | +| Security | [checkov], [dustilock], [grype], [nancy], [osv-scanner], [pinact], [snyk], [tfsec], [trivy], [trufflehog], [terrascan], [zizmor] | +| SQL | [sqlfluff], [sqlfmt], [sql-formatter], [squawk] | +| SVG | [svgo] | +| Swift | [stringslint], [swiftlint], [swiftformat] | +| Terraform | [terraform] (validate and fmt), [checkov], [tflint], [tfsec], [terrascan], [tofu] | +| Terragrunt | [terragrunt] | +| Textproto | [txtpbfmt] | +| Typescript | [deno], [eslint], [oxlint], [prettier], [rome], [semgrep] | +| TOML | [taplo], [toml-tidy] | +| Typescript | [deno], [eslint], [prettier], [rome], [semgrep] | +| YAML | [prettier], [semgrep], [yamlfmt], [yamllint] | [actionlint]: https://trunk.io/linters/infra/actionlint [ansible-lint]: https://github.com/ansible/ansible-lint#readme @@ -138,6 +139,7 @@ trunk check enable {linter} [isort]: https://github.com/PyCQA/isort#readme [ktlint]: https://github.com/pinterest/ktlint#readme [kube-linter]: https://github.com/stackrox/kube-linter#readme +[lintlang]: https://github.com/hermes-labs-ai/lintlang [ls-lint]: https://github.com/loeffel-io/ls-lint#readme [markdownlint]: https://github.com/DavidAnson/markdownlint#readme [markdownlint-cli2]: https://github.com/DavidAnson/markdownlint-cli2#readme diff --git a/linters/lintlang/lintlang.test.ts b/linters/lintlang/lintlang.test.ts new file mode 100644 index 000000000..c9c1b0d92 --- /dev/null +++ b/linters/lintlang/lintlang.test.ts @@ -0,0 +1,3 @@ +import { linterCheckTest } from "tests"; + +linterCheckTest({ linterName: "lintlang" }); diff --git a/linters/lintlang/plugin.yaml b/linters/lintlang/plugin.yaml new file mode 100644 index 000000000..762bbcf3f --- /dev/null +++ b/linters/lintlang/plugin.yaml @@ -0,0 +1,27 @@ +version: 0.1 +tools: + definitions: + - name: lintlang + runtime: python + package: lintlang + shims: [lintlang] + known_good_version: 0.6.0 +lint: + definitions: + - name: lintlang + description: + Static analysis for AI agent instructions, tool descriptions, and agent configuration + files: [markdown, yaml, json, python] + tools: [lintlang] + known_good_version: 0.6.0 + suggest_if: never + commands: + - name: lint + output: sarif + run: lintlang scan --format sarif --fail-on fail ${target} + success_codes: [0, 1] + read_output_from: stdout + batch: true + version_command: + parse_regex: lintlang ${semver} + run: lintlang --version diff --git a/linters/lintlang/test_data/clean.in.yaml b/linters/lintlang/test_data/clean.in.yaml new file mode 100644 index 000000000..ea321afe4 --- /dev/null +++ b/linters/lintlang/test_data/clean.in.yaml @@ -0,0 +1,16 @@ +system_prompt: | + You are a weather information assistant. + Stop and report the failure after one retry. +tools: + - name: get_current_weather + description: Retrieve current weather for one named location. Do not use this tool for forecasts. + parameters: + type: object + properties: + location: + type: string + description: City and country for the requested weather. + required: [location] +constraints: + max_iterations: 2 + timeout_seconds: 30 diff --git a/linters/lintlang/test_data/findings.in.yaml b/linters/lintlang/test_data/findings.in.yaml new file mode 100644 index 000000000..5afb8f24a --- /dev/null +++ b/linters/lintlang/test_data/findings.in.yaml @@ -0,0 +1,10 @@ +system_prompt: | + You are a customer support agent. Help the user with their issues. +tools: + - name: process_ticket + description: "" + parameters: + type: object + properties: + ticket_id: + type: string diff --git a/linters/lintlang/test_data/lintlang_v0.6.0_clean.check.shot b/linters/lintlang/test_data/lintlang_v0.6.0_clean.check.shot new file mode 100644 index 000000000..4e97e436f --- /dev/null +++ b/linters/lintlang/test_data/lintlang_v0.6.0_clean.check.shot @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing linter lintlang test clean 1`] = ` +{ + "issues": [], + "lintActions": [ + { + "command": "lint", + "fileGroupName": "yaml", + "linter": "lintlang", + "paths": [ + "test_data/clean.in.yaml", + ], + "verb": "TRUNK_VERB_CHECK", + }, + { + "command": "lint", + "fileGroupName": "yaml", + "linter": "lintlang", + "paths": [ + "test_data/clean.in.yaml", + ], + "upstream": true, + "verb": "TRUNK_VERB_CHECK", + }, + ], + "taskFailures": [], + "unformattedFiles": [], +} +`; diff --git a/linters/lintlang/test_data/lintlang_v0.6.0_findings.check.shot b/linters/lintlang/test_data/lintlang_v0.6.0_findings.check.shot new file mode 100644 index 000000000..293c36584 --- /dev/null +++ b/linters/lintlang/test_data/lintlang_v0.6.0_findings.check.shot @@ -0,0 +1,64 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing linter lintlang test findings 1`] = ` +{ + "issues": [ + { + "code": "H1.1", + "column": "1", + "file": "test_data/findings.in.yaml", + "issueClass": "ISSUE_CLASS_NEW", + "level": "LEVEL_HIGH", + "line": "1", + "linter": "lintlang", + "message": "Tool 'process_ticket' has no description. Suggested action: Add a specific, disambiguating description that explains WHEN to use this tool, not just WHAT it does.", + "targetType": "yaml", + }, + { + "code": "H2", + "column": "1", + "file": "test_data/findings.in.yaml", + "issueClass": "ISSUE_CLASS_NEW", + "level": "LEVEL_HIGH", + "line": "1", + "linter": "lintlang", + "message": "System prompt defines tools but contains no termination conditions, retry budgets, or progress checks. Suggested action: Add explicit constraints: 'You have a maximum of 5 tool calls per task. If no progress after 2 attempts, stop and report the issue.'", + "targetType": "yaml", + }, + { + "code": "H3", + "column": "1", + "file": "test_data/findings.in.yaml", + "issueClass": "ISSUE_CLASS_NEW", + "level": "LEVEL_MEDIUM", + "line": "1", + "linter": "lintlang", + "message": "Parameter 'ticket_id' in tool 'process_ticket' has no description. Suggested action: Add a description explaining what this parameter means semantically, not just its type.", + "targetType": "yaml", + }, + ], + "lintActions": [ + { + "command": "lint", + "fileGroupName": "yaml", + "linter": "lintlang", + "paths": [ + "test_data/findings.in.yaml", + ], + "verb": "TRUNK_VERB_CHECK", + }, + { + "command": "lint", + "fileGroupName": "yaml", + "linter": "lintlang", + "paths": [ + "test_data/findings.in.yaml", + ], + "upstream": true, + "verb": "TRUNK_VERB_CHECK", + }, + ], + "taskFailures": [], + "unformattedFiles": [], +} +`; From a989b57f4a8278ab1b27b7f45c90dc3a6922902b Mon Sep 17 00:00:00 2001 From: roli-lpci Date: Thu, 17 Sep 2026 08:11:33 -0400 Subject: [PATCH 2/2] Keep LintLang README entry compact --- README.md | 110 +++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 27f1cad0a..68a50f1be 100644 --- a/README.md +++ b/README.md @@ -38,61 +38,61 @@ Enable the following tools via: trunk check enable {linter} ``` -| Technology | Linters | -| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -| All | [codespell], [cspell], [gitleaks], [git-diff-check], [ls-lint], [pre-commit-hooks], [trunk-toolbox], [vale] | -| AI agent instructions and config | [lintlang] | -| Ansible | [ansible-lint] | -| Apex | [pmd] | -| Bash | [shellcheck], [shfmt] | -| Bazel, Starlark | [buildifier] | -| C, C++ | [clang-format], [clang-tidy], [include-what-you-use], [pragma-once] | -| C# | [dotnet-format] | -| CircleCI Config | [circleci] | -| Cloudformation | [cfnlint], [checkov] | -| CMake | [cmake-format] | -| CSS, SCSS | [stylelint], [prettier] | -| Cue | [cue-fmt] | -| Dart | [dart] | -| Docker | [hadolint], [checkov] | -| Dotenv | [dotenv-linter] | -| GitHub | [actionlint], [pinact], [zizmor] | -| Go | [gofmt], [gofumpt], [goimports], [gokart], [golangci-lint], [golines], [semgrep] | -| GraphQL | [graphql-schema-linter], [prettier] | -| HAML | [haml-lint] | -| HTML Templates | [djlint] | -| Java | [google-java-format], [pmd], [semgrep] | -| Javascript | [biome], [deno], [eslint], [oxlint], [prettier], [rome], [semgrep] | -| JSON | [biome], [deno], [eslint], [prettier], [semgrep] | -| Kotlin | [detekt], [ktlint] | -| Kubernetes | [kube-linter] | -| Lua | [stylua] | -| Markdown | [deno], [markdownlint], [markdownlint-cli2], [markdown-link-check], [markdown-table-prettify], [prettier], [remark-lint], [rumdl] | -| Nix | [nixpkgs-fmt] | -| package.json | [sort-package-json] | -| Perl | [perlcritic], [perltidy] | -| PHP | [php-cs-fixer], [phpstan] | -| PNG | [oxipng] | -| PowerShell | [psscriptanalyzer] | -| Prisma | [prisma] | -| Protobuf | [buf] (breaking, lint, and format), [clang-format], [clang-tidy] | -| Python | [autopep8], [bandit], [black], [flake8], [isort], [mypy], [nbstripout], [pylint], [pyright], [semgrep], [yapf], [ruff], [sourcery], [ty] | -| Rego | [regal], [opa] | -| Renovate | [renovate] | -| Ruby | [brakeman], [rubocop], [rufo], [semgrep], [standardrb] | -| Rust | [clippy], [rustfmt] | -| Scala | [scalafmt] | -| Security | [checkov], [dustilock], [grype], [nancy], [osv-scanner], [pinact], [snyk], [tfsec], [trivy], [trufflehog], [terrascan], [zizmor] | -| SQL | [sqlfluff], [sqlfmt], [sql-formatter], [squawk] | -| SVG | [svgo] | -| Swift | [stringslint], [swiftlint], [swiftformat] | -| Terraform | [terraform] (validate and fmt), [checkov], [tflint], [tfsec], [terrascan], [tofu] | -| Terragrunt | [terragrunt] | -| Textproto | [txtpbfmt] | -| Typescript | [deno], [eslint], [oxlint], [prettier], [rome], [semgrep] | -| TOML | [taplo], [toml-tidy] | -| Typescript | [deno], [eslint], [prettier], [rome], [semgrep] | -| YAML | [prettier], [semgrep], [yamlfmt], [yamllint] | +| Technology | Linters | +| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| All | [codespell], [cspell], [gitleaks], [git-diff-check], [ls-lint], [pre-commit-hooks], [trunk-toolbox], [vale] | +| AI agents | [lintlang] | +| Ansible | [ansible-lint] | +| Apex | [pmd] | +| Bash | [shellcheck], [shfmt] | +| Bazel, Starlark | [buildifier] | +| C, C++ | [clang-format], [clang-tidy], [include-what-you-use], [pragma-once] | +| C# | [dotnet-format] | +| CircleCI Config | [circleci] | +| Cloudformation | [cfnlint], [checkov] | +| CMake | [cmake-format] | +| CSS, SCSS | [stylelint], [prettier] | +| Cue | [cue-fmt] | +| Dart | [dart] | +| Docker | [hadolint], [checkov] | +| Dotenv | [dotenv-linter] | +| GitHub | [actionlint], [pinact], [zizmor] | +| Go | [gofmt], [gofumpt], [goimports], [gokart], [golangci-lint], [golines], [semgrep] | +| GraphQL | [graphql-schema-linter], [prettier] | +| HAML | [haml-lint] | +| HTML Templates | [djlint] | +| Java | [google-java-format], [pmd], [semgrep] | +| Javascript | [biome], [deno], [eslint], [oxlint], [prettier], [rome], [semgrep] | +| JSON | [biome], [deno], [eslint], [prettier], [semgrep] | +| Kotlin | [detekt], [ktlint] | +| Kubernetes | [kube-linter] | +| Lua | [stylua] | +| Markdown | [deno], [markdownlint], [markdownlint-cli2], [markdown-link-check], [markdown-table-prettify], [prettier], [remark-lint], [rumdl] | +| Nix | [nixpkgs-fmt] | +| package.json | [sort-package-json] | +| Perl | [perlcritic], [perltidy] | +| PHP | [php-cs-fixer], [phpstan] | +| PNG | [oxipng] | +| PowerShell | [psscriptanalyzer] | +| Prisma | [prisma] | +| Protobuf | [buf] (breaking, lint, and format), [clang-format], [clang-tidy] | +| Python | [autopep8], [bandit], [black], [flake8], [isort], [mypy], [nbstripout], [pylint], [pyright], [semgrep], [yapf], [ruff], [sourcery], [ty] | +| Rego | [regal], [opa] | +| Renovate | [renovate] | +| Ruby | [brakeman], [rubocop], [rufo], [semgrep], [standardrb] | +| Rust | [clippy], [rustfmt] | +| Scala | [scalafmt] | +| Security | [checkov], [dustilock], [grype], [nancy], [osv-scanner], [pinact], [snyk], [tfsec], [trivy], [trufflehog], [terrascan], [zizmor] | +| SQL | [sqlfluff], [sqlfmt], [sql-formatter], [squawk] | +| SVG | [svgo] | +| Swift | [stringslint], [swiftlint], [swiftformat] | +| Terraform | [terraform] (validate and fmt), [checkov], [tflint], [tfsec], [terrascan], [tofu] | +| Terragrunt | [terragrunt] | +| Textproto | [txtpbfmt] | +| Typescript | [deno], [eslint], [oxlint], [prettier], [rome], [semgrep] | +| TOML | [taplo], [toml-tidy] | +| Typescript | [deno], [eslint], [prettier], [rome], [semgrep] | +| YAML | [prettier], [semgrep], [yamlfmt], [yamllint] | [actionlint]: https://trunk.io/linters/infra/actionlint [ansible-lint]: https://github.com/ansible/ansible-lint#readme