aldos operator's manual

ortfero

introduction

aldos is the operating system of the aldan machine. it is intended for single-seat operation: one installation, served by one operator, with a single console as the only point of interaction.

this manual is addressed to the operator. the role is to be distinguished from that of the user. a user invokes a program and, when the program has completed, has no further duty toward the system. the operator is permanently responsible for the condition of the machine. the operator determines which programs are present on the disk, which modules are made available at boot, and the state in which the system is left between sessions. when the disk fills, the operator reclaims it. when a program fails to load, the operator identifies the cause.

aldos provides no facility for remote administration. no other party may be called upon to maintain, repair, or audit the installation. every byte stored on the disk is the consequence of an action taken by the operator or of the execution of a program selected by the operator. the operator is expected to acknowledge this condition before assuming the role.

the operator is accountable for every byte on the disk.

how the system works

aldos is built from a small number of moving parts. the operator should learn each before the prompt is useful.

the system is built in layers, each with its own region of the machine's memory. lowest is the firmware in the boot rom. it brings the machine up, loads the resident binary, and owns every hardware driver — the screen and its cursor, the keyboard, the disk, the host filesystem, the sound device, the network, the clock — which it offers to the layers above through a single call table it publishes in memory at boot. above the firmware sits almac, the resident binary and the only one there is: the language, its compiler, and the prompt. above almac comes aldos itself — the operating-system services, written in almac and loaded from the disk like anything else. above those the core library, and at the top the applications the operator runs.

there is no separate kernel image and no system-call interface. aldos is a set of modules — the task manager, the memory manager, the volume manager, the filesystem, the service manager — and a program reaches one by importing it, exactly as it reaches core/tty or a module of the operator's own. every one of them touches the hardware only through the firmware's call table, and no driver is written twice.

a fiber is a single thread of execution, and the scheduler is cooperative: a fiber runs until it yields, waits on a device, or returns, and nothing takes the processor away from it. the prompt is a fiber like any other, which is why a program written to run forever holds the console for as long as it runs — unless it is started as a service.

a service is named background work: a fiber the system keeps running after the call that started it has returned. the operator lists them with services, ends one with stop, and reads what they have printed with journal. a service has no screen — the console belongs to whatever is in the foreground — so its output goes to the journal under its own name instead.

a hundred times a second the machine takes a timer interrupt. the tick switches no fibers; it drives the work that must go on whatever the foreground is doing — the sound mixdown, the device probes that wake a fiber whose disk transfer or datagram has arrived, and the deadlines that rouse a sleeping one, a service running on a period among them.

modules are units of almac code kept on the disk. nothing is linked in advance; almac compiles a module the first time it is named in an import and keeps it in its working image until the session ends or reset is called. the core modules — the clock, the screen, the heap, files, directories, and the rest — are named the same way. a module may define a setup and a teardown, which the system runs as the module is loaded and as it is given up.

the console is the operator's only window into the running system. it is a text grid and a keyboard, provided by the machine firmware. there is no second screen and no log file the operator must tail. a program that wants pictures rather than text builds a list of drawing commands, hands it to the display processor, and holds the screen until it gives it back.

files and volumes are how the disk is organised. a volume is a mounted unit of storage; each volume sits on a letter drive. files live in directories within a volume. there is no shared root above the drives, and there are two drives with no provision for a third.

the operator should keep one distinction in mind. everything runs in one address space: the aldos modules, the core library, the operator's own definitions and every program are all modules of the one almac image, and nothing isolates one from another. a program that writes where it should not can therefore damage anything, and what stands between the operator and that is the language rather than the machine. one thing is caught: a hardware fault raised by a line typed at the prompt returns the operator to the prompt with a diagnostic. the same fault in a service or any other fiber is not recovered, and stops the machine.

the console

command line

the console runs the almac shell. the prompt is a greater-than sign followed by a space:

>

when a line of input is not yet complete, for example an unclosed compound or an unfinished expression, the shell continues the line with a period and a space:

> fn greet () {
.   tty.say "hello";
. }

