Skip to content

softadastra/kordex

Repository files navigation

Kordex

A JavaScript and TypeScript runtime for reliable local-first applications.

Kordex is a small JavaScript and TypeScript runtime built on top of Vix.cpp and Softadastra.

It is designed for local-first, offline-ready, permission-controlled applications where JavaScript code can run close to the system while native capabilities stay explicit.

Repository · Vix.cpp · Softadastra

What is Kordex?

Kordex is a JavaScript and TypeScript runtime focused on reliability, local execution, explicit permissions, and local-first application design.

It can run JavaScript and TypeScript files, resolve local imports, load JSON files, expose native standard modules, bundle scripts, and connect JavaScript code to native C++ capabilities.

Kordex is not trying to be another general-purpose Node.js clone.

Kordex is built for a different direction:

JavaScript that can keep working locally first.

That means the runtime is designed around:

  • local execution
  • offline-ready workflows
  • explicit permissions
  • native modules written in C++
  • durable local storage
  • embeddable runtime architecture
  • predictable system access
  • reliability-first application foundations

Why Kordex is different

Most JavaScript runtimes focus on online services, server workloads, web tooling, and package ecosystems.

Kordex starts from a different question:

What if the application must keep working even when the network is unstable or unavailable?

This is where Kordex becomes different.

Kordex combines:

  • QuickJS for JavaScript execution
  • Vix.cpp for the C++ runtime, build, system, and developer foundation
  • Softadastra for durable local-first storage, WAL, sync foundations, transport, discovery, and metadata
  • Kordex Std for native standard modules
  • Kordex CLI for a small developer-facing workflow

The goal is not only to execute JavaScript.

The goal is to make JavaScript useful for reliable local-first applications.

Design direction

Kordex should stay:

small
modular
local-first
permission-aware
embeddable
reliable by design
easy to test
safe by default

The runtime should expose native capabilities only when the application explicitly asks for them.

Quick example

Create main.js:

const name = "Kordex";

console.log("Hello from " + name);

Run it:

kordex run main.js

Output:

Hello from Kordex

Install

Kordex is built with the Vix.cpp CLI.

Install Vix.cpp first.

Linux and macOS

curl -fsSL https://vixcpp.com/install.sh | bash

Windows PowerShell

irm https://vixcpp.com/install.ps1 | iex

Verify Vix.cpp:

vix --version

Then build Kordex:

vix build --preset dev-ninja --build-target all -v -- \
  -DKORDEX_ENABLE_QUICKJS=ON \
  -DKORDEX_ENABLE_NATIVE_ENGINE=OFF \
  -DKORDEX_BUILD_APP=ON \
  -DKORDEX_ENABLE_INSTALL=ON

Build Kordex with Softadastra support:

vix build --preset dev-ninja --build-target all -v -- \
  -DKORDEX_ENABLE_QUICKJS=ON \
  -DKORDEX_ENABLE_NATIVE_ENGINE=OFF \
  -DKORDEX_BUILD_APP=ON \
  -DKORDEX_ENABLE_INSTALL=ON \
  -DKORDEX_ENABLE_STD_SOFTADASTRA=ON

Verify Kordex:

kordex version
kordex help

CLI

kordex <command> [options] [args]

Available commands:

help     Show help
init     Create a new Kordex project
run      Run a JavaScript or TypeScript file
check    Check a source file
build    Build a source file or project
repl     Start an interactive Kordex session
install  Install project dependencies
update   Update project dependencies
version  Show Kordex version

Global options:

-h, --help       Show help
-V, --version    Show version
-v, --verbose    Enable verbose output
    --debug      Enable debug output
-q, --quiet      Disable normal output
    --json       Render machine-readable JSON output
    --no-color   Disable colored output
    --dry-run    Show what would happen without executing

Runtime permissions:

--allow-fs
--allow-env
--allow-net
--allow-process
--allow-softadastra

