Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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
  • Exhaustivenesswhen matches cover all enum variants
  • Arguments — task call parameter count and types
  • Nullable safetyT? vs T tracking
  • Scopeself only 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:

SituationNormal mode--strict
data: dynamic = json.parse(...)✓ silentsilent — programmer chose dynamic deliberately
data = json.parse(...) (unannotated)✓ silenterror — no annotation, type cannot be inferred
data = ai.extract(...) (unannotated)✓ silenterror

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.