@@ -1,68 +1,63 @@
11+++
22title = "Toward a New %clay"
3−date = "2016-07-13"
3+date = 2016-07-14
44description = "Urbit's revision-control system, %clay, is itself due for a (medium-sized) revision!"
5−aliases = [
6− "/posts/essays/toward-a-new-clay",
7− "/posts/toward-a-new-clay",
8− "/blog/clay"
9−]
10−
5+aliases = ["/posts/essays/toward-a-new-clay", "/posts/toward-a-new-clay", "/blog/clay"]
116[extra]
127author = "Curtis Yarvin"
138ship = "~sorreg-namtyv"
149+++
1510
1611TLDR: (a) Urbit's revision-control system, `%clay`, is itself due
17−for a (medium-sized) revision! (b) this time, you yourself can
18−really help! (c) please don't give away the buried spoiler!
12+for a (medium-sized) revision! (b) this time, you yourself can
13+really help! (c) please don't give away the buried spoiler!
1914
2015This explanation does not (or at least should not) require you to
2116know anything about Urbit.
2217
2318### But %clay is already pretty cool
2419
25−Of course, nothing in Urbit is allowed to be _lame_. `%clay` is
26−actually quite cool. It does need some work. But first, let's
20+Of course, nothing in Urbit is allowed to be _lame_. `%clay` is
21+actually quite cool. It does need some work. But first, let's
2722talk about what it is and why it's cool.
2823
2924`%clay` is the Arvo vane (Urbit kernel module) for revision
30−control. It's an authenticated, human-memorable global immutable
31−namespace which is also a typed revision-control system. It's
32−also very good at subscription and synchronization. Urbit
25+control. It's an authenticated, human-memorable global immutable
26+namespace which is also a typed revision-control system. It's
27+also very good at subscription and synchronization. Urbit
3328currently uses `%clay` to distribute live hotpatches; we
3429transparently upgrade the whole network with one checkin.
3530
3631### Compared to other revision-control systems
3732
38−`%clay` is clearly a vanilla DVCS in the modern `git` style. Of
33+`%clay` is clearly a vanilla DVCS in the modern `git` style. Of
3934deployed DVCS these days, `%clay` is probably closest in spirit
4035to `bzr` or maybe `fossil`.
4136
4237Obviously, as a part of a larger whole, you would expect any
43−Urbit RCS to be brutally spartan. `%clay` is. It's even more
38+Urbit RCS to be brutally spartan. `%clay` is. It's even more
4439spartan than `bzr`.
4540
46−(In fact, it's really too spartan to fully use at the moment. We
41+(In fact, it's really too spartan to fully use at the moment. We
4742ourselves still use `%clay` mainly as a distribution system, and
48−do all internal development on GitHub. This is because the
43+do all internal development on GitHub. This is because the
4944present `%clay` lacks a few little conveniences, like commit
50−messages. See upgrades, below.)
45+messages. See upgrades, below.)
5146
52−There are lots of normal DVCS things in `%clay`. But there are
53−also cool and unusual ones. Let's take a brief tour of the
47+There are lots of normal DVCS things in `%clay`. But there are
48+also cool and unusual ones. Let's take a brief tour of the
5449high-level system, then describe what we think should change
5550about it.
5651
5752### Anatomy of a DVCS
5853
59−A DVCS is a historical state graph. A point in this graph is a
54+A DVCS is a historical state graph. A point in this graph is a
6055snapshot of some tree-structured system, like a filesystem.
6156
6257These snapshots, including recursive internal nodes, are stored in
63−a content-addressable store. Pointers in this store are used to
58+a content-addressable store. Pointers in this store are used to
6459construct a revision graph, whose edges are edit and/or merge
65−actions. Some sort of namespace attaches meaningful names to
60+actions. Some sort of namespace attaches meaningful names to
6661current revisions in this graph.
6762
6863There are six big questions in the design of a DVCS:
@@ -78,16 +73,16 @@ There are six big questions in the design of a DVCS:
7873
7974A good way to summarize `%clay` (at present) is that its answers
8075to the first four questions are interesting, and its answers to
81−the last two are boring. We'll talk about all six, though.
76+the last two are boring. We'll talk about all six, though.
8277
8378### Global namespace: [ship desk case]
8479
85−The permanent global name of a `%clay` snapshot is a `++beak`. A beak
80+The permanent global name of a `%clay` snapshot is a `++beak`. A beak
8681is a triple: `[ship desk case]`.
8782
88−The `++ship` is an Urbit ship. A ship is a network address, a
89−human-memorable name and a cryptographic identity. The address
90−width is variable; shorter addresses are more desirable. Most
83+The `++ship` is an Urbit ship. A ship is a network address, a
84+human-memorable name and a cryptographic identity. The address
85+width is variable; shorter addresses are more desirable. Most
9186users have 32-bit addresses, which we map to four-syllable
9287synthetic names like `~sorreg-namtyv`.
9388
@@ -100,44 +95,44 @@ In the Urbit path syntax, the beak is the first three segments of
10095the path: `/ship/desk/case/my/cat/picture`.
10196
10297In most cases, a path parser has a default ship, desk and case,
103−each of which can be replaced by `=`. So `/=home=/my/cat/picture`
98+each of which can be replaced by `=`. So `/=home=/my/cat/picture`
10499is the data at `/my/cat/picture` on your own ship, in the `%home`
105−desk, right now. Immutability doesn't have to be inconvenient.
100+desk, right now. Immutability doesn't have to be inconvenient.
106101
107−`%clay` has no concept of a mutable name or a magic `HEAD`. Use
108−the current date. If you're referring to remote data and you're
102+`%clay` has no concept of a mutable name or a magic `HEAD`. Use
103+the current date. If you're referring to remote data and you're
109104worried about clock skew, subtract a second or three, or be
110−prepared to block. (Or keep your clock unskewed, which shouldn't
111−be _that_ hard.) It's not like mutable-name schemes work any
105+prepared to block. (Or keep your clock unskewed, which shouldn't
106+be _that_ hard.) It's not like mutable-name schemes work any
112107better than this anyway.
113108
114−(Immutability is central to `%clay`. `git` merely adopted the
115−reflog. `%clay` was born in it, molded by it...)
109+(Immutability is central to `%clay`. `git` merely adopted the
110+reflog. `%clay` was born in it, molded by it...)
116111
117112`%clay` is objective; each Urbit node hosts only one ship, but
118−treats domestic and foreign data (almost) the same way. If you
113+treats domestic and foreign data (almost) the same way. If you
119114ask your `%clay` repository for someone else's data, it will
120115block the request until it gets the data, which it then caches.
121116At present, we always fulfill requests from the origin ship,
122117though in future we could certainly use it as a tracker.
123118
124119If `%clay` discards cached data, it keeps a hash, so that your
125−urbit can't violate the local illusion of immutability. We
120+urbit can't violate the local illusion of immutability. We
126121can't, of course, prevent anyone else's ship from sending
127−conflicting claims in different directions. But we can prevent
122+conflicting claims in different directions. But we can prevent
128123programs on our own ship from hearing about them, meaning that we
129124retain local referential transparency.
130125
131126### Local structure: dome, arch, leaf and mark
132127
133−A `%clay` snapshot is called a `++dome`. A dome is the `%clay`
128+A `%clay` snapshot is called a `++dome`. A dome is the `%clay`
134129equivalent of a tree-structured filesystem.
135130
136131Each node in this tree is one uniform structure, an `++arch`,
137−which is both file and directory. A `++leaf` or data value in
132+which is both file and directory. A `++leaf` or data value in
138133this arch is a typed document.
139134
140−A logical document type is called a `++mark`. A mark is a
135+A logical document type is called a `++mark`. A mark is a
141136symbolic pointer to a Hoon source file, in the same dome, for an
142137engine that can validate, compare, and/or convert
143138documents of that mark.
@@ -146,8 +141,8 @@ Let's go over arches and marks a little more closely...
146141
147142#### An arch is a uniform filesystem node
148143
149−Most filesystems and RCS have modal nodes. For instance, a git
150−data node can be a blob or a tree. `%clay` (and the Urbit
144+Most filesystems and RCS have modal nodes. For instance, a git
145+data node can be a blob or a tree. `%clay` (and the Urbit
151146namespace in general) has one kind of node, an `arch`:
152147
153148```
@@ -156,24 +151,24 @@ namespace in general) has one kind of node, an `arch`:
156151```
157152
158153An arch has an optional typed-data leaf, and optional named
159−children. In Unix terms, it's a file, a directory, or both. It
154+children. In Unix terms, it's a file, a directory, or both. It
160155can't be neither: an empty arch, with no data and no children, is
161−auto-pruned. As in `git` (but not in Unix), the hierarchy is a
162−pure function of its leaves. Paths exist only because of the
156+auto-pruned. As in `git` (but not in Unix), the hierarchy is a
157+pure function of its leaves. Paths exist only because of the
163158data they point to.
164159
165160The `++knot` names in an arch path are also a little special.
166161They're typed, in a sense; any knot can be parsed invertibly into
167−a typed atom. The atom is an arbitrary unsigned integer. Its
162+a typed atom. The atom is an arbitrary unsigned integer. Its
168163type (an `++aura` if you know Hoon) defines the semantics and
169164presentation of the atom: for instance, a symbol, a decimal,
170165a date, etc.
171166
172167Ultimately a filesystem is a database, and a path is a primary
173−key. It's very useful to be able to store simple data in this
168+key. It's very useful to be able to store simple data in this
174169key, in a standard and unambiguous way.
175170
176−Why uniform nodes? One, they map nicely to information trees
171+Why uniform nodes? One, they map nicely to information trees
177172where a subtree may need some custom collective presentation,
178173not an automatically generated Apache style directory listing.
179174Two, non-uniform nodes introduce a whole pointless category of
@@ -181,34 +176,34 @@ node type conflicts -- for which life is far too short.
181176
182177#### A mark is an executable document type
183178
184−A mark is "like an executable MIME type." It's best defined as a
179+A mark is "like an executable MIME type." It's best defined as a
185180symbolic mapping from a filesystem to a schema engine.
186181
187182If you have a MIME type `text/html`, you need to watch the
188−Internets to track what the W3C thinks HTML is. If you have an
183+Internets to track what the W3C thinks HTML is. If you have an
189184Urbit mark `%html`, you can functionally construct (using our
190185insanely powerful functional build vane `%ford`) a core which
191186can validate or normalize HTML, apply patch and diff logic, and
192−translate to and from other marks. `%ford` can even reason about
187+translate to and from other marks. `%ford` can even reason about
193188translation paths and construct multistep conversions.
194189
195190(Urbit does not actually have this super-smart `%html` mark right
196−now. But it probably should, huh. And this page was composed in
191+now. But it probably should, huh. And this page was composed in
197192Markdown and translated to HTML by `%ford`.)
198193
199−Where does the source code of a mark live? Within the same dome
200−as the data it describes. `%html` files are described by the
194+Where does the source code of a mark live? Within the same dome
195+as the data it describes. `%html` files are described by the
201196Hoon source at `/===/mar/html`, which perhaps gets mapped into
202197your Unix filesystem at `$ship/home/mar/html.hoon`.
203198
204−This Hoon file is not self-contained. It has dependencies. The
199+This Hoon file is not self-contained. It has dependencies. The
205200`%html` mark may depend on various structures and libraries
206−elsewhere in Urbit. But the source code for all them is within
201+elsewhere in Urbit. But the source code for all them is within
207202this dome.
208203
209204One constraint this puts on domes is that _all domes are
210−descendants of the base system dome_. Domes are versions of one
211−reality, not fragments of that reality. You can't create a new
205+descendants of the base system dome_. Domes are versions of one
206+reality, not fragments of that reality. You can't create a new
212207empty dome -- you'd have no mark source, and be unable to install
213208any validated files.
214209
@@ -219,13 +214,13 @@ weird collisions between non-parallel things don't happen.
219214
220215### Unix mapping and mounting
221216
222−Every DVCS is its own filesystem in a sense. But every DVCS
217+Every DVCS is its own filesystem in a sense. But every DVCS
223218works by mapping and mounting itself, in some sense, to Unix.
224219
225220#### Mapping arches to Unix
226221
227−How do we map arches into Unix? The arch structure maps 1:1 to
228−the Unix directory tree. When the arch has a leaf, we derive a
222+How do we map arches into Unix? The arch structure maps 1:1 to
223+the Unix directory tree. When the arch has a leaf, we derive a
229224dot extension from the file's mark.
230225
231226So, supposing we have a leaf `foo` which is an HTML document
@@ -239,19 +234,19 @@ foo/moo.html
239234```
240235
241236This maps invertibly back into `%clay`, and it looks perfectly
242−unremarkable from the Unix side. File completion sometimes gets
237+unremarkable from the Unix side. File completion sometimes gets
243238a little annoying.
244239
245240It would be if nice every possible Unix tree, even every
246241plausible Unix tree, mapped cleanly and completely to a `%clay`
247−dome. There are always horrid exceptions, even in common use --
248−like extensionless Makefiles. The trivial solution is that if
242+dome. There are always horrid exceptions, even in common use --
243+like extensionless Makefiles. The trivial solution is that if
249244`%clay` finds a file mysterious, it won't track it.
250245
251246One often unquestioned assumption in new system software is that
252−compatibility with old content is important. It's nice, but not
253−that important. Most content in a new system is new content.
254−The important compatibility direction is export, not import. So
247+compatibility with old content is important. It's nice, but not
248+that important. Most content in a new system is new content.
249+The important compatibility direction is export, not import. So
255250the new system should subset, not superset, the ancient formats.
256251
257252### Mounting desks to Unix
@@ -262,36 +257,36 @@ the Unix directory of the same name within the pier.
262257When files in a mount directory change, `%clay` notices it
263258through `libuv` filesystem watching (ultimately `inotify()` or
264259`FSEvents`), computes diffs, and automatically commits them to
265−the desk. And if `%clay` creates a new version for its own
260+the desk. And if `%clay` creates a new version for its own
266261urbity reasons, it will revise the Unix files.
267262
268263Keeping all mounted files in the same Unix subdirectory makes it
269−easy to move the whole pier in a tarfile. Edits applied while
264+easy to move the whole pier in a tarfile. Edits applied while
270265the `urbit` process isn't running will be detected and applied
271266the next time it starts.
272267
273268In conventional DVCS terms, `%clay` has a 1:1 static mapping from
274−branches to working directories. Why?
269+branches to working directories. Why?
275270
276−Why not? Do we need that "what branches are checked out in what
277−directories" piece of state? Why force the user to worry about
278−which branches are mounted to which directories? Why not just
279−mount them under their own names? Is there some crippling global
271+Why not? Do we need that "what branches are checked out in what
272+directories" piece of state? Why force the user to worry about
273+which branches are mounted to which directories? Why not just
274+mount them under their own names? Is there some crippling global
280275shortage of disk space for source files? Our planet is running
281−out of inodes? Wut?
276+out of inodes? Wut?
282277
283278### Queries, subscriptions and synchronization
284279
285280There are two ways to get data out of `%clay`: dereference the Urbit
286−namespace, or send a request/subscription. Sync is in userspace.
281+namespace, or send a request/subscription. Sync is in userspace.
287282
288283#### Dereferencing the namespace
289284
290−`%clay` is just part of the full Urbit namespace. The full namespace
285+`%clay` is just part of the full Urbit namespace. The full namespace
291286has a two-character prefix which expresses what vane to query
292−(always `%c` for `%clay`). The suffix is a mode flag; `%x` for
287+(always `%c` for `%clay`). The suffix is a mode flag; `%x` for
293288data, `%y` for a list of children, `%z` for the whole arch
294−subtree, `%w` for the version number. (Each vane has its own
289+subtree, `%w` for the version number. (Each vane has its own
295290modes.)
296291
297292For example, the full path to my cat picture is
@@ -305,7 +300,6 @@ For example, the full path to my cat picture is
305300If the data model is `++image` (hypothetical -- we don't really
306301do image processing in Urbit right now), the normal way to load
307302this data in a Hoon program is
308−
309303```
310304.^(image /cx/~sorreg-namtyv/home/[now]/my/cat/picture)
311305```
@@ -322,15 +316,15 @@ learn it in future, `[~ ~]` if we know we'll never know it, or
322316`[~ ~ value]` if we know it now.
323317
324318In high-level shell programming (`:dojo`), we can make apparently
325−"blocking" requests to `%clay`. What actually happens: when `%clay`
319+"blocking" requests to `%clay`. What actually happens: when `%clay`
326320produces `~`, we stop trying to compute this expression and wait
327−on one or more blocking requests. When we are unblocked, we
321+on one or more blocking requests. When we are unblocked, we
328322recompute again from scratch; the intermediate computation is not
329323saved at all.
330324
331−Urbit doesn't like to block. It likes to save coherent data
332−structures, not incomplete computation contexts. When Urbit
333−pretends to block for you, this is a courtesy service. You
325+Urbit doesn't like to block. It likes to save coherent data
326+structures, not incomplete computation contexts. When Urbit
327+pretends to block for you, this is a courtesy service. You
334328can return the courtesy of not expecting miracles from it.
335329When in doubt, send an actual request.
336330
@@ -341,7 +335,7 @@ namespace, but can (a) read across case (revision) ranges,
341335and (b) filter by subtree.
342336
343337If the revision range in a request stretches into the future, the
344−request becomes a subscription. Urbit messaging always regards a
338+request becomes a subscription. Urbit messaging always regards a
345339single response as a special case of a subscription.
346340
347341Generally, the response stream created by a request starts with
@@ -351,10 +345,10 @@ closed when the request range is complete.
351345
352346#### Userspace synchronization
353347
354−Synchronization per se is done in userspace. In `%clay`, sync just
348+Synchronization per se is done in userspace. In `%clay`, sync just
355349means an application (typically the `%kiln` module in the system
356350app `:hood`) subscribes to a remote desk, and saves its change
357−stream locally. So sync is really an emergent feature of `%clay`.
351+stream locally. So sync is really an emergent feature of `%clay`.
358352
359353### Revision graph
360354
@@ -362,16 +356,16 @@ stream locally. So sync is really an emergent feature of `%clay`.
362356Some changes are proposed below, however.
363357
364358As in any DVCS, a dome is the child of one parent dome (an edit)
365−or more parents (a merge). Often the parent of any revision is
359+or more parents (a merge). Often the parent of any revision is
366360the previous version in the sequence, but it can be anything.
367361
368362### Storage model
369363
370−`%clay`'s storage model is completely uninteresting. It's also a
364+`%clay`'s storage model is completely uninteresting. It's also a
371365little funky and I want to change it, so I'll be super vague.
372366
373367A `++lobe`, a 128-bit atom, is the Merkle hash of a `blob`, which
374−is essentially a leaf. All blobs are stored in a hash table
368+is essentially a leaf. All blobs are stored in a hash table
375369(`(map lobe blob)`), and reference each other through lobes.
376370
377371At present we don't GC this space at all, because we don't
@@ -380,12 +374,12 @@ actually delete any roots.
380374A `blob` may be `%direct`, meaning it's defined as the data
381375itself, or `%delta`, defined as a change against another blob.
382376This is motivated by the desire not to store a full snapshot
383−on every file change. But it may be misguided (see changes #0
377+on every file change. But it may be misguided (see changes #0
384378and #1 below).
385379
386380We cache the full arch tree (`++ankh`) of the latest state in
387−each desk. For current queries, this mitigates a lot of the
388−opportunities for slowness that this data model creates. But the
381+each desk. For current queries, this mitigates a lot of the
382+opportunities for slowness that this data model creates. But the
389383disparity between the speed of the current version and the
390384speed previous version is an undesirable glitch in the API.
391385
@@ -397,38 +391,38 @@ We actually have _three_ motivations for change...
397391
398392At present, we're still using `git` as a development platform.
399393`%clay` is certainly used, but just for its strength --
400−deployment. This is starving Urbit of essential experience and
401−basically keeping it lame. So, change is necessary.
394+deployment. This is starving Urbit of essential experience and
395+basically keeping it lame. So, change is necessary.
402396
403397### Change must come from the community
404398
405−"Why?" you ask? "Why must change come from the community?" Well,
406−one, duh. Change always comes from the community.
399+"Why?" you ask? "Why must change come from the community?" Well,
400+one, duh. Change always comes from the community.
407401
408−But two, a great force for change has departed. Philip Monk,
402+But two, a great force for change has departed. Philip Monk,
409403late maintainer of `%clay` (`~wictuc-folrex` in the old era,
410−`~wicdev-wisryt` in the new), is tired of types and typing. He
404+`~wicdev-wisryt` in the new), is tired of types and typing. He
411405spent September roaming with the bison in Montana, and is now
412−literally on his way to Patagonia. On the one hand, Phil still
406+literally on his way to Patagonia. On the one hand, Phil still
413407exists and is not at all unwilling to answer questions, even dumb
414−questions. On the other hand, _Patagonia_.
408+questions. On the other hand, _Patagonia_.
415409
416−So %clay needs a new owner, or owners. At this point, we think
410+So %clay needs a new owner, or owners. At this point, we think
417411the community might be indoctrinated enough to take a stab.
418412
419413Alas, `%clay` already has a pretty checkered ownership history.
420414Long ago I built a `%clay` that was really the only serious
421−design failure in Arvo. Then Jared Hance, a brilliant summer
415+design failure in Arvo. Then Jared Hance, a brilliant summer
422416intern, took my broken `%clay` and reformed it into a minimal `git`
423−in about a week. Then Philip modified Jared's `%clay` to be a
417+in about a week. Then Philip modified Jared's `%clay` to be a
424418_typed_ revision-control system, which is a pretty cool thing.
425419
426420But... in none of these transitions did `%clay` actually get
427−_rewritten_ per se. While it's a reasonably good vane, it
421+_rewritten_ per se. While it's a reasonably good vane, it
428422does contain one or two historical decisions.
429423
430424We know a lot more about Arvo than we used to, and I think we can
431−revisit many of these decisions. The point of this post is to
425+revisit many of these decisions. The point of this post is to
432426start a `%clay` design discussion that will evolve into actual
433427collective action.
434428
@@ -438,41 +432,41 @@ We're planning a rewards program for contributions to `%clay`.
438432It'll simply involve setting a time period and a pool of real
439433estate, and allocating the pool by judged contribution.
440434
441−This is an experimental program. We'll say more about it later.
442−It may not even happen. It may happen very differently. When in
435+This is an experimental program. We'll say more about it later.
436+It may not even happen. It may happen very differently. When in
443437doubt, don't talk about Fight Club.
444438
445439## Some openings for change
446440
447−Change, of course, must come from the community. No one can
448−dictate change from the top down. We _know_ this. But...
441+Change, of course, must come from the community. No one can
442+dictate change from the top down. We _know_ this. But...
449443
450444This list of suggested changes for the next `%clay` is not in any
451−sort of order: priority, structure, difficulty, etc. Let's talk
452−about the changes first; make actual plans second. The numbers
445+sort of order: priority, structure, difficulty, etc. Let's talk
446+about the changes first; make actual plans second. The numbers
453447here are just for convenience.
454448
455−_All changes in this program will happen on the next-generation
456−(`cc-release`) branch._
449+*All changes in this program will happen on the next-generation
450+(`cc-release`) branch.*
457451
458452### Change #0: state reform
459453
460454As mentioned above, the storage model in `%clay`, as the code is
461−at present, feels a little funky to me. There's nothing terribly
455+at present, feels a little funky to me. There's nothing terribly
462456awful about it, but it doesn't feel quite right and its scaling
463457properties are very questionable.
464458
465459Briefly, `%clay` today actually derives the hierarchy from its
466−leaves -- rather than _logically_ so deriving it. Only leaves
467−are in the object store. This is just weird, and you can feel
468−`%clay` trying to be something other than what it is. (I blame
460+leaves -- rather than _logically_ so deriving it. Only leaves
461+are in the object store. This is just weird, and you can feel
462+`%clay` trying to be something other than what it is. (I blame
469463Jared, though it's actually my fault.)
470464
471465To store a dome snapshot (`++yaki`), the present code keeps a
472−`(map path blob)` at the root of the dome. This is enough to
466+`(map path blob)` at the root of the dome. This is enough to
473467reconstruct the `++arch` structures the namespace exports.
474468However, all kinds of basic arch operations, like basically `ls`,
475−become `O(n)` in the number of leaves in the dome. This is
469+become `O(n)` in the number of leaves in the dome. This is
476470obviously not quite right.
477471
478472I believe the storage structure should be (removing everything
@@ -493,46 +487,46 @@ Here a `++root` is the universal node, with children addressed by
493487hash, but logically representing the abstract `++arch`.
494488
495489Users of hierarchical filesystems basically expect performance
496−qualities that match the filesystem structure. A huge directory
497−in one place shouldn't affect search speeds somewhere else. And
490+qualities that match the filesystem structure. A huge directory
491+in one place shouldn't affect search speeds somewhere else. And
498492of course, `ls` can't be O(n) in the size of the filesystem.
499493
500494### Change #1: store edges, cache snapshots
501495
502−The current `%clay` is snapshot-oriented, like `git`. The actual
503−changes are discarded. I think this is a bad choice.
496+The current `%clay` is snapshot-oriented, like `git`. The actual
497+changes are discarded. I think this is a bad choice.
504498
505499`%clay` is not a research project, and has no idea of going as
506−far as `darcs` in the "set-of-patches" direction. However, at
500+far as `darcs` in the "set-of-patches" direction. However, at
507501present we actually throw away the patch (`++nori`).
508502
509503I think the right DVCS design for `%clay` is a snapshot-oriented
510−system which also keeps the patches. The revision graph has the
511−same general shape as in the old `git` style. But rather than
504+system which also keeps the patches. The revision graph has the
505+same general shape as in the old `git` style. But rather than
512506just deriving the diffs from the snapshots, we can also derive
513−the snapshots from the diffs. When in doubt, we save space by
507+the snapshots from the diffs. When in doubt, we save space by
514508dropping the snapshot, not the diff.
515509
516510For an RCS which is also a general-purpose typed filesystem, it's
517511clear that considering edges (deltas, diffs, changes, etc) as the
518−primary state is optimal. You can use diff functions to derive
512+primary state is optimal. You can use diff functions to derive
519513deltas from snapshots, but in many data models this will always
520−risk losing information from the original action. When in
514+risk losing information from the original action. When in
521515doubt, save what the user did.
522516
523517This is even more true for operations on the tree structure, not
524−on individual leaves. Consider the heuristic energy that `git` has
518+on individual leaves. Consider the heuristic energy that `git` has
525519to go through to figure out when `mv` has been used -- even when
526−`git mv` has been used! (According to the `git` faq, this is
520+`git mv` has been used! (According to the `git` faq, this is
527521because the lowest common denominator remains Linus' style of
528522working with emailed patches.)
529523
530−Edges probably don't even need to be deduplicated. They also can
524+Edges probably don't even need to be deduplicated. They also can
531525contain metadata such as commit messages (which `%clay` has no
532526place for at present).
533527
534528Once edges are recognized as unreclaimed primary state, snapshots
535−can always be derived from the edges. So we can reclaim memory
529+can always be derived from the edges. So we can reclaim memory
536530being used for snapshots.
537531
538532It's also straightforward to have a kind of edge which is a list
@@ -540,27 +534,27 @@ of edges, letting us collapse feature branches trivially.
540534
541535Finally, I think references in edges should wherever possible
542536indirect through the namespace, rather than directly to the
543−content address. The user has strictly more information if you
537+content address. The user has strictly more information if you
544538say you merged `/~sorreg-namtyv/base/987/`, than if all you have
545539is the hash that this reference refers to.
546540
547541### Change #2: unconfuse merge and rebase
548542
549543The dispute between merge and rebase has all the bad smells of
550−a historical wart. But here I'm just not sure what's right.
544+a historical wart. But here I'm just not sure what's right.
551545
552546The user has one _intent_ whether merging or rebasing, which is
553−to combine changes on one desk into another. The _algorithm_
547+to combine changes on one desk into another. The _algorithm_
554548used to construct this change, whether operational transformation
555549(rebasing) or a 3-way diff (merging) has one goal: use all
556550available information to model the authors' editing intent as
557−realistically as possible. If we save edges, we should use
551+realistically as possible. If we save edges, we should use
558552edges.
559553
560554Whether to define the resulting change graph with the typical
561555structure of a merge, or the typical structure of a rebase,
562556strikes me as quite arbitrary, and well into the land of "pick
563−one and force everyone to stick with it." But this call demands
557+one and force everyone to stick with it." But this call demands
564558a real expert on RCS workflow, which I'm not.
565559
566560Since `%clay` is a humble part of a larger system and needs to
@@ -570,23 +564,23 @@ different preferences" is not usually the right answer.
570564### Change #3: comment jihad
571565
572566`%clay` needs to be brought up to the documentation standards of
573−`%jael`. This means (a) the formatting matches; (b) the comments
567+`%jael`. This means (a) the formatting matches; (b) the comments
574568are at the same level of quality and ubiquity.
575569
576570The basic commenting standards are: (a) every core (class) needs
577571a block comment explanation; (b) every gate (function) needs a
578572line comment; (c) every face (variable) needs a line comment.
579573
580−This is obviously not just a clerical task. To write these
581−comments, you need to actually understand the code. This is a
574+This is obviously not just a clerical task. To write these
575+comments, you need to actually understand the code. This is a
582576nontrivial but extremely rewarding task, even if the code you're
583577commenting will get replaced.
584578
585579Also, the _symbols_ in `%clay` must be brought up to `%jael`
586−quality. There is still far too much four-letterism here.
580+quality. There is still far too much four-letterism here.
587581
588582NB: `%clay` is about 3000 lines of pretty clean Hoon, which is
589−certainly not at all undocumented. We're not exactly looking at
583+certainly not at all undocumented. We're not exactly looking at
590584a Matterhorn of reverse engineering here.
591585
592586### Change #4: knot to coin internal paths
@@ -597,26 +591,26 @@ ASCII symbol as an atom) must be within the range of the
597591invertible noun printer, `++co`.
598592
599593`++co` maps a described data value, a `++coin`, to an ASCII
600−string which is a valid URL segment and Unix filename. Its
594+string which is a valid URL segment and Unix filename. Its
601595friend `++so` inverts the function, perfectly.
602596
603−Almost every knot is the simplest kind of `coin`, a `dime.` A
597+Almost every knot is the simplest kind of `coin`, a `dime.` A
604598dime is a single atom with a rendering type (`aura` if you know
605−Hoon). Auras include `@tas` for symbolic text, `@ud` for
606−unsigned decimal, `@p` for Urbit ship, etc. `++co` can also
599+Hoon). Auras include `@tas` for symbolic text, `@ud` for
600+unsigned decimal, `@p` for Urbit ship, etc. `++co` can also
607601print arbitrary cells, though less prettily.
608602
609603This feature is cool because it lets us stuff data into names in
610−a precise and predictable way. Usually the names in a namespace
604+a precise and predictable way. Usually the names in a namespace
611605are human-meaningful and human-originated, and are therefore
612−symbolic, but there are exceptions. For example, blogposts may
606+symbolic, but there are exceptions. For example, blogposts may
613607want to be named by date.
614608
615609However, it is slightly retarded for the fundamental state of our
616610arches to store the _rendered_ string (`++knot`), not the source
617−data (`++coin`). It leads to all kinds of inefficiencies where
618−we're doing way more parsing than we want to. (Parsing also
619−should be jet-propelled, but is not.) It also makes it way too
611+data (`++coin`). It leads to all kinds of inefficiencies where
612+we're doing way more parsing than we want to. (Parsing also
613+should be jet-propelled, but is not.) It also makes it way too
620614easy to sneak in bad data and make it `%clay`'s problem.
621615
622616So, logically, we'd be shifting from
@@ -631,7 +625,7 @@ So, logically, we'd be shifting from
631625
632626Also, a vanilla `++map` might not be quite the right data
633627structure at this point -- we probably want a custom sorted tree,
634−which separates auras and imposes a custom order on each. This
628+which separates auras and imposes a custom order on each. This
635629would let us serve simple range queries quite efficiently, so
636630long as they match the standard aura order (eg, alphabetical
637631order for symbols).
@@ -639,23 +633,23 @@ order for symbols).
639633### Change #5: dome semantics by reference
640634
641635While the principle that a dome contains its own mark source is
642−elegant, it's a pain in the ass to implement properly. `%clay`
636+elegant, it's a pain in the ass to implement properly. `%clay`
643637certainly does not do it justice at present.
644638
645639The complexity is in checking every change to see whether it
646640includes a change to the mark source (which is very unlikely),
647641or a dependency of the mark source (slightly less unlikely).
648642And if so, do we have to update all the leaves in the dome?
649−This is also very unlikely. And yet, it happens.
643+This is also very unlikely. And yet, it happens.
650644
651645Instead, we could simply designate, by beak (ship, desk, and
652−case) a dome which contains the canonical mark source. This
646+case) a dome which contains the canonical mark source. This
653647would rarely change -- you could upgrade a desk to a new mark
654648dome, but it would be a manual operation and probably a rare one.
655649
656650The common case would just be that everyone uses the current
657651version of the `%base` desk when a desk is created, and never
658−changes it. In practice, this means not every two-byte edit
652+changes it. In practice, this means not every two-byte edit
659653needs to get involved in detecting and/or applying schema
660654evolution, a welcome simplification.
661655
@@ -667,14 +661,14 @@ design is one mark per message structure, the mark namespace gets
667661overloaded fast.
668662
669663So we added an app hierarchy within the mark namespace, using hep
670−`-` as a divider. The `:talk` app expects messages with the mark
664+`-` as a divider. The `:talk` app expects messages with the mark
671665`talk-message`, whose sources is in `/===/mar/talk/message`.
672666
673667This helps, but it doesn't solve another two problems: trivial
674668nouns and containers.
675669
676670It's retarded to have to add a source file to send a `@ud` or a
677−`*`. An aura (see above under `coin`) should be a trivial mark.
671+`*`. An aura (see above under `coin`) should be a trivial mark.
678672
679673Also, we need to be able to construct standard containers of
680674marks: lists, maps, sets, and tuples (or, as a database person
@@ -686,32 +680,32 @@ Another kind of complex mark that needs to exist: conflict,
686680difference, and invalid marks.
687681
688682Conflict data and difference data are two types of noun that are
689−generated in normal RCS operation. If we have the concept of an
683+generated in normal RCS operation. If we have the concept of an
690684`%html` noun, we also need the concept of an invertible change
691685from one `%html` file to another; a merge conflict between two
692686`%html` files; and even a conflict between two marks.
693687
694688There are two kinds of changes to a dome: manual and automatic.
695689Manual changes are initiated by the user and should crash, unless
696−manually overridden. Automatic changes should not crash, ever,
697−and should not lose data. If they create problems, which they
690+manually overridden. Automatic changes should not crash, ever,
691+and should not lose data. If they create problems, which they
698692shouldn't, these problems will need to be cleaned up manually.
699693
700694This is a complex space to navigate, but it requires a conflicted
701695merge to be able to resolve to a valid dome containing conflict
702−leaves, not crash. The present `%clay` goes halfway there and
696+leaves, not crash. The present `%clay` goes halfway there and
703697resolves to a scratch desk, but we can go farther: the whole `git`
704−dumpster-fire of "merge state" deserves destruction. One change
698+dumpster-fire of "merge state" deserves destruction. One change
705699is a merge that produces conflicts, the next is an edit that
706700resolves them.
707701
708−Similarly, all sorts of errors can produce invalid leaves. One
702+Similarly, all sorts of errors can produce invalid leaves. One
709703particularly rare case which is nonetheless important is schema
710704evolution: what happens to files in a mark, when the mark source
711−code changes. They all need to be re-normalized. And this
712−operation can fail, producing an invalid value. (We don't do any
705+code changes. They all need to be re-normalized. And this
706+operation can fail, producing an invalid value. (We don't do any
713707of this now, BTW, although `%ford` has the dependency mechanism to
714−make it possible.) Again, in some cases this should crash the
708+make it possible.) Again, in some cases this should crash the
715709update to the mark source; in other cases, there is no local way
716710to handle the crash.
717711
@@ -722,46 +716,46 @@ into using the bad content.
722716
723717The bottom line: a mark needs to be split into two models:
724718`++mark`, the original symbolic mark with its source engine, and
725−something like `++logo`, the meta-mark or mark container. The
719+something like `++logo`, the meta-mark or mark container. The
726720mark is the building block; the logo is the building.
727721
728722### Change #8: filesystem hierarchy standard
729723
730724While all filesystems remain forks of one ur-filesystem, the
731−standard tends to enforce itself. But not define itself.
725+standard tends to enforce itself. But not define itself.
732726
733−I've always hated the current `/mar` for marks, for instance. I
734−prefer `/mac`. But others hate this. And so on. Also, by
727+I've always hated the current `/mar` for marks, for instance. I
728+prefer `/mac`. But others hate this. And so on. Also, by
735729necessity, our nascent "FHS" is heavily biased toward system
736−data, away from user data. This is retarded.
730+data, away from user data. This is retarded.
737731
738−Please focus all bikeshedding energy on this problem! Better to
732+Please focus all bikeshedding energy on this problem! Better to
739733bikeshed about what color to paint the bikeshed, then what shape
740734the bike gears should be.
741735
742736### Change #9: security and access control
743737
744−Oh, yeah, that! They always say not to design security in at the
745−last minute. Unfortunately, this is exactly what we did. There
746−is no security at all in present `%clay`. (There is also no push
738+Oh, yeah, that! They always say not to design security in at the
739+last minute. Unfortunately, this is exactly what we did. There
740+is no security at all in present `%clay`. (There is also no push
747741operation in `%clay`, so it's not as mad as you think -- anyone
748742can read anything, no one can write anything, which is fine in a
749743young network where there are no secrets.)
750744
751745Fortunately, we don't have anything super fancy planned in this
752−area, just basic access-control lists. These obviously need to
746+area, just basic access-control lists. These obviously need to
753747be designed along with the filesystem-hierarchy standard (see
754748elsewhere).
755749
756−Is it even possible to do ACLs properly in `%clay`? At this
757−point, yes. There is an event-oriented security model in Arvo,
750+Is it even possible to do ACLs properly in `%clay`? At this
751+point, yes. There is an event-oriented security model in Arvo,
758752though it isn't really hooked up to anything at the moment.
759−There is also a privilege badge system in `%jael`. The
753+There is also a privilege badge system in `%jael`. The
760754combination of these two features is quite sufficient for a
761755decent ACL model.
762756
763757The idea of event-based security is that every event passed to
764−`%clay` has a security `++mask`. The mask tells us:
758+`%clay` has a security `++mask`. The mask tells us:
765759
766760- the set of ships that has _contaminated_ this event
767761- the set of ships that has _endorsed_ this event
@@ -769,20 +763,20 @@ The idea of event-based security is that every event passed to
769763
770764To simplify this system a little and maybe explain it, the
771765security question in any event is: (a) who has _caused_ this
772−event? (b) who may receive its _effects_? (These sets never
766+event? (b) who may receive its _effects_? (These sets never
773767include your urbit itself, of course, only neighbors.)
774768
775769For example, if we're doing something because ship X sent us a
776770packet, and we're going to leak the results of this something
777771back in a response to ship X, once `%clay` knows what our ship
778772thinks of its neighbor X, we should have a good picture of what
779−effects this event should be allowed to cause. If `%jael` knows
773+effects this event should be allowed to cause. If `%jael` knows
780774that X is our friend, `%clay` can know that X can see our cat
781775picture.
782776
783777Causality is separated out into contamination (data from ship X
784778got into the event) and endorsement (ship X signed the whole
785−event). (This may be overdesign.) All these sets can be defined
779+event). (This may be overdesign.) All these sets can be defined
786780as the empty set (eg, releasing to the empty set means no output)
787781or the universal set (input from the universal set could be from
788782anyone, ie, is unauthenticated).
@@ -791,11 +785,11 @@ anyone, ie, is unauthenticated).
791785
792786When you read a leaf from a `%clay` dome, `%clay` is happy to
793787perform any necessary mark conversions (the actual work is done
794−by the `%ford` build vane). You can also just ask for the leaf
788+by the `%ford` build vane). You can also just ask for the leaf
795789in whatever mark `%clay` has it.
796790
797791It's confusing to think of this mark extension as part of the
798−path. You shouldn't say `+cat /===/app/talk/hoon`. You should say
792+path. You shouldn't say `+cat /===/app/talk/hoon`. You should say
799793`+cat /===/app/talk`, or maybe `+cat %hoon /===/app/talk`.
800794
801795A mark-extended namespace may be added to `%ford`, to compensate.
@@ -804,7 +798,7 @@ But type-converting reads are the rare case, not the common case.
804798### Change #11: real queries and indexes
805799
806800A filesystem should postpone being a database until it can no
807−longer do so. So, please don't think about this problem yet.
801+longer do so. So, please don't think about this problem yet.
808802I'm joking, of course!
809803
810804### Change #12: meta-query
@@ -813,24 +807,24 @@ Make it possible to query the list of desks in a ship :-)
813807
814808### Change #13: completely redesign Unix mounting
815809
816−This is actually a series of changes, described below. But
810+This is actually a series of changes, described below. But
817811broadly...
818812
819813One of Urbit's experiments is live two-way synchronization
820814between the Unix filesystem and the revision-control store.
821−Dropbox style, as it were. I think this experiment is basically
822−a failure. It may be right for cat pictures, but I don't think
815+Dropbox style, as it were. I think this experiment is basically
816+a failure. It may be right for cat pictures, but I don't think
823817it's right for Urbit.
824818
825819The fundamental problem is that there are all sorts of weird,
826−flaky ways applications use a mutable filesystem. It's not at
820+flaky ways applications use a mutable filesystem. It's not at
827821all unusual for an editor to change a file by deleting the old
828822file, then writing the new one in its place.
829823
830−You really don't want this to produce a delete change. A simple
824+You really don't want this to produce a delete change. A simple
831825cooldown timer for the sync helps a lot with this, but causes
832−other weirdnesses. In theory, a sync can even cause another
833−change to the same version of the same desk. And so on.
826+other weirdnesses. In theory, a sync can even cause another
827+change to the same version of the same desk. And so on.
834828
835829The thing we fear is just too funky to work (there is some
836830strange "reflux bug" still affecting it) is any sort of _two-way_
@@ -841,8 +835,8 @@ cold storage, is that there's no useful workflow that actually
841835uses it -- at least, when editing Urbit code.
842836
843837It's actually really nice to have files on a disk that nothing
844−will automatically modify. If you're using `git` and `%clay` in
845−parallel, it's nice to mount your `git` working directory. The
838+will automatically modify. If you're using `git` and `%clay` in
839+parallel, it's nice to mount your `git` working directory. The
846840original Urbit workflow was to work out of a mounted directory,
847841but the two-way updates were just too weird and scary, so now we
848842tend to edit elsewhere and copy in -- which is lame.
@@ -855,25 +849,25 @@ FUSE (in a somewhat experimental state), and filesystem watching
855849
856850The FUSE interface is a good one, though it needs more work.
857851Moreover, it exports the whole Urbit namespace to Unix, not just
858−`%clay`. For reading Urbit data, FUSE is basically ideal.
852+`%clay`. For reading Urbit data, FUSE is basically ideal.
859853
860−The obvious impulse is to make a read-write FUSE. But I don't
854+The obvious impulse is to make a read-write FUSE. But I don't
861855think FUSE should be used for recording changes to an RCS, even
862856though the FUSE API sends you changes as events.
863857
864−There are three reasons for this. One, the actual filesystem
858+There are three reasons for this. One, the actual filesystem
865859writes that Unix apps make are typically of low quality and
866−confusing. Some crack-brained editor will find it completely
860+confusing. Some crack-brained editor will find it completely
867861normal and unremarkable to modify a byte in a file, by deleting
868−the file and rewriting it from scratch. You can use a cooldown
862+the file and rewriting it from scratch. You can use a cooldown
869863timer to wait for this nonsense to converge, but leaving data in
870864heuristic limbo seems like a very bad idea in FUSE-land.
871865
872866The second is that people derive a lot of comfort from seeing
873−actual files on an actual disk. The idea that your datas are
867+actual files on an actual disk. The idea that your datas are
874868stuck in Urbit is slightly terrifying as a user experience.
875−We claim to be reliable. It's actually hard to imagine datas that
876−couldn't be recovered from either snapshot or log. But how can
869+We claim to be reliable. It's actually hard to imagine datas that
870+couldn't be recovered from either snapshot or log. But how can
877871you possibly believe us on this?
878872
879873So I think it's correct to lean all the weight of reading data
@@ -888,35 +882,35 @@ But this is a separate discussion.
888882
889883### Change #15: one-way, nonced working desk
890884
891−A one-way mount is a much less crazy thing. It works the same
885+A one-way mount is a much less crazy thing. It works the same
892886way our two-way mount works today, but with only one writer: the
893887user, via Unix.
894888
895889Since a mount is one-way, it needs to have an absolute write lock
896−on the desk it's writing to. We cannot have a `%home` desk which
890+on the desk it's writing to. We cannot have a `%home` desk which
897891we are also editing with filesystem watching.
898892
899893Instead, we have a temporary and anonymous state that's connected
900−itself with your `%home` desk. Desk names have to be valid
901−symbols, but we can use `hep`, `-`. A reasonable choice is to
894+itself with your `%home` desk. Desk names have to be valid
895+symbols, but we can use `hep`, `-`. A reasonable choice is to
902896pick a random 32-bit name for each mount instance -- so the desk
903−name is not `%home`, but `%home-bosdut-sigder`. (Randomizing
897+name is not `%home`, but `%home-bosdut-sigder`. (Randomizing
904898instead of always using a fixed suffix, say, `%home-work`,
905899just makes all kinds of screwups less likely.)
906900
907901You create a mount simply by mkdiring the desk name in your pier.
908902Just the base name, Urbit will come up with the `%bosdut-sigder`
909−part and put it in a `.desk` file at the desk root. To forget
910−the mount, just delete this file. This avoids the ugly confusion
903+part and put it in a `.desk` file at the desk root. To forget
904+the mount, just delete this file. This avoids the ugly confusion
911905between unmounting a mount, and deleting all the data in it.
912906
913907(Urbit will keep a set of the mount desks it's used and
914−forgotten, not reuse them, and block all requests into them. By
908+forgotten, not reuse them, and block all requests into them. By
915909blocking, we can delete without losing referential transparency.
916910Yes, Virginia, Urbit can forget!)
917911
918912Note that the auto-reload behavior of applications is extremely
919−useful when testing. When testing, you can either switch the
913+useful when testing. When testing, you can either switch the
920914active application desk from `%home` to `%home-bosdut-sigder`,
921915or activate autosync from the latter to the former.
922916
@@ -939,7 +933,7 @@ Otherwise, you're basically, like, reinventing Perforce.
939933
940934More concretely, the Urbit experience today requires `:hood`
941935pokes (Urbit shell commands, basically) for all nontrivial RCS
942−operations, from mounting to merging. Again, there are lots of
936+operations, from mounting to merging. Again, there are lots of
943937situations in which you can write into a mounted filesystem (the
944938protocol for Unix communication could be easily adapted to
945939communicate with a browser-based editor, for instance), but you
@@ -949,20 +943,20 @@ Even commands like mounting and merging are easily communicated,
949943through filesystem writes that any Unix tool (including many
950944macro editors).
951945
952−This is very easy for a filesystem watcher. One such protocol:
946+This is very easy for a filesystem watcher. One such protocol:
953947if you want to send the daemon a command relative to some
954−directory, write a `.ur-command` metafile in that directory. The
948+directory, write a `.ur-command` metafile in that directory. The
955949daemon accepts the command by deleting it.
956950
957951The user experience is that you configure your mounts by simply
958−making the directories and configuring dotfiles in them. Unlike
952+making the directories and configuring dotfiles in them. Unlike
959953in the present system, Urbit will never modify your datas
960954silently in the background.
961955
962956Here's what this looks like:
963957
964−Suppose you want to edit some data in the `%home` desk. Your
965−data is in `/=home=/mar/talk`. You also want a read-only view
958+Suppose you want to edit some data in the `%home` desk. Your
959+data is in `/=home=/mar/talk`. You also want a read-only view
966960of `/=home=/arvo`.
967961
968962From Unix, you do something like this:
@@ -975,18 +969,18 @@ From Unix, you do something like this:
975969 $ touch home/arvo/.read
976970```
977971
978−Want to commit your changes? That means merging the working
979−desk, `%home-bosdut-sigder`, into the `%home`. Put a commit message
980−into `home/.commit` and it'll happen. If there's an error, it
972+Want to commit your changes? That means merging the working
973+desk, `%home-bosdut-sigder`, into the `%home`. Put a commit message
974+into `home/.commit` and it'll happen. If there's an error, it
981975will appear as `.error`.
982976
983977The mount has a .version file which simply contains the change
984−number (of the working desk) which any edits are relative to. If
978+number (of the working desk) which any edits are relative to. If
985979the urbit daemon is running and watching, edits will be absorbed
986980quickly (probably after a heuristic timeout), and the version
987−incremented. But we always are confident that the edits are
981+incremented. But we always are confident that the edits are
988982against the latest version, or at least we can use this as a
989−sanity check. All kinds of insane things can happen to get a
983+sanity check. All kinds of insane things can happen to get a
990984filesystem out of consistency.
991985
992986This design obviously needs a little fleshing out, but I'm quite
@@ -995,12 +989,12 @@ from Unix.
995989
996990## In conclusion
997991
998−There's obviously a lot of fun here! There are two things you
992+There's obviously a lot of fun here! There are two things you
999993can do right now.
1000994
1001995One, talk about `%clay` on [this forum
1002996thread](http://urbit.org/~~/fora/posts/~2016.10.25..17.37.47..6937~/) or
1003−on [:talk](http://urbit.org/stream). Both hosted on Urbit
997+on [:talk](http://urbit.org/stream). Both hosted on Urbit
1004998itself!
1005999
10061000Two, poke around the