Skip to main content

Static linter for AI agent configs, tool descriptions, and system prompts with zero-LLM CI gating

Project description

LintLang

CI PyPI Python License

LintLang statically analyzes the natural-language instructions that control AI agents, catching ambiguous tools, missing limits, and conflicting directives before runtime.

It flags patterns such as:

  • empty, vague, or overlapping tool descriptions;
  • missing stop conditions and unbounded retries;
  • inconsistencies between tool schemas and their descriptions;
  • unscoped context and vague instructions;
  • conflicting output formats and malformed message roles;
  • embedded prompts and uncalibrated thresholds in Python pipelines.

LintLang's default static checks are deterministic and local. They make no LLM, API, telemetry, or network calls.

Quick start

Run once without installing, using uv:

uvx lintlang scan AGENTS.md

For a persistent command in an isolated environment, use pipx:

pipx install lintlang
lintlang scan AGENTS.md

If pipx's app directory is not on PATH, run pipx ensurepath, open a new shell, and retry the scan.

Or install from PyPI into the current Python environment:

python -m pip install lintlang

Requires Python 3.10+.

From your project root, point LintLang at an actual instruction file:

lintlang scan AGENTS.md

If your project uses another filename, replace AGENTS.md with its prompt, tool-definition, agent-configuration, or supported directory path.

3,000+ PyPI downloads · Used in recurring CI by Character.AI's public Larch repository · Independently packaged for Gentoo

When you are ready to make HIGH or CRITICAL findings block CI:

lintlang scan AGENTS.md --fail-on fail

Each finding identifies the affected location, the detected pattern, its severity, and a suggested review action.

Try the bundled example

The source repository includes a deliberately broken example:

git clone --depth 1 https://github.com/hermes-labs-ai/lintlang.git
cd lintlang

lintlang scan samples/bad_tool_descriptions.yaml --fail-on fail

Excerpt from lintlang 0.3.1:

LINTLANG v0.3.1

FAIL — 1 CRITICAL, 2 HIGH, 6 MEDIUM, 3 LOW

H1: Tool Description Ambiguity

  [CRITICAL] tool:process_ticket
  Tool 'process_ticket' has no description.

  [HIGH] tool:get_user_info
  Tool 'get_user_info' has a very short description (13 chars):
  "Get user info"

…

H2: Missing Constraint Scaffolding

  [HIGH] system_prompt
  System prompt defines tools but contains no termination conditions,
  retry budgets, or progress checks.

The command exits with status 1 because it includes --fail-on fail.

Verdicts and CI behavior

Verdict Practical meaning
PASS No MEDIUM, HIGH, or CRITICAL finding remained after the selected checks and filters
REVIEW At least one MEDIUM finding remained
FAIL At least one HIGH or CRITICAL finding remained
ERROR A requested input could not be inspected

PASS applies only to recognized content extracted from the requested inputs and the checks and severity filters selected for that run. It does not mean that every structure in an arbitrary JSON or YAML file was extracted. A clean LintLang scan is not evidence that an agent is safe or runtime-correct.

By default, findings are reported without failing the process.

  • --fail-on fail blocks on FAIL.
  • --fail-on review blocks on REVIEW or FAIL.
  • Missing, malformed, unreadable, or otherwise unscannable requested inputs remain nonzero regardless of the chosen finding threshold.
  • A requested directory with no eligible files also exits nonzero.

Filters such as --min-severity are applied before the verdict. For initial adoption, keep the full output visible and use --fail-on fail to block only the highest-severity findings.

Add it to CI

After choosing one real instruction path in your repository:

jobs:
  lint-agent-instructions:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7

      - name: Inspect agent instructions
        uses: hermes-labs-ai/lintlang@v0.3.2
        with:
          path: AGENTS.md

The release tag pins both the action and the LintLang source it installs. Upgrade that pin deliberately and inspect newly introduced findings before making them blocking.

Add it to pre-commit

Add the hook to .pre-commit-config.yaml with the explicit instruction paths to scan:

