Plan 04 — the pure-core prelude
References: design §5 (the prelude as a trusted corpus), §3.5 (capabilities), examples/read_file.tr.
Goal
The first Trellis code: the pure core prelude, written as .tr specs and
agent-lowered through the real daemon pipeline, human-reviewed to
accepted. It is simultaneously the stdlib, the few-shot corpus that
defines the agent’s Soil style, and the first honest test of the whole
loop. Interpreted on soil0; small (a few thousand lines of Soil).
Scope
read_filefirst (design §5): capabilities, effects,Result, and the runtime boundary in one definition. Promoteexamples/read_file.trinto the real prelude root and lower it for real; reconcile any drift back intoexamples/.- Core types and functions, roughly in dependency order:
Bool(with its JSON special case),Option,Result,List(map, filter, fold, len, nth, append, reverse, sort_by…),Utf8(split, trim, parse-number…),Bytes,BigInt,Mapwith explicit comparator (theMap.Make-as-function idiom, design §3.6), JSON encode/decode surface (thin wrappers over the runtime). The list primitives (list_len,list_nth,list_empty,list_append, …) are native-backed prelude definitions like the fakes — Soil has no list literals or patterns, so nothing list-shaped is writable without them — with names frozen indocs/contracts/soil0-cli.md(impl plan 02 §8.7, resolved 2026-08-22); the rest of theListfunctions are written in Soil on top of them. - Capabilities and fakes. The capability types (
Fs,Net,Clock,Env,Proc,Rand) as opaque types with theirWorldderivations, and the fake constructors with pinned seeds/timestamps — signatures in Trellis, backed bysoil0/soil-rtnative primitives. - Corpus duty. Every lowering is reviewed as a style exemplar, not
just for correctness: idiomatic match shapes, naming, use of local
lets vs private helpers. Style disagreements are settled by PR-style review with the user and become the corpus. - Trust and packaging. The prelude is a Soil root with
soil.toml; on completion, pin its package hash as trusted (design §5); all exported definitionsacceptedandpinned. - Kernel reconciliation (deferred here from the soil0 CLI review,
2026-08-22).
docs/contracts/soil0-cli.md§6.1 and §11 pin provisional prelude surface: the kernel type shapes (FsError,Utf8Error,Path), the builtin names and signatures (clock_now : Clock -> io I64vs design §3.5’s sketchednow : Clock -> io Time; the list primitives;unit;T::compare : T -> T -> I64returning −1/0/1 vs anOrderingsum; the fake constructors and their determinism guarantees). The prelude’s first.trspecs must adopt these exactly, or revise them with the user and update the contract — before the corpus teaches them.
Adoptions (2026-08-23, agentlanguages survey)
- Hostile capability fakes (design §4.5): failing fakes — an
Fsthat errors mid-stream, a backwards-jumpingClock— are ordinary prelude values in the capability modules from the start. - TrellisBench before the corpus grows (design §10): even ~10 spec+tests problems wired through the real daemon per release, so prelude/corpus changes are measured, not vibed. Stand it up at this plan’s kickoff.
The totality problem (known, planned for)
soil0 has no termination checker, so every recursive prelude function
conservatively carries div — but the prelude’s signatures claim
total, and those claims matter for the corpus and for callers. Interim
policy (confirm with user at kickoff): the .tr signatures state the
intended row; the daemon records a per-definition div-unverified flag in
the lock (like a demoted refinement) rather than widening signatures; the
stage-2 termination checker (plan 05) later discharges them in bulk. This
mirrors the demotion philosophy: unproven, visible, tests still gate.
Non-goals
Batteries layers (soil-rs-std, soil-py-std — plan 06), Py
capability, retrieval (whole prelude fits in context), performance.
Testing
- Every definition: expect tests + properties per the effect-row budget
(pure functions fuzzed hard); capability functions get fake-capability
tests;
read_filekeeps its real-mode cram test. - Cross-cutting properties:
sort_bystability and order laws,parse ∘ showidentity on prelude types, Map comparator-order invariants. - Differential where cheap: CLI oracles against Python equivalents
(
statistics,strmethods) for the numeric/string corners.
Exit criteria
- Every exported definition
accepted,pinned, tests green, package hash pinned insoil.toml. - The corpus test: a fresh lowering of a new small function, given the prelude as examples, produces Soil the user judges idiomatic without style corrections.
examples/and the real prelude agree wherever they overlap.
Decision points — resolved 2026-08-22
- Totality gap: signatures claim the intended row; the lock records
checks.termination: "unverified"(mirroring refinement demotion — unproven, visible, tests still gate); soilc’s termination checker (plan 05) discharges the flags in bulk. Recorded in docs/lock-schema.md §4. - Location: in this repo, as a
prelude/Soil root; extraction into its own forkable repo waits for a second user. - Inventory: a concrete reviewed list before lowering begins
(
read_file+ the §5 core types with ~6–12 functions each), then additions strictly by consumer need — the corpus stays curated.