Run JavaScript

Create main.js:

const runtime = "Kordex";

console.log(runtime);

Run:

kordex run main.js

Output:

Kordex

Run TypeScript

Create main.ts:

const name: string = "Kordex";

function hello(value: string): string {
  return "Hello from " + value;
}

console.log(hello(name));

Run:

kordex run main.ts

Output:

Hello from Kordex

TypeScript support is currently MVP-level. It performs basic checking and type stripping before sending JavaScript to the engine.

Use imports

Create message.js:

export function message() {
  return "Import works";
}

Create main.js:

import { message } from "./message.js";

console.log(message());

Run:

kordex run main.js

Output:

Import works

Extension resolution is supported:

import { message } from "./message";

console.log(message());

JSON imports

Create user.json:

{
  "name": "Kordex",
  "type": "runtime"
}

Create main.js:

import user from "./user.json";

console.log(user.name);
console.log(user.type);

Run:

kordex run main.js

Output:

Kordex
runtime

Standard modules

Kordex exposes native modules through the kordex: prefix.

Available standard modules:

kordex:console
kordex:path
kordex:timer
kordex:crypto
kordex:fs
kordex:env
kordex:process
kordex:http
kordex:softadastra

Safe utility modules can be available without special permissions:

kordex:console
kordex:path
kordex:timer
kordex:crypto

Sensitive modules are controlled by explicit runtime permissions:

kordex:fs           -> --allow-fs
kordex:env          -> --allow-env
kordex:process      -> --allow-process
kordex:http         -> --allow-net
kordex:softadastra  -> --allow-softadastra

Permissions

Kordex does not expose sensitive native capabilities silently.

A script must be started with the required permission flag before it can import modules that touch filesystem, environment variables, process execution, network-related helpers, or Softadastra local-first storage.

Example:

kordex run main.js --allow-fs

Without the required permission, Kordex rejects the import.

Example:

permission denied: module "kordex:softadastra" requires --allow-softadastra

This permission model is one of the main design differences between Kordex and traditional JavaScript runtimes.

kordex:console

import { log, info, warn, error, debug } from "kordex:console";

log("log works");
info("info works");
warn("warn works");
error("error works");
debug("debug works");

Run:

kordex run main.js

Output:

[log] log works
[info] info works
[warn] warn works
[error] error works
[debug] debug works

The global console object is also available:

console.log("global console works");
console.error("global console error works");

kordex:path

import {
  normalize,
  join,
  dirname,
  basename,
  extension,
  isAbsolute,
  isRelative,
  separator,
} from "kordex:path";

console.log(normalize("/tmp/kordex/../kordex/app"));
console.log(join("/tmp", "kordex", "app"));
console.log(dirname("/tmp/kordex/app/main.js"));
console.log(basename("/tmp/kordex/app/main.js"));
console.log(extension("/tmp/kordex/app/main.js"));
console.log(isAbsolute("/tmp/kordex"));
console.log(isRelative("./main.js"));
console.log(separator);

Run:

kordex run main.js

Output on Linux/macOS:

/tmp/kordex/app
/tmp/kordex/app
/tmp/kordex/app
main.js
.js
true
true
/

kordex:timer

import { now, sleep, unixMs } from "kordex:timer";

const before = now();

sleep(10);

const after = now();

console.log(after >= before);
console.log(unixMs() > 0);

Run:

kordex run main.js

Output:

true
true

kordex:crypto

import { hash, random, randomInt, equals } from "kordex:crypto";

console.log(hash("kordex"));
console.log(random() >= 0);
console.log(random() < 1);
console.log(randomInt(1, 10) >= 1);
console.log(equals("hello", "hello"));
console.log(equals("hello", "world"));

Run:

kordex run main.js

Output shape:

<hex hash>
true
true
true
true
false

kordex:fs

Filesystem access requires --allow-fs.