whatever the operator types at the prompt is almac source. there are no separate shell commands in the unix sense. the resident commands listed later in this manual are ordinary functions, defined by the standing start-up script, which need no import.

most of the apps on the disk are imported by that same script and bound to a bare name, so they too are called without an import:

> jot '/a/notes/today

what the script does not import, the operator imports by hand and calls through the module's own name:

> import '/a/modules/math/sieve
> sieve.bench

a line the translator refuses is reported and dropped; the report names the module and the line within it, then the reason:

> cd 'nowhere
[repl:1] unknown symbol

editing

backspace deletes the character to the left of the cursor. enter submits the line. tab inserts two spaces; the shell does not align to a tab stop. a single input line holds up to two hundred and fifty-six characters. a multi-line entry, that is text typed across continuation prompts, holds up to four thousand and ninety-six characters in total. when either limit is reached the shell refuses further input on that entry; the operator must submit or abandon what is already typed.

sessions

a complete short session, from prompt to prompt:

> cd '/a
> mkdir 'notes
> touch 'notes/today.moff
> jot 'notes/today.moff
... editor takes the screen, operator edits, ctrl-s saves, ctrl-q exits
> ls
almac.bin
rc.alm
rc/
core/
aldos/
modules/
codex/
notes/
>

the startup script

when the shell begins, after the boot sequence has completed and before the first prompt is issued, it looks for the file /a/rc.alm. if the file is present, the shell evaluates it as almac source in the global namespace. if it is absent, the shell proceeds directly to the prompt.

rc.alm is the operator's point of customisation. the operator places in it any imports that should be in effect at the prompt without typing them by hand, and any functions that the operator wishes to call without first loading a module. anything defined in rc.alm is visible at the prompt thereafter, exactly as if the operator had typed it at the first prompt.

a short example. an operator who reads the system log daily might keep:

import 'core/storage, 'core/bytes, 'core/resource,
  '/a/modules/text/leaf

fn log () raises storage.fault | bytes.fault | resource.fault {
  leaf.at '/a/notes/log.moff;
}

after boot, the operator types log at the prompt and the pager opens on the log file. a zero-argument call needs no parentheses; the shell calls log automatically because the prompt expects a value, not a function.

rc.alm is itself a text file and is edited with jot. an installation that does not require any customisation may omit the file entirely; the shell will not complain about its absence.

files, volumes and devices

paths take the form of a slash, a drive letter, a slash, and the path within the drive. forward slash separates directory components. a single dot refers to the current directory; two dots refer to the parent. a path that does not begin with a slash is taken as relative to the working directory.

drive a is the boot volume. it holds the resident binary /a/almac.bin, the start-up script /a/rc.alm and the module it draws its commands from in /a/rc, the core library in /a/core, the operating-system modules in /a/aldos, and the applications in /a/modules, one directory to a sort — text, graphics, sound, games, demos, math, net, compression and system. the documents this manual belongs to are in /a/codex, and the sample pictures, tunes and recordings in /a/pixels, /a/fotos, /a/plots, /a/songs and /a/music. whatever else is on the disk the operator put there. drive a is read-write.

drive b is a passthrough to a single directory on the machine that hosts aldan. it is mounted at every boot; there is no configuration that removes it, and no installation on which it is absent. what varies is whether the directory behind it exists, not whether the drive is there.

the directory drive b passes through is the one named aldan in the home directory of the account that started the machine: /home/ortfero/aldan on a unix host, c:\users\ortfero\aldan on a windows host. nothing above that directory is reachable from the machine; a path that climbs out of it is refused. a windows host creates the directory at start if it is absent; on every other host the operator creates it. when the directory does not exist, drive b still mounts, but every listing and every open on it fails as not found.

drive b is read-write. a file written there lands in the host's own filesystem, outside the boot volume, and is not undone by powering the machine down.

the two drives differ in one way the operator will meet. on drive a, creating a file that already exists truncates it and reuses the name; on drive b it is refused as already existing. so a command that writes its result to a fixed name — cp onto an existing file, compress over a .lz it made before — succeeds on the boot volume and fails on the host directory until the old file is removed.

