Native Agents and Durable Circuits
Sema has two multi-agent constructs:
agentdeclares a typed, bounded model actor.circuitdeclares durable orchestration using ordinary Sema control flow.
That is the entire language addition. There is no separate graph DSL, mailbox
language, or keyword for every orchestration pattern. Assignments carry values,
parallel creates fan-out/fan-in, spawn creates an owned task, if and
match choose paths, and contracts form gates.
Mental model
Section titled “Mental model”| Surface | Meaning |
|---|---|
agent name(input) -> Output by model: |
A typed model/tool loop with a role instruction, hard contracts, and a budget |
circuit name(input) -> Output !{effects}: |
A durable function whose calls and control flow form a work graph |
parallel [worker(x) for x in xs] |
Ordered, bounded fan-out followed by fan-in |
spawn worker(input) |
An owned Task[Output] that may run independently |
task.join()? |
Wait for the task and propagate a typed task failure |
Agent.build(spec, under=envelope)? |
Validate a dynamically proposed specialist inside fixed authority |
agent and circuit are soft keywords. They are recognized only where a
declaration can begin, preserving the wider identifier namespace.
Declare a typed agent
Section titled “Declare a typed agent”An agent looks like a function, but the runtime owns its bounded model↔tool loop. The declaration fixes its input, output, role, model, tools, budget, and completion contracts:
def search(query: str) -> str !{}: return "source:" + query
agent researcher(question: str) -> str by research_model: sem "Collect one attributable finding and separate fact from inference" use tools [search] budget model_calls=2, tokens=512 ensure len(result) >= 1Tools remain ordinary effect-typed Sema functions. The agent’s effect row is
derived from its model, selected tools, and delegated child pool; it is not
duplicated in the declaration. At assure silver or higher, every agent must
have an explicit model_calls limit.
The call completes only when the model output decodes to the declared type and its hard contracts pass. Budget, decode, policy, stall, and contract failures remain typed failures; a model judge cannot overrule them.
Compose a circuit
Section titled “Compose a circuit”A circuit is normal Sema with durable agent calls:
agent writer(evidence: list[str]) -> str by writer_model: sem "Synthesize evidence with provenance and explicit uncertainty" budget model_calls=1, tokens=512 ensure len(result) >= 1
circuit synthesize(questions: list[str]) -> str !{model.invoke}: budget agents=8, spawn_depth=0, model_calls=16, tokens=8000 evidence = parallel [researcher(question) for question in questions] return writer(evidence)The comprehension is the topology:
┌─ researcher(question 1) ─┐questions ── parallel ───├─ researcher(question 2) ─┼── evidence ── writer └─ researcher(question 3) ─┘parallel [expression for item in items] is the canonical ordered
comprehension form. There is deliberately no par alias; par remains an
ordinary identifier. Sema may dispatch static read-only or disjoint agents in
isolated child sessions. Dynamic agents and work with overlapping or unknown
mutation scope are conservatively serialized.
Decisions, gates, and repair loops
Section titled “Decisions, gates, and repair loops”Circuits do not need display-oriented syntax. Ordinary constructs carry the meaning:
if issue.failed: specialist = Agent.build(spec, under=envelope)? finding = (spawn specialist(issue)).join()? draft = writer(finding) verification = verifier(draft) ensure verification.passed return draftThe runtime derives:
| Program construct | Observed graph shape |
|---|---|
parallel |
fork and merge |
| value dependency | edge between work units |
spawn / join |
task edge and synchronization point |
if / match |
decision and selected path |
loop until / bounded loops |
repeated, bounded subgraph |
ensure, policy, approval, completion policy |
gate with pass, wait, or fail state |
This makes generator→reviewer→repair, panels, routing, monitor-triggered intervention, and recursive orchestrator→worker patterns library patterns over one language rather than new syntax.
Spawn owned work
Section titled “Spawn owned work”Use spawn when the parent should continue before synchronizing:
circuit deliver(request: ChangeRequest) -> PatchArtifact !{agent.spawn, model.invoke}: budget agents=4, spawn_depth=1, model_calls=8, tokens=6000 evidence = explorer(request) implementation = spawn engineer(evidence) patch = implementation.join()? return hardener(patch)spawn returns an owned Task[T]. A child cannot outlive its circuit: circuit
exit joins or cancels outstanding children, and cancellation propagates through
the owned subtree. Lifecycle states are pending, running,
awaiting_signal, suspended, complete, failed, and cancelled.
Admit a dynamic specialist
Section titled “Admit a dynamic specialist”When the required role depends on runtime evidence, an orchestrator can propose
an AgentSpec. Agent.build admits it only under a typed envelope:
from std.agents import AgentSpec, AgentEnvelope
spec = orchestrator(issue)specialist = Agent.build(spec, under=envelope)?finding = (spawn specialist(issue)).join()?The envelope fixes input/output types, allowed models, tool subset, child limits, and sub-budget. Delegated authority is always the intersection of the sealed root, circuit policy, parent policy, envelope, and spawn-site grant:
child authority = sealed root ∩ circuit ∩ parent ∩ envelope ∩ spawn grantA child cannot mint a tool, effect, model, policy, child pool, or fresh budget.
Every child charge accrues to all enclosing budgets. Data-only AgentSpec
admission is distinct from staged Code[Agent[I,O]], which additionally needs
an explicit envelope plus code.exec("agent-sandbox") and agent.spawn.
Durability and resume
Section titled “Durability and resume”The outer circuit owns one local run under .sema/runs/<run-id>/:
- atomic session state;
- segmented JSONL events;
- content-keyed completed-leaf memos;
- content-addressed artifacts.
Stable leaf identity includes the circuit symbol, callsite, agent semantic
hash, serialized input digest, parent path, and dynamic ordinal. Resume reuses
unchanged completed leaves. It may retry an incomplete read-only leaf, but an
external mutation without recorded completion suspends as
NeedsReconciliation instead of guessing.
One run’s durable life, end to end:
flowchart LR R["sema circuit run"] --> J[".sema/runs/<run-id>/\natomic session state\nsegmented JSONL events\nleaf memos + artifacts"] J -->|"crash or interrupt"| S["sema circuit resume\n<run-id>"] S --> M["completed leaves reused\n(content-keyed memos)"] M --> D["unfinished leaves re-run;\nexternal mutation without a\nrecorded completion suspends as\nNeedsReconciliation"] D --> C["run completes"]sema circuit run examples/agent-researchsema circuit list examples/agent-researchsema circuit show examples/agent-research <run-id>sema circuit resume examples/agent-research <run-id>sema circuit cancel examples/agent-research <run-id>These commands manage the durable aggregate. They are not a separate orchestration engine; the circuit remains ordinary checked Sema.
Standard roles and patterns
Section titled “Standard roles and patterns”std.agents provides typed specifications,
envelopes, pools, artifacts, work units, and domain-neutral role presets:
Researcher, Architect, Orchestrator, Reviewer, Verifier, Writer, and
Monitor, plus the scoped coding presets Explorer, Engineer, and
Hardener.
std.circuits provides ordinary-library
patterns for pipelines, fan-out/fan-in, specialist routing,
generator→reviewer→repair, panels, monitor intervention, approval gates, and
provenance-preserving artifact aggregation.
std.completion adds contract-first,
bounded belief completion. Deterministic contracts and policy denials always
take precedence over probabilistic evidence.
Worked projects
Section titled “Worked projects”agent-research— parallel research fan-out, ordered evidence merge, and typed synthesis.agent-software— explorer, owned engineer task, and hardener handoff.agent-scientific— a failed experiment triggers a dynamically admitted proof auditor; publication stays blocked until deterministic verification passes.
For the normative details, see Native agents and durable circuits, the generated grammar, and the effects catalog.