Vale for your domain language — with teeth

The vocabulary your team agreed on.
Enforced on every pull request.

3D-Linter reads a .glossary.yml from your repo and fails PRs that introduce the terms you agreed to avoid — in identifiers, comments, and docs. Deterministic, offline, sub-second.

Why this exists: the streak bug

A habit-tracking app had a glossary with one ambiguous term: “streak.” An engineer implemented it as consecutive days with a vice mark — an app that rewarded seven days of failure in a row. The feature shipped, had to be renamed (“Engagement Streak”), and re-implemented.

The glossary existed. The definition was written down. Nothing enforced it.

Vocabulary drift is a defect class, not a style nit.

How it works

Domain-Driven Design calls it the ubiquitous language; every team that cares about naming keeps the artifact either way — a glossary of canonical terms in a wiki that nothing reads. 3D-Linter moves it into the repo and wires it to CI.

1 — declare

Write the glossary

Canonical terms, the synonyms to avoid, and the reason — versioned and code-reviewed like everything else.

terms:
  - use: practitioner
    avoid: [user, customer]
    reason: '"user" is too generic,
      "customer" implies payment'
2 — gate

Fail the PR, precisely

Only lines the PR introduces are gated. Pre-existing code and third-party APIs never turn red.

✗ signup.go:42
introduces "user" — glossary
says "practitioner":
"user" is too generic
3 — evolve

Let it accumulate

Opt-outs need a written reason, so exceptions stay visible. The glossary grows into a reasoned record of what words mean here.

id := u.ID // 3dl:allow user
   -- passport API field

Built to survive week one

A linter that is wrong too often gets deleted. Precision beats recall in every v0 decision:

The gate is deterministic.
AI is advisory.

Same input, same verdict, every run, offline — that's what a merge-blocking check owes you. No LLM ever sits in the blocking path.

The Gate — free, forever The Advisor — paid, planned
What CLI + GitHub Action: avoid-list enforcement on PR diffs, full-repo audit, suppressions, SARIF/JSON output. bootstrap drafts a glossary from your codebase; semantic-drift PR comments; maintenance reports.
Blocks merges? Yes — reproducibly. Never. Suggestions only.
Network Zero calls. No telemetry, no accounts, no server. Your own LLM API key. Your code never transits ours.

Get started

One command scaffolds the glossary and the workflow; the first PR is gated minutes later.

# install
go install github.com/RomanosTrechlis/3d-linter/cli/cmd/3dl@latest

# scaffold .glossary.yml + .github/workflows/3dl.yml
3dl init

# check locally, exactly like CI will
3dl check --diff main

Or wire the Action directly:

on: pull_request
jobs:
  vocabulary:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - uses: RomanosTrechlis/3d-linter/github-action@master
Go CLI
available
GitHub Action
available
GitLab CI
planned
Jenkins
planned
pre-commit
planned

Fits what you already run