OS, files & hardware

Read and write files, detect the operating system, query environment variables, and reach specialized hardware through the stdlib, FFI, or language bridge.

Run your project

Any program that uses import must be built from the project directory, not as a lone file:

cd myapp
nyra run .
Use nyra run . for projects nyra run main.ny compiles a single file and does not load imports. Multi-file apps and stdlib imports need nyra run . or nyra build .. See Imports guide.

Import stdlib modules with short paths from any project depth:

import "stdlib/fs.ny"
import "stdlib/os.ny"

Filesystem

import "stdlib/fs.ny" (or stdlib/fs/mod.ny) gives you the filesystem API. API reference: Stdlib → fs.

FunctionDescription
write_file(path, content)Create or overwrite a file
read_file(path)Read entire file into a string (owned, auto-dropped)
append_file(path, content)Append to an existing file
exists(path)Returns 1 if path exists, else 0
create_dir(path)Create a directory
remove_file(path) / remove_dir(path)Delete file or directory
import "stdlib/fs.ny"

fn main() {
    write_file("hello.txt", "Written from Nyra\n")
    if exists("hello.txt") == 1 {
        let content = read_file("hello.txt")
        print(content)
    }
}

Example in repo: examples/projects/read_file/main.ny

Operating system

import "stdlib/os.ny" aggregates platform detection, environment, battery, POSIX-style I/O, and syscall helpers (macOS, Linux, Windows). See Stdlib → os.

Platform detection

FunctionReturns
platform_name()"darwin", "linux", or "windows"
is_darwin() / is_linux() / is_windows()bool platform checks
platform_id()Numeric constant (PLATFORM_LINUX, …)
page_size()OS memory page size in bytes

Process & environment

FunctionDescription
os_getenv(name)Read an environment variable. Use os_getenv — not getenv (libc name collision at link time).
os_getpid()Current process ID
os_exit(code)Terminate the process
battery_percent()0–100 on laptops, or -1 if unavailable
import "stdlib/os.ny"

fn main() {
    print(platform_name())
    print(os_getenv("HOME"))
    print(os_getpid())

    if is_darwin() {
        print("Running on macOS")
    } else if is_linux() {
        print("Running on Linux")
    }
}

Run examples from the repo root:

nyra run examples/os/platform/main.ny
nyra run examples/os/battery/main.ny

Run external commands

To spawn another program (like Rust’s Command), use stdlib/process.ny — auto-prelude symbols Command_new, .arg, .run. Returns the child exit code; stdout/stderr inherit your terminal. For shell strings (pipes, globs), run /bin/sh -c "…".

fn main() {
    let code = Command_new("ls").arg("-la").run()
    print(code)

    let sh = Command_new("/bin/sh").arg("-c").arg("uname -a").run()
    print(sh)
}

Full reference: stdlib → Subprocess & commands · example examples/process_command.ny. To capture stdout as a string, use stdlib/bridge/mod.ny (language bridge).

User input

input("prompt") is a builtin — no import required. It reads a line from stdin and returns a string. Full I/O builtins: stdlib → Built-ins → I/O.

fn main() {
    let name = "Ada"  // in apps: let name = input("Enter your name)
    print(`Hello, ${name}!`)
}

Low-level: syscalls & assembly

For kernel-style or driver code, use the POSIX wrappers and raw syscall layer:

APIModulePurpose
os_read, os_write, os_closestdlib/os/unistd.nyFile-descriptor I/O
os_syscall6(num, a0..a5)stdlib/os/unistd.nyRaw syscall with OS-specific number
SYS_* constantssyscall_linux.ny / syscall_darwin.nySyscall numbers for os_syscall6
unsafe { asm "nop" }Nyra languageInline assembly template
cpu_nop(), cpu_pause()stdlib/os/asm.nyPrebuilt asm helpers
import "stdlib/os.ny"

fn main() {
    unsafe {
        asm "nop"
    }
    cpu_nop()
    print(os_getpid())
}

For no_std / embedded / MMIO register access, see Memory → unsafe and stdlib/core/mem.ny (volatile_load_i32, *T pointers). Example: examples/os/asm/main.ny.

Hardware topology (stdlib/os)

Since import "stdlib/os.ny" also pulls hardware helpers:

ModuleKey APIs
cpu.nycpu_brand(), physical/logical cores, cache line, cpu_has_avx2()
memory.nymem_map_anonymous, mem_unmap, hw_page_size(), dma_available()
storage.nydisk_fs_type, disk_total_bytes, disk_free_bytes
netif.nynet_interface_count, net_interface_mac, net_interface_is_up
display.nydisplay_width, display_height, display_refresh_hz, brightness
power.nypower_on_ac(), power_cpu_temp_centi_c() + battery_percent()
syscall_windows.nyWindows Nt / VirtualAlloc constants
import "stdlib/os.ny"

fn main() {
    print(cpu_brand())
    print(cpu_logical_cores())
    print(disk_fs_type("/"))
    print(net_interface_mac(0))
    print(display_width())
}

Example: nyra run examples/os/hw/main.ny

Example: nyra run examples/os/hw/main.ny

Advanced CPU control

Modules: affinity.ny, clocks.ny

CPU affinity

Pin the current OS thread to a logical core — useful for real-time loops and reducing migration overhead.

import "stdlib/os.ny"

fn main() {
    let cores = cpu_logical_cores()
    print(cores)
    let ok = affinity_set_thread_cpu(0)   // 0 on success
    print(ok)
    print(affinity_get_thread_cpu())
}
FunctionNotes
affinity_set_thread_cpu(n)Linux pthread_setaffinity_np, macOS thread policy, Windows SetThreadAffinityMask
affinity_get_thread_cpu()Returns first pinned core or current CPU; -1 if unknown

High-resolution clocks

Cycle counters for micro-benchmarks and profilers. Returns i64.

import "stdlib/os.ny"

fn main() {
    let t0 = clock_monotonic_ns()
    // ... work ...
    let elapsed = clock_elapsed_ns(t0)

    let cycles = clock_rdtsc()   // RDTSC on x86_64, cntvct on ARM64
}
FunctionSource
clock_rdtsc()RDTSC / ARM virtual counter
clock_monotonic_ns()clock_gettime / QPC
clock_elapsed_ns(start)Helper using monotonic clock

USB & serial ports

Modules: usb.ny, serial.ny

USB enumeration

Lists devices via Linux sysfs (/sys/bus/usb/devices). macOS/Windows: use FFI or language bridge for full IOKit/SetupAPI access.

import "stdlib/os.ny"

fn main() {
    let n = usb_device_count()
    print(n)
    if n > 0 {
        print(usb_device_vid(0))    // vendor ID hex
        print(usb_device_pid(0))    // product ID hex
        print(usb_device_path(0))   // sysfs path on Linux
    }
}

Serial (UART / COM)

import "stdlib/os.ny"

fn main() {
    let port = "/dev/ttyUSB0"       // Windows: "COM3"
    let h = serial_open(port, 115200)
    if h >= 0 {
        serial_write(h, "AT\r\n")
        print(serial_read(h, 256))
        serial_close(h)
    }
}

Typical paths: Linux /dev/ttyUSB0, macOS /dev/cu.usbserial-*, Windows COM3.

Signals & kernel IPC

Modules: signals.ny, mqueue.ny

OS signal handling

Nyra uses a poll model: a C handler sets a flag; your main loop calls signal_poll. Do not run Nyra code inside the Unix signal handler.

import "stdlib/os.ny"

fn main() {
    signal_install(SIGINT)
    let mut ticks = 0
    while ticks < 1 {
        if signal_poll(SIGINT) {
            print("Ctrl+C — shutting down")
            break
        }
        ticks = ticks + 1
    }
}

Constants: SIGINT (2), SIGTERM (15), SIGSEGV (11). Windows: supported for SIGINT/SIGTERM via console control events.

Message queues (Linux/macOS/Windows)

import "stdlib/os.ny"

fn main() {
    let mq = mqueue_open("nyra_demo", 8, 256)
    mqueue_send(mq, "payload")
    print(mqueue_recv(mq, 256))
    mqueue_close(mq)
}

Linux: POSIX mqueue (librt). macOS: in-process best-effort queue (name ignored). Windows: mailslot best-effort queue (local IPC).

Hardware crypto & permissions