import {
  exists,
  isFile,
  isDirectory,
  writeText,
  readText,
  remove,
} from "kordex:fs";

const file = "/tmp/kordex-fs-test.txt";

console.log(exists("/tmp"));
console.log(isDirectory("/tmp"));

writeText(file, "Hello from kordex:fs");

console.log(exists(file));
console.log(isFile(file));
console.log(readText(file));

console.log(remove(file));
console.log(exists(file));

Run:

kordex run main.js --allow-fs

Output:

true
true
true
true
Hello from kordex:fs
true
false

Without --allow-fs, kordex:fs is not available to the script.

kordex:env

Environment access requires --allow-env.

import { get, has, set, unset } from "kordex:env";

console.log(has("HOME"));
console.log(get("HOME") !== null);

set("KORDEX_TEST_ENV", "works");

console.log(has("KORDEX_TEST_ENV"));
console.log(get("KORDEX_TEST_ENV"));

unset("KORDEX_TEST_ENV");

console.log(has("KORDEX_TEST_ENV"));

Run:

kordex run main.js --allow-env

Output shape:

true
true
true
works
false

kordex:process

Process access requires --allow-process.

import { cwd, chdir, run } from "kordex:process";

console.log(cwd());

chdir("/tmp");

console.log(cwd());
console.log(run("true"));

Run:

kordex run main.js --allow-process

Output shape:

/path/where/you-started
/tmp
0

kordex:http

HTTP helpers require --allow-net.

kordex:http currently provides HTTP helper utilities, not real network requests.

import {
  GET,
  POST,
  isSuccess,
  isRedirect,
  isClientError,
  isServerError,
  statusText,
  buildUrl,
  normalizeMethod,
  isMethod,
} from "kordex:http";

console.log(GET);
console.log(POST);

console.log(isSuccess(200));
console.log(isRedirect(302));
console.log(isClientError(404));
console.log(isServerError(500));

console.log(statusText(200));
console.log(statusText(404));

console.log(buildUrl("https://example.com/", "/api/users"));
console.log(normalizeMethod("post"));
console.log(isMethod("PATCH"));
console.log(isMethod("CUSTOM"));

Run:

kordex run main.js --allow-net

Output:

GET
POST
true
true
true
true
OK
Not Found
https://example.com/api/users
POST
true
false

kordex:softadastra

Softadastra access requires --allow-softadastra.

This module is the main reliability difference in Kordex.

It connects JavaScript execution to the Softadastra C++ SDK, giving scripts access to a local-first storage foundation.

Softadastra can be used to open a local store, write values, read values back, check keys, inspect the store size, and close the store.

Create main.js:

import * as softadastra from "kordex:softadastra";

console.log("Opening Softadastra local store...");

softadastra.open("durable", "kordex-example", ".kordex/data/example-store.wal");

softadastra.put("runtime", "kordex");
softadastra.put("feature", "local-first");

const runtime = softadastra.get("runtime");
const feature = softadastra.get("feature");

console.log("runtime:", runtime);
console.log("feature:", feature);
console.log("has runtime:", softadastra.contains("runtime"));
console.log("store size:", softadastra.size());

softadastra.close();

console.log("Softadastra store closed.");

Run:

kordex run main.js --allow-softadastra

Expected output:

Opening Softadastra local store...
runtime: kordex
feature: local-first
has runtime: true
store size: 2
Softadastra store closed.

Without permission:

kordex run main.js

Expected error:

permission denied: module "kordex:softadastra" requires --allow-softadastra

Why this matters

Most JavaScript runtimes stop at executing JavaScript and exposing system APIs.

Kordex goes further by connecting JavaScript to a local-first reliability layer.

That means Kordex can become useful for applications where:

  • data must be written locally first
  • the app must survive unstable networks
  • offline mode is not an afterthought
  • local state matters
  • synchronization can be added later
  • system access must stay permission-controlled

This is the long-term difference between Kordex and many other JavaScript runtimes.

