File System
All operations work within directories declared in the manifest (fs.dirs). Paths must be absolute.
Read & Write
- AssemblyScript
- Go
- Rust
import { fsRead, fsWrite, fsCreate } from "@luminarys/sdk-as";
// Read file
const data = fsRead("/data/config.json");
// Write / overwrite
fsWrite("/data/output.txt", Uint8Array.wrap(String.UTF8.encode("content")));
// Create (fails if file exists)
fsCreate("/data/new.txt", Uint8Array.wrap(String.UTF8.encode("new file")));
// Read file
data, err := sdk.FsRead("/data/config.json")
// Write / overwrite
err := sdk.FsWrite("/data/output.txt", []byte("content"))
// Create (fails if file exists)
err := sdk.FsCreate("/data/new.txt", []byte("new file"))
// Read file
let data = fs_read("/data/config.json")?;
// Write / overwrite
fs_write("/data/output.txt", b"content".to_vec())?;
// Create (fails if file exists)
fs_create("/data/new.txt", b"new file".to_vec())?;
Read lines with pagination
- AssemblyScript
- Go
- Rust
import { fsReadLines } from "@luminarys/sdk-as";
const result = fsReadLines("/data/logfile.log", 100, 50);
// result.lines, result.total_lines, result.offset, result.is_truncated
result, err := sdk.FsReadLines(sdk.FSReadLinesRequest{
Path: "/data/logfile.log",
Offset: 100, // start at line 101 (0-based)
Limit: 50, // read 50 lines
})
// result.Lines, result.TotalLines, result.IsTruncated
let result = fs_read_lines(FsReadLinesRequest {
path: "/data/logfile.log".into(),
offset: 100,
limit: 50,
})?;
// result.lines, result.total_lines, result.is_truncated
Parameters:
| Field | Type | Description |
|---|---|---|
path | string | Absolute file path |
offset | int | Start line, 0-based (0 = beginning) |
limit | int | Maximum lines to return (0 = all) |
Response:
| Field | Type | Description |
|---|---|---|
lines | string[] | Array of line contents |
total_lines | int | Total number of lines in the file |
offset | int | Actual offset used |
is_truncated | bool | True if more lines exist beyond the returned range |
Directories
- AssemblyScript
- Go
- Rust
import { fsMkdir, fsLs, fsDelete } from "@luminarys/sdk-as";
// Create directory (recursive, supports brace expansion)
fsMkdir("/data/logs/2026/03");
// List directory
const entries = fsLs("/data");
// entries[i].name, entries[i].size, entries[i].is_dir
// Delete file or directory
fsDelete("/data/temp");
// Create directory (recursive, supports brace expansion)
sdk.FsMkdir("/data/logs/2026/03")
// List directory
entries, _ := sdk.FsLs("/data", false)
for _, e := range entries {
fmt.Printf("%s (%d bytes)\n", e.Name, e.Size)
}
// Delete file or directory
sdk.FsDelete("/data/temp")
// Create directory (recursive, supports brace expansion)
fs_mkdir("/data/logs/2026/03")?;
// List directory
let entries = fs_ls("/data", false)?;
for e in &entries {
println!("{} ({} bytes)", e.name, e.size);
}
// Delete file or directory
fs_delete("/data/temp")?;
fsLs / FsLs / fs_ls parameters:
| Field | Type | Description |
|---|---|---|
path | string | Absolute directory path |
long | bool | If true, populate mod_time, mode, mode_str (slower) |
DirEntry fields:
| Field | Type | Condition | Description |
|---|---|---|---|
name | string | always | File or directory name |
size | int64 | always | Size in bytes (0 for directories) |
is_dir | bool | always | Is a directory |
mod_time | int64 | long=true | Unix timestamp (seconds) |
mode | uint32 | long=true | Permission bits (e.g. 493 = 0o755) |
mode_str | string | long=true | Human-readable, e.g. "drwxr-xr-x" |
Copy & Chmod
- AssemblyScript
- Go
- Rust
import { fsCopy, fsChmod } from "@luminarys/sdk-as";
// Copy file: source → destination
fsCopy("/data/src.txt", "/data/backup/src.txt");
fsChmod("/data/script.sh", 493, false); // 0o755 = 493
// Copy file: source → destination
sdk.FsCopy("/data/src.txt", "/data/backup/src.txt")
sdk.FsChmod("/data/script.sh", 0o755, false)
// Copy file: source → destination
fs_copy("/data/src.txt", "/data/backup/src.txt")?;
fs_chmod("/data/script.sh", 0o755, false)?;
Glob
- AssemblyScript
- Go
- Rust
import { fsGlob } from "@luminarys/sdk-as";
// patterns, path, onlyFiles
const matches = fsGlob(["**/*.go"], "/data/project", true);
// matches[i].path, matches[i].is_dir
matches, _ := sdk.FsGlob(sdk.GlobOptions{
Patterns: []string{"**/*.go"},
Path: "/data/project",
OnlyFiles: true,
})
let matches = fs_glob(GlobOptions {
patterns: vec!["**/*.go".into()],
path: "/data/project".into(),
only_files: true,
..Default::default()
})?;
GlobOptions:
| Field | Type | Default | Description |
|---|---|---|---|
patterns | string[] | required | Glob patterns (union). Supports *, ?, [abc], **, {a,b} |
path | string | sandbox root | Base directory to search |
only_files | bool | false | Return only regular files |
only_dirs | bool | false | Return only directories |
match_hidden | bool | false | Include dot-files and dot-directories |
max_depth | int | 0 (unlimited) | Max directory recursion depth |
ignore_dirs | string[] | [] | Directory names to skip entirely |
GlobEntry (result):
| Field | Type | Description |
|---|---|---|
path | string | Path relative to the search directory |
is_dir | bool | Is a directory |
Grep
- AssemblyScript
- Go
- Rust
import { fsGrep } from "@luminarys/sdk-as";
// pattern, path, fixed, caseInsensitive, withLines
const matches = fsGrep("func main", "/data/project", false, false, true);
// matches[i].path, matches[i].matches[j].line_num, matches[i].matches[j].line
results, _ := sdk.FsGrep(sdk.GrepOptions{
Pattern: "func main",
Path: "/data/project",
WithLines: true,
})
let results = fs_grep(GrepOptions {
pattern: "func main".into(),
path: "/data/project".into(),
with_lines: true,
..Default::default()
})?;
GrepOptions:
| Field | Type | Default | Description |
|---|---|---|---|
pattern | string | required | RE2 regex (or literal when fixed = true) |
path | string | sandbox root | Directory or file to search |
fixed | bool | false | Treat pattern as literal string |
case_insensitive | bool | false | Case-insensitive matching |
with_lines | bool | false | Include full line text in results |
include | string[] | [] | Glob patterns to restrict files |
exclude | string[] | [] | Glob patterns to skip files |
max_count | int | 0 (unlimited) | Max matching lines per file |
max_depth | int | 0 (unlimited) | Max directory recursion depth |
workers | int | 0 (default) | Number of parallel search workers |
type_filter | string | "" | File type filter (e.g. "go", "ts") |
ignore_dirs | string[] | [] | Directory names to skip entirely |
filename_only | bool | false | Return only file paths, no line details |
GrepFileMatch (result):
| Field | Type | Description |
|---|---|---|
path | string | File path relative to the search directory |
matches | GrepLineMatch[] | Matching lines in this file |
GrepLineMatch:
| Field | Type | Description |
|---|---|---|
line_num | int | Line number (1-based) |
line | string | Line content (only when with_lines = true) |
ranges | GrepRange[] | Byte-offset ranges of matches within the line |
GrepRange:
| Field | Type | Description |
|---|---|---|
start | int | Start byte offset (inclusive) |
end | int | End byte offset (exclusive) |
Allowed directories
Query which directories the skill has access to at runtime:
- AssemblyScript
- Go
- Rust
import { fsAllowedDirs } from "@luminarys/sdk-as";
const dirs = fsAllowedDirs();
for (let i = 0; i < dirs.length; i++) {
// dirs[i].path, dirs[i].mode ("ro" | "rw")
}
dirs, _ := sdk.FsAllowedDirs()
for _, d := range dirs {
fmt.Printf("%s (%s)\n", d.Path, d.Mode)
}
let dirs = fs_allowed_dirs()?;
for d in &dirs {
println!("{} ({})", d.path, d.mode);
}
AllowedDir:
| Field | Type | Description |
|---|---|---|
path | string | Absolute directory path |
mode | string | Access mode: "ro" (read-only) or "rw" (read-write) |