devices are referred to by role, not by port. the operator names the keyboard, the display, the disk, the sound channel or the network; the firmware's call table resolves the name. there are no port numbers, no interrupt vectors, and no device addresses for the operator to learn.

there is no disk task. a read or a write is submitted to the device and the calling fiber is put to sleep on it; the timer tick probes the device and wakes the fiber when the transfer has completed, so the rest of the system stays live meanwhile. transfers are serialised in the order they were submitted, and two writes issued in quick succession are never interleaved.

the network is a datagram device: a program opens a socket, sends and receives, and closes it. a receive with nothing waiting parks the calling fiber the way a disk transfer does, and the same tick wakes it when a datagram arrives. sending promises nothing — this is udp — and a failed send is reported as a fault rather than retried.

booting

booting is the sequence from power-on to the first prompt. the operator's role begins at the moment the machine is powered; the firmware needs no input and the operator may not interrupt it.

a successful boot prints nothing until the start-up script runs. the console stays as the firmware cleared it, and the first thing written to it is whatever rc.alm chooses to say — in the shipped script, two lines of heap figures — followed by the prompt. anything printed before that is a diagnostic and names the step that failed.

if the boot does not reach the prompt, the operator should read the console. a failure to load the resident binary is reported by the firmware; a failure inside the start-up script is reported by almac in the form of a module name, a line number and a reason, and the shell goes on to the prompt with whatever the script defined before the bad line. the operator should suspect, in order: a corrupt or missing file at the named step, a damaged merefs volume, and a hardware fault.

programs

a program in aldos is a module, and a module is a text file with the extension .alm. there is no executable format and no loader: the machine carries one binary, the resident almac, and everything else is source compiled on demand. importing a module compiles it into the running image and binds its public names; the compiled code stays there for the rest of the session.

a module has two sections. the first declares what it exports — types, constants, and function signatures — and the second defines them. a program that means to be called from the prompt exports one entry function, and the operator calls it as module.entry, or by the bare name the start-up script binds it to.

two names in a module are special, and neither is declared. setup, if the module defines it, runs once the module has been loaded, after everything it imports is up. teardown runs when the image gives the module up — at reset, and when a compile that imported it fails and is rolled back — and modules are torn down in the reverse of the order they were loaded. a module that takes something over from the machine does it in setup and hands it back in teardown; the task manager, which takes the scheduler slots, is the case they were built for.

nothing reclaims a module while the session lasts. an operator who has imported a great deal, or who has just watched a program misbehave, gets the boot image back with reset.

command reference

each entry in this section follows the same form: name, synopsis, description, options, examples, and notes. a field that does not apply is written with the value "none". the commands are grouped in two parts. resident commands are the shell's own, defined by the standing start-up script and callable at once. applications are modules that live on the disk; the script imports most of them too and binds each to a bare name, so those are called the same way, and the entry a name stands for is given in its notes. an application the script does not import is marked as such, and the operator imports it by hand before calling it.

resident commands.

import

name: import.

synopsis: import 'name. import 'name, 'name, ...

description: import a module from the disk. the operator gives the path to the module's source file, without the .alm extension; the shell compiles the module on demand and keeps it for the session. several modules may be imported with a single import.

options: none.

examples:

> import '/a/modules/text/jot
> import '/a/modules/text/leaf, '/a/modules/games/snake

notes: a module that is already imported is not imported again. an import that names a module the shell cannot find raises a fault and the line is rejected.

reset

name: reset.

synopsis: reset.

description: return the shell to the state it had at boot. every loaded module is given up, in the reverse of the order it was loaded, each one first running its teardown: the services stop and the kernel hands the firmware call table back. the shell then discards everything it holds — modules, definitions, imports — rebuilds itself, and evaluates /a/rc.alm again, so the standing applications and the shell commands return as they were at boot.

options: none.

examples:

> reset

notes: the command is deferred: it takes effect once the line that called it has finished, never in the middle of it. anything the operator defined or imported at the prompt is gone afterwards; anything named in /a/rc.alm comes back. work held on disk is untouched. a running service is stopped, not asked — an operator who wants a service to finish cleanly should stop it first.

tty.say

name: tty.say.

