Declaring effects

Every side effect in Cleat is declared with a needs clause. A function without needs is pure — it cannot perform I/O, make HTTP calls, or access the LLM.

Syntax

cleat
fn fetch(url: string) -> Result[string, string] needs { net } {
    return http.get(url)
}

fn pure_transform(s: string) -> string {
    return strings.to_upper(s)  // no effects needed
}

Built-in effects

EffectGrants access to
llmLLM API calls (agent.run, llm.prompt, llm.generate, llm.tokens)
netNetwork access (http.get, http.post, http.send, server.start)
fsFile system (fs.read, fs.write, fs.list, memory.*)
ioProcess I/O (io.print, env.get, os.exit, supervisor.trace)
logLogging (log.debug, log.info, log.warn, log.error)
cryptoCryptographic operations
timeWall-clock access (time.now)
dbDatabase access (future)
gitGit operations (future)

Compile-time enforcement

cleat
fn bad() -> string {
    return http.get("url")  // ← compile error: missing needs effect: net
}

The compiler produces:

text
error: missing needs effect: net
  --> main.cleat:2:12
   |
 2 |     return http.get("url")
   |            ^

Transitive enforcement

If function A calls function B which needs { net }, then A must also declare needs { net }:

cleat
fn fetch(url: string) -> Result[string, string] needs { net } {
    return http.get(url)
}

fn process() -> Result[string, string] needs { net } {  // must declare net
    return fetch("https://api.example.com")
}

Multiple effects

Declare multiple effects with commas:

cleat
fn main() -> int needs { llm, net, io, log } {
    log.info("starting")
    let result = agent.run("prompt")?
    io.println(result)
    return 0
}

Effects on primitives

PrimitiveEffect rules
agentMust include llm; must cover all tools' effects
guardCheck function can have its own needs
toolEffects propagate to callers
streamEffects propagate to consumers
serverMust include net; must cover all handlers' effects
Edit this page on GitHub