🚧 Glyx is pre-release software. APIs may change before v1.0. Get started β†’
Documentation
Core Concepts
Capability System

Capability System

Glyx gates access to native APIs behind capabilities β€” explicit permissions declared in glyx.config.ts.

Why capabilities exist

A Glyx app can read files, query databases, make network requests, and access the OS keychain. These are powerful APIs. Capabilities ensure:

  1. No surprise access β€” an app can't silently exfiltrate files
  2. Auditable permissions β€” the config is the source of truth
  3. Principle of least privilege β€” declare only what you need

Declaring capabilities

// glyx.config.ts
import { defineConfig } from '@glyx-dev/react'
 
export default defineConfig({
  name: 'my-app',
  capabilities: [
    'fs',       // file system read/write
    'db',       // SQLite
    'network',  // fetch, WebSocket, mDNS
    'clipboard',
  ],
})

What happens without a capability

Capability Demo
glyx.config.ts
export default defineConfig({
            capabilities: [
    "db",
  ],
            })
db.query('SELECT * FROM notes') β†’
[{ id: 1, title: 'My note', body: '...' }, ...]

The error is thrown at the first call to a gated API, not at build time.

Available capabilities

CapabilityGrants access to
fsglyx.fs β€” read, write, watch files
dbglyx.db β€” SQLite queries
networkglyx.network β€” fetch, WebSocket, mDNS
aiglyx.ai β€” local model inference
audioglyx.audio β€” playback and recording
clipboardglyx.clipboard β€” read and write
dialogglyx.dialog β€” open/save file dialogs
notificationglyx.notification β€” OS notifications
trayglyx.tray β€” system tray icons and menus
credentialsglyx.credentials β€” OS keychain
systemglyx.system β€” battery, storage, gamepad
deeplinkglyx.deeplink β€” URL scheme handler
cameraglyx.camera β€” camera device access

Stable β€” The capability system API is stable and will not change in v0.x releases.

Capability scoping

The fs capability supports per-path glob scoping to restrict which directories an app can access:

export default defineConfig({
  name: 'my-app',
  capabilities: [
    { name: 'fs', paths: ['~/Documents/my-app/**', '~/.config/my-app/**'] },
  ],
})

Any fs call targeting a path outside the declared globs throws CapabilityDenied at runtime. Path traversal attempts (e.g. ../../etc/passwd) are rejected before glob evaluation.

Capability providers

Capabilities are delivered in two ways:

Built-in

Core capabilities β€” fs, db, network, clipboard, dialog, notification, credentials, deeplink β€” are compiled directly into the Glyx runtime via Cargo feature flags. They add no startup overhead and are always available when declared.

Dynamic modules

Heavy or platform-specific capabilities β€” audio, ai, camera, gamepad, hid β€” can be provided as separate native libraries loaded at startup. This keeps the core binary lean and lets you ship only the capabilities your app actually needs.

Glyx looks for capability libraries next to the executable at startup:

PlatformFilename pattern
Windowsglyx_cap_audio.dll, glyx_cap_ai.dll, …
macOSlibglyx_cap_audio.dylib, …
Linuxlibglyx_cap_audio.so, …

If a library is present and its ABI version matches, Glyx loads it dynamically. The capabilities declaration in glyx.config.ts still controls whether the JS API is accessible β€” the library provides the implementation.

Hash pinning β€” automatic

glyx package automatically scans for capability modules next to your project, computes their SHA-256, copies them into the dist folder, and writes a glyx-caps.lock file alongside the binary:

target/glyx/dist/my-app/
  my-app.exe
  glyx_cap_audio.dll
  glyx-caps.lock          ← auto-generated, commit this

glyx-caps.lock is a JSON file mapping capability names to hashes:

{
  "audio": "e3b0c44298fc1c149afb4c8996fb92427ae41e4649b934ca495991b7852b855",
  "camera": "a87ff679a2f3e71d9181a67b7542122c"
}

At startup, the loader reads glyx-caps.lock from the exe directory and verifies each module's hash before loading. A tampered or mismatched file is rejected and the capability is treated as absent. In dev mode (glyx dev) no lock file exists so modules load unchecked β€” this is intentional. In release builds, any module without a pinned hash triggers a warning log.

You never need to compute or write hashes manually.

Dynamic modules implement the stable C ABI defined in the glyx-cap-abi crate:

#[repr(C)]
pub struct AudioCap {
    pub version:     u32,
    pub init:        extern "C" fn() -> i32,
    pub play:        extern "C" fn(path: *const c_char, loop_: bool) -> u32,
    pub pause:       extern "C" fn(id: u32),
    pub resume:      extern "C" fn(id: u32),
    pub stop:        extern "C" fn(id: u32),
    pub set_volume:  extern "C" fn(id: u32, vol: f32),
    pub get_volume:  extern "C" fn(id: u32) -> f32,
    pub get_time:    extern "C" fn(id: u32) -> f64,
    pub duration:    extern "C" fn(id: u32) -> f64,
    pub seek:        extern "C" fn(id: u32, secs: f64),
    pub poll:        extern "C" fn() -> *const c_char,
    pub shutdown:    extern "C" fn(),
}

The ABI is versioned (ABI_VERSION) β€” a version mismatch causes the load to fail cleanly with a warning rather than a crash.