keel check
Type-check a Keel program without executing it.
keel check <file.keel>
keel check --strict <file.keel>
What it checks
- Syntax — valid Keel grammar
- Types — type inference and compatibility
- Exhaustiveness —
whenmatches cover all enum variants - Arguments — task call parameter count and types
- Nullable safety —
T?vsTtracking - Scope —
selfonly inside agents, undefined variables
--strict mode
The checker’s default mode accepts bindings whose type cannot be inferred (for example, the result of json.parse or ai.extract without an explicit cast). It silently allows these rather than reporting an error.
--strict changes that: any binding whose inferred type is Unknown becomes a type error. Use it when you want higher confidence that the checker is actually verifying your code.
There are two kinds of unresolved types, and --strict treats them differently:
| Situation | Normal mode | --strict |
|---|---|---|
data: dynamic = json.parse(...) | ✓ silent | ✓ silent — programmer chose dynamic deliberately |
data = json.parse(...) (unannotated) | ✓ silent | ✗ error — no annotation, type cannot be inferred |
data = ai.extract(...) (unannotated) | ✓ silent | ✗ error |
In other words: an explicit dynamic annotation is always accepted. --strict only fires when the checker cannot infer any type, not when the programmer deliberately chose dynamic.
# Passes in normal mode, fails in strict
agent A {
@tools [io]
@on_start {
data = json.parse(raw_input) # unannotated — strict rejects this
io.show("{data}")
}
}
Fix with a dynamic annotation (accept the dynamic type) or a concrete cast:
# Option 1: annotate as dynamic — clean even in --strict
data: dynamic = json.parse(raw_input)
# Option 2: narrow to a concrete type immediately
type Payload { key: str, value: str }
data = json.parse(raw_input) as Payload
Example output
Success:
✓ examples/email_agent.keel is valid
Error with source span:
× Type error
╭─[agent.keel:8:5]
7 │ @on_start {
8 │ greet(42)
· ────┬────
· ╰── task `greet` takes 1 argument(s), got 0 — expected: name
9 │ }
╰────
Every error from keel check includes a line:column pointer and an underlined source excerpt. Arity errors list the expected parameter names as a hint.