synopsis: tty.say expression { "," expression }.

description: write each expression to the console; a newline is appended after the last. several values may be passed in one call. say belongs to the tty module, which the default rc.alm imports, so it is available at the prompt as tty.say with no further import.

options: none.

examples:

> tty.say "hello"
hello
> tty.say (1 + 2)
3
> tty.say "x = ", 42
x = 42

notes: none.

tty.sayin

name: tty.sayin.

synopsis: tty.sayin expression { "," expression }.

description: write each expression to the console with no trailing newline. used when the operator wishes to build a single line of output from several calls. like tty.say, it comes from the tty module imported by the default rc.alm.

options: none.

examples:

> tty.sayin "x = "
> tty.say 42
x = 42

notes: none.

clear

name: clear.

synopsis: clear.

description: clear the screen and return the cursor to the top-left corner.

options: none.

examples:

> clear

notes: clear is defined in the default rc.alm.

date

name: date.

synopsis: date.

description: write the current date and time to the console, in the form yyyy-mm-dd hh:mm:ss.

options: none.

examples:

> date
2026-06-16 14:30:00

notes: date is defined in the default rc.alm.

calendar

name: calendar.

synopsis: calendar.

description: write the previous month, the current month and the next one side by side, three columns across the console, with the current day marked. weeks run from sunday.

options: none.

examples:

> calendar
       july 2026            august 2026         september 2026
su mo tu we th fr sa   su mo tu we th fr sa   su mo tu we th fr sa
...

notes: calendar reads the machine's clock, so it shows whatever date the host is keeping.

ls

name: ls.

synopsis: ls.

description: list the entries in the current working directory. each entry is written on its own line.

options: none.

examples:

> ls
almac.bin
rc.alm
rc/
core/
aldos/
modules/
codex/

notes: a directory is written with a trailing slash, a file without one. ls lists the current working directory only and takes no argument; to list another, the operator uses lsd.

lsd

name: lsd.

synopsis: lsd 'path.

description: list the entries of the directory at the named path, one to a line, without changing the working directory. ls is this command called on the current directory.

options: none.

examples:

> lsd '/a/modules/text
jot.alm
leaf.alm

notes: a directory is written with a trailing slash. the path may be absolute or relative to the working directory.

cd

name: cd.

synopsis: cd 'path.

description: change the working directory to the named path. returns the new working directory as a string.

options: none.

examples:

> cd '/a/notes
/a/notes
> cd '..
/a

notes: there is no resident pwd command. to read the current working directory without changing it, the operator may call cd with '. as the argument; the return value is the working directory.

mkdir

name: mkdir.

synopsis: mkdir 'path.

description: create a new directory at the named path. the parent of the new directory must exist.

options: none.

examples:

> mkdir '/a/notes

notes: mkdir creates a single directory. to create a chain of directories, the operator calls mkdir on each in turn.

rmdir

name: rmdir.

synopsis: rmdir 'path.

description: remove the named directory. the directory must be empty.

options: none.

examples:

> rmdir '/a/notes

notes: rmdir will not remove a directory that contains files or sub-directories. the operator should rm the contents first.

touch

name: touch.

synopsis: touch 'path.

description: if the named file does not exist, create it as an empty file. if it does exist, touch does nothing at all: the file is left as it stands, contents and all.

options: none.

examples:

> touch '/a/notes/today

notes: touch does not create the parent directory. the machine keeps no modification time a touch could bring forward, so this command is only ever a way of making an empty file.

rm

name: rm.

synopsis: rm 'path.

description: remove the named file.

options: none.

examples:

> rm '/a/notes/old

notes: rm removes a single file and does not remove directories. there is no confirmation prompt and there is no recovery.

cat

name: cat.

synopsis: cat 'path.

description: write the contents of the named file to the console.

options: none.

examples:

> cat '/a/notes/today
buy bread.
fix the disk light.

notes: cat is intended for short text files. for a longer file the operator should use leaf.

cp

name: cp.

synopsis: cp 'source, 'destination.

description: copy the source file to the destination. when the destination names an existing directory, the source's own final component is joined onto it and the copy lands inside; otherwise the destination is taken as the literal path of the new file.

