Get psl running in your project in three steps.

Step 1: Create a Config File

Create .python-structure-linter.yaml in your project root and declare your structure rules:

include: [src]
exclude: ["**/__pycache__/**"]

rules:
  - name: context-layers
    type: directory-exists
    description: Each context has domain, application, and adapters layers
    within: src/contexts/{ctx}
    require: [domain, application, adapters]

  - name: domain-components
    type: allowed-children
    description: The domain layer holds only recognized component directories
    within: src/contexts/{ctx}/domain
    kind: dir
    group_level: optional
    allow: [entities, value_objects, events, services, errors]
    ignore: [__init__.py]

  - name: one-class-per-domain-module
    type: symbol-count
    description: Domain modules define a single class
    within: src/contexts/{ctx}/domain/**
    symbol: class
    max: 1
    ignore_files: [__init__.py]

This config scopes the scan to src and defines three rules:

  • context-layers — every context directory under src/contexts/ must contain domain, application, and adapters subdirectories.
  • domain-components — each domain layer may only hold the listed component directories; with group_level: optional, an unlisted directory passes only if it is a grouping tier (e.g. a subdomain) whose own children are all allowed.
  • one-class-per-domain-module — each .py module under a domain layer may define at most one top-level class.

Each rule scopes itself with its own within pattern — there is no separate apply step. Path patterns are project-root-relative: {ctx} matches exactly one segment (captured for readability) and ** matches zero or more.

Step 2: Run the Linter

From your project root, run:

psl check

psl automatically discovers the config file by searching upward from the current working directory for .python-structure-linter.yaml or a [tool.python-structure-linter] section in pyproject.toml.

Step 3: Review the Output

Each violation is reported with the offending path, the rule name, its description, and a concrete message. symbol-count violations append the line of the surplus symbol:

$ psl check
src/contexts/orders
    [context-layers] Each context has domain, application, and adapters layers
    missing required directory 'adapters'

src/contexts/orders/domain/repositories
    [domain-components] The domain layer holds only recognized component directories
    unexpected directory 'repositories' (not an allowed component)

src/contexts/orders/domain/entities/order.py:24
    [one-class-per-domain-module] Domain modules define a single class
    2 top-level class definitions found, at most 1 allowed

Found 3 violation(s).

Fix the reported structure and re-run psl check until you see No violations found. The command exits 0 when clean, 1 when violations are found, and 2 on a config error.

Next Steps

  • Learn every config option, rule type, and path-pattern token in Configuration.