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 canonical catalog of the built-in capabilities and where each one is actually enforced. The row vocabulary itself is open — you may declare capabilities of your own (see Custom capabilities below). For how rows are inferred, declared, and checked, see Functions & Effects and the declarations quick reference; for how authority is 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+, and the runtime refuses to admit it under any policy that forbids or bounds capability.

Each namespace below gets one table:

  • Effect path — the enforced string that appears in rows, journals, and policy rules. Effect instances are parameterized — net.connect("api.internal:443"), fs.read("data/**") — and policies match on instances.
  • Granting operations — the calls and constructs that perform a check_effect_op for this path before doing real work.
  • Enforcement — where the check happens, whether the instance (scope) is enforced, and which Cortex governance capability grants it under a sealed posture. Benign marks the host-free effects auto-granted under every non-admin posture; taint source/sink marks the ends of the untrusted-data watermark (a model/net/ffi return taints the frame; a tainted frame cannot reach an exec sink without human.approve endorsement).

Spec-vocabulary spellings are canonicalized before enforcement: proc.spawn/proc.exec/proc.shellproc.run; net.get/post/… → net.connect; the §3.6 spellings memory.query/memory.retain land on memory.read/memory.write, clock on clock.read, and all config.* on config.read.

Recognized ops vs. mapped effects. Each namespace also carries a recognized-op surface — the typo guard: calling an unrecognized op on a known namespace (fs.raed(...)) is a NameError at the call site, never a silently journaled no-op. That surface is deliberately a superset of the operations that map to an effect today; recognized spellings with no current mapping are reserved vocabulary (calling an unimplemented one still fails loudly): fs.read_bytes/read_csv/write_bytes/glob/walk/stat/size/touch, net.listen/resolve/ping/download/upload/send/receive (as ops — the net.listen effect itself is minted by http.serve), code.eval/format/lint/parse/run/compile, and proc.kill/wait/signal/pid. Every recognized observe, event, config, memory, env, ui, and package op maps to its namespace row above. A few namespaces perform their effect check inside the operation rather than at dispatch, after validating the resource: skills.load/dir (scoped fs.read), lean.check (resource-tagged proc.run), and the python.* bridge (scoped ffi.call). Intentionally dynamic namespaces (log by level, tools/mcp/ skills/stream by name) stay open by design.

Effect path Granting operations Enforcement
model.invoke generate, generate_batch, generate_stream, caption, ocr, vqa, transcribe, transcribe_stream; semantic.* verbs (all except the embed-backed three); code.gen; multimodal message routing (a text model that “sees”/“hears”); simulate def … by, the ~ operator family, check/ensure semantics(…) Checked at the model seam per call. Governance capability sema.effect.model. Taint source.
model.embed embed(...); semantic.similar/cluster/dedup; ~= when a type coerces via embedding Checked at the model seam per call. sema.effect.model. Taint source.
model.load Loading real model weights through the config registry ([models] pointing at files) Checked before the backend loads the artifact. sema.effect.model. Taint source.
Effect path Granting operations Enforcement
fs.read fs.read/read_text/read_json/list/exists/is_dir/is_file; path.exists; io.read_file/read/lines/exists; csv.read_rows; json.parse/read/items; yaml.parse/read; file_sha256; skill loads (skills.load/skills.dir) Checked per operation, confined to the project root. Skill loads are instance-scoped: the declared fs.read("path") scope must admit the canonicalized skill path. Capability sema.effect.fs.read.
fs.write fs.write/write_text/append/remove/delete/mkdir/copy/move/rename; io.write_file/write Checked per operation, confined to the project root. Capability sema.effect.fs.write.
Effect path Granting operations Enforcement
net.connect net.connect/get/post/put/patch/delete/head/request/fetch; service remote calls; model-scheduler remote endpoints Checked per operation plus per endpoint: every URL/host passes check_endpoint against scoped policy instances (net.connect("host") rules); redirects are never followed past authorization (redirect hops re-check). Capability sema.effect.net. Taint source.
net.listen http.serve(port, handler) Checked at bind. Capability sema.effect.net.listen.
Effect path Granting operations Enforcement
proc.run proc.run/spawn/exec/shell (spawn/exec/shell canonicalize to proc.run); lean.check (resource-tagged discovery + pinned execution checks) Checked per operation; lean.check passes an explicit resource identity. Capability sema.effect.exec. Taint sink; under governance the destructive-command denylist and the OS sandbox apply.
Effect path Granting operations Enforcement
code.exec code.exec; running staged Code[T] values Staged code runs are instance-scoped: code.exec("sandbox") must admit the code value’s sandbox. Capability sema.effect.exec. Taint sink.
code.patch code.patch/hotpatch/reload/revert; supervise/heal applied patches Checked per operation; code.hotpatch additionally requires [heal] apply != "staged" (denied + journaled otherwise). Capability sema.effect.code.patch. Taint sink.
(note) code.gen maps to model.invoke — generating code is a model call; only executing or patching it needs code.* authority.
Effect path Granting operations Enforcement
db.read db.query/read/select/count; typed sql"…" SELECTs Checked per operation. Capability sema.effect.db.read.
db.write db.exec/write/run/insert/clear/drop; typed sql"…" writes Checked per operation. Capability sema.effect.db.write.
(note) db.schema is §3.6 vocabulary reserved for schema migration; no runtime operation maps to it yet.
Effect path Granting operations Enforcement
env.read env.var/get/read/has/all Checked per operation. Not in the benign set — a governed posture must grant it.
env.write env.set/unset Checked per operation. Not in the benign set.
memory.read memory.get/recall/query/has/keys/list/search Checked per operation. Benign (auto-granted).
memory.write memory.set/put/store/retain/delete/remove/forget/clear Checked per operation. Benign.
config.read all config.* reads (get/model/temperature/set/has/all) Checked per operation (the §3.6 config.reload/config.watch vocabulary canonicalizes here today). Benign.
clock.read clock.wall_s/wall_now/wall_ms/mono_ms (clock.now is the fixed deterministic epoch and needs no grant) Checked per operation. Benign.
Effect path Granting operations Enforcement
observe.record every observe.* op; log.* at any level; collector channels and the |> tap; monitor declarations Check is deferred-recorded (journal-backed telemetry is the sink). Benign. observe.export is §3.6 vocabulary; observe ops canonicalize to observe.record today.
event.emit emit statements and event.* ops Checked per delivery, policy-checked and journaled. Benign (as is the reserved event.subscribe).
ui.render ui.render/show/print/display/update; io.print/println/print_line Checked per operation. Benign.
ui.notify ui.notify/alert; io.eprint/error Checked per operation. Benign.
human.approve ui.prompt/ui.input — interactive human input is the approval surface Checked per operation; endorsing untrusted data to trusted (§3.5) and posture approval-sets route through it. Headless approval-required checks fail closed to deny.
Effect path Granting operations Enforcement
ffi.call python.import/call/method/attr/str/free (the persistent Python worker); tools.* and mcp.* (tool/MCP servers are foreign calls); native import/bridge extern calls (C, JS) Bridge calls are instance-scoped: Python-worker and C/JS extern calls check a scoped resource identity (python:v1:…, c:v1:bridge=…:member=…) against the declared row instances and policy allows. tools.*/mcp.* are checked at path level (ffi.call). Capability sema.effect.ffi. Taint source.
Effect path Granting operations Enforcement
agent.spawn the spawn expression (agents and durable circuits); running a staged Code value with an agent entry Checked at spawn; sema check requires agent.spawn declared on functions that spawn, and policy examples: verification covers the agent namespace. Capability sema.effect.agent.spawn.
package.install all package.* ops (install/remove/add/update/upgrade/search/list) Checked per operation. Capability package.install.
policy.change policy administration (installing/widening a policy) Danger floor: no posture or program policy may permit past it — policy change is a distinguished, human-approved transaction (Policy).