options: none.

examples:

> cp '/a/notes/today, '/a/notes/yesterday
> cp '/a/notes/today, '/b

notes: cp copies a single file. the destination's parent directory must exist. an existing destination file is overwritten on drive a and refused on drive b, as described under files, volumes and devices.

mv

name: mv.

synopsis: mv 'source, 'destination.

description: move or rename the source file to the destination. used to rename a file within a directory and to move a file from one directory to another.

options: none.

examples:

> mv '/a/notes/old, '/a/archive/old

notes: mv operates on a single file. the destination's parent directory must exist.

fsck

name: fsck.

synopsis: fsck.

description: check the boot volume and reclaim what nothing refers to. the filesystem's write path is ordered so that the only damage a crash can leave is space marked used and referred to by no directory entry; fsck rebuilds both allocation maps from the directory tree and gives that space back. no file is ever lost or moved by it.

options: none.

examples:

> fsck

notes: fsck is a program like any other rather than part of the filesystem, and it works on drive a only. it is worth running after an abrupt power-off; there is no need to run it otherwise.

services

name: services.

synopsis: services.

description: list the background services now running, one name to a line. when none is running, it says so.

options: none.

examples:

> services
no services

notes: a name identifies a service and only one service may hold it, so this listing is also the answer to whether a given name is free. nothing on the shipped disk starts a service: a service is something a program launches for itself through core/service, and until the operator runs such a program this listing stays empty.

stop

name: stop.

synopsis: stop 'name.

description: stop the named service. the service is asked first: it sees the request at the next point it looks, and is given a moment to leave on its own, which lets its cleanup run and its files close. one that does not take the moment is struck off.

options: none.

examples:

> services
  watcher
> stop 'watcher

notes: a service that returns from its own work function unwinds properly; one struck off mid-wait does not. an operator who wants a service to finish cleanly should stop it and let it, rather than resetting the shell out from under it.

restart

name: restart.

synopsis: restart 'name.

description: stop the named service and start it again on a fresh fiber, with the work, the cleanup and the period it was launched with. this is the only sanctioned way to get a new instance of a name.

options: none.

examples:

> restart 'watcher

notes: the service must be running. a stopped one has left nothing to rebuild from and must be started again by whatever started it first.

journal

name: journal.

synopsis: journal.

description: print what the services have been saying. a service has no screen — the console belongs to the foreground — so everything it writes goes into a ring of text off to one side, each line headed by the service's own name, together with the started and stopped lines the system writes itself. journal prints the ring.

options: none.

examples:

> journal
watcher: started
watcher: 3 files changed

notes: the ring holds a fixed number of bytes; when it is full the oldest whole line goes, never a fragment. lines lost that way are counted, and the count is printed before the text, so a gap in the record is always visible as a gap.

memory

name: memory.

synopsis: memory.

description: report what the operating pool is doing: its total and free size, the number of live blocks, what has been asked for against what has actually been reserved, and the difference between them — the page tails that rounding leaves unusable. the live figures are this instant; the boot figures cover every block claimed since the machine came up.

options: none.

examples:

> memory
pool total    : 3712kb
pool free     : 2860kb
live blocks   : 34
...

notes: a claim of sixteen kilobytes or less is carved out of a shared page region and costs close to what it asks for; a larger one is rounded up to whole pages, and it is that rounding the waste figures measure.

halt

name: halt.

synopsis: halt.

description: power the machine off. nothing is asked and nothing is saved; work not already written to the disk is lost.

options: none.

examples:

> halt

notes: services are not stopped first and no teardown runs. an operator who wants a clean shutdown stops the services and leaves the editors before calling it.

reboot

name: reboot.

synopsis: reboot.

description: restart the machine from the reset vector, exactly as a power cycle would. the firmware runs again, the resident binary is loaded again, and rc.alm is evaluated again.

options: none.

examples:

> reboot

notes: reset is the cheaper instrument and is usually the one wanted: it rebuilds the shell without going back through the firmware. reboot is for when the machine itself is in a state the operator does not trust.

help

name: help.

