graded

Effect checker for Gleam via sidecar .graded annotation files.

graded verifies that your Gleam functions respect their declared effect budgets. Annotations live in .graded sidecar files alongside your source — your Gleam code stays clean.

Usage

gleam run -m graded check [directory]   # enforce check annotations (default)
gleam run -m graded infer [directory]   # infer and write effect annotations
gleam run -m graded format [directory]  # normalize .graded file formatting

Programmatic API

Use run to check a directory and get back a list of CheckResult values, each containing any violations found per file. Use run_infer to infer effects and write .graded files.

Types

Errors that can occur during checking, inference, or formatting.

pub type GradedError {
  DirectoryReadError(path: String, cause: simplifile.FileError)
  FileReadError(path: String, cause: simplifile.FileError)
  FileWriteError(path: String, cause: simplifile.FileError)
  DirectoryCreateError(path: String, cause: simplifile.FileError)
  GleamParseError(path: String, cause: glance.Error)
  GradedParseError(path: String, cause: @internal ParseError)
  FormatCheckFailed(paths: List(String))
  CyclicImports(modules: List(String))
}

Constructors

  • DirectoryReadError(path: String, cause: simplifile.FileError)

    Could not read the source directory.

  • FileReadError(path: String, cause: simplifile.FileError)

    Could not read a source or annotation file.

  • FileWriteError(path: String, cause: simplifile.FileError)

    Could not write an annotation file.

  • DirectoryCreateError(path: String, cause: simplifile.FileError)

    Could not create the output directory for annotation files.

  • GleamParseError(path: String, cause: glance.Error)

    A .gleam source file could not be parsed.

  • GradedParseError(path: String, cause: @internal ParseError)

    A .graded annotation file could not be parsed.

  • FormatCheckFailed(paths: List(String))

    One or more .graded files are not formatted (returned by run_format_check).

  • CyclicImports(modules: List(String))

    The project’s import graph contains a cycle. Gleam disallows circular imports at the language level, so this should be unreachable in practice — if it ever fires it indicates a bug in the dependency edge extraction rather than user code.

Values

pub fn infer_path_dep(
  dep_path: String,
  base_kb: @internal KnowledgeBase,
) -> Result(
  dict.Dict(@internal QualifiedName, @internal EffectSet),
  Nil,
)

Build the dependency-graph index for a single path dep, topo-sort it, then infer every module in dependency order. Returns the union of all inferred effects keyed by QualifiedName so the caller can fold them into the global knowledge base. Errors are swallowed (returned as Error(Nil)) to preserve the existing tolerance: a malformed dep shouldn’t break the whole project.

Exposed (pub) primarily so tests can exercise the topological-order path inference on a temporary directory tree without going through gleam.toml resolution. Production callers go through enrich_with_path_deps which reads gleam.toml to discover dep paths.

pub fn main() -> Nil
pub fn run(
  directory: String,
) -> Result(List(@internal CheckResult), GradedError)

Run the checker on all .gleam files in a directory.

Reads the project’s single spec file (default <package_name>.graded) to find inferred public-API effects, check invariants, external hints, and type field annotations, then reports violations per source file.

pub fn run_format(directory: String) -> Result(Nil, GradedError)

Format the project’s spec file in place. The spec file is the single source of truth for hand-written check/external/type lines and the inferred public-API effects.

pub fn run_format_check(
  directory: String,
) -> Result(Nil, GradedError)

Check that the project’s spec file is already formatted. Returns error with the file path if it isn’t. Used by CI as format --check.

pub fn run_infer(directory: String) -> Result(Nil, GradedError)

Infer effects for all .gleam files in directory. Writes two outputs:

  1. Per-module cache files under <cache_dir>/<module_path>.graded, containing the inferred effects of every function in the module (public + private). Regenerated freely; not shipped.

  2. One spec file at <spec_file> containing the inferred effects of every public function across all modules, plus any hand-written check, external effects, or type annotations the user already had in the spec file (those lines are preserved verbatim).

Walks the project’s import graph in topological order so each module is analysed after every other project module it imports — a single pass resolves transitive chains of any depth.

Search Document