Yuneta โ€” the idea, in one page

High-level semantics,
low-level language.

Services, roles and messages without the runtime it usually takes to have them. The contract is not a library you link against: it is the message, which is why any endpoint that speaks it is already in.

state ร— event โ†’ action the whole contract

$ ycommand -c 'set-global-trace level=machine set=1'

๐Ÿ”๐Ÿ”EV_CONNECTEDC_TCP^clisrv-1ST_CONNECTED
๐Ÿ”๐Ÿ”EV_RX_DATAC_TCP^clisrv-1ST_CONNECTED
๐Ÿ”„EV_TX_DATAC_TCP^clisrv-1ST_CONNECTEDfrom C_PROT_TCP4H^tcp4h
๐Ÿ”„EV_TIMEOUT_PERIODICC_TIMER^tickST_IDLEfrom C_YUNO^yuneta_agent
๐Ÿ”„EV_DROPC_TCP^clisrv-1ST_CONNECTEDfrom C_IOGATE^__top_side__

Not a log somebody decided to write: it is the state table executing. Every line was already in the code before anything happened.

C_TCP^clisrv-1
Class and name. The class carries the table; the instance runs it.
ST_CONNECTED
The state it was in when the event arrived, not the one after.
EV_RX_DATA
The event. If that state does not declare it, the line comes out marked as an error.

the map

The empty quadrant

Almost all software picks a side of the axis: either you move up the language to gain application semantics, or you go down to C and give them up. Yuneta sits in the corner almost nobody occupies.

Erlang / OTP Akka microservices C + sockets epoll, libuv Flask, Express YUNETA low language level high low application semantics high
Each dot is a usual way of building services. The top-left corner is empty because it is expensive: you have to write the runtime yourself.

the stack

What is underneath

The difference is not in what the application sees, it is in what holds it up. Where the others rest their semantics on a virtual machine, Yuneta rests them on the operating system.

The usual

Application
Actor frameworkservices, roles, messages
RuntimeVM ยท GC ยท a scheduler of its own
Operating system

Yuneta

Application
gobjshierarchy ยท FSM ยท event bus
Cio_uring ยท one thread per yuno ยท no GC
Operating system

The application layer does not rest on a runtime: it is the runtime, written in C. A yuno is the process that comes out: a tree of gobjs with its own event loop. The binary is static; copy it to another machine and it runs, with nothing to install.

the code

The same vocabulary on both sides

A gobj has no methods, and there is no way to call another object. There are only named events and a table saying what each state accepts. That table is written the same way in C and in the browser, which is why nothing between them needs generated glue.

server ยท c_timer.c

/* what ST_IDLE accepts */
ev_action_t st_idle[] = {
    {EV_TIMEOUT_PERIODIC, ac_timeout, 0},
    {0,0,0}
};
states_t states[] = {
    {ST_IDLE, st_idle},
    {0, 0}
};

browser ยท c_agent_login.js

/* a SPA session */
const states = [
  ["ST_LOGOUT", [
    ["EV_DO_LOGIN",
     ac_do_login, "ST_WAIT_TOKEN"],
    /* โ€ฆ */
  ]],
  ["ST_WAIT_TOKEN", [
    ["EV_LOGIN_ACCEPTED",
     ac_login_accepted, "ST_LOGIN"],
    ["EV_LOGIN_DENIED",
     ac_login_denied, "ST_LOGOUT"]
  ]]
];

A C gclass and a SPA session, as they are written. Same shape, same names, same way of failing: an event that reaches a state which does not declare it is a visible error, not a hidden exception.

the wire

The contract is the message

If what defines a gobj is the event table and not its implementation, any endpoint that speaks that protocol is part of the system, whatever it is written in.

the same model of services and roles on both sides of the wire yuno ยท C yuno ยท ESP32 another language SPA gobj-ui ยท JS agent ยท C
C and JavaScript already share the same gclass layout and the same public API: payloads travel identical byte for byte. The dashed box is the gap left open โ€” a new endpoint only has to speak the protocol.

No methods. No way to call another object.

decision 01 ยท events and FSM, nothing else

the bill

What each decision costs

Every framework publishes its advantages. These are the same decisions with the receipt beside them, because choosing a framework is choosing what it gives up.

Everything is a named event and its state table. Behaviour can be drawn, replayed and walked end to end.
You have to design the states up front. Yuneta will not let you call a method on the object next door.
One thread per yuno. No locks, no mutexes, no atomics anywhere in the framework.
A slow operation blocks its yuno. Work is spread across processes, not threads.
JSON everywhere: payloads, records, logs, commands and statistics. One serializer, one diff, one test assertion.
Parsing is not free. The target is thousands of messages per second per core, not tens of millions.
Append-only storage. The durable queue, the in-memory graph and the ability to replay what happened all come out of it.
You trade disk for keeping everything. There is no rewriting in place.
An abstraction that resembles nothing else: not objects, not actors, not microservices.
There is nothing to copy from. Neither a new programmer nor a model can infer the conventions, so they have to be written down the way a protocol specification is.