@@ -0,0 +1,182 @@
1+# urbit-apps
2+
3+Urbit apps, built with Nix as deskjam files. An app lives on your ship as a
4+desk, a folder of its code and files, and a deskjam is a whole desk in one
5+file. You install it in your ship's web interface with
6+[deskjam](https://github.com/iko-soy/deskjam), without access to the ship's
7+files.
8+
9+## Apps
10+
11+| App | Description | Source | Build |
12+|---|---|---|---|
13+| `%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` |
14+| `%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. 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` |
15+| `%mcp` | An MCP (Model Context Protocol) server at `/mcp` that lets AI tools use your ship, and a proxy at `/apps/mcp/mcp` that offers its tools together with those of remote MCP and OpenAPI servers. A fork of [gwbtc/urbit-mcp](https://github.com/gwbtc/urbit-mcp). | [tloncorp/mcp](https://github.com/tloncorp/mcp) | `nix build .#mcp` |
16+| `%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` |
17+| `%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` |
18+
19+Run the build commands in a checkout of this repo, with Nix and flakes
20+enabled. If flakes aren't enabled, put
21+`--extra-experimental-features 'nix-command flakes'` after `nix`. Without a
22+checkout, give the repo's address instead of `.`, such as
23+`nix build github:iko-soy/urbit-apps#shelf`. Nix fetches each app's source
24+itself, at the version `flake.lock` pins.
25+
26+Each build writes `result/<desk>.deskjam`, such as `result/shelf.deskjam`, in
27+place of the last build's `result`. For an app with a web frontend, a glob,
28+it also writes the glob's files next to it, as `result/<desk>-glob`, and the
29+build fails if `flake.nix` doesn't build them, so a deskjam never comes
30+without its glob. `nix build .#hits-glob` or `.#silo-glob` builds just a glob.
31+`nix build .#deskjam .#hits .#mcp .#shelf .#silo` builds all five, into
32+`result`, `result-1`, `result-2`, `result-3` and `result-4`.
33+
34+You can install these files on your ship with
35+[iko-soy/deskjam](https://github.com/iko-soy/deskjam): see
36+[Installing with deskjam](#installing-with-deskjam).
37+
38+The first build also compiles [jammer](#jammer), the tool that packs the
39+desks. No Hoon is compiled: your ship compiles an app's Hoon when you install
40+it. The flake supports `x86_64-linux`, `aarch64-linux` and `aarch64-darwin`
41+(Apple silicon Macs).
42+
43+## Installing with deskjam
44+
45+[deskjam](https://github.com/iko-soy/deskjam) installs and updates apps from
46+these files. Only install apps you trust: an app's agents, its programs, run
47+as your ship, and can read and change anything on it.
48+
49+If you build on another machine, such as the server your ship runs on, copy
50+the file to the computer your browser runs on first, for example with `scp`.
51+
52+### Getting deskjam
53+
54+deskjam has to be on your ship first, and it can't install itself on a ship
55+that doesn't have it yet. The first time, do one of these:
56+
57+- If you can reach your ship's files, follow deskjam's
58+ [Installation](https://github.com/iko-soy/deskjam#installation).
59+- If another ship publishes it, run `|install ~that-ship %deskjam` in the
60+ dojo, your ship's command line.
61+- If your ship runs upstream deskjam,
62+ [tinnus-napbus/deskjam](https://github.com/tinnus-napbus/deskjam), upload
63+ `result/deskjam.deskjam` through it, following
64+ [Replacing upstream deskjam](https://github.com/iko-soy/deskjam#replacing-upstream-deskjam)
65+ from its step 2. Its pages differ from the steps below. First run
66+ `+vats %deskjam` in the dojo: if its source ship isn't `~`, run
67+ `|pause %deskjam`, or that ship's next release replaces this version. When
68+ you upload, choose `deskjam` under **Stage a desk to merge with**, since
69+ that list starts on whichever desk comes first.
70+
71+After that, update deskjam like any other app, as below.
72+
73+### Installing an app
74+
75+1. Open `https://your-ship/apps/deskjam`.
76+2. Under **upload deskjam**, choose the file, such as `result/shelf.deskjam`,
77+ and click **upload**.
78+3. Under **Install it as a new desk**, keep the name and click **next**.
79+4. On the confirm page, tick **start its agents after uploading** (for an app
80+ without agents, such as silo, **mark it running after uploading**), and
81+ click **confirm**.
82+5. The status page says whether the app runs.
83+
84+Once it runs, see the app's README for how to set it up. mcp's README
85+describes an operator console at `/apps/mcp/`, which this version of mcp
86+doesn't have. MCP clients send mcp's API key in an `X-Api-Key` header, and
87+`.^(@t %gx /=mcp-proxy=/client-key/noun)` in the dojo prints it.
88+
89+### Updating an app
90+
91+Apps installed this way don't update on their own. To update one:
92+
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.
96+2. Upload the new file as above. Under **Update an existing desk**, choose the
97+ app's desk, select **replace it**, and click **next**. Replace makes the
98+ desk exactly the upload, so files a new version removed don't linger.
99+3. The confirm page offers a download of the desk as it is now. Keep it if
100+ you might want to go back, then click **confirm**.
101+
102+Uploading the kept copy with **replace it** puts the old version back. If the
103+update changed the state an agent keeps, that usually fails, and nothing
104+changes. But some agents start afresh from state they can't read, and lose it
105+instead: deskjam's and mcp's do. For mcp, that means a new API key, and its
106+remote servers and OAuth grants are gone.
107+
108+If the app came from another ship with `|install`, kiln, the part of your
109+ship that installs and updates apps, keeps it in sync with that ship. That
110+ship's next release would undo your upload. Tick **stop kiln syncing** on the
111+confirm page to keep yours. That stops all of that ship's updates to the
112+desk, until you run `|install ~that-ship %desk` again, which replaces your
113+upload with their latest release.
114+
115+### Frontends
116+
117+An app's web frontend, its glob, isn't part of its desk. Landscape's
118+`%docket` agent gets it as the app's docket says, and the build puts it next
119+to the deskjam, as `result/<desk>-glob`:
120+
121+- silo's docket has `%docket` download its glob from a url, so `silo.deskjam`
122+ works on any ship. You need `result/silo-glob` only to serve the frontend
123+ from your own ship instead, as deskjam's
124+ [Serving a glob from your ship](https://github.com/iko-soy/deskjam/blob/main/docs/globs.md#serving-a-glob-from-your-ship)
125+ says.
126+- hits' docket has `%docket` get its glob from `~donmec-sallud` over Ames,
127+ with a placeholder hash, so `hits.deskjam` is for that ship. There, install
128+ it, then open `/docket/upload`, choose the desk `hits` and the folder
129+ `result/hits-glob`, and click **glob!**. When you update hits with deskjam,
130+ click **set** in the glob box on the confirm page first, or hits loses its
131+ frontend until you upload it again. Other ships get hits, frontend
132+ included, from that ship once it publishes hits:
133+ `|install ~donmec-sallud %hits`.
134+
135+### Kernel updates
136+
137+When Urbit releases a new kernel, your ship suspends every app whose
138+`sys.kelvin` doesn't list it, and a suspended deskjam can't upload its own
139+update. So as soon as deskjam's `desk/sys.kelvin` lists the new kernel,
140+update deskjam as above, before your ship upgrades. Do the same for the other
141+apps, or they stay suspended until you do. See deskjam's
142+[Kernel updates](https://github.com/iko-soy/deskjam#kernel-updates).
143+
144+deskjam's
145+[Deploying an app](https://github.com/iko-soy/deskjam/blob/main/docs/deploying.md)
146+has the details, including what to do when an upload goes wrong.
147+
148+## How the desks are built
149+
150+- deskjam's, hits' and shelf's own flakes build their desks, so each
151+ `.deskjam` file has the files that repo's own build makes. jammer leaves
152+ out the files a `|commit` would skip too, such as hits' `LICENSE`, which has
153+ no extension.
154+- mcp's repo builds its desk with `zig build`, which copies some files from
155+ other repos at pinned commits. `flake.nix` copies the same files from the
156+ same commits. After moving mcp's pin, check that its `build.zig` still lists
157+ the same files and commits, and change `flake.nix` to match if not: nothing
158+ checks this for you.
159+- silo has no flake. Its CI deploys all of urbit's `pkg/base-dev`, then
160+ landscape's `desk-dev`, then its own `desk/`, and `flake.nix` builds the
161+ same, with landscape at `master`, as the CI takes it, and urbit at
162+ `408k-2`, since the CI's tag isn't public. After moving silo's pin, check
163+ its `.github/helpers/deploy.sh`.
164+- A desk whose docket names a glob only builds with its glob, which
165+ `flake.nix` builds from the app's `ui/`. A glob for a desk whose docket
166+ names none fails the build too.
167+
168+## jammer
169+
170+[`jammer/`](jammer/README.md) is the command-line tool that packs each desk.
171+It packs any desk directory into a deskjam, and unpacks deskjams, without a
172+ship:
173+
174+```console
175+$ nix run . -- jam path/to/desk -d my-app # writes my-app.deskjam
176+$ nix run . -- unjam result/shelf.deskjam # writes ./shelf/
177+$ nix run . -- list result/shelf.deskjam
178+```
179+
180+These write into the current directory. To keep their output out of this
181+repo, run jammer elsewhere: `nix shell .` puts it on your PATH. `nix develop`
182+gives you a shell with the Rust toolchain for working on it.