Check module exports

You can inspect a module:

import * as path from "kordex:path";

console.log(Object.keys(path).sort().join(", "));

Run:

kordex run main.js

Output:

basename, dirname, extension, isAbsolute, isRelative, join, name, namespace, normalize, separator

Examples

The repository includes examples under examples/.

01-hello
02-typescript
03-relative-import
04-extension-resolution
05-directory-index
06-json-import
07-console
08-path
09-timer
10-crypto
11-fs
12-env
13-process
14-http
15-softadastra

Run an example:

kordex run examples/01-hello/main.js

Run the Softadastra example:

kordex run examples/15-softadastra/main.js --allow-softadastra

Create a Kordex project

kordex init app
cd app

Run the default entry:

kordex run

Run a file directly:

kordex run src/main.js

Run TypeScript:

kordex run src/main.ts

Project configuration

Kordex looks for:

kordex.json
package.json

Example kordex.json:

{
  "name": "my-app",
  "version": "0.1.0",
  "entry": "src/main.ts",
  "scripts": {
    "dev": "kordex run src/main.ts",
    "build": "kordex build . --project"
  }
}

When running:

kordex run

Kordex resolves the entry from the project manifest.

Build scripts

Bundle a file:

kordex build main.js --out-dir dist --force

Bundle a project:

kordex build . --project --out-dir dist --force

Choose output file:

kordex build . --project --out-dir dist --out-file app.js --force

Generate a source map:

kordex build . --project --source-map --force

Output:

dist/main.js
dist/main.js.map

REPL

Evaluate code:

kordex repl --eval "1 + 2"

Output:

3

Use Softadastra from REPL eval:

kordex repl --eval "import * as s from 'kordex:softadastra'; console.log(typeof s.open)" --allow-softadastra

Package management

Install dependencies from kordex.json:

kordex install

Install one package:

kordex install softadastra/plugin-example@0.1.0

Update dependencies:

kordex update

The current package workflow generates and updates:

kordex.lock

This is still an MVP. It resolves declared packages and lock metadata without automatically executing downloaded code.

Plugin commands

Project plugin commands can be declared in kordex.json.

{
  "plugins": {
    "commands": [
      {
        "name": "hello",
        "summary": "Run hello plugin",
        "run": "scripts/hello.ts",
        "aliases": ["hi"],
        "permissions": {
          "fs": false,
          "env": false,
          "net": false,
          "process": false,
          "softadastra": false
        }
      }
    ]
  }
}

Then:

kordex hello

or:

kordex hi

Plugin commands have isolated permissions and cannot override built-in commands.

Repository structure

kordex/
├── CMakeLists.txt
├── cmake/
├── docs/
├── examples/
├── modules/
│   ├── runtime/
│   ├── bindings/
│   ├── std/
│   └── cli/
├── README.md
├── CHANGELOG.md
└── LICENSE

Architecture

Kordex follows a layered architecture:

CLI
-> Runtime options
-> Permission bridge
-> Bindings engine
-> Module loader
-> TypeScript loader
-> QuickJS backend
-> Standard native modules
-> ScriptResult

The runtime layer handles project-level and execution-level configuration.

The bindings layer handles JavaScript engine execution, native module registration, module loading, TypeScript transformation, and JavaScript backend integration.

The std layer exposes native modules through the kordex: namespace.

The CLI layer connects everything into a user-facing tool.

Runtime pipeline

For:

kordex run src/main.ts --allow-softadastra

The pipeline is:

CLI parses command
-> project/file resolved
-> RuntimeOptions created
-> permissions converted to StdOptions
-> Engine initialized
-> std modules installed according to permissions
-> Script loaded
-> TypeScript transformed if needed
-> imports resolved
-> modules bundled internally
-> QuickJS eval
-> ScriptResult rendered

Build pipeline

For:

kordex build . --project

The pipeline is:

ProjectDiscovery
-> resolve entry
-> load script
-> analyze import graph
-> transform TypeScript
-> resolve JSON modules
-> bundle modules
-> write dist/main.js
-> optionally write dist/main.js.map

Modules

modules/runtime

Core runtime foundation.

Provides:

  • runtime configuration
  • runtime lifecycle
  • source file loading
  • module resolver
  • runtime loop
  • cancellation
  • timers
  • tasks
  • process facade
  • diagnostics
  • manifest loading
  • permission model foundation

modules/bindings

Native bindings and JavaScript engine bridge.

Provides:

  • engine abstraction
  • QuickJS backend
  • script execution
  • eval()
  • TypeScript loading
  • module loading
  • JSON modules
  • native module bridge
  • native function bridge
  • value conversion
  • module cache
  • permission-aware module loading

modules/std

Standard native modules exposed to scripts.

Provides:

  • kordex:console
  • kordex:path
  • kordex:timer
  • kordex:crypto
  • kordex:fs
  • kordex:env
  • kordex:process
  • kordex:http
  • kordex:softadastra

modules/cli

User-facing command-line interface.

Provides:

  • kordex init
  • kordex run
  • kordex repl
  • kordex check
  • kordex build
  • kordex install
  • kordex update
  • kordex version
  • kordex help

Build from source

Development build:

vix build --preset dev-ninja --build-target all -v -- \
  -DKORDEX_ENABLE_QUICKJS=ON \
  -DKORDEX_ENABLE_NATIVE_ENGINE=OFF \
  -DKORDEX_BUILD_APP=ON

Development build with Softadastra support:

vix build --preset dev-ninja --build-target all -v -- \
  -DKORDEX_ENABLE_QUICKJS=ON \
  -DKORDEX_ENABLE_NATIVE_ENGINE=OFF \
  -DKORDEX_BUILD_APP=ON \
  -DKORDEX_ENABLE_STD_SOFTADASTRA=ON

Build with tests:

vix build --preset dev-ninja --build-target all -v -- \
  -DKORDEX_ENABLE_QUICKJS=ON \
  -DKORDEX_ENABLE_NATIVE_ENGINE=OFF \
  -DKORDEX_BUILD_APP=ON \
  -DKORDEX_BUILD_TESTS=ON

Run tests:

vix tests -- --output-on-failure

Test checklist

Use this checklist when validating the runtime:

global console
kordex:console
kordex:path
kordex:timer
kordex:crypto
kordex:fs with --allow-fs
kordex:env with --allow-env
kordex:process with --allow-process
kordex:http with --allow-net
kordex:softadastra with --allow-softadastra
relative imports
extension resolution
JSON imports
TypeScript loading
build output
project entry

Development status

Kordex is early-stage.

Implemented foundations:

  • runtime module
  • bindings module
  • std module
  • CLI module
  • QuickJS execution
  • TypeScript MVP loader
  • module loader
  • std imports
  • build bundling
  • source map MVP
  • permission bridge
  • project discovery
  • plugin command discovery
  • install/update lock generation
  • Softadastra standard module
  • integration examples

Still planned:

  • full TypeScript compiler integration
  • package downloads from registry
  • real plugin execution
  • richer source maps
  • package import resolution
  • native ES module execution
  • object/function value bridge
  • deeper Softadastra sync integration
  • richer local-first JavaScript APIs

Roadmap direction

Kordex is moving toward a runtime where JavaScript can be used for reliable local-first applications.

The direction is:

JavaScript execution
+ explicit native permissions
+ local durable state
+ offline-first behavior
+ optional synchronization
+ embeddable C++ foundation

This is the difference Kordex wants to bring.

Not only:

run JavaScript

But:

run reliable local-first JavaScript applications

Links

License

MIT License.

About

A JavaScript runtime for reliable local-first applications.

Resources

License

Stars

Watchers

Forks

Contributors