random is canonical §3.6 vocabulary, but no runtime operation maps to it today: the tier-0 engine is deterministic and seeded, so there is no ambient randomness to gate. db.schema, observe.export, config.reload, and config.watch are likewise reserved spellings that today canonicalize onto (or await) their namespace’s enforced paths, as noted above. Declaring them in a row is legal — rows are open — and they journal as declared.

Custom capabilities — the row vocabulary is open

Section titled “Custom capabilities — the row vocabulary is open”

The catalog above is the built-in vocabulary, not a closed set: a row may declare namespaces the runtime has never heard of — !{mysql.query} parses, is containment-checked, and journals like any built-in path. A custom effect is a marker: there is no namespace object behind it (mysql.query(...) in a body is a NameError), so mint one with the wrapper-module pattern — a connector module whose public defs carry the custom effect plus the real underlying effects. Callers transitively need BOTH labels, and a policy can deny either:

# payments.sema — the connector module is the only place the label is minted.
def payments_read(account: str) -> list[dict] !{payments.read, db.read}:
return db.query("SELECT amount, account FROM payments WHERE account = ?", [account])
# main.sema
from payments import payments_read
policy NoPaymentReads:
forbid cap:
payments.read
justification "auditors may not touch payment rows in this scope"
def audit_exposure(account: str) -> int !{payments.read, db.read}:
return len(payments_read(account))
def main() -> None !{payments.read, db.read, db.write, observe.record, ui.render}:
db.exec("CREATE TABLE IF NOT EXISTS payments (account TEXT, amount REAL)")
db.insert("payments", {"account": "acct-1", "amount": 12.5})
log.info("payments visible", rows=audit_exposure("acct-1"))
with policy(NoPaymentReads):
expect n = audit_exposure("acct-1"):
log.info("policy failed to bite", rows=n)
except Denied as d:
# "policy NoPaymentReads denies effect payments.read in
# audit_exposure(): forbidden capability"
log.info("denied as designed", why=d.message)

A caller whose row omits payments.read is rejected by sema check (call to payments_read requires undeclared effect(s) payments.read) and denied by the runtime’s containment check. Two honest boundaries: effect vocabulary is authority labeling, not OS-level confinement — an fs.write holder cannot be kept away from database files by effect kind alone; use scoped instances plus governance postures and the OS sandbox for confinement. And sema check lints near-misses of built-in namespaces (!{fss.read} → “did you mean fs?”) while genuinely distinct custom names stay clean by design.

Effects are enforced by five cooperating layers. Every native boundary performs a per-operation check (check_effect_op) against the active function row before doing real work. Caller containment is enforced twice: sema check rejects a call whose callee’s declared row exceeds the caller’s, and the runtime re-checks the callee row at every call so unchecked entry points cannot launder authority. Active policies deny by path (forbidden capability / not in the policy allow set), journaling every verdict. Scoped instance enforcement applies where resources have identities — net endpoints, skill file loads, staged code.exec sandboxes, and ffi.call bridge members — everything else is path-level. Governance adds what labels cannot: posture allow-sets over the capability map, the untrusted-source-to-exec-sink taint watermark, the destructive-command denylist, and the OS sandbox for governed exec.