on master help sign in
4 files changed+151−23
since splitsnapshots
unifiedsplit
AGENTS.md+121 CLAUDE.md+1 README.md+26−20 flake.lock+3−3
AGENTS.mdnew file+121
@@ -0,0 +1,121 @@
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.mdnew file+1
@@ -0,0 +1 @@
1+AGENTS.md
README.md+26−20
@@ -10,27 +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 .#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 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 .#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 .#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. 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 .#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 .#vita` |
20−
21−Run the build commands in a checkout of this repo, with Nix and flakes
22−enabled. If flakes aren't enabled, put
23−`--extra-experimental-features 'nix-command flakes'` after `nix`. Without a
24−checkout, give the repo's address instead of `.`, such as
25−`nix build github:iko-soy/urbit-apps#shelf`. Nix fetches each app's source
26−itself, at the version `flake.lock` pins.
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`.
2727
2828Each build writes `result/<desk>.deskjam`, such as `result/shelf.deskjam`, in
2929place of the last build's `result`. For an app whose web frontend is a glob,
3030such as hits, it also writes the glob's files next to it, as
3131`result/<desk>-glob`, and the build fails if `flake.nix` doesn't build them,
32−so a deskjam never comes without its glob. `nix build .#hits-glob`,
33−`.#silo-glob` or `.#vita-glob` builds just a glob.
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,
3435`nix build .#accountability .#deskjam .#harness .#hits .#shelf .#silo .#vita`
3536builds all seven, in that order, into `result` and `result-1` to `result-6`.
3637The steps below assume one app's `result`.
@@ -93,9 +94,13 @@ Once it runs, see the app's README for how to set it up.
9394
9495Apps installed this way don't update on their own. To update one:
9596
96−1. Move its pin to the latest commit of its repo, such as with
97− `nix flake update shelf`, and build it again. `nix flake update` moves
98− every app, and nixpkgs.
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.
991042. Upload the new file as above. Under **Update an existing desk**, choose the
100105 app's desk, select **replace it**, and click **next**. Replace makes the
101106 desk exactly the upload, so files a new version removed don't linger.
@@ -176,7 +181,8 @@ has the details, including what to do when an upload goes wrong.
176181 leaves out the files a `|commit` would skip too, such as hits' `LICENSE`,
177182 which has no extension. silo's and vita's flakes build their globs too, and
178183 this flake takes them as they are, with the nixpkgs those flakes pin: so
179− `.#silo-glob` is the same build as `github:iko-soy/silo#glob`. Their desks
184+ `github:iko-soy/urbit-apps#silo-glob` is the same build as
185+ `github:iko-soy/silo#glob`. Their desks
180186 include all of urbit's base-dev, so deskjam's confirm page warns about a
181187 few of its libraries that import files the desks lack, but the apps don't
182188 use them.
flake.lock+3−3
@@ -29,11 +29,11 @@
2929 "urbit": "urbit"
3030 },
3131 "locked": {
32− "lastModified": 1792580792,
33− "narHash": "sha256-fC9y1fVJUZaUqahGyMzzBEXgwd6gOfr9cDbc4aaXpe4=",
32+ "lastModified": 1792584136,
33+ "narHash": "sha256-YnMsLXViNtQi+B029JFuVFYM8IzjGxPQLUCOPjlaktQ=",
3434 "owner": "iko-soy",
3535 "repo": "deskjam",
36− "rev": "d892252eafc5522c9c95a758148c9b3f86e8a857",
36+ "rev": "d0bb6b31803336e66a19ee6daeedd98a02813bd4",
3737 "type": "github"
3838 },
3939 "original": {