on master help sign in
Merge pull request #215 from Fang-/talk-docs
989e5eaKeaton Dunsford
docs/talk/architecture.mdnew file+516
@@ -0,0 +1,516 @@
1+
2+# Hall architecture
3+
4+This document is complemented by Hall's source code, but doesn't require it. Definitions of data structures, code snippets and diagrams will be provided where useful.
5+
6+Hall's implementation is structured according to the new Gall model. Familiarity with its concepts is assumed. See [the new Gall model](gall.md).
7+
8+## Table of contents
9+
10+* [Introduction](#introduction)
11+* [Structures & functionality](#structures--functionality)
12+ * [Circles](#circles)
13+ * [Messages](#messages)
14+ * [Participant metadata](#participant-metadata)
15+ * [Configurations](#configurations)
16+ * [Stories](#stories)
17+ * [General use](#general-use)
18+ * [Federation](#federation)
19+ * [Public membership](#public-membership)
20+* [Interfaces for applications](#interfaces-for-applications)
21+ * [Interactions](#interactions)
22+ * [Queries, prizes and rumors](#queries-prizes-and-rumors)
23+* [Communication between Halls](#communication-between-halls)
24+ * [Interactions](#interactions-1)
25+ * [Querying](#querying)
26+ * [Federation](#federation)
27+* [Hall implementation](#hall-implementation)
28+ * [Subscriptions](#subscriptions)
29+ * [Rumors](#rumors)
30+ * [Messaging](#messaging)
31+* [The future](#the-future)
32+ * [Features and functionality](#features-and-functionality)
33+* [Further reading](#further-reading)
34+
35+
36+## Introduction
37+
38+Talk was Urbit's first big user-facing application. It continues to enjoy a prominent role in the Urbit landscape, but does so as two separate applications this time.
39+
40+The messaging parts of Talk have been separated from its user interface parts. What we ended up with is a shiny new generic messaging bus, and the chat interface we all know and love. The messaging bus, which should now prove useful to many different applications, will be named `Hall`. Applications that use it are referred to as *clients*. One such application, as you might have guessed, is `Talk`.
41+
42+
43+## Structures & functionality
44+
45+### Circles
46+
47+```
48+++ circle {hos/ship nom/term} :< native target
49+```
50+
51+A `circle` is essentially a named collection of messages created by and hosted on a ship's Hall, usually represented as `~ship-name/circle-name`. Most of Hall revolves around doing things with circles.
52+
53+### Messages
54+
55+When we subscribe to a circle, the primary thing we're interested in is its messages. Message data itself isn't that complicated, but a fair amount of metadata comes into play when actually sending a message. Let's work our way up, starting at the contents.
56+
57+```
58+++ speech :> content body
59+ $% {$lin pat/? msg/cord} :< no/@ text line
60+ {$url url/purf:eyre} :< parsed url
61+ {$exp exp/cord res/(list tank)} :< hoon line
62+ {$ire top/serial sep/speech} :< in reply to
63+ {$fat tac/attache sep/speech} :< attachment
64+ {$app app/term sep/speech} :< app message
65+ {$inv inv/? cir/circle} :< inv/ban for circle
66+ == ::
67+```
68+
69+At the heart of every message lies a `speech` that describes the message body. There's a large number of different speech types, from simple text messages to parsed URLs, Hoon expressions and more.
70+
71+```
72+++ audience (set circle) :< destinations
73+++ serial @uvH :< unique identifier
74+++ thought :> inner message
75+ $: uid/serial :< unique identifier
76+ aud/audience :< destinations
77+ wen/@da :< timestamp
78+ sep/speech :< content
79+ == ::
80+```
81+
82+A `speech` is always accompanied by various bits of metadata. We include a unique identifier, a message timestamp and an `audience`, the set of all intended recipients of the message.
83+
84+```
85+++ telegram {aut/ship thought} :< whose message
86+++ envelope {num/@ud gam/telegram} :< outward message
87+```
88+
89+Finally, before sending the message over the wire, we add on the message's original author. In most cases, we also include a sequence number, the index of the message in the originating circle's list of messages. This can be a useful point of reference for clients.
90+
91+### Participant metadata
92+
93+Messages aren't the only thing a subscription gets us. We're also kept up to date with relevant metadata.
94+
95+```
96+++ crowd {loc/group rem/(map partner group)} :< our & srcs presences
97+++ group (map ship status) :< presence map
98+++ status {pec/presence man/human} :< participant
99+++ presence :> status type
100+ $? $gone :< absent
101+ $idle :< idle
102+ $hear :< present
103+ $talk :< typing
104+ == ::
105+++ human :> human identifier
106+ $: han/(unit cord) :< handle
107+ tru/(unit truename) :< true name
108+ == ::
109+++ truename {fir/cord mid/(unit cord) las/cord} :< real-life name
110+```
111+
112+`status` is user-set metadata that describes, well, the status of users in a circle. This encompasses their `presence`, which shows their activity, and their `human` identity, which includes their display handle.
113+For reasons we'll discover shortly, circles keep track of both their own `group` and those of the circles they're subscribed to. `crowd` encapsulates this.
114+
115+### Configurations
116+
117+```
118+++ lobby {loc/config rem/(map circle config)} :< our & srcs configs
119+++ config :> circle config
120+ $: src/(set circle) :< active sources
121+ cap/cord :< description
122+ fit/filter :< message rules
123+ con/control :< restrictions
124+ == ::
125+++ filter :> content filters
126+ $: cas/? :< dis/allow capitals
127+ utf/? :< dis/allow non-ascii
128+ == ::
129+++ control {sec/security ses/(set ship)} :< access control
130+```
131+
132+Another part of metadata we get from circle subscriptions is configurations. Again, circles want to remember their own configuration, as well as those of their subscriptions. But why, precisely?
133+
134+The `config` structure contains `src`, a set of partners. These indicate the different sources a circle is currently pulling content from. This allows circles to aggregate messages from multiple places. In doing so, it also receives metadata from those places, hence why we have structures for storing "remote" presences and configurations alongside local ones.
135+
136+Aside from that, `config` contains a description for the circle, which is exactly what it sounds like. It also specifies a `filter`, which are content formatting rules all messages passing through this circle are made to adhere to.
137+
138+Lastly, there's a `control` structure that contains both a security mode and a list of ships, which is either a white- or blacklist depending on the aforementioned mode. There are four such modes available.
139+
140+```
141+++ security :> security mode
142+ $? $channel :< blacklist
143+ $village :< whitelist
144+ $journal :< pub r, whitelist w
145+ $mailbox :< our r, blacklist w
146+ == ::
147+```
148+
149+A `channel` is publicly readable and writable, with a blacklist for blocking.
150+A `village` is privately readable and writable, with a whitelist for inviting.
151+A `journal` is publicly readable and privately writable, with a whitelist for authors.
152+A `mailbox` is readable by its owner and publicly writable, with a blacklist for blocking.
153+
154+### Stories
155+
156+To see how that all ties together, we're going to take a look at Hall's state.
157+
158+```
159+++ state :> hall state
160+ $: stories/(map term story) :< conversations
161+ :: ... ::
162+ == ::
163+++ story :> wire content
164+ $: grams/(list telegram) :< all messages
165+ locals/group :< local presence
166+ remotes/(map circle group) :< remote presence
167+ shape/config :< configuration
168+ mirrors/(map circle config) :< remote config
169+ :: ... ::
170+ == ::
171+```
172+
173+Stories are the primary driver behind Hall. They are the structures that are used to power circles, which we can now say are named stories hosted on ships.
174+
175+With the configuration described above in mind, we can try and imagine the things we can do with stories. Knowing that we can subscribe them to any number of sources, they can function as central hubs for our messaging, aggregate specific kinds of data feeds, or simply accept whatever messages get sent to it like a regular old chatroom.
176+
177+### General use
178+
179+Upon initial startup, Hall creates a default story, a mailbox named `inbox`. This mailbox is the primary target for anyone and anything that wants to reach its owner. Applications can use it to send notifications and other information to the user (Hall itself does this as well), and users can use it to send direct messages to each other.
180+
181+Applications that use Hall, especially clients, are encouraged to use the default mailbox as the primary messaging hub. This way, users can easily switch between different applications without "losing" their subscriptions, message backlog, etc.
182+
183+As an example, Talk operates like this, serving as an interface for reading from and managing the user's mailbox. Local stories are subscribed to through the `inbox`, which ends up containing all messages the user receives.
184+
185+### Federation
186+
187+Some places, like `urbit-meta`, will want to be easily accessible to everyone on the network, and actually support the load that comes with that. Both these desired can be met through federation.
188+
189+In federation, stories and any changes to them trickle down from ~zod, to other galaxies, to their stars. Only changes to messages and presence can also move upstream, from stars, to galaxies, to ~zod (and then back down again).
190+This way, all planets and comets will be able to subscribe to `/urbit-meta` (that is, the `urbit-meta` circle on their parent ship) and get all updates on the story, regardless of where on the network they originated.
191+
192+### Public membership
193+
194+To aid in discoverability of circles, it is possible for users to make their participation in any given circle public. This data can then be used by things like profile widgets, or read out directly by other users.
195+
196+
197+## Interfaces for applications
198+
199+Applications can interact with Hall in two complementary ways: they can tell it what actions to perform, and they can subscribe to its state and the changes made to it.
200+
201+### Interactions
202+
203+Hall can be commanded by poking it with `action`s.
204+
205+```
206+++ action :> user action
207+ $% :: circle configuration ::
208+ {$create nom/term des/cord sec/security} :< create circle
209+ {$delete nom/term why/(unit cord)} :< delete + announce
210+ {$depict nom/term des/cord} :< change description
211+ {$filter nom/term fit/filter} :< change message rules
212+ {$permit nom/term inv/? sis/(set ship)} :< invite/banish
213+ {$source nom/term sub/? srs/(set source)} :< un/sub to/from src
214+ :: messaging ::
215+ {$convey tos/(list thought)} :< post exact
216+ {$phrase aud/audience ses/(list speech)} :< post easy
217+ :: personal metadata ::
218+ {$notify aud/audience pes/(unit presence)} :< our presence update
219+ {$naming aud/audience man/human} :< our name update
220+ :: changing shared ui ::
221+ {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
222+ {$nick who/ship nic/cord} :< new identity
223+ :: misc changes ::
224+ {$public add/? cir/circle} :< show/hide membership
225+ == ::
226+```
227+
228+The largest part of these actions concern themselves with managing local circles. `nom` is always the name used to identify the relevant story. To disambiguate between "add" and "delete" type actions (for permissions and subscriptions), a loob `?` is used.
229+
230+To send messages, two interfaces are available. `%convey` lets you specify all details of the messages, including its timestamp, serial, and fully assembled audience. `%phrase`, on the other hand, takes care of that for you, allowing you to specify just the target partners and message contents.
231+
232+`%notify` and `%naming` are useful for setting your own presence and nickname in a circle respectively, so others can see if you're active and what to call you by.
233+
234+"Shared UI" encompasses UI data that should be consistent across applications. For example, if the user sets a local nickname for an identity, they expect to see that nickname regardless of the application they're currently using. The same goes for glyph bindings, for easy audience targeting.
235+
236+### Queries, prizes and rumors
237+
238+To receive data from Hall, applications will have to query it. There are two paths that are useful for clients to query. Let's look at them and their results.
239+
240+```
241+++ query :> query paths
242+ $% {$client $~} :< shared ui state
243+ $: $circle :> story query
244+ nom/naem :< circle name
245+ wat/(set circle-data) :< data to get
246+ ran/range :< query duration
247+ == ::
248+ :: ... ::
249+ == ::
250+++ circle-data :> kinds of circle data
251+ $? $grams :< messages
252+ $group-l :< local presence
253+ $group-r :< remote presences
254+ $config-l :< local config
255+ $config-r :< remote configs
256+ == ::
257+++ range :> inclusive msg range
258+ %- unit :< ~ means everything
259+ $: hed/place :< start of range
260+ tal/(unit place) :< opt end of range
261+ == ::
262+++ place :> range indicators
263+ $% {$da @da} :< date
264+ {$ud @ud} :< message number
265+ == ::
266+++ prize :> query result
267+ $% $: $client :< /client
268+ gys/(jug char (set partner)) :< glyph bindings
269+ nis/(map ship cord) :< nicknames
270+ == ::
271+ {$circle burden} :< /circle
272+ :: ... ::
273+ == ::
274+++ burden :< full story state
275+ $: gaz/(list telegram) :< all messages
276+ cos/lobby :< loc & rem configs
277+ pes/crowd :< loc & rem presences
278+ == ::
279+```
280+
281+To be clear, the paths for those queries are `/client` and `/circle/[name]/[data]/[start]/[end]`, where data is at least one `circle-data`, and `start` and `end` are optional and can be either a date or a message number.
282+`/client` queries produce shared UI state. That is, glyph bindings and nicknames.
283+`/circle` queries produce the entire public state of the requested story, including remotes.
284+
285+Any changes to the results of these queries are communicated via the following `rumor`s. It's a fairly long list of potential changes,
286+
287+```
288+++ rumor :< query result change
289+ $% {$client rum/rumor-client} :< /client
290+ {$circle rum/rumor-story} :< /circle
291+ :: ... ::
292+ == ::
293+++ rumor-client :< changed ui state
294+ $% {$glyph diff-glyph} :< un/bound glyph
295+ {$nick diff-nick} :< changed nickname
296+ == ::
297+++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
298+++ diff-nick {who/ship nic/cord} :< changed nickname
299+++ diff-story :> story change
300+ $% {$new cof/config} :< new story
301+ {$config cir/circle dif/diff-config} :< new/changed config
302+ {$status cir/circle who/ship dif/diff-status} :< new/changed status
303+ {$remove $~} :< removed story
304+ :: ... ::
305+ == ::
306+++ rumor-story ::> story rumor
307+ $? diff-story ::< both in & outward
308+ $% {$gram nev/envelope} ::< new/changed msgs
309+ == == ::
310+++ diff-config :> config change
311+ $% {$full cof/config} :< set w/o side-effects
312+ {$source add/? src/source} :< add/rem sources
313+ {$caption cap/cord} :< changed description
314+ {$filter fit/filter} :< changed filter
315+ {$secure sec/security} :< changed security
316+ {$permit add/? sis/(set ship)} :< add/rem to b/w-list
317+ {$remove $~} :< removed config
318+ == ::
319+++ diff-status :> status change
320+ $% {$full sat/status} :< fully changed status
321+ {$presence pec/presence} :< changed presence
322+ {$human dif/diff-human} :< changed name
323+ {$remove $~} :< removed status
324+ == ::
325+++ diff-human :> name change
326+ $% {$full man/human} :< fully changed name
327+ {$handle han/(unit cord)} :< changed handle
328+ {$true tru/(unit truename)} :< changed true name
329+ == ::
330+```
331+
332+These are, as enforced by Gall, the changes as they happen. This makes it possible for very minimal Hall clients to be implemented that only display a stream of changes, rather than keeping state themselves.
333+
334+
335+## Communication between Halls
336+
337+Halls can communicate with other Halls to send commands and subscription updates.
338+
339+### Interactions
340+
341+To request changes to a story, Halls can send `command`s.
342+
343+```
344+++ command :> effect on story
345+ $% {$publish tos/(list thought)} :< deliver
346+ {$present nos/(set term) dif/diff-status} :< status update
347+ :: ... ::
348+ == ::
349+```
350+
351+A `%publish` command contains messages. These are sent to foreign Halls to be published to their stories.
352+
353+The `%present` command is used for sending status updates about our ship.
354+
355+### Querying
356+
357+Halls can query other halls. Here's the peer move we send when we open a query on a foreign circle:
358+
359+```
360+:* ost.bol :< bone
361+ %peer :< move type
362+ /[our-circle]/[host]/[query-path] :< rumor path
363+ [host %hall] :< query target
364+ /circle/[their-circle]/[data]/[start]/[end] :< query path
365+== ::
366+```
367+
368+Again, the rumor path is what our Hall uses to identify what query a received message originates from. Our circle is specified so that we know what story is interested in the changes we get.
369+The query path is slightly more interesting. Of course it specifies the name of their story we want to subscribe our story to, but also a "start" and "end". These can (optionally) be used to specify the range of messages we want to get from our query. Once that range has passed, we stop receiving updates.
370+
371+### Federation
372+
373+Along the way so far, we've skipped some parts of structures. Most of these relate to federation. Let's see what we missed.
374+
375+```
376+++ query :> query paths
377+ $% {$burden who/ship} :< duties to share
378+ {$report $~} :< duty reports
379+ :: ... ::
380+ == ::
381+++ prize :> query result
382+ $% {$burden sos/(map term burden)} :< /burden
383+ :: ... ::
384+ == ::
385+++ rumor :< query result change
386+ $% {$burden nom/term rum/rumor-story} :< /burden
387+ :: ... ::
388+ == ::
389+++ diff-story ::
390+ $% {$bear bur/burden} :< new inherited story
391+ :: ... ::
392+ == ::
393+++ burden :> full story state
394+ $: gaz/(list telegram) :< all messages
395+ cos/lobby :< loc & rem configs
396+ pes/crowd :< loc & rem presences
397+ == ::
398+```
399+
400+We briefly touched upon how federation works on the higher level. On the lower, this is how things go down.
401+
402+1. When Hall boots on a star or galaxy, it starts querying its parent's `/burden` path. (Galaxies query ~zod.)
403+2. Upon receiving that query, the parent sends a `%burden` prize containing all state of its channels (fully public circles) to the child. It also subscribes to `/report` on that child.
404+3. When a new story gets created on the parent, its children get a `%burden` rumor with a `%bear` story diff, and they create a local copy of that channel.
405+4. When something about a parent's story changes, a `%burden` rumor is sent to all its children (because they're querying `/burden`). The children apply this change to their local version of the story.
406+5. When a child's story has a `%grams` or `%status` change, a `%burden` rumor is sent to the parent (because they're querying `/report`). The parent applies this change to their local version of the story, and #4 happens.
407+
408+
409+## Hall implementation
410+
411+Now that we know what gets sent over the wire and why, let's see what happens whenever such events happen. We won't be covering everything, but enough to illustrate the general flow.
412+
413+First though, it's useful to understand how Hall's code is structured. It consists of primary cores, designed to work optimally with Gall.
414+
415+* `++ta` is the transaction core. For every event that happens, be it a poke, peer or diff, the transaction core gets put to work to process it. Once it's done, it produces a list of deltas that describe how our state needs to be modified.
416+* `++da` is the delta application core. It is used to apply `++ta`'s deltas to our application state, and produce a list of side-effects.
417+
418+Both those cores also have a core within themselves dedicated solely to dealing with stories, `++so` and `++sa` respectively.
419+
420+Once all work in an engine core has finished, its `-done` arm is called to produce the result of all the core's computation.
421+
422+In the diagrams that follow, regular lines indicate flows that always happen. Dashed lines indicate flows that are traversed if the described condition is met.
423+Below the diagrams you will find brief explanations of the involved arms. In a particularly bright future, these might be available on-hover instead.
424+For brevity, utility arms that aren't a direct and important part of the flow have been omitted.
425+
426+(You will find that the origins still use old Gall arms, with some glue code in between. At the time of writing, new Gall has not yet been implemented, so this will have to do.)
427+
428+We will only display the delta generation parts of the flow. Delta application is usually implemented simply enough to deduce what it does from looking at the label.
429+
430+### Subscriptions
431+
432+Hall-to-Hall subscriptions happen when a source gets added to a story. This is done with a `%source` action, and results in a `%peer` move being sent (prompted by a `%story %follow` delta).
433+Upon receiving a valid peer on a `/circle` path, the subscribing ship is added to that circle's presence map.
434+
435+![subscriptions implementation flow](./diagrams/flow-subscriptions.png "subscriptions implementation flow")
436+
437+```
438+++ poke-talk-action :< we got poked with an action.
439+ ++ ta-action :< applies an action.
440+ ++ ta-config :< (re)configures a story.
441+:: ::
442+++ peer :< we got peered.
443+ ++ g-query :< resolves query to prize.
444+ ++ ta-subscribe :< act upon subscription.
445+ ++ so-attend :< adds a ship's status to the story.
446+```
447+
448+### Rumors
449+
450+Once a query has opened, Hall will receive updates on it, rumors. The changes describes in these rumors are applied via the following flow.
451+
452+![rumor implementation flow](./diagrams/flow-rumors.png "report diff implementation flow")
453+
454+```
455+++ diff-talk-rumor :< we got a query update.
456+ ++ ta-hear :< applies a rumor to the story it's intended for.
457+ ++ so-hear :< applies a %circle rumor to the story.
458+ ++ so-config-full :< splits a %full diff-config into separate changes.
459+ ++ so-bear :< accept burden, assimilate into the story's state.
460+ ++ so-lesson :< sends a report with presences.
461+```
462+
463+### Messaging
464+
465+To send messages, the user sends a `%convey` or `%phrase` action, resulting in a `%publish` command being sent to the involved partners. Receiving a `%publish` command causes its messages to be added to the story through the creation of a `%story %grams` delta.
466+
467+![messaging implementation flow](./diagrams/flow-messaging.png "messaging implementation flow")
468+
469+```
470+++ poke-talk-action :< we got poked with an action.
471+ ++ ta-action :< applies an action.
472+:: ::
473+++ poke-talk-command :< we get poked with a command.
474+ ++ ta-apply :< applies a command.
475+ ++ ta-think :< consumes each message in the given list.
476+ ++ ta-consume :< conducts a message to each partner in audience.
477+ ++ ta-conduct :< records or sends a message.
478+ ++ ta-transmit :< sends a message to a partner.
479+ ++ ta-record :< stores a message in a story.
480+ ++ so-learn :< either adds or modifies a message.
481+```
482+
483+
484+## The future
485+
486+Hall is neither complete nor perfect. There are features that need to be implemented, varying from small quality of life changes to broad-reaching functionality.
487+
488+### Features and functionality
489+
490+To turn Talk into a [sustainable social platform](https://urbit.org/fora/posts/~2017.4.26..18.00.25..b93c~/), it needs a number of things.
491+
492+Primarily, discoverability of circles. A possible solution for realizing this is making it possible for users to add friends, which would have their Hall subscribe to a list of circles the added friends are in. The existing public membership functionality can be leveraged for this.
493+
494+Eventually, content self-moderation might need to be implemented. Users would flag their content if it is potentially offensive. Others would easily be able to filter out content that might offend them.
495+This functionality brings its own large sets of challenges that need to be tackled.
496+
497+Additionally, federation might be put to broader use. Knowing a circle is federated could help fall back to alternative hosts in case the one Hall originally subscribed to is unavailable.
498+Implementation-wise, care would need to be taken for this to not get ugly. Not to mention, when/how would availability of a host be verified?
499+
500+Other changes that might have a fair impact on the functioning of Hall are un/read states for messages, and being able to use moons to allow your friends to chat with you in a local channel.
501+
502+Smaller functionality that still needs to be implemented includes:
503+* Extended permissions management. Being able to black-/whitelist entire ship classes.
504+* Improved presence functionality. Actually using the presence system, and sending "typing", "idle", etc. statuses.
505+* Polls.
506+
507+And of course there's a lot Talk, the client, can improve on as well.
508+
509+
510+## Further reading
511+
512+To gain a more thorough understanding of Hall's inner workings, take a look at its source code. It comes with inline documentation.
513+[On Github.](https://github.com/urbit/arvo/blob/master/app/hall.hoon)
514+
515+To see an expansive example of a Hall client, take a look at the code of Talk. It, too, comes with inline documentation.
516+[On Github.](https://github.com/urbit/arvo/blob/master/app/talk.hoon)
docs/talk/diagrams/flow-messaging.pngnew file

Binary file not shown.

docs/talk/diagrams/flow-rumors.pngnew file

Binary file not shown.

docs/talk/diagrams/flow-subscriptions.pngnew file

Binary file not shown.

docs/talk/gall-eg.hoonnew file+86
@@ -0,0 +1,86 @@
1+:: counter app
2+:: new gall example, may or may not compile.
3+::
4+|%
5+++ query :> valid queries
6+ $% {$number $~} :< current number
7+ {$mul-of val/@ud} :< is num multiple of?
8+ == ::
9+++ prize :> query results
10+ $% {$number num/@ud} :< /number
11+ {$mul-of mul/?} :< /mul-of
12+ == ::
13+++ rumor :> query result changes
14+ $% {$number delta} :< /number
15+ {$mul-of mul/?} ::TODO or just flip? :< /mul-of
16+ == ::
17+:: the above would ordinarily be placed in sur/, ::
18+:: since other apps might want to use it. ::
19+++ brain {num/@ud $~} :< application state
20+++ delta :> state change
21+ $% {$increment $~} :< +1
22+ {$decrement $~} :< -1
23+ == ::
24+--
25+::
26+|_ {bol/bowl brain}
27+::
28+++ leak :> read permission
29+ |= {who/ship qer/query}
30+ ^- ?
31+ & :: everyone's allowed
32+::
33+++ peek :> synchronous read
34+ |= qer/query
35+ ^- (unit (unit prize))
36+ ?- -.qer
37+ $number ``[%number num]
38+ $mul-of ?: =(0 mul.qer) [~ ~]
39+ ``[%mul-of =(0 (mod num mul.qer))]
40+ ==
41+::
42+++ poke-loob :> regular old poke
43+ |= inc/?
44+ ^- (list delta)
45+ :_ ~
46+ ?: inc [%increment ~]
47+ [%decrement ~]
48+::
49+++ bake :> apply delta to state
50+ |= del/delta
51+ ^- (quip opera +>)
52+ :- ~
53+ ?- -.del
54+ $increment +>(num +(num))
55+ $decrement +>(num (dec num))
56+ ==
57+::
58+++ feel :> delta to rumor
59+ |= {qer/query del/delta}
60+ ^- (unit rumor)
61+ ?- -.qer
62+ $number
63+ `[%number del]
64+ ::
65+ $mul-of
66+ :: since we only want to send a rumor if result
67+ :: changed, we need to deduce the old state from
68+ :: the current state and the delta. depends on the
69+ :: fact that state changes before ++feel. funky!
70+ :: we could, of course, store mul/? in state, and
71+ :: make a delta for it, but should we need to?
72+ =/ old
73+ .= 0
74+ %+ mod
75+ ?- -.del
76+ $increment (dec num)
77+ $decrement +(num)
78+ ==
79+ mul.qer
80+ =/ new =(0 (mod num mul.qer))
81+ ?: =(old new) ~
82+ `[%mul-of new]
83+ ==
84+::
85+:: not pictured: ++path-to-query
86+--
docs/talk/gall-spec_orig.hoonnew file+149
@@ -0,0 +1,149 @@
1+=> |%
2+ --
3+|* $: :> vinyl: historical state (including version)
4+ :> brain: working state of the application (not including version)
5+ :> delta: grain of change across all state
6+ :> prize: (pair mark noun) for namespace value
7+ :> rumor: (pair mark noun) for namespace diff
8+ :> opera: (pair bone card) for operation (old ++move)
9+ :>
10+ vinyl/mold
11+ brain/mold
12+ delta/mold
13+ prize/mold
14+ rumor/mold
15+ opera/mold
16+ ==
17+|_ $: :> ops: pending operations, in reverse order
18+ :> ego: current state
19+ :>
20+ ops/(list opera)
21+ ego/brain
22+ ==
23+:: :: ++bake
24+++ bake :< apply delta
25+ |= $: :> del: change
26+ :>
27+ del/delta
28+ ==
29+ :> core after change (including operations)
30+ ^- _+>
31+ !!
32+:: :: ++cope
33+++ cope :< transaction result
34+ |= $: :> weg: forward identity
35+ :> het: success or error report
36+ :>
37+ weg/(list coin)
38+ het/(unit tang)
39+ ==
40+ :> actions in reverse order
41+ :>
42+ ^- (list delta)
43+ !!
44+:: :: ++fail
45+++ fail :< process error
46+ |= $: :> why: error dump
47+ :>
48+ why/tang
49+ ==
50+ :> actions in reverse order
51+ :>
52+ ^- (list delta)
53+ !!
54+:: :: ++feel
55+++ feel :< update
56+ |= $: :> del: change
57+ :> pex: preparsed path, inside-first
58+ :>
59+ del/delta
60+ pex/(list coin)
61+ ==
62+ :> query updates in reverse order
63+ :>
64+ ^- (list rumor)
65+ !!
66+:: :: ++hear
67+++ hear :< subscription update
68+ |= $: :> weg: forward identity
69+ :>
70+ weg/(list coin)
71+ ==
72+ :> actions in reverse order
73+ :>
74+ ^- (list delta)
75+ !!
76+:: :: ++pull
77+++ pull :< subscription cancel
78+ |= $: :> weg: forward identity
79+ :> het: error report, if any
80+ :>
81+ weg/(list coin)
82+ het/(unit tang)
83+ ==
84+ :> actions in reverse order
85+ :>
86+ ^- (list delta)
87+ !!
88+:: :: ++leak
89+++ leak :< check access
90+ |= $: :> lec: leakset (~ means public)
91+ :> pex: preparsed path, inside-first
92+ :>
93+ lec/(unit (set ship))
94+ pex/(list coin)
95+ ==
96+ :> if path `pex` is visible to ships in `lec`
97+ ^- ?
98+ !!
99+:: :: ++load
100+++ look :< asynchronous read
101+ |= $: :> pex: preparsed path, inside-first
102+ :>
103+ pex/(list coin)
104+ ==
105+ :> actions in reverse order
106+ ^- _+>
107+ !!
108+:: :: ++prep
109+++ prep :< load system
110+ |= $: old/vinyl
111+ ==
112+ :> core after boot
113+ ^- _+>
114+ !!
115+:: :: ++peek
116+++ peek :< synchronous read
117+ |= $: :> pex: preparsed path, inside-first
118+ :>
119+ pex/(list coin)
120+ ==
121+ :> value at `pec`; ~ for unavailable, [~ ~] for invalid
122+ :>
123+ ^- (unit (unit prize))
124+ !!
125+:: :: ++poke
126+++ poke :< generic poke
127+ |= $: :> ost: opaque cause
128+ :> msg: message with mark and vase
129+ :>
130+ ost/bone
131+ msg/cage
132+ ==
133+ :> actions in reverse order
134+ :>
135+ ^- (list delta)
136+ !!
137+:: :: ++pour
138+++ pour :< arvo response
139+ |= $: :> weg: forward identity
140+ :> sin: response card
141+ :>
142+ weg/(list coin)
143+ sin/sign
144+ ==
145+ :> actions in reverse order
146+ :>
147+ ^- (list delta)
148+ !!
149+--
docs/talk/gall.mdnew file+245
@@ -0,0 +1,245 @@
1+
2+# The new Gall model
3+
4+This document is complemented by the source code of applications that use the new Gall model (like [hall](https://github.com/urbit/arvo/blob/master/app/hall.hoon)), but doesn't require it. Code snippets will be provided where useful. Some knowledge of Hoon and the functioning of Hoon apps is assumed.
5+
6+New Gall has not yet fully solidified. As such, structure and naming are tentative to change.
7+
8+## Table of contents
9+
10+* [Renewing a pillar of Arvo](#renewing-a-pillar-of-arvo)
11+ * [Problems](#problems)
12+ * [Solutions](#solutions)
13+* [As seen in new Gall](#as-seen-in-new-gall)
14+ * [Structures](#structures)
15+ * [Arms](#arms)
16+* [By example](#by-example)
17+ * [State & deltas](#state--deltas)
18+ * [Queries & rumors](#queries--rumors)
19+ * [Responding to queries](#responding-to-queries)
20+ * [Updating state & query results](#updating-state--query-results)
21+* [Criticism](#criticism)
22+* [Further reading](#further-reading)
23+
24+## Renewing a pillar of Arvo
25+
26+When you write an app, Gall is responsible for making sure its event arms like `++poke` get called when they need to. In essence, it provides developers with a consistent interface for hooking their app up to the operating system.
27+It's not doing a lot to make sure this is done in a structured way though, which results in apps (especially larger ones) feeling like big tangled messes. Something needs to be done about this.
28+
29+### Problems
30+
31+Imagine a `++poke`, `++diff`, or even a `++peer` arm. In current implementations, you'll often see their product defined through cast as the following:
32+`^- (quip move +>)`
33+Or (sadly) more commonly:
34+`^- {(list move) _+>.$}`
35+
36+These arms are producing both side-effects and new state. To do this, their code has to simultaneously figure out "how does this poke/diff/whatever change our state?" and "what side-effects does this change have?".
37+You'll find that the logic relating to these two often becomes tangled, making the flow of the whole more difficult to understand. And the side-effects more often than not relate to subscriptions, for which the developer may be writing a lot of boilerplate code. Gall currently does not help in either of these places.
38+
39+> The main significant cost of software development is the cost of
40+untangling what the computer is doing, and or is supposed to be doing,
41+over and over again in your head. Any way of lowering this untangling
42+cost is extremely welcome.
43+
44+-- *~sorreg-namtyv*
45+
46+### Solutions
47+
48+Let's imagine a world in which Gall *does* help, in both those places.
49+
50+It would be wonderful if Gall could take care of all standard subscription management logic for you, and direct the flow of code as it concludes is appropriate.
51+Applications, then, would have to help Gall by providing the different parts of this flow, and the checks that allow Gall to make the right decisions. This takes some work out of the developer's hands and results in more structured application code.
52+
53+If we expand on that a bit we can even have Gall help us in untangling state changes from side effects. We do so by separating state changes into two phases: *analyzing* what changes need to be made, and *applying* those changes.
54+But where do the side-effects go then? We need to realize there's two kinds: side-effects that are subscription updates, and those that aren't. The latter get produces by applying state changes, while the former get integrated into the Gall flow we described above.
55+Since subscriptions are essentially queries to an app, requesting a specific part of its data/state, we can deduce subscription updates from state changes. We merely provide the logic, and Gall chains it all together.
56+
57+Having Gall support all this allows us to cleanly and structurally untangle state change analysis, application, and subscription logic into their own arms.
58+For trivial apps, this might result in some arms with trivial code. Though it may feel like writing cruft, it makes understanding the app just as simple as it actually as.
59+For more complex apps, all logic is no longer a big chunk of "what do we do when x happens?", but rather a couple of smaller chunks, like "x happened, how does that change our state?" and "if our state changes like y, what does that mean for subscription z?" These are precisely the kinds of questions that application developers should be asked.
60+
61+
62+## As seen in new Gall
63+
64+Of course for the above to be made into reality, Gall will need to see some changes. Let's outline the new structures and the arms they get passed between.
65+
66+### Structures
67+
68+This wouldn't be Urbit if we had some cool new terminology for people to learn. These ones are (for the most part) semantically sensible though, and you might already see how these relate to the story above.
69+
70+`brain`: application state.
71+`delta`: change to application state.
72+`opera`: side-effect, operation, move.
73+`query`: request (to an app) for data on a specific path.
74+`prize`: query result.
75+`rumor`: change to a query result.
76+
77+These should be fairly straightforward. Like packets are to Urbits, `delta`s are to `brain`s and `rumor`s are to `prize`s. If one diligently updates the `prize` they received using all the `rumor`s that are relevant to it, they will always have the same `prize` as if they queried for it all over again.
78+
79+### Arms
80+
81+This also wouldn't be Urbit if we couldn't boil that down to a few simple pseudocode functions. Let's try, shall we?
82+
83+```
84+++ bake |= {brain delta} ^- {brain opera}
85+++ peek |= {brain query} ^- (unit (unit prize))
86+++ feel |= {query delta} ^- (unit rumor)
87+++ gain |= {prize rumor} ^- prize
88+
89+:: for any given brain, delta and query:
90+.= (peek brain:(bake brain delta) query)
91+ (gain rumor:(feel query delta) prize:(peek brain query))
92+```
93+
94+There, in the first three arms we already have the bulk of new Gall! `++gain` won't be part of it, since most applications don't need to keep track of `prize`s directly. Those that do may still implement and hook it up themselves though.
95+
96+Of course, these aren't all of the new Gall arms. Most important to still mention is `++leak`, which takes a `ship` and `query` and checks if the former has permission to ask for the latter.
97+There's also `++look` for asynchronous reads, `++hear` for subscription updates (rumors), `++fail` for dealing with process errors, `++cope` for dealing with transaction results, and `++pour` for dealing with responses from arvo.
98+`++prep`, `++poke` and `++pull` continue to function as they do right now.
99+For a more verbose specification of all of these, see the new Gall spec.
100+
101+
102+## By example
103+
104+To help solidify this and see what this would looks like in the wild, let's make a very simple example app. It's a counter that can go up and down, and can be queried for its value, or whether or not its value is a multiple of x. First we write all the structures that will support our app, and then we implement the arms that operate on them.
105+(The app code in its entirety can be found [here](gall-eg.hoon).)
106+
107+### State & deltas
108+
109+Below is the application state, and the deltas we'll be using to modify it.
110+
111+```
112+|%
113+++ brain {num/@ud $~} :< application state
114+++ delta :> state change
115+ $% {$increment $~} :< +1
116+ {$decrement $~} :< -1
117+ == ::
118+```
119+
120+Fairly simple, right? We store a number, and every change either in- or decrements it.
121+
122+### Queries & rumors
123+
124+Let's also define the queries we'll be supporting, their results, and the changes to their results. Instead of only allowing people to query the current number, let's make it a tad more interesting by allowing them to query whether or not the current number is a multiple of something.
125+
126+```
127+++ query :> valid queries
128+ $% {$number $~} :< current number
129+ {$mul-of val/@ud} :< is num multiple of?
130+ == ::
131+++ prize :> query results
132+ $% {$number num/@ud} :< /number
133+ {$mul-of mul/?} :< /mul-of
134+ == ::
135+++ rumor :> query result changes
136+ $% {$number delta} :< /number
137+ {$mul-of mul/?} :< /mul-of
138+ == ::
139+--
140+```
141+
142+You'll see the `rumor` for a `/number` query just contains a delta. In this specific case, a change in state maps directly to a change to `prize`. For `/mul-of` queries, things aren't that simple.
143+
144+### Responding to queries
145+
146+Now, let's implement all the arms that will be called as things start happening. First, we want to implement `++leak`, which checks if a given `ship` is allowed to make a certain `query`. In this case, we're fine with everyone checking out our application's data.
147+
148+```
149+|_ {bol/bowl brain}
150+::
151+++ leak :> read permission
152+ |= {who/ship qer/query}
153+ ^- ?
154+ & :: everyone's allowed
155+```
156+
157+Next, let's create the `prize`s for the folks that make it through `++leak`. We'll be producing a `(unit (unit prize))` so we can potentially say `~` for "unavailable" and `[~ ~]` for "invalid query".
158+
159+```
160+++ peek :> synchronous read
161+ |= qer/query
162+ ^- (unit (unit prize))
163+ ?- -.qer
164+ $number ``[%number num]
165+ $mul-of ?: =(0 mul.qer) [~ ~]
166+ ``[%mul-of =(0 (mod num mul.qer))]
167+ ==
168+```
169+
170+### Updating state & query results
171+
172+Our app can get queried! If they're interested enough, they'll want to receive updates on that whenever relevant state changes. First, let's see how state changes happen. We still have regular old `++poke` arms, let's use that to prompt our application to change its state.
173+
174+```
175+++ poke-loob :> regular old poke
176+ |= inc/?
177+ ^- (list delta)
178+ :_ ~
179+ ?: inc [%increment ~]
180+ [%decrement ~]
181+::
182+++ bake :> apply delta to state
183+ |= del/delta
184+ ^- (quip opera +>)
185+ :- ~
186+ ?- -.del
187+ $increment +>(num +(num))
188+ $decrement +>(num (dec num))
189+ ==
190+```
191+
192+`delta`s get redirected into `++bake` so that our state can get changed as described. After this happens the same `delta`s get, for each active query, routed into `++feel`. That then figures out what the `rumor` relevant to the query is, if applicable.
193+
194+```
195+++ feel :> delta to rumor
196+ |= {qer/query del/delta}
197+ ^- (unit rumor)
198+ ?- -.qer
199+ $number
200+ `[%number del]
201+ ::
202+ $mul-of
203+ :: since we only want to send a rumor if result
204+ :: changed, we need to deduce the old state from
205+ :: the current state and the delta. depends on the
206+ :: fact that state changes before ++feel. funky!
207+ :: we could, of course, store mul/? in state, and
208+ :: make a delta for it, but should we need to?
209+ =/ old
210+ .= 0
211+ %+ mod
212+ ?- -.del
213+ $increment (dec num)
214+ $decrement +(num)
215+ ==
216+ mul.qer
217+ =/ new =(0 (mod num mul.qer))
218+ ?: =(old new) ~
219+ `[%mul-of new]
220+ ==
221+```
222+
223+As we saw earlier, for `/number` queries the `delta`s match one-on-one with the relevant `rumor`s. For `/mul-of` queries we do a little bit of work to see if anything actually changed. No need to send a `rumor` if it hasn't.
224+
225+
226+## Criticism
227+
228+* Where event arms currently get passed a `wire`, and the new Gall described above passes them a custom `query` structure, the original new Gall spec gave them `(list coin)`, a "pre-parsed wire". These structures (eg `[%$ p=[p=~.ud q=123]]`) are uncomfortable to work with. Even with a "coin list parsing library" it still doesn't feel ideal.
229+Because of custom structures being easier to work with than lists of knots or coins, writing a `++path-to-query` arm by hand is a small cost for huge gains.
230+
231+* Why do `prize` units mean what they do? Would have expected `~` to mean "invalid" and `[~ ~]` to mean "unavailable" as opposed to the other way around.
232+
233+* The original new Gall spec mentions output lists (like `(list delta)` etc.) to be in reverse order. This was done because adding to the head of a list (`[item list]`) is easier than appending to the tail of a list (`(weld list [item ~])` or other).
234+While it's technically easier to produce a list in reverse order, semantically it's yet another thing to keep in mind. Luckily, most of the "add to x, produce all of it later" code is set-and-forget, so probably not a huge deal, but do we really fear a few stray `++flop`s that much?
235+
236+* There's some weirdness with relation to relying on old state in `++feel` to determine whether a query result actually changed. Just relying on state in general for delta-to-rumor conversion may or may not violate the new Gall spec.
237+
238+* The original new Gall spec specifies `++leak` as taking a `(unit (set ship))`, where `~` means public. Is there a use case for checking more than just a single ship?
239+
240+* Gall should probably cache `++feel` results during a single pass, to avoid the cycles of generating what it can be certain of is the same `(unit rumor)`. (But then for eg `/circle/nom/13` and `/circle/nom/14` it would still recalculate. Better than nothing.)
241+
242+
243+## Further reading
244+
245+[Original new Gall spec by ~sorreg-namtyv](gall-spec_orig.hoon)
docs/talk/interface.mdnew file+386
@@ -0,0 +1,386 @@
1+
2+# Hall interface
3+
4+This document describes the different interfaces Hall provides and the data that is accessible and modifyable through them. Knowledge of the Urbit application model (including [new gall](gall.md)) and #[Hall's architecture](architecture.md) is assumed.
5+
6+While the structures here are given in Hoon, they match fairly closely to their JSON equivalent. Most important to note is that `$%({$x y/z})` becomes accessible as `json.x.y`.
7+
8+
9+## Table of contents
10+
11+* [Queries](#queries)
12+ * [/client](#client)
13+ * [/client prize](#client-prize)
14+ * [/client rumor](#client-rumor)
15+ * [/public](#public)
16+ * [/public prize](#public-prize)
17+ * [/public rumor](#public-rumor)
18+ * [/peers](#peers)
19+ * [/peers prize](#peers-prize)
20+ * [/peers rumor](#peers-rumor)
21+ * [/circle](#circle)
22+ * [/circle prize](#circle-prize)
23+ * [/circle rumor](#circle-rumor)
24+* [Actions](#actions)
25+ * [Circle configuration](#circle-configuration)
26+ * [Messaging](#messaging)
27+ * [Personal metadata](#personal-metadata)
28+ * [Changing shared UI](#changing-shared-ui)
29+ * [Miscellaneous changes](#miscellaneous-changes)
30+
31+
32+## Queries
33+
34+Queries are the paths you pass into `%peer` moves. Internally, they get translated to a `++query` structure for easier handling. We'll be giving examples of valid query paths alongside the structures themselves.
35+
36+### /client
37+
38+To be able to keep certain UI elements like glyphs and local nicknames consistent across different Hall clients, they can query Hall for the current UI state.
39+
40+```
41+++ query ::
42+ $% {$client $~} :< shared ui state
43+ :: .... ::
44+ == ::
45+```
46+
47+Valid paths include:
48+
49+```
50+:> all shared ui state
51+/client
52+```
53+
54+#### /client prize
55+
56+Contains a map of glyphs and the audiences they map to, as well as a map of ships and their locally set nicknames.
57+
58+```
59+++ prize :> query result
60+ $% {$client prize-client} :< /client
61+ :: ... ::
62+ == ::
63+++ prize-client :> shared ui state
64+ $: gys/(jug char audience) :< glyph bindings
65+ nis/(map ship nick) :< local nicknames
66+ == ::
67+```
68+
69+#### /client rumor
70+
71+Contains either a bound or unbound glyph and its target, or a ship with its new ncikname. A `nic`kname of `''` means the associated ship no longer has a nickname set for it.
72+
73+```
74+++ rumor :> query result change
75+ $% {$client rum/rumor-client} :< /client
76+ :: ... ::
77+ == ::
78+++ rumor-client :< changed ui state
79+ $% {$glyph diff-glyph} :< un/bound glyph
80+ {$nick diff-nick} :< changed nickname
81+ == ::
82+++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
83+++ diff-nick {who/ship nic/nick} :< changed nickname
84+```
85+
86+
87+### /public
88+
89+To aid in circle discoverability, users can add circles to their "public membership" list. This can then be queried for by, for example, a profile page.
90+
91+```
92+++ query ::
93+ $% {$public $~} :< public memberships
94+ :: .... ::
95+ == ::
96+```
97+
98+Valid paths include:
99+
100+```
101+:> all public memberships
102+/public
103+```
104+
105+#### /public prize
106+
107+Contains the set of circles the user has on their public list.
108+
109+```
110+++ prize :> query result
111+ $% {$public cis/(set circle)} :< /public
112+ :: ... ::
113+ == ::
114+```
115+
116+#### /public rumor
117+
118+Contains a circle that was either added or removed from the public list.
119+
120+```
121+++ rumor :> query result change
122+ $% {$public add/? cir/circle} :< /public
123+ :: ... ::
124+ == ::
125+```
126+
127+### /peers
128+
129+To allow a circle owner to inspect who is actually currently subscribed to their stories, they can issue a query to retrieve subscription data.
130+
131+```
132+++ query ::
133+ $% {$peers nom/naem} :< readers of story
134+ :: .... ::
135+ == ::
136+```
137+
138+Query paths are structured as follows:
139+
140+```
141+/peers/[circle-name]
142+```
143+
144+Valid paths include:
145+
146+```
147+:> peers for circle %urbit-meta
148+/peers/urbit-meta
149+```
150+
151+#### /peers prize
152+
153+Contains a map of ships and the different queries they currently have active for the selected story.
154+
155+```
156+++ prize :> query result
157+ $% {$peers pes/(jar ship query)} :< /peers
158+ :: ... ::
159+ == ::
160+```
161+
162+#### /peers rumor
163+
164+Contains a ship and a query, and a flag to indicate whether that subscription has started or ended.
165+
166+```
167+++ rumor :> query result change
168+ $% {$peers add/? who/ship qer/query} :< /peers
169+ :: ... ::
170+ == ::
171+```
172+
173+### /circle
174+
175+Circle queries allow for the retrieving of data from stories. Their messages, configuration, presences, can all be accessed. Since this is a lot of data, there are lots of possibilities for filtering it built in to the query itself.
176+
177+A quick refresher on the difference between "local" and "remote" presence and configuration: "local" means it pertains to the circle itself, "remote" means it pertains to one of its configured sources. The latter is primarily useful to clients when using a circle for aggregation, like the `%inbox`.
178+
179+```
180+++ query ::
181+ $% $: $circle :> story query
182+ nom/naem :< circle name
183+ wer/(unit circle) :< from source
184+ wat/(set circle-data) :< data to get
185+ ran/range :< query duration
186+ == ::
187+ :: .... ::
188+ == ::
189+++ circle-data :> kinds of circle data
190+ $? $grams :< messages
191+ $group-l :< local presence
192+ $group-r :< remote presences
193+ $config-l :< local config
194+ $config-r :< remote configs
195+ == ::
196+++ range :> inclusive msg range
197+ %- unit :< ~ means everything
198+ $: hed/place :< start of range
199+ tal/(unit place) :< opt end of range
200+ == ::
201+++ place :> range indicators
202+ $% {$da @da} :< date
203+ {$ud @ud} :< message number
204+ == ::
205+```
206+
207+Query paths are structured as follows:
208+
209+```
210+/circle/[circle-name]/(from-circle)/[what/data]/(range-start(/range-end))
211+(from-circle) : optional message source, ~ship/circle
212+[what/data] : one or more of grams, group, group-l, group-r,
213+ : config, config-l, config-r, combined using /
214+(range) : an optional range with an optional end, its points denoted
215+ : in either message number (@ud) or date (@da)
216+```
217+
218+Valid paths include:
219+
220+```
221+:> get all messages from circle %urbit-meta
222+/circle/urbit-meta/grams
223+:> get all messages, all presences and local configs from %urbit-meta
224+/circle/urbit-meta/grams/group/config-l
225+:> get all messages %urbit-meta has heard from its source ~zod/fora
226+/circle/urbit-meta/~zod/fora/grams
227+:> get the first 100 messages from %urbit-meta
228+/circle/urbit-meta/grams/0/99
229+:> get the first 100 messages %urbit-meta has heard from its source ~zod/fora
230+/circle/urbit-meta/~zod/fora/grams/0/99
231+:> get all messages from %urbit-meta, starting now
232+/circle/urbit-meta/grams/group/(scow %da now)
233+:> get all messages from %urbit-meta, starting now, ending at the 100th message
234+/circle/urbit-meta/grams/(scow %da now)/99
235+:> get local presences from %urbit-meta for a week
236+/circle/urbit-meta/group-l/(scow %da now)/(scow %da (add now ~d7))
237+```
238+
239+#### /circle prize
240+
241+Contains (where applicable) messages in envelopes (with message numbers), local and remote configurations and presences.
242+
243+```
244+++ prize :> query result
245+ $% {$circle package} :< /circle
246+ :: ... ::
247+ == ::
248+++ package :> story state
249+ $: nes/(list envelope) :< messages
250+ cos/lobby :< loc & rem configs
251+ pes/crowd :< loc & rem presences
252+ == ::
253+```
254+
255+#### /circle rumor
256+
257+Contains a detailed change description of the data relevant to the query that changed.
258+Messages are wrapped in envelopes to include their sequence number, and note the source they were heard from.
259+Configuration and status changes specify the circle they apply to.
260+
261+```
262+++ rumor :> query result change
263+ $% {$circle rum/rumor-story} :< /circle
264+ :: ... ::
265+ == ::
266+++ rumor-story :> story rumor
267+ $% {$new cof/config} :< new story
268+ {$gram src/circle nev/envelope} :< new/changed message
269+ {$config cir/circle dif/diff-config} :< new/changed config
270+ {$status cir/circle who/ship dif/diff-status} :< new/changed status
271+ {$remove $~} :< removed story
272+ == ::
273+++ diff-config :> config change
274+ $% {$full cof/config} :< set w/o side-effects
275+ {$source add/? src/source} :< add/rem sources
276+ {$caption cap/cord} :< changed description
277+ {$filter fit/filter} :< changed filter
278+ {$secure sec/security} :< changed security
279+ {$permit add/? sis/(set ship)} :< add/rem to b/w-list
280+ {$remove $~} :< removed config
281+ == ::
282+++ diff-status :> status change
283+ $% {$full sat/status} :< fully changed status
284+ {$presence pec/presence} :< changed presence
285+ {$human dif/diff-human} :< changed name
286+ {$remove $~} :< removed status
287+ == ::
288+++ diff-human :> name change
289+ $% {$full man/human} :< fully changed name
290+ {$handle han/(unit cord)} :< changed handle
291+ {$true tru/(unit truename)} :< changed true name
292+ == ::
293+```
294+
295+
296+## Actions
297+
298+Actions can be sent by poking Hall with data marked as `%hall-action`. Actions are used for all user operations. If an error or other unexpected behavior occurs while executing an action, Hall notifies the user by sending an `%app` message to their `%inbox`.
299+
300+### Circle configuration
301+
302+Since all of these apply to a specific circle, they all specify a name `nom` of the circle to operate on.
303+
304+```
305+++ action :> user action
306+ $% {$create nom/naem des/cord sec/security} :< create circle
307+ {$delete nom/naem why/(unit cord)} :< delete + announce
308+ {$depict nom/naem des/cord} :< change description
309+ {$filter nom/naem fit/filter} :< change message rules
310+ {$permit nom/naem inv/? sis/(set ship)} :< invite/banish
311+ {$source nom/naem sub/? srs/(set source)} :< un/sub to/from src
312+ :: ... ::
313+ ==
314+```
315+
316+`%create`: Creates a circle with description `des` and security mode `sec`. If this mode is a whitelist, the user is automatically added to it.
317+
318+`%delete`: Deletes the circle. If a reason `why` is provided, posts that as the last message to the circle before deleting it.
319+
320+`%depict`: Set the description of the circle to `des`.
321+
322+`%filter`: Set the filter (message sanitation rules) for the circle to `fit`.
323+
324+`%permit`: Either invite or banish ships to/from the circle, modifying the access control list accordingly. Regardless of whether this actually makes any changes, sends an `%inv` message to the involved ships' `%inbox`es.
325+
326+`%source`: Add or remove sources to/from the circle, un/subscribing it to/from the `grams`, `group-l` and `config-l` each one.
327+
328+### Messaging
329+
330+There are two interfaces for telling hall to send a message. The first takes entire `thought`s, the second only `speech`es and the audience to send them to.
331+
332+```
333+++ action :> user action
334+ $% {$convey tos/(list thought)} :< post exact
335+ {$phrase aud/audience ses/(list speech)} :< post easy
336+ :: ...
337+ ==
338+```
339+
340+`%convey`: Sends the thoughts to their audiences.
341+
342+`%phrase`: Turns the speeches into thoughts by applying sane defaults for metadata (auto-generated `uid`, `now` for `wen`), and then sends those thoughts.
343+
344+### Personal metadata
345+
346+These concern the presence users have in circles they are participating in.
347+
348+```
349+++ action :> user action
350+ $% {$notify aud/audience pes/(unit presence)} :< our presence update
351+ {$naming aud/audience man/human} :< our name update
352+ :: ... ::
353+ ==
354+```
355+
356+`%notify`: Sets the user's presence in the audience circles to `pes`. A good client will automatically set these based on the user's activity. (`%talk` on typing, `%idle` on idle, `%gone` on sign-off.)
357+
358+`%naming`: Sets the user's name (handle and real name) for the given audience. Good clients can display these in place of ship names.
359+
360+### Changing shared UI
361+
362+When the user makes any changes to shared UI elements (elements that should persist between clients), this has to be communicated to Hall.
363+
364+```
365+++ action :> user action
366+ $% {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
367+ {$nick who/ship nic/nick} :< new identity
368+ :: ... ::
369+ ==
370+```
371+
372+
373+`%glyph`: Adds or removed a binding of a glyph to an audience.
374+
375+`%nick`: Sets a local nickname for a ship. An empty nickname `''` means the ship has no nickname.
376+
377+### Miscellaneous changes
378+
379+```
380+++ action :> user action
381+ $% {$public add/? cir/circle} :< show/hide membership
382+ :: ... ::
383+ ==
384+```
385+
386+`%public`: Adds or removes a circle to/from the user's public membership list.
docs/using/messaging.md+213−110
@@ -11,23 +11,27 @@ title: Messaging (:talk)
11
11
12<div class="col-md-8">
12<div class="col-md-8">
13
13
14−`:talk` is the Urbit messaging and notifications protocol. Today we use
14+`:talk` is the built-in frontend for the Urbit messaging and notifications
15−`:talk` just to chat and coordinate, but it's really a general purpose
15+protocol, `:hall`. Today we use `:hall` just to chat and coordinate, but
16−piece of infrastructure.
16+it's really a general purpose piece of infrastructure.
17
17
18For the time being come join us in `/urbit-meta` by using the
18For the time being come join us in `/urbit-meta` by using the
19<a href="#-quickstart">quickstart</a> below.
19<a href="#-quickstart">quickstart</a> below.
20
20
21−Today `:talk` is sort of like a distributed, encrypted Slack that can be
21+Today `:hall` is sort of like a distributed, encrypted Slack that can be
22−used from the CLI and the browser. There’s no central `:talk` server.
22+used from the CLI and the browser. There’s no central `:hall` server.
23Any Urbit can host one.
23Any Urbit can host one.
24
24
25−`:talk` is a general purpose tool for both aggregating and publishing
25+`:hall` is a general purpose tool for both aggregating and publishing
26−streams of messages. Applications can use `:talk` as their transport
26+streams of messages. Applications can use `:hall` as their transport
27−protcol, API connectors can push disparate data sources into `:talk`,
27+protocol, API connectors can push disparate data sources into `:hall`,
28and so on. There are lots of things a distributed message protocol can
28and so on. There are lots of things a distributed message protocol can
29be used for that we haven't even thought of.
29be used for that we haven't even thought of.
30
30
31+Here we'll be discussing how to operate the default CLI frontend, `:talk`,
32+to send and receive messages. For a more in-depth look at `:hall`'s
33+internals, take a look at its [documentation](#TODO).
34+
31</div>
35</div>
32
36
33</div>
37</div>
@@ -35,36 +39,29 @@ be used for that we haven't even thought of.
35## Quickstart
39## Quickstart
36
40
37For the most part we use `:talk` as a single-instance of Slack: one main
41For the most part we use `:talk` as a single-instance of Slack: one main
38−channel (`/urbit-meta`) and dms. Everyone is more than welcome in
42+channel (`/urbit-meta`) and direct messages. Everyone is more than welcome
39−`/urbit-meta`. It's the place to get help, ask questions and chat about
43+in `/urbit-meta`. It's the place to get help, ask questions and chat about
40Urbit in general.
44Urbit in general.
41
45
42Let's join `/urbit-meta`:
46Let's join `/urbit-meta`:
43
47
44Use `ctrl-x` to switch from `:dojo` to `:talk`.
48Use `ctrl-x` to switch from `:dojo` to `:talk`.
45
49
46−If you're a planet:
47−
48− ~your-urbit:talk> ;join /urbit-meta
50+To join `/urbit-meta`:
49−
50−If you're a comet:
51
51
52− ~your-really-long-urbit:talk> ;join ~binzod/urbit-meta
52+ ~your-urbit:talk[] ;join /urbit-meta
53
53
54You'll see:
54You'll see:
55
55
56− ---------:talk| %porch subscribed to /urbit-meta, called `>`
56+ --------------| ;join /urbit-meta
57− ---------:talk| rules of /urbit-meta:
57+ --------------| new glyph '>'
58− ---------:talk| don't be rude
59− ---------:talk| urbit-meta is politically correct and safe for work
60− ~binzod= ~your-urbit admitted to %urbit-meta
61 ~your-urbit:talk>
58 ~your-urbit:talk>
62
59
63Post a line to `/urbit-meta`:
60Post a line to `/urbit-meta`:
64
61
65 ~your-urbit:talk> hello, world
62 ~your-urbit:talk> hello, world
66
63
67−You'll see, echoed back at you through `~binzod`:
64+You'll see, echoed back at you:
68
65
69 ~your-urbit> hello, world
66 ~your-urbit> hello, world
70
67
@@ -80,11 +77,11 @@ Now you and `~talsur-todres` can exchange messages directly.
80
77
81To set your audience back to `/urbit-meta`:
78To set your audience back to `/urbit-meta`:
82
79
83− ~your-urbit:talk> ;~binzod/urbit-meta
80+ ~your-urbit:talk> ;/urbit-meta
84
81
85Use `;leave` to unsubscribe from a channel:
82Use `;leave` to unsubscribe from a channel:
86
83
87− ~your-urbit:talk> ;leave ~binzod/urbit-meta
84+ ~your-urbit:talk> ;leave /urbit-meta
88
85
89There are two ways of using `:talk`: from the CLI or through a web ui
86There are two ways of using `:talk`: from the CLI or through a web ui
90available at `http://your-urbit.urbit.org/talk` (or
87available at `http://your-urbit.urbit.org/talk` (or
@@ -101,51 +98,67 @@ Now you can tell your friends to `;join ~your-urbit/my-channel`.
101
98
102## Manual
99## Manual
103
100
104−`:talk`'s design is similar in spirit to
101+`:hall`'s design is similar in spirit to
105[nntp](https://en.wikipedia.org/wiki/Network_News_Transfer_Protocol),
102[nntp](https://en.wikipedia.org/wiki/Network_News_Transfer_Protocol),
106the underlying protocol for Usenet.
103the underlying protocol for Usenet.
107
104
108−Our design is pretty simple: `:talk` messages are called ‘posts’. Posts
105+Our design is pretty simple: `:hall` messages go to ‘circles’. Any urbit
109−go to ‘stations’. Any urbit can host or subscribe to any number of
106+can host or subscribe to any number of circles.
110−stations.
111
107
112−There are four kinds of stations: a write-only `%mailbox` for direct
108+There are four kinds of circles: a write-only `%mailbox` for direct
113−messages, an invite-only `%party` for private conversation, a read-only
109+messages, an invite-only `%village` for private conversation, a read-only
114`%journal` for curated content, and a public-access `%channel` for
110`%journal` for curated content, and a public-access `%channel` for
115general use.
111general use.
116
112
117### Posts
113### Posts
118
114
119−For the time being a post is either a line, a URL or a command.
115+A post can be a variety of different data structures. Let's look at the
116+ones you can use from within `:talk`: lines, URLs, expressions and
117+replies.
120
118
121#### Lines
119#### Lines
122
120
123−A line is 64 bytes of ASCII lowercase, spaces and punctuation. If the
121+A line is simply a string of text. Depending on the filtering rules set
122+by the circle's host, these may or may not include uppercase and Unicode
123+characters.
124−line starts with '@', it's an action (IRC `/me`).
124+If the line starts with `@`, it's an action (IRC `/me`).
125
125
126−The `:talk` interface will let you keep typing past 64 bytes, but insert
127−a Unicode bullet-point character in an appropriate space in your post,
128−to show you the prospective linebreak. Your essay will be posted in
129−multiple lines.
130−
131− ~your-urbit:talk> this is a long message, so it will by truncated right at this•spot
126+ ~your-urbit:talk> @sends a message
132
127
133will print as
128will print as
134
129
135− ~your-urbit; this is a long message, so it will by truncated right at this
130+ ~your-urbit sends a message
136− ~your-urbit; spot
137
131
138#### URLs
132#### URLs
139
133
140A URL is any valid URL.
134A URL is any valid URL.
141
135
142− ~your-urbit:talk> http://example.com
136+ ~your-urbit:talk> http://example.com/
137+
138+### Expressions
139+
140+Expressions can be used to show and evaluate Hoon code. Send an expression
141+by prefacing your message with `#`.
142+
143+ ~your-urbit:talk> #(add 1 2)
144+
145+will print as
146+
147+ ~your-urbit# (add 1 2)
148+ 3
143
149
144−### Commands
150+### Replies
145
151
146−A command is a hoon expression, prefaced by '\#'.
152+To indicate what you're saying is in direct response to a specific
153+message, select the message (see Activating Lines below) and type your
154+response.
147
155
156+ ~some-urbit> hello! how are you?
148− ~your-urbit:talk> #(add 2 2)
157+ ~your-urbit:talk> ; good, thanks!
158+
159+will print as
160+
161+ ~your-urbit>^ good, thanks!
149
162
150### Activating Lines
163### Activating Lines
151
164
@@ -153,17 +166,18 @@ A line number identifying the *subsequent* line is displayed every 5
153lines.
166lines.
154
167
155 ---------[0]
168 ---------[0]
156− ~your-urbit; this is my message
169+ ~your-urbit> this is my message
157− ~your-urbit@ this is an @ message
170+ ~your-urbit> this is another message
158− ~your-urbit; this is a long message, so it will by truncated right at this
171+ ~your-urbit sends a message
159− ~your-urbit; spot
160 ~your-urbit/ http://example.com/
172 ~your-urbit/ http://example.com/
173+ ~your-urbit# (add 1 2)
174+ 3
161 ---------[5]
175 ---------[5]
162− ~your-urbit# (add 2 2) 4
176+ ~your-urbit>^ that's my message!
163
177
164You can use a line number to *activate* a line:
178You can use a line number to *activate* a line:
165
179
166− ~your-urbit:talk> ;0
180+ ~your-urbit:talk> ;5
167
181
168which prints the number, line identifier, timestamp, sender, audience,
182which prints the number, line identifier, timestamp, sender, audience,
169and contents:
183and contents:
@@ -171,64 +185,133 @@ and contents:
171 ? 0
185 ? 0
172 0v3.hl51p.jhege.amhec.vb37r.3rejr at ~2016.6.24..04.48.21..a235
186 0v3.hl51p.jhege.amhec.vb37r.3rejr at ~2016.6.24..04.48.21..a235
173 ~your-urbit to ~another-urbit
187 ~your-urbit to ~another-urbit
188+ in reply to: ~your-urbit:
174− this is my message
189+ > this is my message
190+ that's my message!
175
191
176−Activating a URL will print the full URL (it could have been truncated),
192+If information got truncated — like happens for long URLs or expressions —
177−and activating a command will evaluate it.
193+or if there's additional information available — as is the case with
194+replies and attachments — activating the message will show you all the
195+details.
178
196
179You can activate the most recent line with `;`, the second-most recent
197You can activate the most recent line with `;`, the second-most recent
180with `;;`, and so on.
198with `;;`, and so on.
181
199
182−### Creating and managing stations
200+### Creating and managing circles
201+
202+`;create [type] %name 'description'`
203+Creates and joins a circle, where `[type]` is any of the following:
204+- `channel`: public circle. Has a blacklist for write control.
205+- `village`: invite-only circle.
206+- `journal`: publicly readable, invite-only for writing.
207+- `mailbox`: publicly writeable, can only be read by its host.
208+
209+`;delete %name 'optional reason'`
210+Deletes a circle. If a reason is specified, that gets sent to all
211+subscribers before the circle gets deleted.
212+
213+`;depict %name 'description'`
214+Changes the description of circle `%name`.
215+
216+`;filter %name [capitals] [unicode]`
217+Configures the message filter for circle `%name`: whether to allow
218+capital and/or unicode characters. `y`/`&`/`true` for allowed,
219+`n`/`|`/`false` for disallowed.
220+
221+`;invite %name ~someone`
222+Invite someone into your circle `%name`. If they were previously banished,
223+removes them from the blacklist.
224+Can also invite multiple ships at once, `~comma, ~separated`.
225+
226+`;banish %name ~someone`
227+Banish someone from your circle `%name`. If they were previously invited,
228+removes them from the whitelist.
229+Can also banish multiple ships at once, `~comma, ~separated`.
183
230
184−`;create journal %serious-journal 'description'` - Creates a `%journal`,
231+`;source %name ~other/circle`
185−a privately writable publicly readable station.
232+Adds `~other/circle` as a source for circle `%name`. This causes all
233+messages sent to `~other/circle` to also appear in `%name`.
186
234
187−`;create channel %serious-channel 'description'` - Creates a `%channel`,
235+`;unsource %name ~other/circle`
188−a publicly readable publicly writeable station.
236+Removes `~other/circle` as a source for circle `%name`.
189
237
190−### Presence
238+### Membership
191
239
240+If you have joined a circle, you can make this information publicly
241+available to help others find that circle as well.
242+
243+`;show ~some/circle`
244+Adds a circle to your public membership list.
245+
246+`;hide ~some/circle`
247+Removes a circle from your public membership list.
248+
249+### Status
250+
192−You'll see presence notifications when people enter or leave stations
251+You'll see status notifications when people enter or leave stations
193you're subscribed to.
252you're subscribed to.
194
253
254+`;set quiet`
195−`;set quiet` - Turn off presence notifications
255+Turn off status (and config) notifications.
256+
257+`;unset quiet`
258+Turn on status (and config) notifications.
196
259
197−`;unset quiet` - Turn on presence notifications
260+`;who`
261+List everyone in all your subscribed circles. Optionally specify a
262+specific circle to list members of just those.
263+
264+`;attend ~some/circle [presence]`
265+Manually set your presence to show up as one of the following. (In the
266+future, a sufficiently advanced client can automatically set these for
267+you.)
268+- `talk` - typing
269+- `hear` - listening
270+- `idle` - inactive
271+- `gone` - not present
272+
273+`;name ~some/circle 'my handle'`
274+Set a handle ("name") for yourself in a specific circle. It will display
275+to users who have done `;set nicks`, but gets truncated if it's longer
276+than 14 characters.
277+
278+### Audience
198
279
199−`;who` - list everyone in all your stations
280+An audience consists of one or more messaging targets. These can be
281+circles or ships. (In the latter case, it's secretly the `~ship/inbox`
282+circle.)
200
283
201−### Station Glyphs
284+### Circle glyphs
202
285
203−Glyphs are assigned by station hash out of the following list
286+Glyphs are assigned by circle hash out of the following list
204
287
205 > = + - } ) , . " ' ^ $ % & @
288 > = + - } ) , . " ' ^ $ % & @
206
289
207Alphanumeric characters and `|#;:*~_` are reserved; all others (the
290Alphanumeric characters and `|#;:*~_` are reserved; all others (the
208−above lists, and `\/!?({<`) can be manually assigned.
291+above list, and `\/!?({<`) can be manually assigned.
209
292
293+`;bind + /urbit-test`
210−`;bind > /urbit-test` - assigns the `>` glyph to `/urbit-test`.
294+Assigns the `+` glyph to `/urbit-test`.
211
295
296+`;unbind + /urbit-test`
297+Unassigns the `+` glyph from `/urbit-test`.
298+
212−To see what station is bound to a glyph:
299+To see what circle is bound to a glyph:
213
300
214 ;what +
301 ;what +
215− {[%.y p=[p=~binzod q=~.urbit-meta]]}
302+ /urbit-test
216
303
217### Prefixes
304### Prefixes
218
305
219Received posts are prefixed with a glyph to let you know what the
306Received posts are prefixed with a glyph to let you know what the
220audience is. You can activate an individual post to see the full
307audience is. You can activate an individual post to see the full
221−audience.
308+audience.
222−
309+There are a few special-purpose glyphs.
223−`|` - Informational messages
224−
225−`:` - Posts directly to you
226
310
311+- `|` - Informational messages
312+- `:` - Posts directly to you
227−`;` - Posts to you and others (a multiparty conversation)
313+- `;` - Posts to you and others (a multiparty conversation)
228−
229−`*` - Posts to a complex audience that doesn't directly include you.
314+- `*` - Posts to a complex audience that doesn't directly include you.
230−
231−### Audience
232
315
233#### Prompt
316#### Prompt
234
317
@@ -241,57 +324,77 @@ Here we're talking to the station bound to `=`:
241
324
242Here we're talking directly to `~dannum-mitryl`:
325Here we're talking directly to `~dannum-mitryl`:
243
326
244− ~your-urbit:talk(~dannum-mitryl)
327+ ~your-urbit:talk[~dannum-mitryl]
245
328
246#### Configuration
329#### Configuration
247
330
331+`;~urbit/station`
248−`;~urbit/station` - Set audience to `~urbit/station`
332+Set audience to `~urbit/station`.
249
333
334+`;=`
250−`;=` - Set audience to the station bound to the `=` glyph
335+Set audience to the station bound to the `=` glyph.
251
336
337+`;~dannum-mitryl`
252−`;~dannum-mitryl` - Set audience to `~dannum-mitryl` (a direct post).
338+Set audience to `~dannum-mitryl` (a direct post).
253
339
340+`;%station`
254−`;%station` - Set audience to a station on your own ship
341+Set audience to a station on your own ship.
255
342
256−`;~dannum-mitryl this is a private message` - Set the audience and send
343+`;~dannum-mitryl this is a private message`
257−a post in the same line. This works for all of the above.
344+Set the audience and send a post to it. This works for all of the above.
258
345
259−Your audience is configured 'implicitly' with regard to the following
346+Your audience is configured with regard to the following rules (in order):
260−rules (in order):
261
347
262−- if you manually locked the audience, that audience.
348+- if you manually set the audience, that audience.
263−- if typing a post, the audience when you started typing.
264- if you activated a post, the post you activated.
349- if you activated a post, the post you activated.
265−- audience of the last post received.
266- audience of the last post sent.
350- audience of the last post sent.
267
351
268−Clear any 'implicit' audience setting by moving your cursor to the start
352+### Local nicknames
269−of the line and pressing backspace (whether the line is empty or not).
353+
270−Posting a line clears the typing and activation configurations.
354+`;nick`
355+List all local nicknames.
356+
357+`;nick ~some-urbit`
358+Look up a nickname.
359+
360+`;nick plato`
361+Search in reverse.
271
362
272−### Nicknames
363+`;nick ~some-urbit plato`
364+Create a nickname.
273
365
274−`;nick` - list all nicknames
366+`;nick ~some-urbit ~`
367+Clear an assigned nickname.
275
368
276−`;nick ~your-urbit` - look up a nickname
369+`;set nicks`
370+Show nicknames instead of urbit names. If no local nickname is set, uses
371+that user's handle. If the user has no handle, just the urbit name.
277
372
278−`;nick plato` - search in reverse
373+`;unset nicks`
374+Show urbit names instead of nicknames.
279
375
280−`;nick ~your-urbit plato` create a nickname
376+Nicknames and handles longer than 14 character will be truncated in
377+output. Nicknames are strictly local - like the names on entries in a
378+phonebook.
281
379
282−`;nick ~your-urbit ~` clear an assigned nickname
380+### Miscellaneous configuration
283
381
284−`;set noob` show nicknames instead of urbit names
382+`;set showtime`
383+Show the timestamp for each message.
285
384
286−`;unset noob` show urbit names instead of nicknames
385+`;unset showtime`
386+Stop showing the timestamp for each message.
287
387
288−All nicknames must be 14 characters or less, lowercase. Nicknames are
388+`;set timezone [+/-][hours]`
289−strictly local - like the names on entries in a phonebook. Sometimes in
389+Adjust the display of the timestamps to a specific timezone. Relative to UTC.
290−a post you want to mention someone you know by a nickname. Just type
291−`~plato`, and `:talk` will replace it with `~your-urbit`.
292
390
293−### Timestamps
391+`;set notify`
392+Emit a terminal bell sound if your six-syllable ship name is mentioned in
393+a message.
294
394
295−`;set showtime` - Show the timestamp for each message
395+`;unset notify`
396+Do not notify when your ship name is mentioned.
296
397
297−`;unset showtime` - Stop showing the timestamp for each message
398+`;set width [number]`
399+Set the rendering width of `:talk` to a specific number of characters.
400+(Minimum of 30.)