id: FR-COMP-009
title: Native Agent Model (agent, send ... to, receive from, try receive from, stop) and Retirement of Legacy spawn/join
status: implemented
priority: must
created: 2026-10-22
updated: 2026-10-30
depends_on:
- FR-COMP-001
- FR-COMP-002
- FR-COMP-008
verified_by: []
FR-COMP-009 — Native Agent Model (agent, send ... to, receive from, try receive from, stop) and Retirement of Legacy spawn/join
Statement
The Ridgun language and ridgunc / stable toolchain SHALL replace legacy unstructured spawn/join thread primitives with a native, strongly-typed Agent Model built directly on standard Ridgun functions (fn :: and op ::) and deterministic RMM1/RMM2 memory management:
- Zero Boilerplate Agent Creation (
agent):
- Any standard Ridgun function or operator (
fn ::orop ::) MAY be instantiated as an autonomous agent without introducing special declaration headers: - Stateless Agent (
ag = agent fn): Givenfn :: M1 ... Mn => R,agent fncreates an agent with an input mailbox of type(M1, ..., Mn)(orM1when $n = 1$) and an output mailbox of typeR. - Stateful Agent (
ag = agent fn init_state): Given a state-transition functionfn :: S M => Sorfn :: S M => S Rand an initial stateinit_state :: S,agent fn init_statecreates an isolated stateful agent initialized withinit_state. - When
fn :: S M => S, each processed message transitions the internal states' = fn s msg, deterministically releases the previous states(RMM1/RMM2), and enqueuess'in the agent's output queue. - When
fn :: S M => S R(a 2-element tuple/sequence return type where the first component isSand the second isR), each processed message transitions the internal state tos', deterministically releases the previous states(RMM1/RMM2), and enqueues the responser :: Rin the agent's output queue.
- Asynchronous Message Sending (
send ... to) & Synchronous Request-Reply (ask):
send <msg> to <agent>(and multi-argumentsend <arg1> <arg2> ... to <agent>, which packs the arguments into a tuple message) SHALL immediately dispatch the message to<agent>in the background without blocking the caller, and may be used either as a standalone statement (send x to ag) or bound (_ = send x to ag).ask <agent> <msg...>(Akka prefix style) andask <msg...> to <agent>(Ridguntostyle) SHALL perform a synchronous request-reply on<agent>, returning the typed responseRdirectly.
- Blocking and Non-Blocking Response Retrieval (
receive from&try receive from):
receive from <agent>SHALL await completion of the oldest in-flight job and return the next responseRfrom<agent>'s output mailbox in FIFO order.try receive from <agent>SHALL poll<agent>'s oldest in-flight job or output mailbox without blocking and returnSome r(Option R) if a response is ready orNoneif still running or empty.
- Deterministic Lifecycle & Cleanup (
stop&agent alive):
stop <agent>(usable as a standalone statement or expression) SHALL terminate<agent>, close its mailboxes, and deterministically release its held state and queued values viaRMM1/RMM2.agent alive <agent>SHALL returnTrue(Bool) while the agent is active andFalseafterstop <agent>.
- Type Representation (
Agent) & Retirement ofspawn/join,global ::,context ::,shared ::, andatomic:
- Type signatures SHALL support
Agent(both unparameterizedAgentand parameterizedAgent In Out/(Agent In Out)). - Legacy unstructured
spawnandjoinbuilt-ins, as well as global/scoped state constructs (global ::,context ::,shared ::,atomic, and userwith <ctx> = <val> do), SHALL be removed from the language, documentation, harnesses, and books in favor of explicit parameters,||/||map/||filter(for structured dataflow parallelism), andagent(for decoupled stateful/service processes).
- True Background Concurrent Execution (
b_id 57async_spawn,b_id 58async_poll,b_id 59async_await) & Smart Compile-Time Strategy Selection:
- Both stateless (
agent fn, status3) and stateful (agent fn init_state, status2) agents SHALL dispatch their handlers asynchronously in the background viab_id 57(async_spawn) immediately whensend ... to agis called, returning in ~0 ms without blocking the sender even when the handler sleeps (sys sleep ms) or executes heavy CPU work. try receive from agSHALL poll the in-flight background job viab_id 58(async_poll) without blocking (Nonewhile running,Some rwhen finished, transitioning stateful agent stateS -> S'upon harvesting), andreceive from agSHALL await completion viab_id 59(async_await/FUTEX_WAIT).- Independent
||DAG waves ($\ge 2$ heavy branches via"__rg_par_eval__") and||map/||filterconsult the static analyzer's 4-tierRFnSummaryclassification to select inline sequential execution vs multicore OS kernel thread execution (NCallBuiltin 54/56).
- Fire-and-Forget Sink Agents (
agent sink), Global Mailboxes (agent ::), Observability & Shared Channel/Agent Descriptors (v0.9.30):
- Local Sink Agents (
agent sink):ag = agent sink step_fn [init_state] [, mailbox N drop|block] [, drain D]creates a fire-and-forget sink agent that processes messages in FIFO order (step_fn :: M => ()for stateless sinks orstep_fn :: S M => Sfor stateful sinks), releasing previous states viaRMM1/RMM2without accumulating an output response queue. - Top-Level Global Sink Agents (
agent ::):agent :: <name> = sink step_fn [init_state] [, mailbox N drop|block] [, drain D]declares a module-level sink agent initialized beforemainand drained in reverse declaration order at program exit. - Compile-Time One-Way Enforcement: Calling
receive from,try receive from, orask ... toon a sink agent (SinkAgent) SHALL be rejected at compile time with a descriptive type error. - Bounded Mailboxes & Observability Intrinsics:
mailbox N dropcaps pending messages atNand drops excess messages without blocking the sender, incrementing the dropped counter read byagent dropped <ag> => Int.mailbox N blockprocesses all messages in order without dropping.agent flush <ag> => ()drains all in-flight and queued messages of<ag>, andagent state <ag> => Sflushes and returns a snapshot of<ag>'s current internal state for deterministic testing.with agent <global_ag> = <replacement_ag> do <body>temporarily redirects sends to<global_ag>to<replacement_ag>for the dynamic extent of<body>and restores<global_ag>on exit.- Shared
Channel&AgentDescriptors: Variables holdingChannel,Agent, orSinkAgentdescriptors MAY be passed across multiplesend ... toorsend ... throughcalls (fan-in/fan-out across worker agents) without triggeringErrUseAfterSend, while regular heap payloads sent through channels or to agents remain affine (ErrUseAfterSend).
Rationale
- Orthogonal Concurrency Model:
||,||map, and||filtersolve scoped computational fork-join parallelism with compile-time DAG verification, whileagentsolves long-lived, decoupled service concurrency (HTTP/TCP connection handlers, session stores, state machines, actors) with isolated state and typed message queues. - Best of Erlang + Akka Typed + Native RMM: Ridgun agents combine Erlang's true memory isolation and inline
receive fromergonomics with Akka Typed's compile-time message type safety and Ridgun's zero-GC deterministicRMM1/RMM2state reclamation.
Acceptance Criteria
- AC-1 (Stateless & Multi-Argument Agents): Creating
ag = agent fn, sending single or multi-argument messages viasend ... to ag, and collecting results viareceive from agreturns the exact computed outputs in FIFO order. - AC-2 (Stateful Agents
S M => SandS M => S R): Creatingag = agent fn init_statepreserves and updates isolated state across multiple messages without locks or memory leaks, supporting bothS M => S(counter) andS M => S R(persistent HTTP/session handler returning new state + response). - AC-3 (Non-Blocking
try receive fromandstop/agent alive):try receive from agreturnsNonewhen no response is queued andSome rwhen ready;stop agtransitionsagent alive agfromTruetoFalseand frees the agent's state. - AC-4 (Retirement of
spawn/join):spawnandjoinare removed from the compiler, harnesses, and all 7 book editions (docs/book/). - AC-5 (Smart Compile-Time Strategy Selection & Persistent Worker Pool):
compiler.rgautomatically selects lightweight green execution (StratInlineSequential) for trivial functions and multicore OS thread execution (SYS_clone,NCallBuiltin 54/56) for heavy/recursiveagents,||DAG waves, and||map/||filter, backed by a persistent pre-warmedSYS_futexworker thread pool inx86_64.rgthat reuses spawned OS worker threads across batches without repeated stack teardown. - AC-6 (Sink Agents
agent sink, Top-Levelagent ::,with agent, and Shared Descriptors): Localagent sinkand top-levelagent :: <name> = sink ...process fire-and-forget messages without accumulating output queues, enforcemailbox N drop(agent dropped), supportagent flush,agent state, andwith agent <global> = <spy> do ..., rejectreceive from/try receive from/askat compile time, and allowChannel/Agentdescriptors to be shared across multiple worker agents without false-positiveUseAfterChannelSendError.