File I/O in Scala Golem Agents
SkillFiles & storageReading and writing files from a Scala Golem agent. Use when the user asks to read files, write files, or do filesystem operations from agent code in Scala.
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the File I/O in Scala Golem Agents skill
What this skill tells your AI
The instructions your AI receives, as published by golemcloud/golem in golem-skills/skills/scala/golem-file-io-scala/SKILL.md and read by ahel’s review.
Overview
Golem Scala agents are compiled to JavaScript via Scala.js and run in a QuickJS-based WASM runtime. The runtime provides node:fs for filesystem operations, accessible via Scala.js JavaScript interop. Standard JVM file I/O (java.io.File, java.nio.file.*) is not available.
To provision files into an agent's filesystem, load the golem-add-initial-files skill. To understand the full runtime environment, load the golem-js-runtime skill.
Setting Up the node:fs Facade
Define a Scala.js facade object for the node:fs module:
import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport
@js.native
@JSImport("node:fs", JSImport.Namespace)
private object Fs extends js.Object {
def readFileSync(path: String, encoding: String): String = js.native
def readFileSync(path: String): js.typedarray.Uint8Array = js.native
def writeFileSync(path: String, data: String): Unit = js.native
def existsSync(path: String): Boolean = js.native
def readdirSync(path: String): js.Array[String] = js.native
def appendFileSync(path: String, data: String): Unit = js.native
def mkdirSync(path: String, options: js.Object): Unit = js.native
}
Important: WASI modules like
node:fsare not available during the build-time pre-initialization (wizer) phase — they are only available at runtime. Use lazy val to defer initialization:// ✅ CORRECT — lazy val defers import to first runtime use private lazy val fs: Fs.type = Fs // ❌ WRONG — top-level val triggers import during pre-initialization and fails private val fs: Fs.type = Fs
Reading Files
Text Files
val content: String = Fs.readFileSync("/data/config.json", "utf-8")
Binary Files
val bytes: js.typedarray.Uint8Array = Fs.readFileSync("/data/image.png")
Writing Files
Only files provisioned with read-write permission (or files in non-provisioned paths) can be written to.
Fs.writeFileSync("/tmp/output.txt", "Hello, world!")
Checking File Existence
if (Fs.existsSync("/data/config.json")) {
val content = Fs.readFileSync("/data/config.json", "utf-8")
}
Listing Directories
val files: js.Array[String] = Fs.readdirSync("/data")
files.foreach(println)
Complete Agent Example
import golem.runtime.annotations.{agentDefinition, agentImplementation}
import golem.BaseAgent
import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport
import scala.concurrent.Future
@js.native
@JSImport("node:fs", JSImport.Namespace)
private object Fs extends js.Object {
def readFileSync(path: String, encoding: String): String = js.native
def appendFileSync(path: String, data: String): Unit = js.native
}
@agentDefinition()
trait FileReaderAgent extends BaseAgent {
class Id(val name: String)
def readGreeting(): Future[String]
def writeLog(message: String): Future[Unit]
}
@agentImplementation()
final class FileReaderAgentImpl(private val name: String) extends FileReaderAgent {
override def readGreeting(): Future[String] = Future.successful {
Fs.readFileSync("/data/greeting.txt", "utf-8").trim
}
override def writeLog(message: String): Future[Unit] = Future.successful {
Fs.appendFileSync("/tmp/agent.log", message + "\n")
}
}
Key Constraints
- Use
node:fsvia@JSImport— standard JVM file I/O (java.io.File,java.nio.file.*) does not work in Scala.js - Use lazy val or defer
node:fsaccess to method bodies to avoid pre-initialization failures - Files provisioned via
golem-add-initial-fileswithread-onlypermission cannot be written to - The filesystem is per-agent-instance — each agent has its own isolated filesystem
- File changes within an agent are persistent across invocations (durable state)
Signals
- GitHub stars
- 2k
- Forks
- 210
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
golem-file-io-scala- Source
- github.com/golemcloud/golem