Skip to main content

Polyglot ubiquitous language linter for codebases and coding agents

Project description

dddlint

Polyglot ubiquitous language linter. Reads class, function, method, and type names across 306 languages and enforces them against a domain vocabulary — banned terms, non-canonical synonyms, and one concept spelled multiple ways.

Works with any language tree-sitter recognises, without per-language queries. Slots into pre-commit hooks, CI pipelines, and coding agent loops via a non-zero exit code on findings. Ships with an LSP server for inline editor diagnostics and rename code actions.

Install

uv add dddlint

Quick start

# lint current directory (looks for dddlint.yaml)
dddlint lint

# lint a specific path
dddlint lint src/

# open an interactive language graph in the browser
dddlint html

# start the LSP server (stdio)
dddlint lsp

Config

Place dddlint.yaml at the project root. When a path is passed to lint or html, the config is looked up in that directory first, then falls back to the current working directory.

similarity_threshold: 0.85   # Jaccard threshold for drift detection
enforce_canonical: true       # flag alias terms in addition to forbidden ones

# terms that must never appear in a definition name
forbidden:
  - util
  - helper
  - manager

# canonical terms and their aliases
synonyms:
  - canonical: customer
    aliases: [client, user, accountholder]
  - canonical: order
    aliases: [purchase, transaction]

# high-level business domains
domains:
  - name: commerce
    include: ["**/commerce/**"]
    synonyms:
      - canonical: order
        aliases: [purchase]

# bounded contexts — same structure as domains, applied after (context wins on conflict)
contexts:
  - name: billing
    include: ["**/billing/**"]
    forbidden: [discount]
    synonyms:
      - canonical: invoice
        aliases: [bill, statement]

# register file extensions for languages not auto-detected
languages:
  svelte:
    extensions: [".svelte"]

Global rules apply everywhere. Domain rules apply to matching paths. Context rules apply after domains, so a context can override a domain synonym.

Rules

Rule Severity Description
forbidden error A definition name contains a banned term
alias warning A definition uses a non-canonical synonym — includes a rename suggestion
drift info The same concept is spelled multiple ways across the codebase
config:forbidden-canonical-clash error A term is both forbidden and a canonical synonym
config:alias-conflict warning The same alias maps to different canonicals in different scopes
config:duplicate-name info Two domains or contexts have suspiciously similar names

Config rules are checked against dddlint.yaml itself on every run.

LSP

The LSP server publishes diagnostics on file open and save, scanning the entire workspace each time so cross-file drift is always caught. Alias findings include a code action to rename the identifier to the canonical term with case preserved (ClientRepoCustomerRepo, get_clientget_customer).

Neovim — add to init.lua:

vim.api.nvim_create_autocmd("BufReadPost", {
  callback = function(args)
    local root = vim.fs.root(args.buf, { "dddlint.yaml" })
    if root then
      vim.lsp.start({
        name = "dddlint",
        cmd = { "dddlint", "lsp" },
        root_dir = root,
      }, { bufnr = args.buf })
    end
  end,
})

The autocmd fires on every buffer, attaches only when dddlint.yaml is found, and is language-agnostic — no filetype list required.

VS Code — via a generic LSP client extension:

{
  "lsp.servers": {
    "dddlint": {
      "command": ["uvx", "dddlint", "lsp"],
      "filetypes": ["*"]
    }
  }
}

Helix.helix/languages.toml:

[language-server.dddlint]
command = "dddlint"
args = ["lsp"]

Language support

Extraction is powered by tree-sitter-language-pack, which covers 306 languages including:

Ada · Agda · Arduino · Bash · C · C++ · C# · Clojure · COBOL · Crystal · CSS · D · Dart · Dockerfile · Elixir · Elm · Erlang · F# · Fortran · GDScript · GLSL · Go · GraphQL · Groovy · Hack · Haskell · HCL · HTML · Java · JavaScript · Julia · Kotlin · Lean · Lua · MATLAB · Mojo · Nix · OCaml · Odin · Pascal · Perl · PHP · PowerShell · Prolog · Python · R · Racket · Ruby · Rust · Scala · Scheme · Solidity · SQL · Svelte · Swift · Terraform · TLA+ · TOML · TypeScript · V · VHDL · Vim · Vue · WebAssembly · XML · YAML · Zig — and 243 more.

CI

# .github/workflows/dddlint.yml
- run: uvx dddlint lint

Exit code is 0 when clean, 1 when findings exist.

Pre-commit

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: dddlint
        name: dddlint
        entry: dddlint lint
        language: python
        pass_filenames: false

Offline use

The language pack downloads parsers on first use. For CI or air-gapped runs, warm the cache in the image:

python -c "import tree_sitter_language_pack as t; t.download_all()"

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

dddlint-0.1.2.tar.gz (168.0 kB view details)

Uploaded Source

Built Distribution

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

dddlint-0.1.2-py3-none-any.whl (16.5 kB view details)

Uploaded Python 3

File details

Details for the file dddlint-0.1.2.tar.gz.

File metadata

  • Download URL: dddlint-0.1.2.tar.gz
  • Upload date:
  • Size: 168.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for dddlint-0.1.2.tar.gz
Algorithm Hash digest
SHA256 01a7ef94a50f4123d9dfeb8c07c576c196677686101343d8895c6a56790c03dc
MD5 5a38cb75cd4777e81900ec889506e6da
BLAKE2b-256 2f2165d988a539b01ae39698d1eff99c71d798d63c4300ddf65fbfc6d0f1ce9c

See more details on using hashes here.

Provenance

The following attestation bundles were made for dddlint-0.1.2.tar.gz:

Publisher: workflow.yaml on benomahony/dddlint

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

File details

Details for the file dddlint-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: dddlint-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 16.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for dddlint-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 664cffdf93f63c6d12a1c98a74ab2aa86274b8f4ac182761f2c0400ba39a39e4
MD5 8df2f5c6149819c0c41697db49b90d90
BLAKE2b-256 c642542dd0450acb216db85a7340aeca745c2c082ab5e43a780f7a73650ac303

See more details on using hashes here.

Provenance

The following attestation bundles were made for dddlint-0.1.2-py3-none-any.whl:

Publisher: workflow.yaml on benomahony/dddlint

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