tricu

A lazy functional language based on Tree Calculus
Log | Files | Refs | README | LICENSE

build-and-run.md (12105B)


Build and run

Run these commands from the extracted tricu directory. You need Nix with flakes enabled. Native development uses the Haskell host; builds and tests run through Nix. The native Haskell C interface provides embedding through C, Python, native JavaScript, and PHP. An opt-in archive-linked full host incorporates PIC Haskell archives into one shared object on x86-64 Linux: nix build .#tricu-haskell-ffi-archive --no-link. Both linkage variants expose reduction, bundle loading and IO and require their native Nix runtime closures. An opt-in Nix-free transfer prototype packages native dependencies with relative loader paths and tests execution with /nix/store absent. The compiler rebuilding guide covers CLI/shared-library execution checks and compiler acceptance.

Build the host

nix build .#
result/bin/tricu --help

The host evaluates trees and provides IO. The source compiler is a separate, compiled tricu program, included at bootstrap/build-stable.arboricx.

The executable automatically selects that packaged stable compiler. It locates its installed data independently of the caller's working directory, authenticates the bundle, and imports it indexed into the selected store. Missing or corrupt package data terminates compilation with an error.

The compiler's bytes and source provenance are recorded in bootstrap/stable-compiler.json. python3 test/shipped_compiler.py verifies the bundle against its recorded snapshots and published executable tree.

Run a program

Create a UTF-8 source file. Strings and comments support Unicode; identifiers remain ASCII. Malformed UTF-8 and an initial BOM are rejected. See source characters.

WORK=$(mktemp -d)
cat > "$WORK/hello.tri" <<'EOF'
!export main

first [value | _] = value
first _ = 0

main = first [42 7]
EOF

result/bin/tricu eval "$WORK/hello.tri" \
  --store "$WORK/application" --format number
# 42

--store holds application objects, build records, and the automatically imported compiler. The selected stable compiler supports the current language features.

The module exports main, which eval selects. first matches equations in order: a nonempty list returns its first value; the fallback returns zero. --format number tells the host how to display the resulting tree.

Package a program

Compile the same module into a self-contained bundle:

result/bin/tricu arboricx compile --file "$WORK/hello.tri" \
  --store "$WORK/application" --output "$WORK/hello.arboricx"

result/bin/tricu arboricx import \
  --file "$WORK/hello.arboricx" --store "$WORK/runtime"

Set APP_MANIFEST to the full manifest hash printed by this import, then run:

APP_MANIFEST=PASTE_THE_MANIFEST_HASH_HERE
result/bin/tricu arboricx run --module "$APP_MANIFEST" --name main \
  --store "$WORK/runtime" --format number
# 42

This last command executes the stored program. Bundle import defaults to indexed storage, preserving shared branches. Importing native library dependencies is a different operation; see modules and the artifact checks before choosing flat storage.

For IO programs, select --io. Current runtimes execute IO with OS process authority and reject v1 permission-grant arguments. Use trusted store directories; path confinement requires external isolation. See the structured IO contract and execution options.

WORK is temporary and contains all objects created by this example. Keep it if you want to reuse them, or remove it when finished.

For exact-version registry publication and dependency fetching, see Packages. For a whole application dependency set, use a project declaration and consolidated lock; resolve/update, fetch, bind and check remain separate from compilation. Offline explain and diff reports show selected dependencies, local evidence and structural changes without running exported programs.

Deploy the Arboricx registry (Linux)

The arboricxServer flake output builds the image arboricx-server:latest. It compiles tricu-apps/arboricxServer.tri directly using the repository tricu.workspace source locations and packaged stable compiler at build time. Startup runs the compiled manifest directly from a read-only Nix store. Compilation and workspace resolution finish during the image build; registry storage holds runtime data.

nix build .#arboricxServerTest --no-link
nix build .#arboricxServer -o result-server

docker load < result-server
mkdir -p registry-store
docker run -d --name arboricx-registry --restart unless-stopped \
  --user "$(id -u):$(id -g)" --read-only \
  --cap-drop ALL --security-opt no-new-privileges \
  -p 127.0.0.1:8080:8080 \
  --mount "type=bind,src=$PWD/registry-store,dst=/app/store" \
  arboricx-server:latest
curl --fail http://127.0.0.1:8080/_arboricx/health