synopsis: help.

description: print the list of shell commands and applications, each with its arguments and a line of description, followed by a note on how string arguments are written.

options: none.

examples:

> help
commands:
  clear                 clear the screen
  date                  print the current date and time
...

notes: the listing is written out by hand in the start-up script's command module rather than derived from what is bound, so an operator who adds a command of their own adds it there too if it is to appear.

applications.

jot

name: jot.

synopsis: jot 'path.

description: a full-screen text editor. jot takes the console, loads the named file into a buffer, and lets the operator move the cursor with the arrow keys and edit the buffer in place. ctrl-s writes the buffer to the file. ctrl-q exits and returns the console to the shell.

options: none.

examples:

> jot '/a/notes/today
... editor takes the screen, operator edits, ctrl-s saves, ctrl-q exits
>

notes: jot is jot.in of /a/modules/text/jot, bound by the start-up script. jot edits in memory: no change is written to the disk until the operator presses ctrl-s, and an operator who quits with ctrl-q before saving loses every change made since the last save.

leaf

name: leaf.

synopsis: leaf 'path.

description: a pager for reading a file too long to cat. leaf takes the console, displays the first page of the file, and lets the operator scroll. the arrow keys scroll one line at a time; page-up and page-down scroll half a page. ctrl-q exits.

options: none.

examples:

> leaf '/a/codex/aldos_operators_manual.moff
... file fills the screen, operator scrolls, ctrl-q exits
>

notes: leaf is leaf.at of /a/modules/text/leaf, bound by the start-up script. leaf is read-only: the operator may scroll but cannot edit. to edit a file, use jot.

snake

name: snake.

synopsis: snake.

description: a game. a snake moves across the screen, lengthening when it eats and ending when it strikes a wall or itself. the arrow keys steer. ctrl-q exits.

options: none.

examples:

> snake
... game runs, operator steers, ctrl-q exits
>

notes: snake is snake.play of /a/modules/games/snake, bound by the start-up script. the score is shown at the top of the screen and is not preserved between runs.

sieve

name: sieve.

synopsis: sieve.bench. sieve.print n.

description: a processor benchmark and a prime number stream. sieve.bench drains the sieve of eratosthenes over and over for a fixed window, counts the instructions the processor actually retired while it did so, and returns the best rate it reached in whole millions of instructions a second. the value is printed at the prompt. sieve.print n prints the primes not exceeding n. programs may drain the same stream themselves: sieve.create sets a sieve.stream record up, sieve.next hands out one prime at a time until it returns false, and sieve.dispose disposes the stream.

options: none.

examples:

> import '/a/modules/math/sieve
> sieve.bench
... the benchmark runs for about a second
10
> sieve.print 30
2 3 5 7 11 13 17 19 23 29

notes: the start-up script does not import sieve; the operator imports it. the count is read from the processor's own retired-instruction counter, so the figure is a property of the machine rather than of this program, and two benchmarks that agree on it are measuring the same thing. the stream sieves into a claimed flag store covering numbers up to 100000, the greatest n it accepts; asking past that raises a contract failure.

golife

name: golife.

synopsis: golife.play.

description: a demonstration of conway's game of life. golife takes the console and evolves a grid of cells one generation at a time. space pauses and resumes, r reseeds the grid at random, and ctrl-q exits. the generation and population counts are shown above the grid.

options: none.

examples:

> import '/a/modules/demos/golife
> golife.play
... the grid evolves, operator watches, ctrl-q exits
>

notes: the start-up script does not import golife; the operator imports it.

glance

name: glance.

synopsis: glance 'path.

description: a viewer for pixl images, the machine's lossless raster format. glance takes the console, reads the file, and draws it on the screen with the blit display-list command, one byte per pixel through the aurora system palette. an image smaller than the 720x480 screen is centred. ctrl-q exits and gives the console back.

options: none.

examples:

> glance '/a/pixels/kandinsky/several_circles.pixl
... the image fills the screen, ctrl-q exits
>

