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
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
| Function | Signature | Description |
|---|
readFile | readFile(path: String) -> String | Reads the entire file at path and returns its contents as a string |
writeFile | writeFile(path: String, content: String) | Writes content to path, creating or overwriting the file |
exists | exists(path: String) -> bool | Returns true if the path exists (file or directory) |
rm | rm(path: String) | Deletes the file or directory at path |
mkdir | mkdir(path: String) | Creates path as a directory (including all parent directories) |
listDir | listDir(path: String) -> Array | Returns an array of filename strings for the entries in path |
cwd | cwd() -> String | Returns 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.
| Protocol | Physical location | Access |
|---|
app://file.txt | Application directory (CWD of the running process) | Read / Write |
user://file.txt | User home directory | Read / Write |
tmp://file.txt | System temporary directory | Read / Write |
res://file.txt | Resources bundled inside the .clsapp package | Read-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
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
| Function | Signature | Description |
|---|
get | get(url: String) -> String | Performs an HTTP GET request to url and returns the response body |
post | post(url: String, body: String) -> String | Performs 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.