Modules

Packages, Modules, and Files

Paradox organizes code using three levels:

Packages

A package is defined by a dox.yaml file in a directory:

name: my-project
description: My domain specification

The name field defines the package name used in imports. The directory containing dox.yaml is the package root. A package contains one or more modules.

Modules

A module is a directory. All .dox files in a directory are merged into a single module — file names are purely organizational and have no effect on building or compiling (Go-style). Subdirectories are submodules, accessed via path syntax:

std/                   # "std" module (root of the std package)
  dox.yaml             # package manifest: name: "std"
  std.dox              # ┐
  collection.dox       # │ all merged into the "std" module
  algebra.dox          # │
  numeric.dox          # │
  function.dox         # │
  persist.dox          # ┘
  ast/                 # "std/ast" submodule
    foundation.dox     # ┐
    declaration.dox    # │ all merged into "std/ast"
    expression.dox     # │
    type.dox           # │
    term.dox           # │
    primitive.dox      # ┘

Files

Individual .dox files within a module directory are organizational only. You can split code across as many files as you like — they all become part of the same module. There is no import collection or import numeric; those are files inside std/, so you get them all with import std.

Import System

Paradox has two forms of import:

Package Imports

Import a package (or submodule) by name:

import std
import std/ast

Package names are resolved via the PARADOX_ATLAS environment variable, which contains a colon-separated list of absolute paths to package directories. Each path must contain a dox.yaml. When you import std, Paradox finds the directory whose dox.yaml has name: "std" and loads all .dox files in that directory.

To import a submodule, use path syntax: import std/ast loads all .dox files from the ast/ subdirectory within the std package.

Local Path Imports

Import subdirectories relative to the current project:

import /models
import /api/types

Path imports start with / and reference directories relative to the project root. All .dox files in the target directory are loaded as a module.

Multi-File Projects

Split large domain models across multiple files. All .dox files in a directory are part of the same module:

my-project/
  dox.yaml             # name: "my-project"
  types.dox            # ┐ all part of root module
  validation.dox       # ┘
  models/              # submodule, import with /models
    user.dox           # ┐ all part of "models" module
    pet.dox            # ┘
| In types.dox -- no import needed for validation.dox (same directory)
import std
import /models

Files in the same directory are automatically available to each other with no import required.

A file cannot import its own package. If machine.dox is part of the std package, writing import std inside it is a self-import error. Files within a package can reference each other’s types without importing their own package.

PARADOX_ATLAS

The PARADOX_ATLAS environment variable is a colon-separated search path of absolute directory paths. Each directory must contain a dox.yaml file. When you write import std, Paradox walks the atlas left to right, finds the first directory whose dox.yaml has name: "std", and loads all .dox files from that directory.

export PARADOX_ATLAS="/path/to/std:/path/to/my-lib:/path/to/other-pkg"

Requirements

Every entry in PARADOX_ATLAS must be:

  1. An absolute path (starts with /) — relative paths are rejected

  2. A valid filesystem path — no null bytes or illegal characters

  3. A directory containing a dox.yaml with at least a name field

If any entry fails these checks, Paradox will refuse to start and report the offending path.

dox.yaml

Each package directory has a dox.yaml manifest:

name: my-package
description: A useful domain specification

The name field is the identifier used in import statements. The description is optional metadata.

Resolution

When resolving import foo:

  1. Split PARADOX_ATLAS on :

  2. For each directory, parse its dox.yaml

  3. Return the first match where name equals foo

  4. If no match, report an error

For submodule imports like import foo/bar, Paradox finds the foo package as above, then loads .dox files from the bar/ subdirectory within that package.

Checking the Atlas

To see what packages are available in the current atlas:

paradox atlas

When using nix develop, PARADOX_ATLAS is set automatically to include the standard library.

See Also