DocsOther languages

libkore

C, Zig, Lua and WASI

The foreign surfaces over libkore's Rust host: generated C headers, Zig modules, an embeddable Lua 5.5, and a WASI 0.2 component host.

Source: docs/languages.md

One host, several languages

Every language surface in libkore sits on the same Rust-founded host. A Rust program owns the process, its service faces and its executor; C, Zig, Lua and WASI code runs inside it, on that executor, with that process's capabilities. None of them adds a second scheduler, a global allocator of its own or a global filesystem root, and none is a sandbox inside the process: the process's capabilities remain the security boundary.

LanguageThis alpha
RustThe foundation, with native ownership types
CGenerated filesystem, time, random, task and joined worker APIs
ZigTarget-specific translation of the C header, with generated module namespaces
LuaEmbeddable Lua 5.5: an interactive mode, or an opt-in restricted read-only worker
WASIAn embedder-composed WASI 0.2 component host
PythonPlanned: a handwritten ownership and scheduling adapter

Filesystem support is a requirement for every language surface, not an add-on.

C

kore-ffi generates kore.h from its actual extern "C" functions with cbindgen 0.29.4. The header groups 64 functions into families: allocation, filesystem, DAG links, atomic-word waits, hash tables, random values, tasks, threads, SPMD dispatch and time.

The model is callback-driven. The Rust host moves its attached Fs into a kore_ffi::Session and awaits Session::run(step, user). Each callback receives the previous completion, queues one operation and returns; KORE_STATUS_QUEUED means the adapter accepted the request, not that the I/O succeeded. The next callback carries the native completion:

C
#include "kore.h"

uint32_t c_submit_write(KoreFsContext *ctx, KoreFsHandle handle) {
    uint8_t data[] = { 17, 23, 31, 47 };
    KoreStatus first = kore_fs_write(ctx, handle, 13, data, sizeof data);
    data[0] = 99; /* Rust must have copied this before the foreign stack returns. */
    if (first != KORE_STATUS_QUEUED) return 1;
    if (kore_fs_close(ctx, handle) != KORE_STATUS_BUSY) return 2;
    return 0;
}

uint32_t c_read_completion(KoreFsContext *ctx, const KoreFsCompletion *completion) {
    uint8_t data[4] = { 0 };
    if (completion->abi_version != KORE_ABI_VERSION || completion->operation != KORE_OP_READ ||
        completion->status != KORE_STATUS_OK || completion->count != 4) return 1;
    if (kore_fs_read_data(ctx, data, 3) != KORE_STATUS_BUFFER_TOO_SMALL) return 2;
    if (kore_fs_read_data(ctx, data, 4) != KORE_STATUS_OK) return 3;
    return data[0] == 17 && data[3] == 47 ? 0 : 4;
}

The adapter copies write input before the submission call returns, caps one transfer at 4096 bytes, and holds at most eight native views behind generational handles. completion.count is the acknowledged count; loops must read it. Every eight completed turns it yields to the executor, so a callback can't starve other tasks, but it does not preempt code inside a callback: return promptly.

Allocation goes through the host's installed global allocator. Include <kore/stdlib.h> for malloc, calloc, realloc and free aliases, or enable kore-ffi's c-stdlib feature to export those symbols on Kore targets:

C
#include <kore/stdlib.h>

void example(void) {
    unsigned char *buffer = calloc(128, 1);
    if (!buffer) return;
    unsigned char *grown = realloc(buffer, 4096);
    if (grown) buffer = grown;
    free(buffer);
}

<kore/pthread.h> maps pthread lifecycle, TLS keys, cleanup handlers and deferred cancellation onto native threads, with default attributes only. Asynchronous cancellation is refused. There is no standalone C runtime or C main yet: C code is linked into a Rust-founded program.

Zig

build.zig exports a kore module that Zig 0.16.0 translates from the C header for the consumer's target at build time, so no host-specific layout is checked in. The generated namespaces are alloc, dag, fs, futex, hash, random, spmd, task, thread and time, with every declaration under kore.abi. kore.allocator is a real std.mem.Allocator:

Zig
const std = @import("std");
const kore = @import("kore");

fn example() !void {
    var values: std.ArrayList(u64) = .empty;
    defer values.deinit(kore.allocator);
    try values.append(kore.allocator, 42);
}

Lua

kore-lua is an embeddable Lua 5.5 engine, not a hosted lua executable. The embedding program chooses a policy:

ModeScript surfaceLifecycle
Interactive (default)io, os, coroutine and the task's kore.* librariesThe embedder may evaluate successive chunks
Read-only workerPure Lua libraries and read-only kore.fs queries, under heap, instruction and output budgetsThe embedder terminates and reaps the whole task on stop or deadline

Interactive io and os work over the task's own filesystem; os.execute and io.popen don't exist. A script holds handles, an index and a generation, never a native view. kore.fs also says what io can't: ask for rights by name, find out what rights you hold, and choose behavior separately from authority.

Lua
-- Least authority, on purpose: a read route to a file this task may well
-- be able to write.
local f = assert(kore.fs.open("/etc/hosts", "r"))

-- What does this task actually hold here?
local held = assert(kore.fs.rights("/var/log"))
if not held.write then
  return nil, "this task was not endowed with write authority there"
end

-- Create if missing, keep what is there: no io mode string means this.
local g = assert(kore.fs.open(path, "rw", {create = true}))

do
  local h <close> = assert(kore.fs.open("/tmp/scratch", "rw", {create = true}))
  h:write(payload)
end   -- retired here, whether the block ended or threw

Native modules load only from the task's read-only libs/ grant, and only images stamped executable.

WASI

kore-wasi hosts WASI 0.2 components in the wasi:cli/command world. It links wasi:cli, wasi:clocks, wasi:filesystem (one preopen, the task's root view), wasi:io (the process's native streams) and wasi:random (libkore's ChaCha generator). Any other import, such as wasi:sockets, is refused when the component is instantiated, not when it is called.

The embedder composes it with its own Wasmtime engine and native owners; async imports suspend the Wasmtime fiber onto Kore's executor. There is no standalone runner, and Kore-target builds of kore-wasi are certified in Kore's own userland workspace, so libkore's cross check omits it.