notes: an image larger than the screen is refused, since the display processor neither scales nor clips a blit. a file carrying its own palette is shown in it — the processor takes a palette window, and glance points it at the chunk inside the file. entries the file does not supply keep their system-palette colors, and leaving the viewer puts the console's palette back. glance is glance.at of /a/modules/graphics/glance, bound by the start-up script. a pixl body is already laid out the way the display processor wants it, so the file is shown where it lies and never copied into a second plane — which is what lets a full-screen picture be shown at all.

gaze

name: gaze.

synopsis: gaze 'path.

description: a viewer for foto images, the machine's lossy raster format. gaze reads the file, decodes it back to one palette index per pixel, and draws it with the blit display-list command. an image smaller than the 720x480 screen is centred; ctrl-q exits.

options: none.

examples:

> gaze '/a/fotos/kandinsky/several_circles.foto
... the image fills the screen, ctrl-q exits
>

notes: gaze is gaze.at of /a/modules/graphics/gaze, bound by the start-up script. glance is the same viewer over the lossless format, and the two differ in where the plane comes from: a pixl body already is the plane, while a foto has to be decoded into one. neither scales nor clips, so an image larger than the screen is refused.

plot

name: plot.

synopsis: plot 'path.

description: a viewer for the plot format, which is line art written as text: a pen that moves without drawing and a pen that draws as it moves, one command to a line, in pixels of the 720x480 plane. plot reads the file, turns each line into a display-list command, and holds the screen until q or escape.

options: none.

examples:

> plot '/a/plots/vicsek.plot
... the drawing fills the screen, q exits
>

notes: plot is plot.show of /a/modules/graphics/plot, bound by the start-up script. a picture longer than the display list can hold is drawn as far as it fits and reported as truncated; a file too large to read is refused outright.

galaxy

name: galaxy.

synopsis: galaxy.

description: a demonstration: a percolation model of a spiral galaxy. cells on a set of rotating rings ignite star formation in their neighbours a step later, and because the rings turn at different speeds the fronts are sheared into trailing arms. space pauses and resumes, r reseeds, and q or escape exits.

options: none.

examples:

> galaxy
... the arms wind up, operator watches, q exits
>

notes: galaxy is galaxy.play of /a/modules/demos/galaxy, bound by the start-up script. the picture is a display list of short strokes, one to a lit cell, brightest at the leading edge of a front and fading along its trail.

phono

name: phono.

synopsis: phono 'path.

description: play a recorded sound file in the echo format. phono decodes the file a block at a time and feeds the sound device, pacing itself on how much is still queued, and rewrites a position line under the prompt once a second. the arrow keys seek backwards and forwards; ctrl-q stops.

options: none.

examples:

> phono '/a/music/bach/bwv639.echo
0:12 / 3:24   arrows: seek   ctrl+q: stop

notes: phono is phono.play of /a/modules/sound/phono, bound by the start-up script. echo is a lossy format and the file's own duration is read from its header before playback begins, so the total shows at once. a seek decodes cold from the nearest sync block rather than from the start of the file.

play

name: play.

synopsis: play 'path.

description: play a tune written in the song format — a text file of patch declarations, phrases of note rows, and a chain naming the order they play in. play installs a patch on a track whenever a row calls for a different one, triggers the notes at the file's tempo, and stops at the end of the chain or on ctrl-q.

options: none.

examples:

> play '/a/songs/ode_of_joy.song
... the tune plays, ctrl+q stops
>

notes: play is play.play of /a/modules/sound/play, bound by the start-up script. a song is line-oriented text and may be written and edited with jot; an unknown directive is ignored rather than refused, so a file may carry a title or a source line. two tunes ship on the disk, in /a/songs.

jingle

name: jingle.

synopsis: jingle.

description: play a short phrase written to show what the synth can do: a filtered pulse lead, a saw bass under it, noise percussion, and a pitch slide on the closing note. it returns when the phrase is over.

options: none.

examples:

> jingle

notes: jingle is jingle.play of /a/modules/sound/jingle, bound by the start-up script. rendering hangs off the timer tick rather than off this program, so the phrase keeps time even while other work is running.

compress

name: compress.

synopsis: compress 'path.

