Skip to content
A clean, flat 2D illustration in retro 8-bit style uses a five-color corporate palette. It displays a folder icon for workspace root, overlapping icons for PDF, DOCX, CSV, JSON, and XML files, along with simple gear and funnel icons symbolizing filtering and searching. A shield icon represents gitignore rules, and a pencil stands for output writing. All icons are geometric, minimalistic, and arranged compactly on a blank background.

Files

GenAIScript provides access to the file system of workspace and to the selected files in the user interface.

The file paths are rooted in the project workspace folder. In Visual Studio Code, this is the root folder opened (multi-root workspaces are not yet supported). Using the command line, the workspace root is the current working directory when launching the CLI.

The variable env.files contains an array of files that have been selected by the user through the user interface or the command line.

You can pass env.files directly in the def function and add additional filters to the files.

def("PDFS", env.files, { endsWith: ".pdf" })

By default, the .gitignore (workspace level) and .gitignore.genai (project level) files are respected when selecting files.

Turn off this mode by setting the ignoreGitIgnore option to true:

script({
// don't filter env.files
ignoreGitIgnore: true,
})

or on the cli run command:

Terminal window
genaiscript run --ignore-git-ignore

.gitignore.genai is an extra file that is used to filter files in the project. It is useful when you want to exclude files from the project that are not relevant for the script beyond the .gitignore file.

Use defFileOutput to specify allowed file output paths and the description of the purpose of those files.

defFileOutput("src/*.md", "Product documentation in markdown format")

The workspace object provides access to the file system of the workspace.

Performs a search for files under the workspace. Glob patterns are supported.

const mds = await workspace.findFiles("**/*.md")
def("DOCS", mds)

The .gitignore are respected by default. You can disable this behavior by setting the ignoreGitIgnore option to true.

Performs a regex ‘grep’ search for files under the workspace using ripgrep. The pattern can be a string or a regular expression.

const { files } = await workspace.grep("monkey", "**/*.md")
def("FILE", files)

The pattern can also be a regex, in which case sensitivity follows the regex option.

const { files } = await workspace.grep(/[a-z]+\d/i, "**/*.md")
def("FILE", files)

The .gitignore are respected by default. You can disable this behavior by setting the ignoreGitIgnore option to true.

Reads the content of a file as text, relative to the workspace root.

const file = await workspace.readText("README.md")
const content = file.content

It will automatically convert PDFs and DOCX files to text.

Reads the content of a file as JSON (using a JSON5 parser).

const data = await workspace.readJSON("data.json")

Reads the content of a file as XML format.

const data = await workspace.readXML("data.xml")

Reads the content of a file as CSV format.

const data = await workspace.readCSV("data.csv")

In Typescript, you can type the output.

const data = await workspace.readCSV<{ name: string; value: number }>(
"data.csv"
)

This helper API tries to infer the data type automatically and parse it out. It supports JSON, JSON5, YAML, XML, INI, TOML, CSV, XLSX.

const data = await workspace.readData("filename.csv")

You can provide a JSON schema to validate the parsed data. By default, invalid data is silently ignored and the return value is undefined but you can force the API to throw using throwOnValidationError.

const data = await workspace.readJSON("data.json", {
schema: { type: "object", properties: { ... }, },
throwOnValidationError: true
})

Writes text to a file, relative to the workspace root.

await workspace.writeText("output.txt", "Hello, world!")

Appends text to a file, relative to the workspace root.

await workspace.appendText("output.txt", "Hello, world!")

The GenAIScript workspace file system includes enhanced security features to prevent writing files outside the workspace and provides configurable file access policies.

All file write operations are restricted to the current workspace (project folder). The system prevents:

  • Writing to absolute paths outside the workspace (e.g., /etc/passwd)
  • Path traversal attacks (e.g., ../../../etc/passwd)
  • Access to parent directories beyond the workspace root
// ✅ Safe - within workspace
await workspace.writeText("output/results.json", JSON.stringify(data));
// ❌ Blocked - outside workspace
await workspace.writeText("/etc/passwd", "malicious content");
// ❌ Blocked - path traversal
await workspace.writeText("../../../etc/passwd", "malicious content");

Writing to .env files is blocked by default to prevent accidental exposure of secrets:

  • Direct .env files in any directory
  • Files matching the .env pattern (.env.*, .env.local, etc.)
// ❌ Blocked - environment file
await workspace.writeText(".env", "SECRET=value");

The fs_write_file system tool provides LLMs with controlled file writing capabilities:

script({
title: "Safe file operations",
system: ["fs_write_file"]
})
$`Create a README.md file with project documentation.`
// The LLM can now use fs_write_file to create files safely within the workspace

When file operations are blocked, you’ll see descriptive error messages:

  • writing outside workspace not allowed: /path/to/file
  • writing .env not allowed
  • writing to disallowed file: config/secret.txt
  • writing to file not in allowed list: script.exe

For scripts that require unrestricted file system access outside the workspace boundaries, you can use Node.js file system APIs directly. Use this approach with extreme caution as it bypasses all workspace security protections:

// Import Node.js file system modules for unchecked operations
const fs = await import('fs')
const path = await import('path')
// ⚠️ WARNING: This bypasses workspace security!
// Write to any location on the file system
const absolutePath = path.join('/tmp', 'unrestricted-file.txt')
fs.writeFileSync(absolutePath, 'This file is written outside workspace boundaries')
// Read from any location
const systemFile = fs.readFileSync('/etc/hosts', 'utf8')

Important considerations when using direct Node.js file system APIs:

  • Security Risk: No path validation or boundary checking
  • Portability: Absolute paths may not work across different operating systems
  • Permissions: Operations may fail due to file system permissions
  • Responsibility: You are responsible for validating paths and ensuring safe operations

When to use direct Node.js APIs:

  • System administration scripts that need access to system files
  • Build tools that operate on files outside the project
  • Migration scripts that access multiple project directories
  • Advanced automation that requires unrestricted file access

Best practices:

  • Always validate and sanitize file paths when using user input
  • Use path.resolve() and path.normalize() to handle paths safely
  • Check file permissions before attempting operations
  • Consider using the workspace APIs first and only escalate to direct Node.js APIs when necessary

The paths object contains helper methods to manipulate file names.

By default, files are resolved relative to the workspace root. You can use the path object to resolve paths relative to the current specification, env.spec.

const cur = path.dirname(env.spec.filename)
const fs = path.join(cur, "myfile.md")

File path “globs” are patterns used to match file and directory names. They are commonly used in Unix-like operating systems and programming languages to specify sets of filenames with wildcard characters. This section covers the basics of using globs in file paths with workspace.findFiles.

Glob patterns can have the following syntax:

  • * to match zero or more characters in a path segment
  • ? to match on one character in a path segment
  • ** to match any number of path segments, including none
  • {} to group conditions (e.g. **/*.{ts,js} matches all TypeScript and JavaScript files)
  • [] to declare a range of characters to match in a path segment (e.g., example.[0-9] to match on example.0, example.1, …)
  • [!...] to negate a range of characters to match in a path segment (e.g., example.[!0-9] to match on example.a, example.b, but not example.0)

Note: a backslash (\“) is not valid within a glob pattern. If you have an existing file path to match against, consider to use the relative pattern support that takes care of converting any backslash into slash. Otherwise, make sure to convert any backslash to slash when creating the glob pattern.