Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Tasks

Alpha (v0.1). Breaking changes expected.

Tasks are Keel’s functions. They’re named, reusable, and the last expression in the body is the return value.

Basic tasks

task greet(name: str) -> str {
  "Hello, {name}!"
}

Call it:

msg = greet("World")   # "Hello, World!"

Parameters

# Typed parameters
task add(a: int, b: int) -> int {
  a + b
}

# Default values
task compose(email: str, tone: str = "friendly") -> str {
  draft "response to {email}" { tone: tone }
}

# Struct parameters (inline type)
task triage(email: {body: str, from: str}) -> Urgency {
  classify email.body as Urgency fallback medium
}

Implicit return

The last expression in a task body is the return value:

task double(x: int) -> int {
  x * 2              # this is the return value
}

Use return for early exits:

task handle(email: {body: str, from: str}) -> str {
  if email.from.contains("noreply") {
    return "Skipped automated email"
  }
  draft "response to {email}" { tone: "professional" } ?? "(draft failed)"
}

Task composition

Tasks can call other tasks:

task add(a: int, b: int) -> int { a + b }
task double(x: int) -> int { add(x, x) }

result = double(5)   # 10

Top-level vs agent tasks

Tasks defined outside agents are reusable and testable. Tasks defined inside agents can access self:

# Top-level: shared, testable
task triage(email: {body: str}) -> Urgency {
  classify email.body as Urgency fallback medium
}

# Agent-scoped: can access self.state
agent Bot {
  state { count: int = 0 }

  task increment() {
    self.count = self.count + 1
  }
}

Prefer top-level tasks for any logic that doesn’t need agent state.

Pipeline composition

email |> triage |> respond |> log

# With arguments
email |> triage |> respond(tone: "formal")

The |> operator passes the left-hand value as the first argument to the right-hand function.