repos:
  - repo: https://github.com/hermes-labs-ai/lintlang
    rev: v0.3.2
    hooks:
      - id: lintlang
        args: [AGENTS.md]

Activate it and test the configured paths:

pre-commit install
pre-commit run lintlang

Replace or extend args with the prompt, tool-definition, agent-configuration, or supported directory paths your repository owns. The hook scans only those configured paths and reports findings without blocking on a verdict by default. After reviewing the repository's baseline, opt into blocking FAIL findings:

hooks:
  - id: lintlang
    args: [AGENTS.md, --fail-on, fail]

Missing, unreadable, or malformed configured inputs still return nonzero.

For machine-readable output:

lintlang scan AGENTS.md --format json --fail-on fail

What it inspects

LintLang currently accepts:

  • JSON and YAML objects using recognized top-level agent fields such as system_prompt, instructions, tools, functions, messages, and selected response-schema fields;
  • .txt, .md, and .prompt instruction files;
  • Python files, using AST extraction for prompt-like strings and threshold assignments.

Nested vendor-specific layouts and raw top-level YAML arrays are not automatically normalized. A syntactically valid input must still match a recognized shape for its structured tools or messages to be inspected.

The checks cover reader-facing categories including tool clarity, execution bounds, schema-description alignment, context boundaries, instruction specificity, output contracts, message-role structure, and Python pipeline hygiene.

Use narrow, intentional paths. Directory scans can discover Markdown and Python files that were not written as agent configuration; use .lintlangignore or --exclude where needed.

For exact H-series and Python rule identifiers:

lintlang patterns

See the full technical reference for detector details.

Where it fits

syntax and schema validation
        ↓
LintLang static language checks
        ↓
runtime agent evaluation
        ↓
domain and security review

LintLang is useful during authoring and pull-request review, before runtime testing. It does not:

  • determine whether an instruction is factually or semantically correct;
  • observe an agent selecting or executing tools;
  • prove that a finding causes a runtime failure;
  • certify an agent as safe or production-ready;
  • replace runtime evaluation or human review.

Suggestions are review aids, not guaranteed meaning-preserving fixes.

Ecosystem

Public ecosystem signals include:

These represent three distinct ecosystem signals: direct package execution, product influence, and downstream packaging.

Optional instruction preflight

Secondary capability: provider-neutral instruction preflight inspects one present instruction plus explicit context.

More

License

Apache License 2.0

LintLang is maintained by Hermes Labs.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lintlang-0.3.2.tar.gz (145.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lintlang-0.3.2-py3-none-any.whl (65.5 kB view details)

Uploaded Python 3

File details

Details for the file lintlang-0.3.2.tar.gz.

File metadata

  • Download URL: lintlang-0.3.2.tar.gz
  • Upload date:
  • Size: 145.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lintlang-0.3.2.tar.gz
Algorithm Hash digest
SHA256 c01a6bc3f78cc810ed5a571d612068983b898af4ea0e74ec07e0efaffb87b051
MD5 1f7e499f2907d1e86925ada4e8849bd0
BLAKE2b-256 fceb36789b4a4c5c0befa2dc02cc2672521b18bc91da1f6197feecc89097b2a5

See more details on using hashes here.

Provenance

The following attestation bundles were made for lintlang-0.3.2.tar.gz:

Publisher: publish.yml on hermes-labs-ai/lintlang

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lintlang-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: lintlang-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 65.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lintlang-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 31c4866831475d9bb265c91141fe50c3cded809ef7fb09e9d5cf9b8c8ae6597f
MD5 9df727e67ef9cac45ed616d7f62e0a0b
BLAKE2b-256 29c4ba13397e7823532212055a63172bf91934459b5841e648566e9cbb5de33d

See more details on using hashes here.

Provenance

The following attestation bundles were made for lintlang-0.3.2-py3-none-any.whl:

Publisher: publish.yml on hermes-labs-ai/lintlang

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page