@@ -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.