read_file
The prelude’s read_file, slated to be the first real definition: a .tr
spec (prose, capability-style signature, fake-capability test, real-mode
cram test), its .soil lowering, and its .lock entry. The canonical
files live in examples/;
these are included verbatim.
read_file.tr
---
name: read_file
---
# read_file
Reads an entire file into a UTF-8 string. Returns `Err` if the file does not
exist, cannot be read, or is not valid UTF-8. Never panics.
```soil-sig
read_file : (fs : Fs) -> (path : Path) -> io (Result Utf8 FsError)
```
```test found-and-missing
with fs = fake_fs {"config.toml": "port = 8080"}
(fs, "config.toml") => {"tag": "Ok", "value": "port = 8080"}
(fs, "missing.toml") => {"tag": "Err", "value": {"tag": "NotFound", "value": {"path": "missing.toml"}}}
```
One real-mode test against the actual filesystem:
```cram real-read
with file "config.toml" = "port = 8080"
$ trellis call read_file '"config.toml"'
{"tag": "Ok", "value": "port = 8080"}
```
read_file.soil
read_file : (fs : Fs) -> (path : Path) -> io (Result Utf8 FsError)
read_file fs path =
match fs_read_bytes fs path with
| Err e -> Err e
| Ok bytes ->
match utf8_decode bytes with
| Ok text -> Ok text
| Err _ -> Err (NotUtf8 { path = path })
read_file.lock
{
"lock_format": 1,
"name": "read_file",
"kind": "function",
"versions": { "trellis": "0.1", "soil": "0.1" },
"spec": {
"provenance": "human",
"hashes": {
"formal": "sha256:0be4d1c7",
"test": "sha256:9a31e0f8",
"prose": "sha256:5cc2071d"
},
"prose_state": "fresh",
"blocks": [
{ "block": "soil-sig", "author": "human" },
{ "block": "test found-and-missing", "author": "human" },
{ "block": "cram real-read", "author": "human" }
],
"pinned": true,
"escape_hatches": []
},
"lowering": {
"soil_hash": "sha256:ce8842a0",
"provenance": "human-verified",
"provider": "claude-code",
"model": "claude-opus-4-7",
"private_helpers": [],
"calls": [
{ "name": "fs_read_bytes", "hash": "sha256:44f7b2e9" },
{ "name": "utf8_decode", "hash": "sha256:d10a93c5" }
]
},
"checks": {
"types": "ok",
"refinements": "none",
"demoted": []
},
"tests": [
{ "name": "found-and-missing#1", "tier": "expect", "mode": "sandboxed", "origin": "spec", "result": "pass" },
{ "name": "found-and-missing#2", "tier": "expect", "mode": "sandboxed", "origin": "spec", "result": "pass" },
{ "name": "real-read#1", "tier": "cram", "mode": "real", "origin": "spec", "result": "pass" }
],
"oracles": [],
"accepted": true
}