Skip to main content

Code Quality

GospeLib enforces code quality through linters, formatters, and type checkers for each language. This guide covers how to run them and what standards are enforced.

Quick Reference

# Run all linters (TS/JS projects via Nx)
pnpm lint

# Format all files
pnpm format

# Type-check all TS projects
pnpm typecheck

TypeScript / JavaScript

ESLint

Flat config in eslint.config.mjs with typescript-eslint strict preset:

# Lint all TS/JS projects
pnpm lint

# Lint only affected projects
pnpm nx affected -t lint --parallel=4

# Auto-fix
pnpm nx run <project>:lint --fix

Key rules enforced:

RuleLevelNotes
no-unused-varserrorIgnores variables prefixed with _
no-explicit-anywarnPrefer typed alternatives
strict TypeScriptenabledVia tsconfig.base.json

Prettier

Configured in the root with:

  • Print width: 100
  • Indent: 2 spaces
  • Single quotes
  • Semicolons enabled
# Format all supported files
pnpm format

# Check formatting without writing
pnpm prettier --check .

TypeScript Strict Mode

The base tsconfig.base.json enables:

  • strict: true
  • noUnusedLocals: true
  • noUnusedParameters: true
  • noFallthroughCasesInSwitch: true
  • verbatimModuleSyntax: true
  • isolatedModules: true
# Run type checking across all projects
pnpm typecheck

Python

Ruff (Linting + Formatting)

Ruff handles both linting and formatting for all Python services. Configuration is per-service in pyproject.toml:

[tool.ruff]
line-length = 100
target-version = "py312"
# Lint
cd services/content && uv run ruff check .

# Lint with auto-fix
cd services/content && uv run ruff check . --fix

# Format
cd services/content && uv run ruff format .

mypy (Type Checking)

mypy runs in strict mode:

[tool.mypy]
strict = true
cd services/content && uv run mypy .

Combined lint check

# Lint + type-check a Python service
cd services/content && uv run ruff check . && uv run mypy .

Use the VS Code tasks for convenience:

  • Lint: Python (Content)cd services/content && uv run ruff check . && uv run mypy .
  • Lint: Python (AI)cd services/ai && uv run ruff check . && uv run mypy .
  • Lint: Python (Ingest)cd services/ingest && uv run ruff check . && uv run mypy .

Go

go vet + golangci-lint

Each Go service has a .golangci.yml enabling these linters:

  • govet, errcheck, staticcheck, unused, gosimple
  • ineffassign, typecheck, gocritic
  • Line length: 120 characters
# Vet + lint a Go service
cd services/gateway && go vet ./... && golangci-lint run

Formatting

Go uses gofmt (tabs, not spaces) — enforced by golangci-lint:

# Format Go code
gofmt -w services/gateway/

EditorConfig

The .editorconfig at the repo root normalizes editor settings:

ScopeIndentSizeEOL
Default (*)spaces2LF
*.pyspaces4LF
*.gotabs4LF
*.mdLF (no trailing whitespace trim)

Pre-Commit Pipeline

Every commit runs through this pipeline automatically:

git commit
→ Husky pre-commit hook
→ lint-staged
→ *.{js,jsx,ts,tsx,mjs,cjs,mts,cts} → eslint --fix → prettier --write
→ *.{json,md,yml,yaml,css,scss} → prettier --write
→ Husky commit-msg hook
→ commitlint (Conventional Commits)

Commit message format

Commits must follow Conventional Commits enforced by commitlint:

feat(content): add witness endpoint
fix(gateway): handle missing JWT gracefully
docs(guides): add testing guide

Valid scopes: web, mobile, admin, gateway, content, auth, billing, ai, notifications, ingest, ui, sdk, types, config, infra, ci, deps

Use pnpm commit for an interactive commit prompt (Commitizen).

CI Integration

The CI pipeline runs lint checks on every PR:

# What CI runs
pnpm nx affected -t lint --parallel=4
pnpm nx affected -t typecheck --parallel=4

All lint and type-check failures block merge.

Troubleshooting

ESLint reports errors in files I didn't change

Run pnpm nx affected -t lint to lint only files affected by your branch. If the issue persists, the base branch may have introduced a new rule.

mypy reports errors in third-party packages

Add type stubs or ignore the specific import:

import some_untyped_lib # type: ignore[import-untyped]

golangci-lint is slow

Increase the timeout in .golangci.yml:

run:
timeout: 5m