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.
The deterministic core: !{}
Section titled “The deterministic core: !{}”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.
How to read the tables
Section titled “How to read the tables”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_opfor 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.approveendorsement).
Spec-vocabulary spellings are canonicalized before enforcement:
proc.spawn/proc.exec/proc.shell → proc.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. |
env, memory, config, clock
Section titled “env, memory, config, clock”| 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. |
observe, event, ui, human
Section titled “observe, event, ui, human”| 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. |
agent, package, policy
Section titled “agent, package, policy”| 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). |
Vocabulary without a runtime surface yet
Section titled “Vocabulary without a runtime surface yet”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.semafrom 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.
The enforcement model, honestly
Section titled “The enforcement model, honestly”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.
See also
Section titled “See also”- Effects & Capabilities — granting and confining authority.
- Functions & Effects — how rows are written and inferred.
- Declarations quick reference — row syntax at a glance.
- Policy — the full
policyconstruct. - CLI reference —
sema check(row discipline) andsema assure --grade silver(explicit rows required).