Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/elfrask/cls/llms.txt

Use this file to discover all available pages before exploring further.

CLS programs never reference raw operating-system paths like /home/alice/project/config.json or C:\Users\Alice\AppData\.... Instead, they use a Virtual File System (VFS) with protocol-based URIs such as app://config.json or tmp://cache.dat. The VFS layer maps each protocol prefix to an appropriate real directory at runtime — the application directory, the user’s home folder, the system temp directory, or the resource bundle inside a packaged .clsapp file — which means the same CLS source code works correctly on every platform and in every deployment environment without any path manipulation. The VFS also enforces a chroot-style security jail around each protocol root. Path traversal sequences (../) that would escape the mapped directory are detected and rejected at the Rust layer before any filesystem call is made, so a CLS program cannot accidentally (or maliciously) read files outside the boundaries it was granted access to.

Protocol reference

Each protocol prefix maps to a fixed real-world location determined by the runtime at startup.
ProtocolMapped PathAccessUse Case
app://Application directory (CWD / project root)Read / WriteProject-local config, data files, logs
user://User home directoryRead / WriteUser preferences and persistent data
tmp://System temp directoryRead / WriteEphemeral caches, scratch files
res://Resources inside .clsapp bundleRead-onlyBundled assets (images, templates, embedded data)
Protocol names (app, user, tmp, res) are reserved by the VFS resolver. Custom route aliases may be added by the host node but cannot override these four built-in protocols.

app:// — Application directory

app:// maps to the working directory of the running CLS program — typically the project root when using clx run, or the directory containing the .clsapp bundle when running with clxr. Use it for any file that lives alongside your source code or that your program owns.

user:// — User home directory

user:// maps to the platform home directory (e.g. ~ on Unix, %USERPROFILE% on Windows). It is the right place to store user-specific settings and data that should persist across runs, since the home directory survives program restarts and system updates.

tmp:// — Temporary directory

tmp:// maps to the OS-provided temporary directory (/tmp on Linux/macOS, %TEMP% on Windows). Files written here may be cleaned up by the OS at any time. Use tmp:// for intermediate results, caches, and data that only needs to survive a single session.

res:// — Bundled resources (read-only)

res:// maps into the ZIP archive inside a .clsapp bundle. It is read-only — writes are rejected at the protocol level. Use res:// to ship assets (fonts, default configs, templates, embedded databases) that are baked into the application at build time and must be accessible at runtime without any installation step.
res:// is only meaningful inside packaged .clsapp files run by clxr. When running source code directly with clx run during development, res:// has no archive to read from and all accesses will fail. See Desktop vs. runtime for the recommended development workflow.

Using VFS with the fs module

The fs module exposes VFS operations through a simple, protocol-aware API. Pass any VFS URI as the path argument — the runtime automatically resolves the protocol prefix and enforces the security jail.
import "fs" as fs;

// Read a JSON config from the application directory
let raw = fs.readFile("app://config.json");
let config = JSON.parse(raw);

// Write a computed cache to the temp directory
let cacheData = computeCache();
fs.writeFile("tmp://cache.dat", cacheData);

// Check if a user preferences file already exists
if fs.exists("user://prefs.json") {
  let prefs = fs.readFile("user://prefs.json");
  applyPreferences(JSON.parse(prefs));
}

// Read a bundled asset from inside a .clsapp package
let template = fs.readFile("res://templates/welcome.html");
render(template);
Paths without a protocol prefix are treated as relative to app://:
import "fs" as fs;

// Equivalent to fs.readFile("app://data.txt")
let content = fs.readFile("data.txt");
Always prefer explicit protocol prefixes in code you intend to ship. Implicit app:// resolution is convenient during development but makes the intent of path access less clear to future readers.

Available fs operations

FunctionSignatureDescription
fs.readFile(path: string) → stringRead file contents as a UTF-8 string
fs.writeFile(path: string, data: string) → voidWrite a string to a file (creates parent dirs)
fs.exists(path: string) → boolCheck whether a file or directory exists
fs.listDir(path: string) → string[]List entries in a directory
fs.createDir(path: string) → voidCreate a directory (and all parents)
fs.remove(path: string) → voidDelete a file or directory tree

Sandbox security

VFS access is not granted automatically. The interpreter.sandbox block in cls.json controls which categories of access the runtime permits. Both flags default to false (all access denied).
{
  "interpreter": {
    "sandbox": {
      "allowFs": true,
      "allowNet": false,
      "maxExecutionTime": 5000
    }
  }
}
interpreter.sandbox.allowFs
boolean
default:"false"
When false (the default), any call to the fs module raises a runtime permission error. Set to true to grant the program full VFS access across all protocols (app://, user://, tmp://, res://).
interpreter.sandbox.allowNet
boolean
default:"false"
When false, all outbound network connections are blocked. Set to true to allow HTTP, TCP, and UDP operations.
interpreter.sandbox.maxExecutionTime
integer
default:"5000"
Wall-clock timeout in milliseconds. The program is forcibly terminated if execution exceeds this limit. Set to 0 to disable. Useful as a safeguard in untrusted or embedded contexts.

Path traversal protection

Even when allowFs is true, the VFS security layer prevents a program from escaping its allocated directory roots. Each protocol is backed by a chroot jail: the Rust resolve_safe function normalises every path component and rejects any ../ sequence that would resolve outside the base directory. Absolute paths (starting with / or a drive letter) are also rejected.
// These will throw a runtime error regardless of allowFs:
fs.readFile("app://../../../etc/passwd");   // path traversal blocked
fs.readFile("app:///etc/passwd");           // absolute path blocked
Setting allowFs: true grants access to all four VFS protocols. There is no per-protocol permission granularity in the current release. Programs with allowFs: true can write to user:// and tmp:// as well as read from app:// and res://.

Desktop (clx) vs. runtime (clxr)

CLS programs can be executed in two contexts, and VFS behaviour differs slightly between them.
Featureclx run (desktop)clxr (runtime)
app://Maps to the project root (CWD)Maps to the directory containing the .clsapp bundle
user://Maps to the developer’s home directoryMaps to the end-user’s home directory
tmp://System temp dirSystem temp dir
res://Not available — no ZIP archiveReads from the ZIP archive inside .clsapp
fs module availableYes (when allowFs: true)Yes (when allowFs: true)
The fs module — and therefore all VFS access — is only available in the clx desktop node. The clxr lightweight runtime does not expose fs by default; it must be explicitly injected by the host application through the module resolver. Scripts intended to run purely in clxr should not depend on fs unless the deployment target is known to provide it.
When developing locally, use app:// paths for all file access and substitute test fixtures for anything you would eventually ship via res://. Only the final packaged .clsapp produced by clx build will have a populated res:// archive.

End-to-end example

The following scenario demonstrates reading runtime configuration from app://, writing a derived cache to tmp://, and accessing a bundled HTML template via res:// in a packaged application.
{
  "name": "my-app",
  "version": "1.0.0",
  "entry": "src/main.clsx",
  "interpreter": {
    "sandbox": {
      "allowFs": true,
      "allowNet": false,
      "maxExecutionTime": 10000
    }
  }
}

Build docs developers (and LLMs) love