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.

The fs and http modules are desktop-only — they are provided by the clx node and injected into the module resolver via add_internal. They are not part of cls-runtime’s core standard library and are therefore not available in the lightweight clxr runtime. If your script targets clxr or is embedded in a host application that does not inject these modules, any import "fs" or import "http" statement will throw a RuntimeError: module 'fs' not found. Access to both modules is also controlled by the sandbox configuration in cls.json. When allowFs or allowNet is set to false, the module will still load but any function call will be denied at the OS level (for fs) or network layer (for http).

fs Module

import "fs" as fs;
The fs module exposes filesystem operations. All path arguments can be either a plain OS path ("config.json", "/tmp/out.txt") or a VFS protocol URI ("app://config.json", "tmp://cache.dat"). VFS paths are resolved through CLS’s VfsResolver, which maps protocol prefixes to physical directories in a portable way.

Function Reference

FunctionSignatureDescription
readFilereadFile(path: String) -> StringReads the entire file at path and returns its contents as a string
writeFilewriteFile(path: String, content: String)Writes content to path, creating or overwriting the file
existsexists(path: String) -> boolReturns true if the path exists (file or directory)
rmrm(path: String)Deletes the file or directory at path
mkdirmkdir(path: String)Creates path as a directory (including all parent directories)
listDirlistDir(path: String) -> ArrayReturns an array of filename strings for the entries in path
cwdcwd() -> StringReturns the current working directory as an absolute path string

VFS Protocol URIs

The fs module automatically routes paths that contain :// through the VfsResolver. This lets scripts use portable, sandboxed paths instead of absolute OS paths.
ProtocolPhysical locationAccess
app://file.txtApplication directory (CWD of the running process)Read / Write
user://file.txtUser home directoryRead / Write
tmp://file.txtSystem temporary directoryRead / Write
res://file.txtResources bundled inside the .clsapp packageRead-only
import "fs" as fs;

# Portable app-relative path
var config = fs.readFile("app://config.json");

# Temp file
fs.writeFile("tmp://session.dat", "token=abc123");

# Bundled resource
var template = fs.readFile("res://templates/welcome.html");

http Module

import "http" as http;
The http module exposes simple synchronous HTTP calls backed by the ureq Rust crate. Both functions perform a blocking network request and return the response body as a string.

Function Reference

FunctionSignatureDescription
getget(url: String) -> StringPerforms an HTTP GET request to url and returns the response body
postpost(url: String, body: String) -> StringPerforms an HTTP POST request to url with the given body string and returns the response body

Sandbox Configuration

Desktop projects declare sandbox permissions in cls.json:
{
  "name": "my-app",
  "version": "0.1.0",
  "entry": "src/main.clsx",
  "interpreter": {
    "sandbox": {
      "allowFs": true,
      "allowNet": true
    }
  }
}
Setting allowFs: false prevents all fs function calls at runtime. Setting allowNet: false prevents all http function calls. Both default to false in a new project — you must explicitly enable the permissions you need.
Attempting to import or use fs or http in the clxr lightweight runtime, or in an embedded Interpreter that was not configured with these modules via add_internal, will throw a RuntimeError. Similarly, calling fs.readFile or http.get when the sandbox denies the corresponding permission will throw a RuntimeError at the point of the call.

Examples

Reading a configuration file

import "fs" as fs;
import "json" as json;

function loadConfig() -> Any {
    if (!fs.exists("app://config.json")) {
        throw("config.json not found");
    };
    var text = fs.readFile("app://config.json");
    return json.parse(text);
};

var config = loadConfig();
print("host:", config["host"]);
print("port:", config["port"]);

Writing a log file

import "fs" as fs;

function appendLog(message: String) {
    var timestamp = toString(now());
    var line = "[${timestamp}] ${message}\n";

    var existing = "";
    if (fs.exists("app://app.log")) {
        existing = fs.readFile("app://app.log");
    };

    fs.writeFile("app://app.log", existing + line);
};

appendLog("Application started");
appendLog("Processing complete");

Listing a directory

import "fs" as fs;

var entries = fs.listDir("app://data");
for each name in (entries) {
    print(name);
};

Making an HTTP GET request

import "http" as http;
import "json" as json;

async function fetchUser(id: int) -> Any {
    var url = "https://jsonplaceholder.typicode.com/users/${id}";
    var body = http.get(url);
    return json.parse(body);
};

async function main() -> int {
    var user = await fetchUser(1);
    print("name:", user["name"]);
    print("email:", user["email"]);
    return 0;
};

await main();

Making an HTTP POST request

import "http" as http;
import "json" as json;

function postData(endpoint: String, payload: Any) -> Any {
    var body = json.stringify(payload);
    var response = http.post(endpoint, body);
    return json.parse(response);
};

var result = postData(
    "https://api.example.com/events",
    { "event": "login", "user": "alice" }
);
print("response id:", result["id"]);
http.get and http.post are synchronous and will block the executing thread until the network response arrives. For non-blocking behaviour, wrap the call in an async function and combine it with async.all or async.race as needed.

Build docs developers (and LLMs) love