on master help sign in
Add burn and new-oxal from brbenji/burn, document installing every app from ~donmec-sallud with shelf.iko.soy as the list, and expand AGENTS.md's routes, checks and fake-ship testing notes
commit83692732f09ca5cf1f228c51a22a6f9c660db9e9 authoriko <ilyakooo0@gmail.com> dateThu 22 Oct 2026, 00:46 (4 days ago) parent0c7b7d7
4 files changed+158−62
unifiedsplit
AGENTS.md+89−49 README.md+32−13 flake.lock+17 flake.nix+20
AGENTS.md+89−49
@@ -4,22 +4,24 @@
44
55`urbit-apps` is a Nix flake that builds Urbit apps' desks into `.deskjam`
66files, the upload format of [deskjam](https://github.com/iko-soy/deskjam),
7−with each app's frontend glob next to it. `jammer/` is the Rust CLI that packs
8−them. `README.md` documents the apps for users: read it before changing what
9−the flake builds.
7+with its glob next to each one, for an app whose frontend is one. `jammer/`
8+is the Rust CLI that packs them. `README.md` documents the apps for users:
9+read it before changing what the flake builds.
1010
1111## Code map
1212
13−- `flake.nix`: one input per app, plus any dependencies an app's own build
14− pins. Each app is an `<app>-desk` built with `mkDeskjam` and exposed as
15− `packages.<system>.<app>`; frontends are `packages.<system>.<app>-glob`.
13+- `flake.nix`: nixpkgs, flake-utils, one input per app, and the commits
14+ harness' build pins. Each app is an `<app>-desk` built with `mkDeskjam` and
15+ exposed as `packages.<system>.<app>`. Globs are `packages.<system>.<app>-glob`,
16+ for hits, silo and vita. jammer is `packages.<system>.jammer` and `default`.
1617 - `mkDeskjam { desk, src, glob ? null }` packs the desk folder `src` into
1718 `$out/<desk>.deskjam` and copies `glob` next to it as `$out/<desk>-glob`.
1819 - `names-glob` reads a `desk.docket-0` with `urbit eval`, as the docket mark
1920 does. `mkDeskjam` fails the build when the docket names a glob (a
2021 `glob-http` or `glob-ames` clause, and no `site` clause) but has no
21− `glob`, when it has a `glob` for a docket that names none, and when the
22− docket isn't valid Hoon.
22+ `glob`, when it has a `glob` for a docket that names none, and when Hoon
23+ can't read the docket as a list of clauses. It doesn't check that the
24+ docket has the clauses the mark needs, such as `title`.
2325 - `mkGlob` builds a frontend with `buildNpmPackage` (`npm run build`, then
2426 its `dist/`), for apps whose own flakes don't build their globs.
2527 - `harness-git` and `harness-src` run harness' own `zig build` offline; see
@@ -33,24 +35,33 @@ the flake builds.
3335## Working conventions
3436
3537- Use jj, not git, and pass `--git` to `jj diff` and `jj show`. Commit or push
36− only when asked. Nix only sees files jj tracks. Never write to `/nix` by
37− hand.
38+ only when asked. Never write to `/nix` by hand.
39+- Nix only sees files jj tracks, and jj tracks a new file at its next
40+ command. After adding a file, run `jj status` before building, not
41+ `git add`.
42+- jammer writes `<desk>.deskjam` or `<desk>/` in the current directory, and jj
43+ would track them in this repo. Run it elsewhere, or give `jam` and `unjam`
44+ an `-o` outside the repo; `nix shell .` puts it on your PATH.
3845- Don't change the app repos from here. When one needs a change, write a
3946 prompt the user can give an agent in that repo: the problem, with evidence,
4047 the change, and how to check it.
4148- Add an app by the first route its repo allows:
42− 1. Its flake follows the convention: `packages.<system>.desk` is the full
43− desk, `.glob` is the built frontend if its docket names a glob, and
44− `default` is `desk`. Add it as a flake input, with
45− `src = app.packages.${system}.desk` and
46− `glob = app.packages.${system}.glob`. Have its `nixpkgs` follow this
47− flake's only if its flake builds no frontend; otherwise keep the nixpkgs
48− it pins, so its glob is the same build as in its own repo.
49+ 1. Its flake builds the full desk, as `packages.<system>.desk`, or as
50+ `default` if it has no `desk`, like vita's. Add it as a flake input, with
51+ `src = app.packages.${system}.desk`, or `.default`. If its docket names a
52+ glob and its flake builds it, use `glob = app.packages.${system}.glob`;
53+ if not, build it here with `mkGlob`, as for hits. Have its `nixpkgs`
54+ follow this flake's only if its flake builds no frontend; otherwise keep
55+ the nixpkgs it pins, so its glob is the same build as in its own repo.
4956 2. It has no flake, and its `desk/` is the whole desk: a `flake = false`
50− input, with `src = "${app}/desk"`.
57+ input, with `src = "${app}/desk"`. If its docket names a glob, build it
58+ with `mkGlob`, starting its `npmDepsHash` at `pkgs.lib.fakeHash`.
5159 3. Its own build tool assembles the desk: run that build in Nix, with its
52− fetches pinned as inputs, as for harness. Don't reimplement its steps,
53− and make the build fail loudly when upstream pins something new.
60+ fetches pinned as inputs, as for harness. Don't reimplement its steps.
61+ Replace only a step that can't run in the sandbox, as `flake.nix` does
62+ for harness' npm steps, with `--replace-fail`, so a change upstream
63+ stops the build. Make the build fail loudly when upstream pins
64+ something new.
5465- Before adding an app, check:
5566 - that its `sys.kelvin` lists the current kernel, `[%zuse 408]`. Kernel
5667 numbers count down, so 411 is older than 408. Don't package an app that
@@ -58,23 +69,35 @@ the flake builds.
5869 - its desk name, from its README or its docket's `base`.
5970 - whether its docket names a glob, and where else its frontend could come
6071 from, such as files its own agent serves from the desk.
61− - that `jammer jam -v` reports no missing marks, and that the desk has the
62− libraries its Hoon imports.
72+ - that `jammer jam -v` reports no missing marks, and that deskjam's confirm
73+ page, on a fake ship, finds nothing missing that its agents and marks
74+ need. Its warning that other files import files the desk lacks, as for
75+ silo's base-dev libraries, is fine if nothing uses them.
6376- The flake supports `x86_64-linux`, `aarch64-linux` and `aarch64-darwin`;
6477 nixpkgs 26.11 dropped `x86_64-darwin`. An app's flake must provide its
6578 outputs on all three.
66−- Keep `README.md` in step with the flake: the app's row in the Apps table
67− (description, source link, `nix build github:iko-soy/urbit-apps#<app>`), the
68− glob and build-all commands, the Frontends section for an app with a glob,
69− and its bullet in "How the desks are built". Write in its voice: short,
70− plain sentences. In a table cell, escape `|` as `\|`, even inside backticks.
79+- Keep `README.md` in step with the flake. Give the app its row in the Apps
80+ table (description, source link,
81+ `nix build github:iko-soy/urbit-apps#<app>`), and add it wherever the README
82+ lists apps like it: the glob and build-all commands and their counts, the
83+ Frontends section, which names every app, with a glob or without, and
84+ "How the desks are built", including its npm hashes. Search the README for
85+ a similar app's name to find them all, and keep the lists in alphabetical
86+ order. Write in the README's voice: short, plain sentences.
87+- In a README table cell, escape `|` as `\|`, even inside backticks. GitHub
88+ drops the cells an unescaped one adds, so a rendered table won't show it.
89+- The README says `~donmec-sallud` publishes every app in its table, and
90+ [shelf.iko.soy](https://shelf.iko.soy) lists the apps it offers. Only the
91+ user can publish an app there: when you add one that shelf.iko.soy doesn't
92+ list, say so in your report.
7193- Format `flake.nix` with `nix run --inputs-from . nixpkgs#nixfmt -- flake.nix`.
7294- `nix flake update` moves every input except those pinned by a commit in
7395 their URL, such as `harness-grubbery` and `harness-tlon`; move those by
7496 editing the URL.
75−- When a frontend's `package-lock.json` changes, its build stops on a hash
76− mismatch. Set its hash (`npmDepsHash`, or the `hash` of harness' `npmDeps`)
77− to `pkgs.lib.fakeHash`, build, and use the hash shown after `got:`.
97+- When a frontend's `package-lock.json` changes, its build stops with a hash
98+ mismatch, or `npmDepsHash is out of date`. Set its hash (`npmDepsHash`, or
99+ the `hash` of harness' `npmDeps`) to `pkgs.lib.fakeHash`, build, and use
100+ the hash shown after `got:`.
78101
79102## Validation
80103
@@ -84,27 +107,44 @@ Run from the repository root:
84107nix run --inputs-from . nixpkgs#nixfmt -- --check flake.nix
85108nix flake check --all-systems --no-build
86109nix build --no-link --print-out-paths .#<app>
110+grep '^|' README.md | sed 's/\\|//g' | awk -F'|' 'NF != 6'
87111```
88112
89−For a change that shouldn't change a desk, `cmp` each app's new `.deskjam`
90−with its old one. For one that should, `jammer unjam` both, `diff -r` them,
91−and check that only the expected files changed. `nix build --rebuild` of a
92−glob checks that it's reproducible.
93−
94−For a new app, also compare its deskjam with what the app's own procedure
95−makes. deskjam's `tests/fakezod/pack.sh` packs a desk folder with
96−`urbit eval`, byte for byte as jammer does. Then render the README with
97−`nix run --inputs-from . nixpkgs#pandoc -- -f gfm -t html README.md`, and
98−check that every table row has four cells.
99−
100−To test an app on a ship, use deskjam's fake-ship harness, `tests/fakezod` in
101−iko-soy/deskjam. `bootstrap.sh` boots a fake `~zod` with deskjam, and
102−`smoke-test.sh` shows how to drive deskjam's pages with curl. Set `HTTP_PORT`
103−and `AMES_PORT`, and don't pick 31337 plus a galaxy's number as the Ames
104−port: the fake ship sends that galaxy's packets there, so they loop back.
105−Upload a glob at `/docket/upload` as a browser does: a `desk` part, then one
106−`glob` part per file, named `<folder>/<path>`, with its content type. Stop
107−the ship with `stop.sh` when done.
113+The last command prints any README table row with a stray `|`; it should
114+print nothing.
115+
116+For a change that shouldn't change a desk, build every app before and after
117+it, and `cmp` each `.deskjam`. Store paths don't tell: they change whenever
118+jammer is rebuilt. For a change that should, unpack both with
119+`jammer unjam OLD.deskjam -o old` and `jammer unjam NEW.deskjam -o new`, and
120+check that `diff -r old new` shows only the expected changes. To check that a
121+glob is reproducible, build it, then run `nix build --rebuild` on it a few
122+times; `--rebuild` fails on a glob that isn't built yet.
123+
124+For a new app, check that its deskjam has what the app's install steps make.
125+`|new-desk` adds `mar/hoon`, `mar/kelvin`, `mar/noun`, `mar/txt` and
126+`sys.kelvin` from `%base` to what you copy in. Make that folder, pack it with
127+deskjam's `tests/fakezod/pack.sh`, which makes the same bytes as jammer with
128+`urbit eval`, and `cmp` the two. pack.sh stops on a file jammer skips, such
129+as hits' `LICENSE`, which has no extension: pack a copy without such files.
130+
131+To test an app on a ship, clone iko-soy/deskjam outside this repo and use its
132+fake-ship harness, `tests/fakezod`, which keeps its pier in its
133+`tests/fakezod/.work`:
134+
135+- `bootstrap.sh` boots a fake `~zod` with deskjam, and a desk `%harness` whose
136+ `%logtap` agent copies the ship's output into the log. This repo's harness
137+ app is also `%harness`, and replacing that desk deletes logtap: move
138+ `%logtap` to a desk of its own before installing it.
139+- Set `HTTP_PORT`, and an `AMES_PORT` outside 31337 to 31592. A fake ship
140+ sends galaxy N's packets to port 31337 + N, so a ship on one of those ports
141+ loops them back to itself. The harness' default, 31483, is in that range.
142+- `smoke-test.sh` shows how to drive deskjam's pages with curl. It has no
143+ glob: for an app with one, post the confirm page's **set** form first, as
144+ the README's Frontends section says.
145+- Upload a glob at `/docket/upload` as a browser does: a `desk` part, then one
146+ `glob` part per file, named `<folder>/<path>`, with its content type.
147+- Stop the ship with `stop.sh` when done.
108148
109149Quirks:
110150
README.md+32−13
@@ -6,14 +6,20 @@ file. You install it in your ship's web interface with
66[deskjam](https://github.com/iko-soy/deskjam), without access to the ship's
77files.
88
9+Every app here is also published from `~donmec-sallud`, so you can install
10+it from that ship instead, with nothing to build: see
11+[Installing from ~donmec-sallud](#installing-from-donmec-sallud).
12+
913## Apps
1014
1115| App | Description | Source | Build |
1216|---|---|---|---|
1317| `%accountability` | Watches all 256 galaxies from your ship. Every 10 minutes it checks each one's keys on chain, whether it answers, and which `%kids` OTA it serves, and logs every change. A dashboard at `/apps/accountability` and a public JSON API show the results. It needs `%azimuth` running, as on a livenet ship. | [sigilante/accountability](https://github.com/sigilante/accountability) | `nix build github:iko-soy/urbit-apps#accountability` |
18+| `%burn` | Shares a Plex server's media library between ships. Every byte goes over Ames and is checked against its hash, so a ship behind NAT can share with no port forwarding. Its page is new-oxal's `/new-oxal/plex`, so install `%new-oxal` too. | [brbenji/burn](https://github.com/brbenji/burn) | `nix build github:iko-soy/urbit-apps#burn` |
1419| `%deskjam` | Install and update apps, and upload and download desks, as deskjam files, in your ship's web interface at `/apps/deskjam`. A fork of [tinnus-napbus/deskjam](https://github.com/tinnus-napbus/deskjam). | [iko-soy/deskjam](https://github.com/iko-soy/deskjam) | `nix build github:iko-soy/urbit-apps#deskjam` |
1520| `%harness` | Runs AI agents on your ship. Talk to them in its web app at `/apps/harness`, in Tlon, or from an editor, while the ship keeps the conversations, permissions and work. Models come from providers you configure, such as OpenRouter, OpenAI or Anthropic. Its Tlon features and its documents need `%groups`. Installing it takes a few minutes, while Clay builds it. | [mopfel-winrux/urbit-agent-harness](https://github.com/mopfel-winrux/urbit-agent-harness) | `nix build github:iko-soy/urbit-apps#harness` |
1621| `%hits` | Ranks apps by how many installs they have among the ships around you, which gossip their installs to their Pals and the ships they chat with in Tlon. There's no central server. It works without `%pals`, but then hears only from the ships you chat with. It only counts apps that kiln syncs from another ship, as after `\|install`: not ones installed from a deskjam file, or ones you stop kiln syncing. Its frontend is a glob: see [Frontends](#frontends). A fork of [urbit/hits](https://github.com/urbit/hits). | [iko-soy/hits](https://github.com/iko-soy/hits) | `nix build github:iko-soy/urbit-apps#hits` |
22+| `%new-oxal` | A networked reactive database, shown as a tree-shaped spreadsheet. Its views include burn's page, at `/new-oxal/plex`, which needs `%burn`. It comes from burn's repo. | [brbenji/burn](https://github.com/brbenji/burn) | `nix build github:iko-soy/urbit-apps#new-oxal` |
1723| `%shelf` | A public web page that lists the apps your ship publishes, so anyone can install them on their own ship. It answers at `/shelf`, for a reverse proxy to serve at the root of its own domain, and needs `%landscape`, which fresh ships have. | [iko-soy/shelf](https://github.com/iko-soy/shelf) | `nix build github:iko-soy/urbit-apps#shelf` |
1824| `%silo` | A file manager for the S3 storage your ship uploads to: add a bucket's credentials, then browse its files and upload new ones. It has no agents of its own, and uses `%storage` from `%landscape`, which fresh ships have. Its frontend is a glob: see [Frontends](#frontends). A fork of [arthyn/silo](https://github.com/arthyn/silo). | [iko-soy/silo](https://github.com/iko-soy/silo) | `nix build github:iko-soy/urbit-apps#silo` |
1925| `%vita` | Tracks how your published apps spread: how many ships sync each of your desks, and the daily active users that apps using its `vita-client` library report, with a dashboard for creating and maintaining apps. Its frontend is a glob: see [Frontends](#frontends). A fork of [assemblycapital/vita](https://github.com/assemblycapital/vita), updated for kernel 408. | [iko-soy/vita](https://github.com/iko-soy/vita) | `nix build github:iko-soy/urbit-apps#vita` |
@@ -32,8 +38,8 @@ such as hits, it also writes the glob's files next to it, as
3238so a deskjam never comes without its glob.
3339`nix build github:iko-soy/urbit-apps#hits-glob`, or `#silo-glob` or
3440`#vita-glob`, builds just a glob. In a checkout,
35−`nix build .#accountability .#deskjam .#harness .#hits .#shelf .#silo .#vita`
36−builds all seven, in that order, into `result` and `result-1` to `result-6`.
41+`nix build .#accountability .#burn .#deskjam .#harness .#hits .#new-oxal .#shelf .#silo .#vita`
42+builds all nine, in that order, into `result` and `result-1` to `result-8`.
3743The steps below assume one app's `result`.
3844
3945You can install these files on your ship with
@@ -45,6 +51,15 @@ desks. No Hoon is compiled: your ship compiles an app's Hoon when you install
4551it. The flake supports `x86_64-linux`, `aarch64-linux` and `aarch64-darwin`
4652(Apple silicon Macs).
4753
54+## Installing from ~donmec-sallud
55+
56+`~donmec-sallud` publishes every app in the [table](#apps). To install one
57+from it, run `|install ~donmec-sallud` and the app's name in the dojo, your
58+ship's command line, as in `|install ~donmec-sallud %shelf`. Your ship gets
59+the app, frontend included, and its updates from that ship.
60+[shelf.iko.soy](https://shelf.iko.soy) lists all the apps `~donmec-sallud`
61+offers, with the command that installs each.
62+
4863## Installing with deskjam
4964
5065[deskjam](https://github.com/iko-soy/deskjam) installs and updates apps from
@@ -62,8 +77,8 @@ that doesn't have it yet. The first time, do one of these:
6277
6378- If you can reach your ship's files, follow deskjam's
6479 [Installation](https://github.com/iko-soy/deskjam#installation).
65−- If another ship publishes it, run `|install ~that-ship %deskjam` in the
66− dojo, your ship's command line.
80+- Install it from `~donmec-sallud`: run `|install ~donmec-sallud %deskjam`
81+ in the dojo.
6782- If your ship runs upstream deskjam,
6883 [tinnus-napbus/deskjam](https://github.com/tinnus-napbus/deskjam), upload
6984 `result/deskjam.deskjam` through it, following
@@ -115,12 +130,13 @@ instead: deskjam's does. If your ship serves the app's glob, also copy its old
115130`result/<desk>-glob` somewhere before you build the new version, and upload it
116131at `/docket/upload` after putting the old version back.
117132
118−If the app came from another ship with `|install`, kiln, the part of your
119−ship that installs and updates apps, keeps it in sync with that ship. That
120−ship's next release would undo your upload. Tick **stop kiln syncing** on the
121−confirm page to keep yours. That stops all of that ship's updates to the
122−desk, until you run `|install ~that-ship %desk` again, which replaces your
123−upload with their latest release.
133+If the app came from another ship with `|install`, such as
134+`~donmec-sallud`, kiln, the part of your ship that installs and updates apps,
135+keeps it in sync with that ship. That ship's next release would undo your
136+upload. Tick **stop kiln syncing** on the confirm page to keep yours. That
137+stops all of that ship's updates to the desk, until you run
138+`|install ~that-ship %desk` again, which replaces your upload with their
139+latest release.
124140
125141### Frontends
126142
@@ -157,9 +173,9 @@ To let other ships install an app from yours, frontend included, publish it:
157173`:treaty|publish %hits` makes it public and lists it in Landscape, and
158174`|public %hits` is enough for `|install ~your-ship %hits`.
159175
160−The other apps have no glob: accountability, deskjam, harness and shelf
161−serve their pages from their own agents. harness' frontend is in its desk,
162−so `harness.deskjam` already has it.
176+The other apps have no glob: accountability, burn, deskjam, harness,
177+new-oxal and shelf serve their pages from their own agents. harness' frontend
178+is in its desk, so `harness.deskjam` already has it.
163179
164180### Kernel updates
165181
@@ -188,6 +204,9 @@ has the details, including what to do when an upload goes wrong.
188204 use them.
189205- accountability has no flake, and its `desk/` is the whole desk, which
190206 `flake.nix` packs as it is.
207+- burn has no flake either. Its repo holds two whole desks, `burn/` and
208+ `new-oxal/`, which `flake.nix` packs as they are, as `%burn` and
209+ `%new-oxal`.
191210- harness' repo builds its desk with `zig build`. It builds `fe/`, its
192211 frontend, into the desk's `web/`, which harness' own agent serves; fetches
193212 grubbery and some of Tlon's files with git, at commits it pins; and patches
flake.lock+17
@@ -16,6 +16,22 @@
1616 "type": "github"
1717 }
1818 },
19+ "burn": {
20+ "flake": false,
21+ "locked": {
22+ "lastModified": 1786378297,
23+ "narHash": "sha256-wezDIDk5CUhMXP2SDexV0c3xznZ7SbPx9vAoRTQaitM=",
24+ "owner": "brbenji",
25+ "repo": "burn",
26+ "rev": "bcc3613ebec2c20d69cb2b3658b43b5ea4134b69",
27+ "type": "github"
28+ },
29+ "original": {
30+ "owner": "brbenji",
31+ "repo": "burn",
32+ "type": "github"
33+ }
34+ },
1935 "deskjam": {
2036 "inputs": {
2137 "fang-suite": "fang-suite",
@@ -250,6 +266,7 @@
250266 "root": {
251267 "inputs": {
252268 "accountability": "accountability",
269+ "burn": "burn",
253270 "deskjam": "deskjam",
254271 "flake-utils": "flake-utils",
255272 "harness": "harness",
flake.nix+20
@@ -37,6 +37,13 @@
3737 flake = false;
3838 };
3939
40+ # Two full desks: burn/, whose agent is the backend, and new-oxal/, which
41+ # serves burn's page at /new-oxal/plex.
42+ burn = {
43+ url = "github:brbenji/burn";
44+ flake = false;
45+ };
46+
4047 harness = {
4148 url = "github:mopfel-winrux/urbit-agent-harness";
4249 flake = false;
@@ -62,6 +69,7 @@
6269 silo,
6370 vita,
6471 accountability,
72+ burn,
6573 harness,
6674 harness-grubbery,
6775 harness-tlon,
@@ -235,6 +243,16 @@
235243 src = "${accountability}/desk";
236244 };
237245
246+ burn-desk = mkDeskjam {
247+ desk = "burn";
248+ src = "${burn}/burn";
249+ };
250+
251+ new-oxal-desk = mkDeskjam {
252+ desk = "new-oxal";
253+ src = "${burn}/new-oxal";
254+ };
255+
238256 # harness' build.zig fetches grubbery, and its scripts/stage-tlon.mjs
239257 # Tlon's files, with git, at commits they pin. This git answers from
240258 # the inputs pinned to the same commits, and fails on any other, so a
@@ -330,6 +348,8 @@
330348 vita-glob = vita.packages.${system}.glob;
331349 accountability = accountability-desk;
332350 harness = harness-desk;
351+ burn = burn-desk;
352+ new-oxal = new-oxal-desk;
333353 default = jammer;
334354 };
335355