Exchange with the kernel
How the parts of the platform talk to each other: the socket and JSON-RPC lines, the wrapper of a message, the introduction of a function to the kernel, the kernel methods and events. Needed by whoever writes a function of the platform or studies how it is made.
Introduction
The contract of the exchange between the parts of the platform: a Unix socket inside the machine and the connection of the workshop over 127.0.0.1. The platform opens nothing to the outside. The version of the contract is 1. Channels and passing on — The make-up of the platform, 3.3, 3.7, file formats — File formats.
Methods whose name begins with core. are handled only by the kernel. The others belong to the function that declared them at introduction.
The contract is divided by owners. This part holds what is common to all: the wire, the wrapper of a message, the introduction to the kernel, the kernel methods and events. The other parts of the contract:
Table 1 — Introduction
| File | What is in it |
|---|---|
| Methods of the graph | the methods of the function of the graph: process, program, run, variables, questions |
| Methods of modules | the contract with a module and the methods of the function of modules |
| Methods of the workshop and the pulpit | the data of the workshop, the methods of the window, the pulpit |
| Methods of the platform services | settings, localization, observability, sources, the door for programs, the assistant |
| Error codes | error codes: who throws them and when |
1 Scope
- function ↔ kernel — the Unix socket
data/run/ogas.sock; - the function of modules ↔ a module — the
stdin/stdoutof the module, which the kernel passes as bytes; - the workshop ↔ the function
ui— TCP127.0.0.1, further through the kernel to the functions (Methods of the workshop and the pulpit, section 2).
Functions do not call each other's code — only methods through the kernel. A module does not connect to the socket of the kernel.
2 Passing messages
JSON-RPC 2.0 sets the form of a message, but neither the way of passing it nor the border between messages. The platform sets the border itself: one message — one line (JSON Lines).
- UTF-8, without a byte order mark (BOM);
- one JSON value per line, with
\nat the end;\rbefore\nis allowed and dropped; - no more than 4 MiB per line;
- empty lines are forbidden;
jsonrpcmust be"2.0";- several requests as one array are forbidden: a JSON array at the top level is
Invalid Request(-32600) and the channel is closed; - the
idof a request is only a string of the form<sender>-<counter>; numbers and a repeatedidin one connection are forbidden; - an answer holds the same
id; - a notification has no
idand gets no answer.
If a line cannot be parsed, the channel is closed — but first, if an answer can still be sent, Parse error goes out (-32700, id: null). The kernel itself goes on working.
The JSON-RPC codes -32700, -32600, -32601, -32602 and -32603 mean the same as in the specification. Domain errors are given with the code -32000 and the field data.error_code (Error codes).
The length of queues is limited by the setting core.rpc_queue. A request that came into a full queue gets the refusal backpressure; notifications at such a moment may be merged or dropped. The output of a module to stdout is never dropped: if it is not read in time, the step ends with the error transport_overflow. Of stderr only the end, of limited length, is kept.
3 The common wrapper of a message
A request:
{
"jsonrpc": "2.0",
"id": "graph-17",
"method": "core.process.spawn",
"params": {
"command_id": "cmd-17",
"command": "python3",
"args": ["main.py"],
"cwd": "modules/echo"
}
}
Success:
{
"jsonrpc": "2.0",
"id": "graph-17",
"result": {
"process_handle": "proc-1",
"pid": 1234,
"state": "running"
}
}
An error:
{
"jsonrpc": "2.0",
"id": "graph-17",
"error": {
"code": -32000,
"message": "process spawn failed",
"data": {
"error_code": "process_spawn_failed",
"category": "runtime",
"message_key": "error.process_spawn_failed",
"retryable": false,
"trace_id": "trace-1"
}
}
}
The sender of a call. A call the kernel passes to a function carries the field source beside params: the id of the function whose call the kernel passes, or core if the kernel itself calls. The kernel sets it; a field source written by the caller itself does not reach the owner of the method. An owner to whom it matters who calls checks source, not the parameters (Protection, section 4).
command_id — protection against repeated delivery. It is not the transport id of JSON-RPC.
- The changing methods of the kernel (
core.event.publish,core.process.spawn,core.process.stop,core.process.kill,core.document.write,core.document.remove,core.shutdown,core.space.places) require the field; without it —invalid_request. - When an answer is lost, the sender repeats the same command with the same
command_id, and the kernel returns the former result. - A function puts a mark of its start into
command_id, so that after a restart its new commands do not match old ones in the cache of the kernel. - The key is sender + method +
command_id. On a repetition the kernel compares the print of the body (without thecommand_iditself): another body with the same key iscommand_id_conflict. - While a command is being carried out, a repetition waits for the same result and starts no second action.
- The cache does not apply to queries and to
core.process.stdin.write. The oldest finished records are pushed out of the cache; those being carried out are not.
After a crash the guarantee holds only for the commands whose result is already written to disk. The platform gives no guarantee that an outside action is done exactly once.
4 The introduction of a function to the kernel (handshake)
The kernel passes a function a one-time launch token in the variable OGAS_LAUNCH_TOKEN. The function connects to the socket from OGAS_SOCKET and sends as its first message:
{
"jsonrpc": "2.0",
"id": "graph-1",
"method": "function.handshake",
"params": {
"launch_token": "...",
"id": "graph",
"implementation_version": "1.0.0",
"contracts": { "core": 1, "graph": 1, "surface": 1 },
"commands": ["process.run.start", "process.run.stop"],
"queries": ["process.snapshot", "function.health"],
"events": ["run.changed"],
"surfaces": ["graph.editor"],
"capabilities": []
}
}
Success:
{
"jsonrpc": "2.0",
"id": "graph-1",
"result": {
"status": "ready",
"function_id": "graph",
"granted_capabilities": []
}
}
When the introduction is refused:
- the wrong token —
invalid_launch_token; - the version of the contract in
contracts.coredoes not fit —contract_incompatible; - the user or the process number at the other end of the socket (
SO_PEERCRED) does not match the OS process the kernel started —peer_mismatch; - the first message was not an introduction — the channel is closed.
capabilities is an optional list of rights; unknown names are not read. A right the function asks for must be listed in its entry of the register, otherwise — capability_denied. The answer holds granted_capabilities. The right process is needed for core.process.spawn, core.process.stdin.write, core.process.stop and core.process.kill; without it these methods answer capability_denied.
locales is an optional list of dictionary folders, the paths relative. The kernel remembers them and gives them by core.locales, and does not read the files themselves. One segment of a path may be *: such a folder means each folder of this place inside the installation folder where the rest of the path exists — the kernel finds them anew at each core.locales and skips hidden ones (the name begins with a dot). So the function of modules declares modules/*/locales, and the texts of a module put into the folder by hand, made or added by an import are seen without a restart and without a new declaration.
5 The kernel methods
All of them, except the introduction, are called by a function on an already accepted connection.
5.1 core.status
A snapshot of the health of the kernel and the functions (not modules). There are no required parameters:
{
"core": {
"pid": 12,
"started_at": "2026-08-30T12:00:00Z",
"data_dir": "/home/user/Concept/core/data",
"functions_ready": 6,
"functions_failed": 0
},
"metrics": {
"rpc_requests": 12,
"rpc_errors": 0,
"health_failures": 0,
"function_restarts": 0,
"document_writes": 3,
"processes_spawned": 1
},
"functions": [
{
"id": "graph",
"interactive": false,
"state": "ready",
"pid": 34,
"restart_count": 0,
"last_health_at": "2026-08-30T12:00:05Z",
"last_error": null,
"last_error_code": null,
"last_error_data": null
}
]
}
interactive is the mark from the description of the function: it needs the workshop. Other parts tell the functions of the window by it, without knowing their names. state: starting | ready | failed | restarting. About the last failure of a function — last_error (a message for the journal), last_error_code (the code, its text for the person is error.<code> in the dictionary of the kernel) and last_error_data (what the code names: for function_dependency_unavailable — { "dependency" }, the missing dependency). A function that is not in the register or is disabled in it is not in the list. The journal of details: data/logs/core.jsonl.
5.2 core.health
A query without required parameters. The answer:
{ "status": "ok", "contract": 1, "functions": 6, "processes": 2 }
5.3 function.health
The kernel calls this method at a function, not the other way round. The answer is { "status": "ok" } or an error. If there is no answer for longer than core.health_timeout_ms, the function counts as failed (failed).
5.4 core.process.spawn
Parameters:
Table 2 — core.process.spawn
| Field | Type | Required | Meaning |
|---|---|---|---|
command_id |
string | yes | to recognise a repeated delivery |
command |
string | yes | the name of the executable file or a path from the installation folder or the data folder |
command_base |
string | no | what the path command is counted from: install (the default) or data — the data folder |
args |
list of strings | no | the command line arguments |
cwd |
string | no | the working folder; the installation folder by default |
cwd_base |
string | no | what cwd is counted from: install (the default) or data — the data folder; with data the folder is made if it is not there |
env |
object «name → value» | no | additional environment variables |
limits |
object | no | limits of a group of programs: group — the name of the group (small Latin letters, digits, _), memory_mb — the memory of the whole group in megabytes, cpu_cores — how many processor cores it may take; 0 — no limit |
The kernel first cleans the environment, then adds PATH, LANG, LC_ALL and the variables from env. The kernel puts in no Python variables — they are passed by the function with the right process. A path with a slash is brought to an unambiguous form from its folder and cannot go beyond it. In the data folder the folders on the path are checked through links, as for any path there; the program itself may be a link outside — the interpreter of the environment of a process links to the Python it is made from — and must lead to a file (Protection, T-03). The answer: process_handle, pid, state. The owner of this process_handle is the function over whose connection the request came. No right process — capability_denied.
The kernel holds no knowledge of Python: the interpreter and the arguments are chosen by the function of modules.
Limits. With limits the kernel puts the program in a group: the limits are held by Linux itself — the user's systemd, the group is the instance's own, and all programs of one group name share its memory and processors. A program that took the group past its limit of memory is stopped by Linux, and process.io.closed says so with the field limit: "memory". If the user's systemd does not answer, a start with limits is refused with process_limits_unavailable and is not made without them: a limit that is not held is not promised. Whether systemd works is told by the line process_limits of the command doctor.
5.5 core.process.stdin.write
Parameters: process_handle and line — a whole JSON line, necessarily with \n at the end. What is inside line the kernel does not parse. If the answer to a write was lost, it must not be repeated to a module for which a repetition is not harmless.
5.6 core.process.stop
Parameters: command_id (required), process_handle. An ordinary stop: SIGTERM through pidfd, waiting core.process_stop_grace_ms, then SIGKILL through the same pidfd if the OS process is still alive. Repeating the stop is safe: for an OS process that has already ended the answer { "state": "exited", "signal_sent": false } comes. The same at core.process.kill. No right process — capability_denied.
5.7 core.process.kill
Parameters: command_id (required) and process_handle. An immediate SIGKILL through pidfd — after the waiting term ran out or by an emergency command.
5.8 core.document.read
Parameters: path from OGAS_DATA_DIR, without ... The answer is the content of the document. If there is no file, the neighbouring {name}.bak is read, when it is there: it means the writing broke off after the current file was renamed into the backup. If that is not there either — document_not_found. A damaged current file is not silently replaced by the backup.
5.9 core.document.list
Parameters: prefix from OGAS_DATA_DIR, without ..; sizes: true — count the size of each entry. The answer is { "entries": [{ "name", "path", "directory", "modified_ms", "bytes" }] }: modified_ms — the time of change in milliseconds from the epoch, bytes — only with sizes, for a folder together with its content, links count by themselves. If there is no folder, the list is empty. The kernel does not parse the meaning of the files themselves.
5.10 core.document.write
Parameters: command_id (required), path, document. The kernel checks the path, UTF-8 and the size (no more than core.document_max_bytes), and if the document has format at the top level — that it looks like <name>/<number> (document_invalid). Which versions are understood the owner of the document decides when reading (File formats, section 15); settings keys with secret names are refused by the function of settings, and the kernel checks only the wrapper. Writing goes so: a temporary file in the same folder, fsync of the file, the former file is renamed into .bak (not copied), the temporary one takes its place, fsync of the folder. A failure during writing does not destroy the former generation: on disk there stays either a whole current file or a whole backup.
The documents of a process may be written with indents for readability. The size is counted in bytes of the written UTF-8.
5.11 core.document.remove
Parameters: command_id (required), path. Deletes a file or a folder whole inside the data folder. A symbolic link is deleted as a link, its target stays in place. The path must consist of at least two parts (runs/<run_id>, not runs), so that one call does not wipe out a whole section; otherwise — document_remove_refused. The answer is { "path", "removed" }; if there was nothing to delete, removed: false comes, not an error.
5.12 core.locales
Gives the dictionary folders: its own core/kernel/locales and those the functions named at introduction in the field locales; a folder with a segment * is expanded into the folders that exist at this moment (section 4). The query has no parameters. The answer: { "dirs": ["core/kernel/locales", "functions/graph/locales", ...] } — the paths are counted from OGAS_INSTALL_DIR, without .. and not from the root. The function i18n reads only these folders and its own.
5.13 core.settings.schema
The schema of the keys core.* — the content of the file core/kernel/settings.schema.json (ogas.settings-schema/1). There are no parameters. The function of settings asks for it at its start; the kernel itself reads core.* by the same schema (Settings, section 3).
5.14 core.event.publish
Parameters: command_id (required), event_type, payload. The kernel gives the event the number event_id and sends the notification event to all functions. The answer: { "event_id", "source" }.
5.15 core.event.subscribe
Parameters: last_event_id — the last number the subscriber got, or null. The numbers do not grow one by one: an event sent to one function gets a number too, and only it sees it — so a step of a number greater than one is not a loss. If this number is still in the memory of the latest events, the kernel sends what was missed; if not, it answers { "resync_required": true }, and the subscriber asks for the state anew. The events process.io.* are not in this memory: the stream of a module is not restored by a subscription.
5.16 core.shutdown
Parameters: command_id (required). Stops the instance: new starts are forbidden, the kernel publishes system.stopping and ends the OS processes. The answer is { "status": "stopping" }.
5.17 core.space
A query: how much room the platform takes. Parameters: fresh — true when a fresh count is needed, not the one kept a short while. Answer: { used_bytes, budget_bytes, free_bytes, keep_free_bytes, room_bytes, places: [{ path, bytes }] }. The data folder and the folders the parts named to the kernel (core.space.places) are counted; a folder inside another is not counted a second time, nor is a file with several names (the packages of environments are links into one cache). budget_bytes — the budget core.disk_budget_gib, null — no budget; free_bytes — how much more the tightest disk of these folders takes; room_bytes — how much may be taken without going past either the budget or core.disk_free_min_gib. The kernel reads both keys again at every question, so they act without a restart.
5.18 core.space.check
A query: whether something new fits. Parameters: bytes — the size of the new thing, 0 — the size is unknown, fresh. Answer { fits: true, room_bytes }; it does not fit — the refusal space_budget_exceeded (it would go past the budget) or space_disk_full (it would go past the room kept free), with needed_bytes and room_bytes in the data of the error. A new thing of unknown size fits while any room is left. Those who take room ask: a download from a source, an install of an environment, the start of a run.
5.19 core.space.places
A command: the folders in which a part keeps its things outside the data folder. Parameters: command_id (required), places — a list: a full path or { path, backup }, where backup: true — a backup takes the folder; every call names all folders of the part anew. The kernel keeps what was named in data/places.json (ogas.places/1) too, so a backup can be made while the platform is stopped.
6 Events about the OS process of a module
A notification of the kernel (without id):
{
"jsonrpc": "2.0",
"method": "event",
"params": {
"event_id": 42,
"event_type": "process.io.chunk",
"event_version": 1,
"time": "2026-08-30T12:00:01.250Z",
"source": "core",
"trace_id": null,
"payload": {
"process_handle": "proc-1",
"stream": "stdout",
"sequence": 0,
"chunk": "{\"jsonrpc\":\"2.0\",\"id\":\"module-3\",\"result\":{}}\n"
}
}
}
When both streams are closed:
{
"jsonrpc": "2.0",
"method": "event",
"params": {
"event_id": 43,
"event_type": "process.io.closed",
"event_version": 1,
"time": "2026-08-30T12:00:01.300Z",
"source": "core",
"trace_id": null,
"payload": {
"process_handle": "proc-1",
"exit_code": 0,
"termination": "exited"
}
}
}
The fields of the event, as of any kernel event, lie in payload (section 7). termination takes the values exited (left by itself) and killed (ended by a signal); limit: "memory" — the limit of memory of its group stopped it (limits, section 5.4). An OS process that did not start makes no events: it has no process_handle, and the refusal comes as the answer to core.process.spawn (process_spawn_failed). After process.io.closed the kernel forgets this OS process, and core.health.processes counts only the living ones. stderr has its own counter sequence. Bytes that do not form UTF-8 are replaced in stderr by the sign U+FFFD.
process.io.chunk and process.io.closed the kernel sends only to the function that owns the process_handle, and does not write them into the common memory of the latest events. The other events (function.ready, process.started, system.stopping and those published through core.event.publish) are got by all connected functions.
7 Events
Each kernel event: event_id, event_type, event_version, time, source (core or the id of the function that published the event), trace_id (from payload.trace_id, otherwise null), payload. Each type of event has a text for the person event.<type> in the dictionary of its owner — the kernel or the function that declared the event at introduction: with it the journal names the event.
The required set: system.ready, system.stopping, system.activate, function.ready, function.failed, function.restarted, function.handshake_failed, function.handshake_timeout, process.started, process.io.chunk, process.io.closed, run.changed, node.changed, problem.opened, problem.resolved, logs.removed, sources.download.changed, profile.changed, profile.sending.changed, profile.checked, settings.changed, settings.schema.registered, settings.value_invalid, i18n.key_missing, function.work_failed. (resync_required is not an event but a field of the answer of core.event.subscribe, section 5.)
system.ready — { functions }: the instance came up; functions — the functions the kernel started. A function that connected later gets it with a catching-up subscription (section 5).
function.handshake_failed — { error_code, message, function_id? }: the kernel refused a connection the introduction. function_id is there only if the connection called itself a function from the register: the words of a stranger connection do not get onto the bus.
function.handshake_timeout — { function_id, error_code }: a started function did not introduce itself to the kernel within core.function_start_timeout_ms; function.failed follows.
system.activate — { reason: "second_launch" }: the workshop was started once more while the instance works. The window function opens the window if there is none (The make-up of the platform, 3.6.3).
function.restarted — { function_id, cause, attempt, max, delay_ms, level: "warn" }: the kernel restarts a function; cause — why: function_exited (left by itself) or health_timeout (did not answer the health check, and the kernel stopped it). A warning, not a problem: a spent restart budget gives function.failed with error_code: function_restart_exhausted.
function.failed — { function_id, error_code, dependency? }: the function does not work and the kernel no longer starts it — the restarts are spent (function_restart_exhausted), the function left or fell silent and no restart is due to it (function_exited, health_timeout), its channel broke (function_lost), it did not start, did not introduce itself in time, is of another version of the contract or was left without a required dependency (function_dependency_unavailable, then dependency names it). The function of observation opens a problem by it with the name of the function and the cause.
function.work_failed — { work, error_code, message, … }: a function did not finish work nobody waits an answer for (background work): unloading modules after a run, clearing old runs, writing a checkpoint, a timer or a clock event going off, stopping services and modules. work — what work it was, in simple words for whoever looks into the journal; the other fields say what it was about (process_id, run_id, module_id). Any function may publish it, and need not declare it separately. By error_code observation opens a problem, as for any event with a code (File formats, section 13). An event the kernel did not take the function tells into its stderr, and the kernel keeps the stderr of functions in its journal (The make-up of the platform, 3.8.2), so a failure is not lost without a trace.
node.changed — a step of a run: { run_id, process_id, node_id, execution_id, status }, where status is queued — the step came to the module and waits its turn: the places at the module are taken by other steps (parallelism of the manifest); running — the module took the step; completed, failed or cancelled — the step was broken off by stopping the run or its group. A step that found a place at once publishes no queued. It is published for module nodes and for the nodes a branch stands on — a question, waiting for a signal and a pause (The make-up of the platform, 3.8.2): for these status is waiting when the branch stood still, then completed (the branch went on) or cancelled (the wait was taken off by stopping the group or because another packet of the round was taken), and execution_id is empty — a wait has no attempt of a step. The event about a wait is published after the checkpoint holding it is written.
The events of a live program (The program: graph and runs, sections 2, 9):
program.changed—{ process_id, on }: the program was switched on or off;variable.changed—{ process_id, variable_id, value, partial }: a variable was written; a value larger than 16 KiB the event does not carry — instead ofvalueit haslarge: true, and whoever shows it reads the value itself with the requestprocess.variable.listwithvariable_id;partial: true— while a module gives its result in parts;notice.posted—{ process_id, run_id, node_id, title, text }: a «Notify» node calls the person; the window puts the notification over what is open;show.changed—{ process_id, node_id, run_id }: a «Show» node showed something new; what exactly —process.show.get;event.dropped—{ process_id, node_id, waiting, reason, level: "warn" }: an event did not begin a run.reason—overflow, when there are alreadygraph.queue_depthwaiting, orskip, when the overlap rule of the event is «skip» (The program: graph and runs, section 5); forskipthe fieldwaitingis zero;ask.openedandask.closed—{ process_id, run_id, node_id, ask_id, question, kind, choices, fill }: anasknode opened a question to the person, and the question is closed.ask_id— it is answered by it (process.ask.answer);kind— what the question waits for, a parameter of the node:text— a line,choice— one ofchoices,confirm— «yes» or «no»,number— a number,image,audio,video,file— a reference to a file of this kind;fill— for a question by a line, the text the answer field begins with: the field of the data of the question by the path from the parameterfillof the node, otherwisenull;signal.sent—{ process_id, name, key, run_id, node_id, delivered }: a signal was sent from outside.delivered: falsemeans nobody waited for it and it is not kept (The program: graph and runs, section 22).module.partial—{ run_id, node_id, execution_id, port, data }: a part of the result of a step; published by the function of modules, listened to by the function of the graph;module.emit—{ process_id, module_id, port, data, node_id? }: a service gave a packet outside a step; withnode_id— for one node of its own;module.signal—{ process_id, module_id, name, key, data }: a module sent a signal to its own program; published by the function of modules, listened to by the function of the graph;message.sent—{ process_id, name, delivered, events }: a message was sent to a program — by a «Send» node or by the methodprocess.message.send;events— the events that took it, with their answer (a run or a queue);delivered: false— none took it;module.raised—{ module_id, process_id, run_id, mode, process_handle }: the function of modules brought a module up; a service and a test call have norun_id. Whether a node goes on from its saved memory is said by its step (resumed), not by bringing up: a module is one for all its nodes (Modules, section 4);module.ended—{ module_id, process_id, run_id, mode, process_handle, reason, saved, nodes }: the OS process of a module is ended.reason—resources(room on the video card was needed by another),run_ended(the run of a long module ended),switched_off(the program of a service was switched off),step_ended(a step module did its step),timeout(the module did not answer within the term of the step),lost(did not answerping),exited(ended by itself);saved— whether the memory is saved;nodes— the nodes whose memory the module served and saved;module.log—{ module_id, process_id, run_id, node_id, level, message }: a module wrote into its journal;run_idandnode_id— of the step going at it, and between steps — of the run of a long module, or nothing;level—info,warnorerror;module.progress—{ module_id, run_id, node_id, execution_id, ratio }: how much is done in a step, from 0 to 1; the function of modules passes it no more often than twice a second, and always the value 1;packet.absorbed—{ run_id, process_id, node_id, port, packet_id }: a packet from an output without links was passed nowhere; published by the function of the graph once per packet (The program: graph and runs, 10.2).
The events of documents. Each command that writes or deletes a document leaves an event: the function of observation writes it into the journal, and the order of changes is restored by the journal (Rules of development, 2.7.3):
process.changed—{ process_id, generation, command }: the graph of a process is written;command—process.create,process.saveorprocess.import,generation— the generation of the graph after writing;process.exported—{ process_id, path }: the pack of a process is written into the folderpath;run.kept—{ run_id, kept }: a run is marked «Keep» or the mark is taken off;runs.removed—{ process_id, removed, reason }: past runs are deleted.reason—clear, when the person deleted them (process.runs.clear; without a process — the runs of all processes,process_id: null), orruns_keep, when the rulegraph.runs_keeplet them go after a run; by the rule the event is published only if something was deleted;canvas.changed—{ process_id, generation }: the pulpit of a process is written; published by the function of the pulpit.canvas.images.changed—{ process_id, name }: a picture of the pulpit was put into the process folder or removed from it;name— the name of the picture, ornullwhen pictures came with a handed-over process or an own look of an element changed. Published by the function of the pulpit; a window showing the pulpit of this process reads its pictures anew.ui.face.asked—{ process_id }: a start asked to show the face of the program of this process (The workshop, 6.6); published by the window function. By it an already open window comes forward and shows the face.
8 Compatibility
If the meaning of a required field or method changes, the version of the contract contract grows. Adding an optional field does not change the version. Unknown optional fields are not read.
The contract promises neither JSON-RPC 1.0, nor several requests as one array, nor numeric ids, nor work over HTTP.
9 Authorization
There is no sign-in by name and password in the platform: one person works on the machine. A function is admitted to the kernel by four conditions: mode 0600 on the socket, the one-time launch token, the user and process number at the other end of the socket (SO_PEERCRED) matching the OS process the kernel started, and the declared id matching the entry of the register. A module calls no kernel methods at all. A process_handle belongs only to the function that got it. The window of the workshop is admitted by the address 127.0.0.1, the session token of the function ui and the closed list of kernel methods (Protection, 3.10). A program of the person is admitted by the door for programs: an open setting, the address 127.0.0.1, the key of the door and a closed list of methods (Methods of the platform services, section 5).
10 Limits of the contract
- there is no machine-readable description of all messages; the fields are set by the tables of this part;
- how many latest events the kernel keeps in memory is set only by the default value
1024and is not checked under load; - there is no access to the platform over the network, and no contract is described for it.