The process listens on 0.0.0.0:8080 inside the container. The example publishes only host loopback; put a protected reverse proxy in front of it for remote access. The bind mount must be writable by the selected UID/GID. Preserve and back up registry-store across replacements; do not mount over /nix/store. The default runner uses IO with OS process authority. Each connection owns its socket and upload resources; admission waits for the oldest child at a window of 16 connections. A stalled oldest connection can delay later requests, including health checks. Uploads process bounded chunks. Bundle downloads authenticate into anonymous disk snapshots and transfer native byte chunks; package metadata still uses whole-value reads. Each active snapshot uses at most the configured artifact byte limit in temporary disk space under store/tmp. Provision that filesystem for the admission window, including slow clients holding verified snapshots. Storage initialization and socket bind/listen failures exit nonzero. Monitor the HTTP health endpoint externally.

Endpoints include the landing page, GET /_arboricx/health, POST /_arboricx/bundle (201 with a SHA-256 hash), GET /_arboricx/bundle/hash/HASH, and GET /_arboricx/package/NAME/VERSION. Package indexes are read-only over HTTP; use administrative publication to populate them in the mounted root. Uploads store opaque bytes: hashing is not bundle validation or authorization.

Deployment requirements: this research registry requires an external layer for authentication, TLS, quotas and request deadlines. Protect uploads at the proxy and apply connection/time/rate and storage limits. The current HTTP parser caps headers at 64 KiB and bodies at 1 MiB. The runner uses one Haskell capability and a 2 GiB managed-heap limit. Set container resource limits for total process memory appropriate to the workload. Retain the previous image and a storage backup for rollback.

For native operation, build .#arboricxServerRunner and run result/bin/arboricx-server from a writable directory; it uses ./store and the same fixed port. .#arboricxServerBundle exposes server.arboricx, manifest, and the indexed runtime store. The opt-in arboricxServerTest exercises the actual runner: startup failures, health, binary uploads/downloads, invalid paths, package lookup, and persistence across restart. It also checks failed logging after publication, fragmented uploads, early EOF and cleanup, FIFO admission, and repeated 64-KiB/1-MiB upload/download workloads. Reports under retention/ record allocation, GC-sampled live heap and RSS; upload and bundle-download guards are 128 MiB RSS and 16 MiB live heap. compiler-download.json measures first-byte and total latency for the actual site compiler, including concurrent requests, corruption, HEAD and client disconnects. The checks run the native entrypoint directly. Container-engine integration requires a separate check.

Embed an installed Python application

The file-integrity application packages a compiled tricu worker with a Python CLI. It streams files through IO, records and verifies JSON manifests, and reuses a loaded worker for sequential API calls. Runtime needs neither compiler data nor source lookup.

nix build .#tricu-filecheck .#tricu-filecheck-test --no-link

Explore workflow values

The workflow laboratory defines one static pipeline in tricu, explains it, structurally inserts approval, and interprets it through a Python host with explicit local artifact authority.

nix build .#tricu-workflow-demo .#tricu-workflow-demo-test --no-link

Explicit compiler selection

For development or a pinned alternate compiler, import a caller-selected bundle:

result/bin/tricu arboricx import --file bootstrap/build-stable.arboricx \
  --store "$WORK/tools" --indexed
COMPILER_MANIFEST=PASTE_THE_FULL_MANIFEST_HASH_HERE
result/bin/tricu eval "$WORK/hello.tri" --store "$WORK/application" \
  --toolchain "$COMPILER_MANIFEST" --tool-store "$WORK/tools" --format number

Use the manifest hash printed on the last import line, not a mutable alias or individual export hash. --tool-store requires --toolchain and otherwise defaults to the application store. An explicit selection never falls back to package data. The packaged compiler and execution default use IO with OS process authority. A retained v1 compiler must run with its matching retained v1 runtime; the current host rejects --toolchain-io-version 1. No failure-based protocol fallback is performed.

For retained source/compiler/dependency inputs and an independent offline replay, see provenance capture, verify and rebuild.

Interactive use

Run result/bin/tricu (or result/bin/tricu repl) for a portable session. Definitions and expressions use the same compiler as files. Use !help for multiline blocks, imports, loading files, and session operations; see interactive semantics.

Where next

Historical registry runners

The v1 handler, chunked-upload and body-probe runner outputs are retired from current Nix packages. Their source and executable evidence belong to the frozen rollback toolchains. Use the default IO runner and its acceptance gate above. The explicit arboricxStreamingRunner and arboricxStreamingTest outputs exercise the same supported composition and gates under their descriptive names.

The current tests retain startup, restart, binary/path/package, malformed framing, early-EOF cleanup, FIFO admission, and failed-logging-after-publication controls. Paths resolve under OS process authority, including symlink traversal. An object can remain published after logging fails. See body retention measurements for upload/download regression guards and measurement limits.