Skip to content

Effects Catalog

An effect row is the part of a function’s type that names the authority the function may exercise: def f(x: T) -> R !{fs.read, model.invoke}. This page is the authoritative catalog of the capabilities a row may name. For how rows are inferred, declared, and checked, see Functions & Effects; for how they are granted and confined, see Effects & Capabilities.

A function typed with the empty row !{} provably performs no model calls and no I/O. It is a type-enforced sublanguage, not a convention — the deterministic core of Sema. An omitted row is not a wildcard: it asks the compiler to infer the minimal row from the body, which is fail-closed (a function that touches nothing infers !{}). Authority is always conspicuous.

def add(a: int, b: int) -> int !{}: # provably pure — no model, no I/O
return a + b
def load_config(path: str) -> Config !{fs.read}: # authority is stated
...

!{*} is the explicit all-effects top (⊤) — a loud, greppable escape hatch for spikes and REPL work, not the meaning of silence. sema check warns on it at bronze and errors at silver+.

Every capability belongs to a namespace (fs, net, model, …) and names a specific operation (fs.read, model.invoke, …). The table below is the authoritative set of effect capabilities and the constructs that typically require them. Effect instances are parameterized — net.connect("api.internal:443"), fs.read("data/**") — and policies match on those instances (see below).

Effect Meaning Typically required by
fs.read Read files under the project root (read, list, stat). File reads: io/fs reads, config loading, read_* helpers.
fs.write Write, append, copy, or remove files under the project root. File writes: report/artifact output, snapshots, caches on disk.
net.connect Open an outbound network connection (HTTP/HTTPS). net.* fetches, service calls to a remote endpoint, remote model APIs.
net.listen Bind and accept inbound connections. Serving an HTTP endpoint / a service that listens.
model.invoke Call a generative model (text/tool generation). simulate def … by <model>; the ~ semantic operators (~=/~!=/~</~in/~[query]/…) when calibrated; semantic.* verbs (filter/rank/map/classify/extract/summarize/translate/cluster/dedup/…); check/ensure semantics(…).
model.embed Compute embeddings for a value. ~= and similarity when a type coerces via embed; semantic.cluster/dedup; explicit embed(...).
model.configure Configure/select a model resource (bind roles, calibration, sampling). Model registry setup and with model(...) rebinding; pinning a judge/calibration for a decision site.
observe.record Record telemetry to the run journal. collector channels and the `
db.read Read from the database (queries). db.query/db.read; typed sql"…" SELECTs.
db.write Write to the database (insert/update/exec). db.exec/db.insert; typed sql"…" writes.
db.path Bind the database to a filesystem path. Selecting the embedded SQLite location ([db] path).
db.url Bind the database to a DSN. Selecting a database by DSN ([db] url), including a @provides("db") backend.
env.read Read the process environment. env.* reads; configuration sourced from the environment.
env.write Write the process environment. env.* writes that set variables for the run.
proc.run Run a subprocess and read its result. proc.* invocations that shell out (returns {stdout, stderr, code}).
ui.notify Emit a user-facing notification/alert. Alerts and user prompts routed to the terminal/UI.
ui.render Render user-facing output. Rendering to the terminal/UI.
memory.read Read the in-process key/value store. std.cache @memoize (in-run memo), scratch state across a run.
memory.write Write the in-process key/value store. @memoize cache fills; ephemeral run-scoped state.
event.emit Publish a domain event. emit in the event/emit/subscriber system (Events).
code.* Generate, patch, or evaluate staged code. reflect/Code[T]/runtime eval; supervise/heal code repair.
ffi.call Call foreign (e.g. Python) functions. native/ported interop and ffi.call (Python Interop).
clock.read Read the (deterministic) clock. Timestamps; time-budgeted work. Returns a fixed epoch so runs replay identically.
random.* Draw randomness (seeded/deterministic). Sampling, jitter, shuffles — reproducible under a fixed seed.
config.* Read or bind configuration. The config/DI layer and sema.toml-sourced settings (Packaging).
package.* Package-manager operations. Dependency resolution / install (sema add/remove).
policy.* Install or scope a policy. with policy(...) and policy administration (Policy).
human.* Request human input or approval. Human-in-the-loop approval, supervise/heal escalation.

Sema separates two things that look similar:

  • Declaring a capability is open. An effect row may name any capability, so !{fs.raed} still parses — rows are intentionally extensible, and a later real capability shows up as a signature diff, not a silent change.
  • Calling an operation is checked. Calling an operation resolves like any builtin. A call to an unrecognized op on a known namespace — fs.raed("x"), model.invok(...) — raises a NameError at the call site rather than silently journaling an effect and returning None. Each namespace has a recognized callable surface; typos are caught, not swallowed.

Statement position is guarded the same way: an unknown word …: directive parses as inert (the declarative-config escape), but sema check warns on any directive in a def/simulate body that no runtime handler recognizes — so a misplaced or misspelled clause surfaces at check time instead of doing nothing at runtime.

def fetch(url: str) -> Response !{net.connect}:
return net.fetch(url) # ok — net.fetch is a recognized net op
def broken(url: str) -> Response !{net.connect}:
return net.ftech(url) # NameError at the call site — not a silent None

A function’s row is an upper bound on the authority it may use; a policy grants and confines that authority, matching on effect instances:

policy ReadOnlyData:
allow: fs.read("data/**")
forbid: fs.write
forbid: net.connect
examples:
- fs.read("data/reports/q3.json") -> allow
- fs.write("data/out.json") -> deny
with policy(ReadOnlyData):
load_inputs() # may read data/**, may not write or connect

Policy examples are verified at load (sema check errors if an examples: entry contradicts the rules). Confinement is transitive over closures: a closure created under a policy that forbids a capability stays forbidden even when it is invoked elsewhere. The runtime is an effect-handler stack, so policy enforcement, record/replay, mocking, and batching are all handlers over these same operations — one mechanism, applied per function row (and, for net, per endpoint).