Modules: hw_crypto.ny, permissions.ny — OS-level hardware RNG and privilege drop. For everyday app randomness (dice, shuffles, simulations), use random(), random(min, max), random_f64() — ChaCha20 seeded from OS/hardware entropy. Import stdlib/random.ny for shuffle_pick. For application crypto (SHA, HMAC, AES), use stdlib/crypto/mod.ny.

Everyday random vs hardware TRNG

APIModuleUse when
random(min, max)builtin / random.nyGames, shuffles — ChaCha20 stream
random_bytes(n)stdlib/crypto/random.nyHex-encoded random bytes (same ChaCha20 backend)
hw_random_bytes(n)stdlib/os/hw_crypto.nyRaw OS TRNG for keys, tokens, crypto seeds

Hardware TRNG

import "stdlib/os.ny"

fn main() {
    let raw = hw_random_bytes(32)
    print(raw.len())
    print(hw_secure_enclave_available())
}

Full Secure Enclave / Intel SGX key sealing needs platform-specific FFI beyond this hook.

Privilege dropping & sandbox hints

import "stdlib/os.ny"

fn main() {
    print(perm_getuid())
    print(perm_geteuid())
    // perm_drop_to_uid(1000)   // needs root; drops to user 1000
    // perm_chroot("/var/jail") // Linux/macOS: chroot (needs privileges). Windows: best-effort SetCurrentDirectory.
    print(perm_sandbox_seatbelt_available())  // macOS Seatbelt present
}

Combined advanced demo: nyra run examples/os/adv/main.ny

GPIO / specialized hardware (FFI)

Nyra does not ship a GPIO or serial-port stdlib like Arduino. Use one of these patterns:

1. FFI with a C library

When a mature C API exists (libusb, libserialport, OpenSSL, SQLite, …), declare it with extern fn and link the native library:

extern fn strlen(s){
    print(strlen("hello"))
}

In nyra.mod:

link usb-1.0
link -L /opt/homebrew/lib

Guides: FFI & ABI · NyraPkg (link, link-source) · examples/ffi/call_libc/

2. Language bridge (Python / Node / Java)

When the hardware library lives in pip, npm, or Maven, run a subprocess worker and exchange JSON lines:

import "stdlib/bridge/mod.ny"

fn main() {
    let req = bridge_op_add(1, 2)
    let out = bridge_exec_arg("python3", "workers/bridge_worker.py", req)
    print(bridge_result(out))
}

Extend workers to call pyserial, RPi.GPIO, numpy, etc. Nyra stays the orchestrator. See examples/bridge/ and FFI & ABI.

3. Network-connected devices

Hardware that speaks TCP or HTTP can be reached with the net stdlib — no native driver required:

import "stdlib/net/tcp.ny"
import "stdlib/net/http/mod.ny"

See net/http API.

4. Bare-metal / drivers (no_std)

For kernels, firmware, or memory-mapped I/O:

See Compilation targets (--freestanding).

Cheat sheet

GoalApproach
Create / read filesimport "stdlib/fs.ny"
Detect OS, read env, batteryimport "stdlib/os.ny"
Run shell / system commandCommand_new / .runstdlib/process
Capture subprocess stdoutstdlib/bridge/mod.ny
Prompt user on terminalinput("...") builtin
Existing C libraryextern fn + link in nyra.mod
Python / npm hardware libsstdlib/bridge/mod.ny
CPU affinity / RDTSCaffinity.ny, clocks.ny
USB list / serial portusb.ny, serial.ny
SIGINT / mqueuesignals.ny + mqueue.ny (Linux POSIX; macOS/Windows best-effort)
Random / HW cryptorandom.ny, hw_crypto.ny, permissions.ny
CPU topology / disk / netifcpu.ny, storage.ny, netif.ny
Embedded / MMIOno_std + stdlib/core/mem.ny
Device over networkstdlib/net/tcp.ny or net/http

Full example

Combine filesystem, OS detection, user input, and battery into one project (myapp/main.ny):

import "stdlib/fs.ny"
import "stdlib/os.ny"

fn main() {
    let name = "Ada"

    let info = `OS: ${platform_name()}
PID: ${os_getpid()}
HOME: ${os_getenv("HOME")}
User: ${name}
`
    write_file("system_info.txt", info)
    print(read_file("system_info.txt"))

    let bat = battery_percent()
    if bat >= 0 {
        print(`Battery: ${bat}%`)
    }
}
cd myapp
nyra run .

Related docs