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
.gleamsource file could not be parsed. -
GradedParseError(path: String, cause: @internal ParseError)A
.gradedannotation file could not be parsed. -
FormatCheckFailed(paths: List(String))One or more
.gradedfiles are not formatted (returned byrun_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 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:
-
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. -
One spec file at
<spec_file>containing the inferred effects of every public function across all modules, plus any hand-writtencheck,external effects, ortypeannotations 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.