on e244079 help sign in
5 files changed+162−408
since splitsnapshots
unifiedsplit
AGENTS.md−121 CLAUDE.md−1 README.md+63−78 flake.lock+49−138 flake.nix+50−70
AGENTS.mddeleted−121
@@ -1,121 +0,0 @@
1−# Agent guidance
2−
3−## Project
4−
5−`urbit-apps` is a Nix flake that builds Urbit apps' desks into `.deskjam`
6−files, 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.
10−
11−## Code map
12−
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`.
16− - `mkDeskjam { desk, src, glob ? null }` packs the desk folder `src` into
17− `$out/<desk>.deskjam` and copies `glob` next to it as `$out/<desk>-glob`.
18− - `names-glob` reads a `desk.docket-0` with `urbit eval`, as the docket mark
19− does. `mkDeskjam` fails the build when the docket names a glob (a
20− `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.
23− - `mkGlob` builds a frontend with `buildNpmPackage` (`npm run build`, then
24− its `dist/`), for apps whose own flakes don't build their globs.
25− - `harness-git` and `harness-src` run harness' own `zig build` offline; see
26− the README's "How the desks are built".
27−- `flake.lock`: the revision of every app and dependency.
28−- `jammer/`: the packer. Its build takes only `Cargo.toml`, `Cargo.lock`,
29− `src/` and `tests/`, and runs its tests.
30−- `README.md`: the apps table, installing and updating with deskjam,
31− frontends, and how each desk is built.
32−
33−## Working conventions
34−
35−- 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−- Don't change the app repos from here. When one needs a change, write a
39− prompt the user can give an agent in that repo: the problem, with evidence,
40− the change, and how to check it.
41−- 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− 2. It has no flake, and its `desk/` is the whole desk: a `flake = false`
50− input, with `src = "${app}/desk"`.
51− 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.
54−- Before adding an app, check:
55− - that its `sys.kelvin` lists the current kernel, `[%zuse 408]`. Kernel
56− numbers count down, so 411 is older than 408. Don't package an app that
57− only supports older kernels.
58− - its desk name, from its README or its docket's `base`.
59− - whether its docket names a glob, and where else its frontend could come
60− 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.
63−- The flake supports `x86_64-linux`, `aarch64-linux` and `aarch64-darwin`;
64− nixpkgs 26.11 dropped `x86_64-darwin`. An app's flake must provide its
65− 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.
71−- Format `flake.nix` with `nix run --inputs-from . nixpkgs#nixfmt -- flake.nix`.
72−- `nix flake update` moves every input except those pinned by a commit in
73− their URL, such as `harness-grubbery` and `harness-tlon`; move those by
74− 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:`.
78−
79−## Validation
80−
81−Run from the repository root:
82−
83−```sh
84−nix run --inputs-from . nixpkgs#nixfmt -- --check flake.nix
85−nix flake check --all-systems --no-build
86−nix build --no-link --print-out-paths .#<app>
87−```
88−
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.
108−
109−Quirks:
110−
111−- `urbit eval` colors its output, ends lines with CRLF, and exits 0 even when
112− the Hoon crashes. Check its output, not its exit status.
113−- In the build sandbox, npm packages' `#!/usr/bin/env node` scripts only run
114− after `patchShebangs`, which `npmHooks.npmConfigHook` does once. Another
115− `npm ci` puts the unpatched scripts back.
116−- `nix build` of several targets writes `result`, then `result-1` and so on.
117− Nix reuses a `github:` flake it fetched within the last hour, unless given
118− `--refresh`.
119−
120−In the final report, summarize the change, the checks run, and anything left
121−unchecked.
CLAUDE.mddeleted−1
@@ -1 +0,0 @@
1−AGENTS.md
README.md+63−78
@@ -10,31 +10,28 @@ files.
1010
1111| App | Description | Source | Build |
1212|---|---|---|---|
13−| `%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` |
14−| `%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` |
15−| `%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` |
16−| `%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` |
17−| `%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` |
18−| `%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` |
19−| `%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` |
20−
21−The build commands need Nix with flakes enabled, but no clone of this repo:
22−Nix fetches it from GitHub, and each app's source at the version `flake.lock`
23−pins. If flakes aren't enabled, put
24−`--extra-experimental-features 'nix-command flakes'` after `nix`. In a
25−checkout of this repo, `.` builds your working copy instead, as in
26−`nix build .#shelf`.
13+| `%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 .#accountability` |
14+| `%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 .#deskjam` |
15+| `%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 need `%groups`. | [mopfel-winrux/urbit-agent-harness](https://github.com/mopfel-winrux/urbit-agent-harness) | `nix build .#harness` |
16+| `%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 installed from another ship with `|install`, not ones installed from a deskjam file. 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 .#hits` |
17+| `%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 .#shelf` |
18+| `%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. | [arthyn/silo](https://github.com/arthyn/silo) | `nix build .#silo` |
19+
20+Run the build commands in a checkout of this repo, with Nix and flakes
21+enabled. If flakes aren't enabled, put
22+`--extra-experimental-features 'nix-command flakes'` after `nix`. Without a
23+checkout, give the repo's address instead of `.`, such as
24+`nix build github:iko-soy/urbit-apps#shelf`. Nix fetches each app's source
25+itself, at the version `flake.lock` pins.
2726
2827Each build writes `result/<desk>.deskjam`, such as `result/shelf.deskjam`, in
2928place of the last build's `result`. For an app whose web frontend is a glob,
3029such as hits, it also writes the glob's files next to it, as
3130`result/<desk>-glob`, and the build fails if `flake.nix` doesn't build them,
32−so a deskjam never comes without its glob.
33−`nix build github:iko-soy/urbit-apps#hits-glob`, or `#silo-glob` or
34−`#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`.
37−The steps below assume one app's `result`.
31+so a deskjam never comes without its glob. `nix build .#hits-glob` or
32+`.#silo-glob` builds just a glob. `nix build .#accountability .#deskjam
33+.#harness .#hits .#shelf .#silo` builds all six, into `result` and `result-1`
34+to `result-5`.
3835
3936You can install these files on your ship with
4037[iko-soy/deskjam](https://github.com/iko-soy/deskjam): see
@@ -82,10 +79,9 @@ After that, update deskjam like any other app, as below.
82792. Under **upload deskjam**, choose the file, such as `result/shelf.deskjam`,
8380 and click **upload**.
84813. Under **Install it as a new desk**, keep the name and click **next**.
85−4. On the confirm page, if the app's frontend is a glob, first click **set**
86− in the glob box, as [Frontends](#frontends) says. Then tick
87− **start its agents after uploading** (for an app without agents, such as
88− silo, **mark it running after uploading**), and click **confirm**.
82+4. On the confirm page, tick **start its agents after uploading** (for an app
83+ without agents, such as silo, **mark it running after uploading**), and
84+ click **confirm**.
89855. The status page says whether the app runs.
9086
9187Once it runs, see the app's README for how to set it up.
@@ -94,26 +90,19 @@ Once it runs, see the app's README for how to set it up.
9490
9591Apps installed this way don't update on their own. To update one:
9692
97−1. Build it again. Nix reuses a copy of this repo it fetched in the last hour,
98− so add `--refresh` to get the pins it has now:
99− `nix build --refresh github:iko-soy/urbit-apps#shelf`. To build an app's
100− newest commit before this repo pins it, add
101− `--override-input shelf github:iko-soy/shelf`. In a checkout,
102− `nix flake update shelf` moves the pin, and `nix flake update` moves every
103− app, and nixpkgs.
93+1. Move its pin to the latest commit of its repo, such as with
94+ `nix flake update shelf`, and build it again. `nix flake update` moves
95+ every app, and nixpkgs.
104962. Upload the new file as above. Under **Update an existing desk**, choose the
10597 app's desk, select **replace it**, and click **next**. Replace makes the
10698 desk exactly the upload, so files a new version removed don't linger.
107993. The confirm page offers a download of the desk as it is now. Keep it if
108− you might want to go back. If your ship serves the app's glob, click
109− **set** in the glob box first. Then click **confirm**.
100+ you might want to go back, then click **confirm**.
110101
111102Uploading the kept copy with **replace it** puts the old version back. If the
112103update changed the state an agent keeps, that usually fails, and nothing
113104changes. But some agents start afresh from state they can't read, and lose it
114−instead: deskjam's does. If your ship serves the app's glob, also copy its old
115−`result/<desk>-glob` somewhere before you build the new version, and upload it
116−at `/docket/upload` after putting the old version back.
105+instead: deskjam's does.
117106
118107If the app came from another ship with `|install`, kiln, the part of your
119108ship that installs and updates apps, keeps it in sync with that ship. That
@@ -131,20 +120,18 @@ folder is what you upload at `/docket/upload`: choose the app's desk and the
131120folder, and click **glob!**. Use a browser other than Safari, which can't
132121upload folders.
133122
134−hits', silo's and vita's dockets have `%docket` get their globs from
135−`~donmec-sallud` over Ames, with a placeholder hash. On your ship:
136−
137−1. When you install the deskjam, click **set** in the glob box on the confirm
138− page first, so your ship serves the glob instead. **set** reloads the page
139− and clears the boxes below it, so tick **start its agents after uploading**
140− after it, then confirm.
141−2. Once the app runs, upload its `result/<desk>-glob`.
142−
143−On `~donmec-sallud`, their dockets already name your ship, so skip **set**,
144−and just upload the glob. Without its glob, an app runs, but has no frontend.
145−deskjam's
146−[Serving a glob from your ship](https://github.com/iko-soy/deskjam/blob/main/docs/globs.md#serving-a-glob-from-your-ship)
147−has the details.
123+- silo's docket has `%docket` download its glob from a url, so `silo.deskjam`
124+ works on any ship, with nothing to upload.
125+- hits' docket has `%docket` get its glob from `~donmec-sallud` over Ames,
126+ with a placeholder hash. On your ship, click **set** in the glob box on the
127+ confirm page when you install `hits.deskjam`, so your ship serves the glob
128+ instead, and once hits runs, upload `result/hits-glob`. On
129+ `~donmec-sallud`, hits' docket already names your ship, so just upload the
130+ glob. Without its glob, hits runs, but has no frontend.
131+- To serve silo's frontend from your own ship too, click **set** the same way
132+ and upload `result/silo-glob`, as deskjam's
133+ [Serving a glob from your ship](https://github.com/iko-soy/deskjam/blob/main/docs/globs.md#serving-a-glob-from-your-ship)
134+ says.
148135
149136When you update an app whose glob your ship serves, click **set** in the glob
150137box on the confirm page first, which keeps the glob your ship serves now.
@@ -176,16 +163,10 @@ has the details, including what to do when an upload goes wrong.
176163
177164## How the desks are built
178165
179−- deskjam's, hits', shelf's, silo's and vita's own flakes build their desks,
180− so each `.deskjam` file has the files that repo's own build makes. jammer
181− leaves out the files a `|commit` would skip too, such as hits' `LICENSE`,
182− which has no extension. silo's and vita's flakes build their globs too, and
183− this flake takes them as they are, with the nixpkgs those flakes pin: so
184− `github:iko-soy/urbit-apps#silo-glob` is the same build as
185− `github:iko-soy/silo#glob`. Their desks
186− include all of urbit's base-dev, so deskjam's confirm page warns about a
187− few of its libraries that import files the desks lack, but the apps don't
188− use them.
166+- deskjam's, hits' and shelf's own flakes build their desks, so each
167+ `.deskjam` file has the files that repo's own build makes. jammer leaves
168+ out the files a `|commit` would skip too, such as hits' `LICENSE`, which has
169+ no extension.
189170- accountability has no flake, and its `desk/` is the whole desk, which
190171 `flake.nix` packs as it is.
191172- harness' repo builds its desk with `zig build`. It builds `fe/`, its
@@ -194,24 +175,28 @@ has the details, including what to do when an upload goes wrong.
194175 grubbery's desk under harness' own. `flake.nix` runs the same `zig build`
195176 with npm's packages fetched ahead, and a stand-in `git` that answers from
196177 inputs pinned to the same commits, and fails if the build asks for any
197− other. When a new version of harness pins other commits, change the commit
198− in `harness-grubbery`'s or `harness-tlon`'s url in `flake.nix` to the one
199− the error names: `nix flake update` won't move them. The build also fails
200− if the desk has no `web/index.html`, so it can't come out without its
201− frontend. Two of grubbery's libraries in it, `lib/verb.hoon` and
202− `lib/xray.hoon`, import files the desk lacks, so deskjam's confirm page
203− warns about them, but harness doesn't use them.
204−- A desk whose docket names a glob only builds with its glob, and a glob for
205− a desk whose docket names none fails the build too. `flake.nix` reads each
206− docket as the docket mark does, with Hoon's own parser in `urbit eval`, so
207− this holds however the docket is laid out, and a docket that isn't valid
208− fails the build.
209−- A hash in `flake.nix` pins the npm packages of the frontends it builds
210− itself: `hits-glob`'s `npmDepsHash`, and the `hash` of harness' `npmDeps`.
211− silo's and vita's are in their own flakes. When moving an app's pin changes
212− its `package-lock.json`, its build stops with a hash mismatch, or
213− `npmDepsHash is out of date`. Set that hash to `pkgs.lib.fakeHash`, build
214− again, and put the hash the error shows after `got:` in its place.
178+ other: when a new version of harness pins other commits, move
179+ `harness-grubbery` or `harness-tlon` to them. The build also fails if the
180+ desk has no `web/index.html`, so it can't come out without its frontend.
181+- silo has no flake. Its CI deploys all of urbit's `pkg/base-dev`, then
182+ landscape's `desk-dev`, then its own `desk/`, and `flake.nix` builds the
183+ same, with landscape at `master`, as the CI takes it. The CI's urbit tag
184+ isn't public, so `flake.nix` takes `408k-2`, the release of the newest
185+ kernel silo lists; when silo lists a newer one, move `silo-urbit` to its
186+ tag. A few of base-dev's libraries import files the desk lacks, so
187+ deskjam's confirm page warns about them, but silo doesn't use them. silo's
188+ old esbuild names two unused variables at random, so `silo-glob` can differ
189+ by a few bytes from one build to the next, and
190+ `nix build --rebuild .#silo-glob` can fail. The page works the same either
191+ way.
192+- A desk whose docket names a glob, however the docket is laid out, only
193+ builds with its glob, which `flake.nix` builds from the app's `ui/`. A glob
194+ for a desk whose docket names none fails the build too.
195+- A hash in `flake.nix` pins each frontend's npm packages: each glob's
196+ `npmDepsHash`, and the `hash` of harness' `npmDeps`. When moving an app's
197+ pin changes its `package-lock.json`, its build stops with a hash mismatch,
198+ or `npmDepsHash is out of date`. Set that hash to `pkgs.lib.fakeHash`,
199+ build again, and put the hash the error shows after `got:` in its place.
215200
216201## jammer
217202
flake.lock+49−138
@@ -29,11 +29,11 @@
2929 "urbit": "urbit"
3030 },
3131 "locked": {
32− "lastModified": 1792584136,
33− "narHash": "sha256-YnMsLXViNtQi+B029JFuVFYM8IzjGxPQLUCOPjlaktQ=",
32+ "lastModified": 1792565467,
33+ "narHash": "sha256-kkNjvyRPQf1CS+cYHDAuUK7LuEJJkT3Q9e4swcfh1Xc=",
3434 "owner": "iko-soy",
3535 "repo": "deskjam",
36− "rev": "d0bb6b31803336e66a19ee6daeedd98a02813bd4",
36+ "rev": "0da5be5e86de673dc8c5f8586b48143d7d9a3d67",
3737 "type": "github"
3838 },
3939 "original": {
@@ -135,11 +135,11 @@
135135 "urbit": "urbit_2"
136136 },
137137 "locked": {
138− "lastModified": 1792579499,
139− "narHash": "sha256-DVg1FSxZd2kZrwCebUWirVWTaya6NpqLAgI5dkk9r9I=",
138+ "lastModified": 1792571528,
139+ "narHash": "sha256-OC1Yg4iinINxUmRfYD6b+615tsIfM62Uq4szkWshUpc=",
140140 "owner": "iko-soy",
141141 "repo": "hits",
142− "rev": "49f410ce92c29e8e1029e4302aa1f5d7a7e2b19d",
142+ "rev": "deaf7b9eaf51bd6a0df96cf74ee5a81126ba6608",
143143 "type": "github"
144144 },
145145 "original": {
@@ -165,47 +165,13 @@
165165 "type": "github"
166166 }
167167 },
168− "landscape_2": {
169− "flake": false,
170− "locked": {
171− "lastModified": 1781809004,
172− "narHash": "sha256-jRsjR0oOcXFWOZZwNg7Fi946IxuYGUrktNcF/aZIHz4=",
173− "owner": "tloncorp",
174− "repo": "landscape",
175− "rev": "46c6ed8738082b6a94558710b1e3619befa83057",
176− "type": "github"
177− },
178− "original": {
179− "owner": "tloncorp",
180− "ref": "develop",
181− "repo": "landscape",
182− "type": "github"
183− }
184− },
185− "landscape_3": {
186− "flake": false,
187− "locked": {
188− "lastModified": 1781809004,
189− "narHash": "sha256-jRsjR0oOcXFWOZZwNg7Fi946IxuYGUrktNcF/aZIHz4=",
190− "owner": "tloncorp",
191− "repo": "landscape",
192− "rev": "46c6ed8738082b6a94558710b1e3619befa83057",
193− "type": "github"
194− },
195− "original": {
196− "owner": "tloncorp",
197− "repo": "landscape",
198− "rev": "46c6ed8738082b6a94558710b1e3619befa83057",
199− "type": "github"
200− }
201− },
202168 "nixpkgs": {
203169 "locked": {
204− "lastModified": 1792506237,
205− "narHash": "sha256-Q/8KLB6jNfpaUN1HAedE/u/Et9feE/zYSsutBLKrCFk=",
170+ "lastModified": 1792208399,
171+ "narHash": "sha256-mN15cwddbOOIzzXSSwYUeRfOYeizz47Vy6y3Hzq6DuY=",
206172 "owner": "NixOS",
207173 "repo": "nixpkgs",
208− "rev": "5adc50831c259f87faeb09ddf930d43597197473",
174+ "rev": "7a6522c868711d06e3a520bbcdfafe9806f4337f",
209175 "type": "github"
210176 },
211177 "original": {
@@ -215,38 +181,6 @@
215181 "type": "github"
216182 }
217183 },
218− "nixpkgs_2": {
219− "locked": {
220− "lastModified": 1792503283,
221− "narHash": "sha256-vhe2jyvRCgufWPqDuDq1S3t3ypE+ka46IFutV02xKso=",
222− "owner": "NixOS",
223− "repo": "nixpkgs",
224− "rev": "cd4ea8d57de16f4810bc5f14207bac45fbf19f67",
225− "type": "github"
226− },
227− "original": {
228− "owner": "NixOS",
229− "ref": "nixos-26.05",
230− "repo": "nixpkgs",
231− "type": "github"
232− }
233− },
234− "nixpkgs_3": {
235− "locked": {
236− "lastModified": 1792502884,
237− "narHash": "sha256-IoNisKcGbUjdd45qCqywGMCYmZ5EnkxezvLII0FWwNA=",
238− "owner": "NixOS",
239− "repo": "nixpkgs",
240− "rev": "02c087f3fe673c9e317f206a627cb6b910336dbe",
241− "type": "github"
242− },
243− "original": {
244− "owner": "NixOS",
245− "ref": "nixos-unstable",
246− "repo": "nixpkgs",
247− "type": "github"
248− }
249− },
250184 "root": {
251185 "inputs": {
252186 "accountability": "accountability",
@@ -259,7 +193,8 @@
259193 "nixpkgs": "nixpkgs",
260194 "shelf": "shelf",
261195 "silo": "silo",
262− "vita": "vita"
196+ "silo-landscape": "silo-landscape",
197+ "silo-urbit": "silo-urbit"
263198 }
264199 },
265200 "shelf": {
@@ -269,11 +204,11 @@
269204 ]
270205 },
271206 "locked": {
272− "lastModified": 1792580705,
273− "narHash": "sha256-LHPVjGLwQX6arH3N28HpW7L6bqxNcNrLQEnckXOhrBo=",
207+ "lastModified": 1792533784,
208+ "narHash": "sha256-5NHB+yqWIG/heOrp1YJ1FLQ9CvbwHUisMj28vSNNJPI=",
274209 "owner": "iko-soy",
275210 "repo": "shelf",
276− "rev": "7bd213ef50331e5c1a483519beab6a5411300d61",
211+ "rev": "868b75a07af54e5ecab8db21cae33e9b7d2869d4",
277212 "type": "github"
278213 },
279214 "original": {
@@ -283,92 +218,88 @@
283218 }
284219 },
285220 "silo": {
286− "inputs": {
287− "landscape": "landscape_2",
288− "nixpkgs": "nixpkgs_2",
289− "urbit": "urbit_3"
290− },
221+ "flake": false,
291222 "locked": {
292− "lastModified": 1792581195,
293− "narHash": "sha256-ZNqCGv5+l5RtiEdT77dbYIlD4roYbQbG1uKnNeN+Vcw=",
294− "owner": "iko-soy",
223+ "lastModified": 1782065203,
224+ "narHash": "sha256-kzP/ArfkVr5hguMldPYzWfBDlOvQ42rYV062LesFoX4=",
225+ "owner": "arthyn",
295226 "repo": "silo",
296− "rev": "2d145ca828134f0ab94103089cdd54776cc67b1d",
227+ "rev": "912b7caf56a2b9d037ca0ae9a152013631bab72e",
297228 "type": "github"
298229 },
299230 "original": {
300− "owner": "iko-soy",
231+ "owner": "arthyn",
301232 "repo": "silo",
302233 "type": "github"
303234 }
304235 },
305− "systems": {
236+ "silo-landscape": {
237+ "flake": false,
306238 "locked": {
307− "lastModified": 1681028828,
308− "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
309− "owner": "nix-systems",
310− "repo": "default",
311− "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
239+ "lastModified": 1711487686,
240+ "narHash": "sha256-Tm76Hb7hO5+LgMTZSJKor6Bla+L2Qto84i2a+I4FfUc=",
241+ "owner": "tloncorp",
242+ "repo": "landscape",
243+ "rev": "90a17528a938eebda57e837b7fec76d543f5f7cf",
312244 "type": "github"
313245 },
314246 "original": {
315− "owner": "nix-systems",
316− "repo": "default",
247+ "owner": "tloncorp",
248+ "ref": "master",
249+ "repo": "landscape",
317250 "type": "github"
318251 }
319252 },
320− "urbit": {
253+ "silo-urbit": {
321254 "flake": false,
322255 "locked": {
323− "lastModified": 1784122708,
324− "narHash": "sha256-9lrulpAMdMtc9OZ7LeRWHkAgnibLSiDiB+BVwcffiCs=",
256+ "lastModified": 1785851358,
257+ "narHash": "sha256-eHoGwqirk7zMpOn/y8dKqozz5IiQ7nqek/ypxIOaRiU=",
325258 "owner": "urbit",
326259 "repo": "urbit",
327− "rev": "0a9a312e133891937de9c4df1ebecad5cf669c7c",
260+ "rev": "5a187fededc4582a34fcd6055c67bb63e0917b94",
328261 "type": "github"
329262 },
330263 "original": {
331264 "owner": "urbit",
265+ "ref": "408k-2",
332266 "repo": "urbit",
333− "rev": "0a9a312e133891937de9c4df1ebecad5cf669c7c",
334267 "type": "github"
335268 }
336269 },
337− "urbit_2": {
338− "flake": false,
270+ "systems": {
339271 "locked": {
340− "lastModified": 1785851358,
341− "narHash": "sha256-eHoGwqirk7zMpOn/y8dKqozz5IiQ7nqek/ypxIOaRiU=",
342− "owner": "urbit",
343− "repo": "urbit",
344− "rev": "5a187fededc4582a34fcd6055c67bb63e0917b94",
272+ "lastModified": 1681028828,
273+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
274+ "owner": "nix-systems",
275+ "repo": "default",
276+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
345277 "type": "github"
346278 },
347279 "original": {
348− "owner": "urbit",
349− "ref": "408k-2",
350− "repo": "urbit",
280+ "owner": "nix-systems",
281+ "repo": "default",
351282 "type": "github"
352283 }
353284 },
354− "urbit_3": {
285+ "urbit": {
355286 "flake": false,
356287 "locked": {
357− "lastModified": 1785851358,
358− "narHash": "sha256-eHoGwqirk7zMpOn/y8dKqozz5IiQ7nqek/ypxIOaRiU=",
288+ "lastModified": 1784122708,
289+ "narHash": "sha256-9lrulpAMdMtc9OZ7LeRWHkAgnibLSiDiB+BVwcffiCs=",
359290 "owner": "urbit",
360291 "repo": "urbit",
361− "rev": "5a187fededc4582a34fcd6055c67bb63e0917b94",
292+ "rev": "0a9a312e133891937de9c4df1ebecad5cf669c7c",
362293 "type": "github"
363294 },
364295 "original": {
365296 "owner": "urbit",
366− "ref": "408k-2",
367297 "repo": "urbit",
298+ "rev": "0a9a312e133891937de9c4df1ebecad5cf669c7c",
368299 "type": "github"
369300 }
370301 },
371− "urbit_4": {
302+ "urbit_2": {
372303 "flake": false,
373304 "locked": {
374305 "lastModified": 1785851358,
@@ -384,26 +315,6 @@
384315 "repo": "urbit",
385316 "type": "github"
386317 }
387− },
388− "vita": {
389− "inputs": {
390− "landscape": "landscape_3",
391− "nixpkgs": "nixpkgs_3",
392− "urbit": "urbit_4"
393− },
394− "locked": {
395− "lastModified": 1792581006,
396− "narHash": "sha256-6dr0bBsj1nY8YFZJshqhLaeqDZDFvPSXIw3MOJN8Bm0=",
397− "owner": "iko-soy",
398− "repo": "vita",
399− "rev": "dc3554e22e7e68ccb36efcc8cc149561fe95afb8",
400− "type": "github"
401− },
402− "original": {
403− "owner": "iko-soy",
404− "repo": "vita",
405− "type": "github"
406− }
407318 }
408319 },
409320 "root": "root",
flake.nix+50−70
@@ -12,7 +12,7 @@
1212 inputs.flake-utils.follows = "flake-utils";
1313 };
1414
15− # Its packages.<system>.desk is the full desk: it vendors its lib/,
15+ # Its packages.<system>.default is the full desk: it vendors its lib/,
1616 # mar/ and sur/ files.
1717 shelf = {
1818 url = "github:iko-soy/shelf";
@@ -26,10 +26,21 @@
2626 inputs.nixpkgs.follows = "nixpkgs";
2727 };
2828
29− # silo's and vita's flakes build their desks and their globs, with the
30− # nixpkgs they pin, so both come out as their own repos build them.
31− silo.url = "github:iko-soy/silo";
32− vita.url = "github:iko-soy/vita";
29+ silo = {
30+ url = "github:arthyn/silo";
31+ flake = false;
32+ };
33+ # Desk dependencies, as silo's .github/helpers/deploy.sh takes them. It
34+ # takes urbit at a tag from a repo variable; 408k-2 is the release of the
35+ # 408 kernel, the newest silo's sys.kelvin lists.
36+ silo-urbit = {
37+ url = "github:urbit/urbit/408k-2";
38+ flake = false;
39+ };
40+ silo-landscape = {
41+ url = "github:tloncorp/landscape/master";
42+ flake = false;
43+ };
3344
3445 # Its desk/ is the full desk: it vendors its lib/, mar/ and sur/ files.
3546 accountability = {
@@ -60,7 +71,8 @@
6071 shelf,
6172 hits,
6273 silo,
63− vita,
74+ silo-urbit,
75+ silo-landscape,
6476 accountability,
6577 harness,
6678 harness-grubbery,
@@ -96,42 +108,15 @@
96108 };
97109 };
98110
99− # Reads the docket file it's given as the docket mark does, with
100− # `ream` and `slap` in `urbit eval`, so any layout Hoon accepts reads
101− # the same. Exits 0 if it names a glob: a glob-http or glob-ames
102− # clause, and no site clause, which lib/docket prefers. Exits 1 if
103− # it doesn't, and 2 if it isn't a valid docket.
104− names-glob = pkgs.writeShellApplication {
105− name = "names-glob";
106− runtimeInputs = [
107− pkgs.urbit
108− pkgs.util-linux
109− ];
110− excludeShellChecks = [ "SC2016" ];
111− text = ''
112− # the file's bytes as a Hoon @ux literal: an atom, first byte
113− # lowest, with a dot between each group of four hex digits
114− hex=$(od -An -v -tx1 -w1 "$1" | tac | tr -d ' \n' | sed 's/^0*//')
115− atom=0x$(printf '%s' "''${hex:-0}" | rev | sed -E 's/([0-9a-f]{4})/\1./g; s/\.$//' | rev)
116− out=$(
117− {
118− printf '=/ tex `@t`%s\n' "$atom"
119− echo '=/ cls ;;((list [@tas *]) q:(slap !>(~) (ream tex)))'
120− echo '=/ has |=(t=@tas (lien cls |=([h=@tas *] =(h t))))'
121− echo '?&(!(has %site) |((has %glob-http) (has %glob-ames)))'
122− } | urbit eval 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | tr -d '\r'
123− )
124− case $(printf '%s\n' "$out" | tail -n 1) in
125− '%.y') exit 0 ;;
126− '%.n') exit 1 ;;
127− *)
128− echo "$1 isn't a valid docket: Hoon can't read it as a list of clauses" >&2
129− printf '%s\n' "$out" >&2
130− exit 2
131− ;;
132− esac
133− '';
134− };
111+ # Exits 0 if the docket file it's given names a glob: a glob-ames or
112+ # glob-http term outside the docket's cords, tapes and comments,
113+ # however the docket is laid out.
114+ names-glob = pkgs.writers.writePerlBin "names-glob" { } ''
115+ local $/;
116+ my $docket = <>;
117+ $docket =~ s/'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|::[^\n]*//g;
118+ exit($docket =~ /(?<![\w-])glob-(?:ames|http)(?![\w-])/ ? 0 : 1);
119+ '';
135120
136121 # Pack the desk `src` into $out/<desk>.deskjam.
137122 #
@@ -156,19 +141,13 @@
156141 ''
157142 cp -r --no-preserve=mode ${src} ${desk}
158143 glob=${pkgs.lib.optionalString (glob != null) "${glob}"}
159− names=
160− if [ -f ${desk}/desk.docket-0 ]; then
161− if names-glob ${desk}/desk.docket-0; then
162− names=yes
163− elif [ $? != 1 ]; then
144+ if [ -f ${desk}/desk.docket-0 ] && names-glob ${desk}/desk.docket-0; then
145+ if [ -z "$glob" ]; then
146+ echo "The docket of %${desk} names a glob: give mkDeskjam the built frontend as glob" >&2
164147 exit 1
165148 fi
166− fi
167− if [ -n "$names" ] && [ -z "$glob" ]; then
168− echo "The docket of %${desk} names a glob: give mkDeskjam the built frontend as glob" >&2
169− exit 1
170− elif [ -z "$names" ] && [ -n "$glob" ]; then
171− echo "%${desk} has no docket that names a glob, but mkDeskjam got one" >&2
149+ elif [ -n "$glob" ]; then
150+ echo "The docket of %${desk} names no glob, but mkDeskjam got one" >&2
172151 exit 1
173152 fi
174153 mkdir $out
@@ -180,12 +159,12 @@
180159
181160 deskjam-desk = mkDeskjam {
182161 desk = "deskjam";
183− src = deskjam.packages.${system}.desk;
162+ src = deskjam.packages.${system}.deskjam;
184163 };
185164
186165 shelf-desk = mkDeskjam {
187166 desk = "shelf";
188− src = shelf.packages.${system}.desk;
167+ src = shelf.packages.${system}.default;
189168 };
190169
191170 # Build a frontend: `npm run build` in its npm project `src`, whose
@@ -218,16 +197,23 @@
218197 glob = hits-glob;
219198 };
220199
221− silo-desk = mkDeskjam {
200+ silo-glob = mkGlob {
222201 desk = "silo";
223− src = silo.packages.${system}.desk;
224− glob = silo.packages.${system}.glob;
202+ src = "${silo}/ui";
203+ npmDepsHash = "sha256-kZaVn4+ORa9Cm100f8/VS1sCWwHOC6rxDvLnz4S5+p0=";
225204 };
226205
227− vita-desk = mkDeskjam {
228− desk = "vita";
229− src = vita.packages.${system}.default;
230− glob = vita.packages.${system}.glob;
206+ # The desk silo's deploy.sh commits: all of urbit's pkg/base-dev, then
207+ # landscape's desk-dev, then silo's desk/ over them.
208+ silo-desk = mkDeskjam {
209+ desk = "silo";
210+ src = pkgs.runCommand "silo-desk" { } ''
211+ mkdir $out
212+ cp -rL --no-preserve=mode ${silo-urbit}/pkg/base-dev/. $out/
213+ cp -rL --no-preserve=mode ${silo-landscape}/desk-dev/. $out/
214+ cp -rL --no-preserve=mode ${silo}/desk/. $out/
215+ '';
216+ glob = silo-glob;
231217 };
232218
233219 accountability-desk = mkDeskjam {
@@ -261,7 +247,7 @@
261247 case $1 in
262248 init | remote) ;;
263249 cat-file) pinned "''${3%"^{commit}"}" ;;
264− checkout | fetch) for arg; do :; done; pinned "$arg" ;;
250+ checkout) for arg; do :; done; pinned "$arg" ;;
265251 show) pinned "''${2%%:*}"; cat "$src/''${2#*:}" ;;
266252 *) echo "git: unexpected command: $*" >&2; exit 1 ;;
267253 esac
@@ -300,16 +286,12 @@
300286 runHook postBuild
301287 '';
302288 installPhase = ''
303− runHook preInstall
304289 if [ ! -f zig-out/web/index.html ]; then
305290 echo "harness' desk has no web/index.html: its frontend is missing" >&2
306291 exit 1
307292 fi
308293 cp -r zig-out $out
309− runHook postInstall
310294 '';
311− # the output is a desk: leave its files as they are
312− dontFixup = true;
313295 };
314296
315297 harness-desk = mkDeskjam {
@@ -325,9 +307,7 @@
325307 hits = hits-desk;
326308 inherit hits-glob;
327309 silo = silo-desk;
328− silo-glob = silo.packages.${system}.glob;
329− vita = vita-desk;
330− vita-glob = vita.packages.${system}.glob;
310+ inherit silo-glob;
331311 accountability = accountability-desk;
332312 harness = harness-desk;
333313 default = jammer;