description: compress the named file with the lz codec, writing the result beside it under the same name with .lz appended. the original is left alone.

options: none.

examples:

> compress '/a/notes/log.moff
> lsd '/a/notes
log.moff
log.moff.lz

notes: compress is lz.compress of /a/modules/compression/lz, bound by the start-up script. a fault part way through removes the partial output rather than leaving a file that is neither one thing nor the other. on drive b an existing .lz of the same name must be removed first.

decompress

name: decompress.

synopsis: decompress 'path.

description: decompress a .lz file, writing the original back beside it under the name with .lz removed. the .lz file is left alone.

options: none.

examples:

> decompress '/a/notes/log.moff.lz

notes: decompress is lz.decompress of /a/modules/compression/lz, bound by the start-up script. a path that does not end in .lz is refused; so is a file whose contents are not an lz stream this version can read.

pack

name: pack.

synopsis: pack 'dir.

description: archive a whole directory tree into one file, named after the tree with .pack appended. the archive stores bytes and does not compress them; the same tree always gives the same archive.

options: none.

examples:

> pack '/a/notes
> lsd '/a
notes/
notes.pack

notes: an archive is built from a directory in one act and is never edited afterwards. to compress it as well, run compress over the .pack.

unpack

name: unpack.

synopsis: unpack 'path.

description: restore the tree an archive carries, at the directory the archive is named after — dir.pack becomes dir again.

options: none.

examples:

> unpack '/a/notes.pack

notes: unpacking destroys. what stands at the target directory is taken apart first, so what remains afterwards is the archive and nothing else: anything under that directory the archive does not name is gone. the archive is opened before the target is touched, so a file that is not an archive takes nothing with it, and a target that comes out naming a whole drive is refused rather than emptied.

catalog

name: catalog.

synopsis: catalog 'path.

description: list the tree inside an archive without unpacking it, one entry to a line, indented by depth, each file followed by its size.

options: none.

examples:

> catalog '/a/notes.pack
today.moff  1204
old/
  log.moff  8817

notes: nothing is written and nothing is extracted; the archive is only read.

udp

name: udp.

synopsis: udp.echo port. udp.say "host", port, "message".

description: the two smallest network programs there are, meant for finding out whether a machine's network works at all. udp.echo binds the given port and answers every datagram back to whoever sent it, printing each as it arrives; a datagram beginning with "bye" ends it. udp.say opens a socket, ships one datagram to the named address and port, and closes.

options: none.

examples:

> udp.echo 7777
... on the host: echo hi | nc -u 127.0.0.1 7777
> udp.say "127.0.0.1", 9999, "hello"

notes: udp is imported by the start-up script but bound to no bare name, so it is called through the module. the address is written as a dotted quad in quotes and is refused if it is not one, which is what keeps a mistyped address from quietly naming another machine. a receive holds only the fiber that called it — the rest of the system runs on.

fex

name: fex.

synopsis: fex.generate 'dir, 'name, 'intro. fex.identity 'root. fex.publish 'root. fex.inventory 'root. fex.roster 'root. fex.fetch 'root, 'path.

description: the client for fex, by which a member publishes one directory — a capsule — to a relay and reads it back from there a file at a time. generate makes the member's key pair and card; identity prints the fingerprint by which another member checks it; publish sends the capsule up; inventory lists what the relay holds, a path and a size to a line; roster lists who else is registered there; and fetch brings one named file back down.

options: none.

examples:

> fex.generate '/b/fex/keys, 'alice, "family photos"
> fex.identity '/b/fex
> fex.publish '/b/fex
> fex.inventory '/b/fex
> fex.fetch '/b/fex, 'docs/readme.txt

notes: fex is imported by the start-up script but bound to no bare name, so it is called through the module. a member owns exactly one capsule and can read no one else's; every datagram is sealed under a key each side works out on its own from the two cards, so the relay is trusted to hold bytes and nothing more. a relay's own card is made with fex.generate_relay, which takes the address it answers on as a further argument. nothing in this client ever deletes anything. the machine has no source of randomness, so a key made here is only as unguessable as the moment it was made — which is the first thing to replace if these keys are ever to guard something that matters.