on master help sign in
whoops forgot to add these files in last commit
commited182172bd0617042baee71148af7b68beadf6c4 authorTinnus Napbus <admin@tinnus-napbus.xyz> dateSat 30 Oct 2021, 03:52 (5 years ago) parent005a8e9
4 files changed+2022
content/docs/arvo/gall/data-types.md+492 content/docs/arvo/gall/gall-api.md+958 content/docs/arvo/gall/gall.md+558 content/docs/userspace/gall-guide.md+14
content/docs/arvo/gall/data-types.mdnew file+492
@@ -0,0 +1,492 @@
1++++
2+title = "Data Types"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+This document describes the data types for Gall defined in `lull.hoon`.
8+
9+## `bitt`
10+
11+```hoon
12++$ bitt (map duct (pair ship path))
13+```
14+
15+Incoming subscriptions.
16+
17+This is the structure Gall uses to keep track of subscribers to our Gall agent.
18+The `sup` field of a [`bowl`](#bowl) contains the `bitt` for our agent.
19+
20+## `boat`
21+
22+```hoon
23++$ boat
24+ %+ map [=wire =ship =term]
25+ [acked=? =path]
26+```
27+
28+Outgoing subscriptions.
29+
30+This is the structure Gall uses to keep track of subscriptions our agent has
31+initiated. The `wex` field of a [`bowl`](#bowl) contails the `boat` for that
32+agent.
33+
34+The `wire` field is the `wire` which [`sign:agent`](#signagent)s will come in on.
35+The `ship` and `term` fields are the ship and the name of the agent to which our
36+agent has subscribed.
37+
38+The `acked` field is `%.y` if they have acknowledged our subscription request,
39+and `%.n` if they have not. The `path` field is the `path` on the other agent to
40+which our agent has subscribed.
41+
42+## `bowl`
43+
44+```hoon
45++$ bowl :: standard app state
46+ $: $: our=ship :: host
47+ src=ship :: guest
48+ dap=term :: agent
49+ == ::
50+ $: wex=boat :: outgoing subs
51+ sup=bitt :: incoming subs
52+ == ::
53+ $: act=@ud :: change number
54+ eny=@uvJ :: entropy
55+ now=@da :: current time
56+ byk=beak :: load source
57+ == == ::
58+```
59+
60+Additional agent state.
61+
62+A `bowl` is given to the agent core each time an event comes in. The fields are
63+as follows:
64+
65+- `our`: Our ship.
66+- `src`: The ship from which the current request originated.
67+- `dap`: The name of our agent.
68+- `wex`: Outgoing subscriptions. That is, subscriptions our agent has initiated.
69+ See the [`boat`](#boat) section for details of the type.
70+- `sup`: Incoming subscriptions. That is, subscriptions others have made to our
71+ agent. See the [`bitt`](#bitt) section for details of the type.
72+- `act`: The total number of [`move`](/docs/arvo/overview#move)s our agent has
73+ processed so far.
74+- `eny`: 512 bits of entropy.
75+- `now`: The current date-time.
76+- `byk`: The ship, desk and `case` in Clay from which this agent was loaded. The
77+ `case` will be `[%da @da]` where the `@da` is the when the agent was loaded. A
78+ `beak` is a triple of `[ship desk case]`.
79+
80+## `dude`
81+
82+```hoon
83++$ dude term
84+```
85+
86+Agent name.
87+
88+## `gill`
89+
90+```hoon
91++$ gill (pair ship term)
92+```
93+
94+A general contact: A pair of the ship and agent name.
95+
96+## `scar`
97+
98+```hoon
99++$ scar
100+ $: p=@ud
101+ q=(map duct bone)
102+ r=(map bone duct)
103+ ==
104+```
105+
106+Opaque duct - used internally.
107+
108+## `suss`
109+
110+```hoon
111++$ suss (trel dude @tas @da)
112+```
113+
114+Configuration report.
115+
116+## `well`
117+
118+```hoon
119++$ well (pair desk term)
120+```
121+
122+Desk and agent.
123+
124+## `neat`
125+
126+```hoon
127++$ neat
128+ $% [%arvo =note-arvo]
129+ [%agent [=ship name=term] =deal]
130+ [%pyre =tang]
131+ ==
132+```
133+
134+Like a [`note:agent`](#noteagent), except the `%agent` case has a [`deal`](#deal) instead
135+of just a [`task:agent`](#taskagent). This is used for messages that come in over the
136+network and would not be used manually.
137+
138+## `deal`
139+
140+```hoon
141++$ deal
142+ $% [%raw-poke =mark =noun]
143+ task:agent
144+ ==
145+```
146+
147+Like a [`task:agent`](#taskagent) but with the additional case of a raw poke.
148+This is used for messages that come in over the network and would not be used
149+manually.
150+
151+## `unto`
152+
153+```hoon
154++$ unto
155+ $% [%raw-fact =mark =noun]
156+ sign:agent
157+ ==
158+```
159+
160+Like a [`sign:agent`](#signagent) but with the additional case of a raw fact.
161+This is used for messages that come in over the network and would not be used
162+manually.
163+
164+## `agent`
165+
166+```hoon
167+++ agent
168+ =< form
169+ |%
170+```
171+
172+Container for Gall agent types. The most significant arm is
173+[`form:agent`](#formagent), which specifies the structure of the agent itself.
174+There are also some additional structures defined here, mostly defining the
175+kinds of messages agents can send. The different arms of the core in `agent`
176+are considered separately below.
177+
178+### `step:agent`
179+
180+```hoon
181++$ step (quip card form)
182+```
183+
184+A cell of [`card:agent`](#cardagent)s to be sent and a new agent state. This is the
185+type returned by most arms of an agent. A `(quip a b)` is the same as `[(list a) b]`, it's just a more convenient way to specify it.
186+
187+### `card:agent`
188+
189+```hoon
190++$ card (wind note gift)
191+```
192+
193+An effect - typically a message to be sent to another agent or vane. A list of
194+these are returned by most agent arms along with a new state in a
195+[`step:agent`](#stepagent). A `wind` is the following:
196+
197+```hoon
198+++ wind
199+ |$ [a b]
200+ $% [%pass p=path q=a]
201+ [%slip p=a]
202+ [%give p=b]
203+ ==
204+```
205+
206+Gall will not allow a `%slip`, so in practice a `card` will be one of:
207+
208+- `[%pass path note]`
209+- `[%give gift]`
210+
211+For `%pass`, `p` specifies the `wire` on which a response should be returned.
212+See [`note:agent`](#noteagent) and [`gift:agent`](#giftagent) below for details of their
213+types.
214+
215+### `note:agent`
216+
217+```hoon
218++$ note
219+ $% [%agent [=ship name=term] =task]
220+ [%arvo note-arvo]
221+ [%pyre =tang]
222+ ==
223+```
224+
225+The type for messages initiated by our agent. This is opposed to
226+[`gift:agent`](#giftagent), which is the type for responding to other agents or
227+vanes, or for sending out updates to subscribers. The three cases are:
228+
229+- `%agent`: Poke another agent, subscribe to another agent, or cancel a
230+ subscription to another agent. The `ship` and `name` fields are the ship and
231+ agent to which the `task` should be sent. The `task` is the request itself,
232+ see [`task:agent`](#taskagent) below for its possible types.
233+- `%arvo`: Pass a `task` to a vane. The type of a `note-arvo` is:
234+ ```hoon
235+ +$ note-arvo
236+ $~ [%b %wake ~]
237+ $% [%a task:ames]
238+ [%b task:behn]
239+ [%c task:clay]
240+ [%d task:dill]
241+ [%e task:eyre]
242+ [%g task:gall]
243+ [%i task:iris]
244+ [%j task:jael]
245+ [%$ %whiz ~]
246+ [@tas %meta vase]
247+ ==
248+ ```
249+ You can refer to the `/sys/lull.hoon` source code for all the possible vane
250+ tasks, or see each vane's API Reference section in the [Arvo
251+ documentation](/docs/arvo/overview)
252+- `%pyre`: This is for aborting side-effects initiated during agent
253+ installation. The `tang` is an error message.
254+
255+A `note:agent` is always wrapped in a `%pass` [`card:agent`](#cardagent).
256+
257+### `task:agent`
258+
259+```hoon
260++$ task
261+ $% [%watch =path]
262+ [%watch-as =mark =path]
263+ [%leave ~]
264+ [%poke =cage]
265+ [%poke-as =mark =cage]
266+ ==
267+```
268+
269+The types of messages initiated by our agent and sent to another agent. This is
270+in contrast to [`gift:agent`](#giftagent)s, which are responses to incoming
271+messages from agents or updates to agents already subscribed. The five kinds
272+are:
273+
274+- `%watch`: Subscribe to `path` on the target ship and agent.
275+- `%watch-as`: Same as `%watch`, except you ask the target's Gall to convert
276+ subscription updates to the `mark` you specified rather than just giving you
277+ the `mark` produced by the agent.
278+- `%leave`: Cancel subscription. The particular subscription to cancel will be
279+ determined by the `wire` given in the `p` field of the containing `%pass`
280+ [`card:agent`](#cardagent).
281+- `%poke`: Poke the target ship and agent with the given `cage`, which is a pair
282+ of `[mark vase]`.
283+- `%poke-as`: Same as `%poke`, except the `cage` will be converted to the
284+ specified `mark` before sending.
285+
286+A `task:agent` is always wrapped in a `%pass` [`card:agent`](#cardagent).
287+
288+### `gift:agent`
289+
290+```hoon
291++$ gift
292+ $% [%fact paths=(list path) =cage]
293+ [%kick paths=(list path) ship=(unit ship)]
294+ [%watch-ack p=(unit tang)]
295+ [%poke-ack p=(unit tang)]
296+ ==
297+```
298+
299+The types of messages our agent can either send in response to messages from
300+other agents, or send to subscribed agents. This is in contrast to
301+[`task:agent`](#taskagent)s, which are messages to other agents our agent
302+initiates rather than sends in response. The four kinds are:
303+
304+- `%fact`: An update to existing subscribers. The `paths` field specifies which
305+ subscription paths the update should go out to. The `cage` is the data, and is
306+ a `[mark vase]`.
307+- `%kick`: Kick subscriber, ending their subscription. The `paths` field
308+ specifies which paths the subscriber should be kicked from, and the `ship`
309+ field specifies the ship to kick. If the `ship` field is null, all subscribers
310+ on the specified paths are kicked. Gall will automatically remove the
311+ subscription from our agent's [`bitt`](#bitt) (inbound subscription `map`),
312+ and subscriber will no longer receive updates on the `path`s in question.
313+- `%watch-ack`: Acknowledge a subscription request. If `p` is null, it's an ack
314+ (positive acknowledgement), and if `p` is non-null, it's a nack (negative
315+ acknowledgement). Simply crashing will caused Gall to nack a subscription
316+ request, and not crashing but not explicitly producing a `%watch-ack` `gift`
317+ will cause Gall to ack a subscription request. Therefore, you'd typically only
318+ explicitly produce a `%watch-ack` `gift` if you wanted to nack a subscription
319+ request with a custom error in the `tang`.
320+- `%poke-ack`: Acknowledge a poke. If `p` is null, it's an ack, and if `p` is
321+ non-null, it's a nack. Simply crashing will cause Gall to nack a poke, and not
322+ crashing but not explicitly producing a `%poke-ack` `gift` will cause Gall to
323+ ack a poke. Therefore, you'd typically only explicitly produce a `%poke-ack`
324+ `gift` if you wanted to nack a poke with a custom error in the `tang`.
325+
326+A `gift:agent` is always wrapped in a `%give` [`card:agent`](#cardagent).
327+
328+### `sign:agent`
329+
330+```hoon
331++$ sign
332+ $% [%poke-ack p=(unit tang)]
333+ [%watch-ack p=(unit tang)]
334+ [%fact =cage]
335+ [%kick ~]
336+ ==
337+```
338+
339+A `sign` is like a [`gift:agent`](#giftagent) but it's something that comes
340+_in_ to our agent from another agent rather than something we send out. The
341+possible types are:
342+
343+- `%poke-ack`: Another agent has acked (positively acknowledged) or nacked
344+ (negatively acknowledged) a `%poke` [`task:agent`](#taskagent) we previously
345+ sent. It's an ack if `p` is null and a nack if `p` is non-null. The `tang`
346+ contains an error or traceback if it's a nack.
347+- `%watch-ack`: Another agent has acked or nacked a `%watch`
348+ [`task:agent`](#taskagent) (subscription request) we previously sent. It's an
349+ ack if `p` is null and a nack if `p` is non-null. The `tang` contains an error
350+ or traceback if it's a nack. If it's a nack, Gall will automatically remove
351+ the subscription from our agent's [`boat`](#boat) (outbound subscription
352+ map).
353+- `%fact`: An update from another agent to which we've previously subscribed
354+ with a `%watch` [`task:agent`](#taskagent) (subscription request). The `cage`
355+ contains the data, and is a `[mark vase]`.
356+- `%kick`: Our subscription to another agent has been ended, and we'll no longer
357+ receive updates. A `%kick` may be intentional, but it may also happen due to
358+ certain network conditions or other factors. As a result, it's best to try and
359+ resubscribe with another `%watch` [`task:agent`](#taskagent), and if they
360+ nack the `%watch`, we can conclude it was intentional and give up.
361+
362+### `form:agent`
363+
364+```hoon
365+++ form
366+ $_ ^|
367+ |_ bowl
368+ ++ on-init
369+ *(quip card _^|(..on-init))
370+ ::
371+ ++ on-save
372+ *vase
373+ ::
374+ ++ on-load
375+ |~ old-state=vase
376+ *(quip card _^|(..on-init))
377+ ::
378+ ++ on-poke
379+ |~ [mark vase]
380+ *(quip card _^|(..on-init))
381+ ::
382+ ++ on-watch
383+ |~ path
384+ *(quip card _^|(..on-init))
385+ ::
386+ ++ on-leave
387+ |~ path
388+ *(quip card _^|(..on-init))
389+ ::
390+ ++ on-peek
391+ |~ path
392+ *(unit (unit cage))
393+ ::
394+ ++ on-agent
395+ |~ [wire sign]
396+ *(quip card _^|(..on-init))
397+ ::
398+ ++ on-arvo
399+ |~ [wire sign-arvo]
400+ *(quip card _^|(..on-init))
401+ ::
402+ ++ on-fail
403+ |~ [term tang]
404+ *(quip card _^|(..on-init))
405+ --
406+--
407+```
408+
409+This defines the structure of the agent itself. The agent is a door with a [`bowl`](#bowl) as its sample and exactly ten arms. Below we'll describe each arm briefly.
410+
411+#### `on-init`
412+
413+- Accepts: Nothing.
414+- Produces: [`step:agent`](#stepagent)
415+
416+This arm is called when the agent is initially installed.
417+
418+#### `on-poke`
419+
420+- Accepts: `cage`
421+- Produces: [`step:agent`](#stepagent)
422+
423+This arm is called when another agent pokes our agent.
424+
425+#### `on-watch`
426+
427+- Accepts: `path`
428+- Produces: [`step:agent`](#stepagent)
429+
430+This arm is called when another agent subscribes to our agent.
431+
432+#### `on-leave`
433+
434+- Accepts: `path`
435+- Produces: [`step:agent`](#stepagent)
436+
437+This arm is called when another agent unsubscribes from a subscription path on
438+our agent.
439+
440+#### `on-peek`
441+
442+- Accepts: `path`
443+- Produces: `(unit (unit cage))`
444+
445+This arm is called when a [scry](/docs/arvo/concepts/scry) is performed on our
446+agent.
447+
448+#### `on-agent`
449+
450+- Accepts: `[wire sign:agent]`
451+- Produces: [`step:agent`](#stepagent)
452+
453+This arm is called when another agent give our agent a
454+[`sign:agent`](#signagent).
455+
456+#### `on-arvo`
457+
458+- Accepts: `[wire sign-arvo]`
459+- Produces: [`step:agent`](#stepagent)
460+
461+This arm is called when a vane gives our agent a `gift`. A `sign-arvo` is:
462+
463+```hoon
464++$ sign-arvo
465+ $% [%ames gift:ames]
466+ $: %behn
467+ $% gift:behn
468+ $>(%wris gift:clay)
469+ $>(%writ gift:clay)
470+ $>(%mere gift:clay)
471+ $>(%unto gift:gall)
472+ ==
473+ ==
474+ [%clay gift:clay]
475+ [%dill gift:dill]
476+ [%eyre gift:eyre]
477+ [%gall gift:gall]
478+ [%iris gift:iris]
479+ [%jael gift:jael]
480+ ==
481+```
482+
483+You can refer to the `/sys/lull.hoon` source code, or the API Reference of each
484+vane in the [Arvo documentation](/docs/arvo/overview).
485+
486+#### `on-fail`
487+
488+- Accepts: `[term tang]`
489+- Produces: [`step:agent`](#stepagent)
490+
491+This arm is called if certain errors occur in Gall, such as if our agent tries
492+to create a duplicate subscription.
content/docs/arvo/gall/gall-api.mdnew file+958
@@ -0,0 +1,958 @@
1++++
2+title = "API Reference"
3+weight = 3
4+template = "doc.html"
5++++
6+
7+## Reference Agent
8+
9+This app stores a number for each user. You can increment your number, increment
10+someone else's number, start tracking someone else's number by poking. It
11+exposes a scry namespace to inspect everyone's number.
12+
13+### `app/example-gall.hoon`
14+
15+```hoon
16+:: Import sur/example-gall
17+/- *example-gall
18+:: Import lib/default-agent
19+/+ default-agent
20+|%
21++$ card card:agent:gall
22++$ note
23+ $%
24+ [%arvo =note-arvo]
25+ [%agent [=ship name=term] =task:agent:gall]
26+ ==
27++$ state-zero [%0 local=@ud]
28++$ state-one [%1 local=@ud remote=(map @p @ud)]
29++$ versioned-state
30+ $%
31+ state-zero
32+ state-one
33+ ==
34+--
35+=| state-one
36+=* state -
37+^- agent:gall
38+|_ =bowl:gall
39++* this .
40+ def ~(. (default-agent this %|) bowl)
41+::
42+:: Set local counter to 1 by default
43+++ on-init
44+ ^- (quip card _this)
45+ `this(local 1)
46+:: Expose state for saving
47+++ on-save
48+ !>(state)
49+::
50+:: Load old state and upgrade if neccessary
51+++ on-load
52+ |= old=vase
53+ ^- (quip card _this)
54+ =/ loaded=versioned-state
55+ !<(versioned-state old)
56+ ?- -.loaded
57+ %0
58+ `this(local local.loaded) :: Upgrade old state
59+ %1
60+ `this(state loaded)
61+ ==
62+::
63+:: Respond to poke
64+:: App can be poked in the dojo by running the following commands
65+:: Increment local counter
66+:: :example-gall &example-gall-action [%increment ~]
67+:: Increment ~zod's counter
68+:: :example-gall &example-gall-action [%increment-remote ~zod]
69+:: Subscribe to ~zod's counter
70+:: :example-gall &example-gall-action [%view ~zod]
71+:: Unsubscribe from ~zod's counter
72+:: :example-gall &example-gall-action [%stop-view ~zod]
73+::
74+++ on-poke
75+ |= [=mark =vase]
76+ ^- (quip card _this)
77+ :: Ensure poke is of mark %example-gall-action
78+ ?> =(mark %example-gall-action)
79+ =/ act=example-gall-action !<(example-gall-action vase)
80+ ?- act
81+ ::
82+ :: Increment local counter and send new counter to subscribers
83+ ::
84+ [%increment ~]
85+ :- [%give %fact ~[/local] %atom !>(+(local))]~
86+ this(local +(local))
87+ ::
88+ :: Send remote %increment poke
89+ ::
90+ [%increment-remote who=@p]
91+ :_ this
92+ :~ :*
93+ %pass
94+ /inc/(scot %p who.act)
95+ %agent
96+ [who.act %example-gall]
97+ %poke %example-gall-action !>([%increment ~])
98+ == ==
99+ ::
100+ :: Subscribe to a remote counter
101+ ::
102+ [%view who=@p]
103+ :_ this
104+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
105+ ::
106+ :: Unsubscribe from remote counter and remove from state
107+ ::
108+ [%stop-view who=@p]
109+ :_ this(remote (~(del by remote) who.act))
110+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
111+ ::
112+ ==
113+::
114+:: Print on unsubscribe
115+::
116+++ on-leave
117+ |= =path
118+ ^- (quip card _this)
119+ ~& "Unsubscribed by: {<src.bowl>} on: {<path>}"
120+ `this
121+::
122+:: Handle new subscription
123+::
124+:: When another ship subscribes to our counter, give them the current state of
125+:: the counter immediately
126+::
127+++ on-watch
128+ |= =path
129+ ^- (quip card _this)
130+ :_ this
131+ :: Crash if we see a subscription we don't recognise
132+ ?+ path ~|("unexpected subscription" !!)
133+ ::
134+ [%local ~]
135+ [%give %fact ~ %atom !>(local)]~
136+ ==
137+::
138+:: Expose scry namespace
139+::
140+:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
141+:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
142+:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
143+:: remote counters
144+++ on-peek
145+ |= =path
146+ ^- (unit (unit cage))
147+ ?+ path [~ ~]
148+ ::
149+ :: Produce local counter
150+ ::
151+ [%x %local ~]
152+ ``[%atom !>(local)]
153+ ::
154+ :: Produce remote counter
155+ ::
156+ [%x %remote who=@ta ~]
157+ =* location i.t.t.path :: Ship name is third in the list
158+ =/ res
159+ (~(got by remote) (slav %p location))
160+ ``[%atom !>(res)]
161+ ::
162+ :: Produce listing of remote counters
163+ ::
164+ [%y %remote ~]
165+ =/ dir=(map @ta ~)
166+ %- molt :: Map from list of k-v pairs
167+ %+ turn :: iterate over list of k-v pairs
168+ ~(tap by remote) :: list of k-v pairs from map
169+ |= [who=@p *]
170+ [(scot %p who) ~]
171+ ``[%arch !>(`arch`[~ dir])]
172+ ==
173+::
174+:: Handle sign from agent
175+::
176+++ on-agent
177+ |= [=wire =sign:agent:gall]
178+ ^- (quip card _this)
179+ ?- -.sign
180+ ::
181+ :: Print error if poke failed
182+ ::
183+ %poke-ack
184+ ?~ p.sign
185+ `this
186+ %- (slog u.p.sign)
187+ `this
188+ ::
189+ :: Print error if subscription failed
190+ ::
191+ %watch-ack
192+ ?~ p.sign
193+ `this
194+ =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
195+ %- (slog tank u.p.sign)
196+ `this
197+ ::
198+ :: Do nothing if unsubscribed
199+ ::
200+ %kick `this
201+ ::
202+ :: Update remote counter when we get a subscription update
203+ ::
204+ %fact
205+ :- ~
206+ ?. ?=(%atom p.cage.sign)
207+ this
208+ this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
209+ ==
210+::
211+:: Handle arvo signs
212+::
213+:: We never give any cards to arvo. Therefore we never need to handle any signs
214+:: from arvo. We use the default-agent library to avoid implementing this arm,
215+:: as gall apps must have all the arms.
216+::
217+++ on-arvo on-arvo:def
218+::
219+:: Handle error
220+::
221+:: Print errors when they happen
222+::
223+++ on-fail
224+ |= [=term =tang]
225+ ^- (quip card _this)
226+ %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
227+ `this
228+--
229+
230+```
231+
232+### `sur/example-gall.hoon`
233+
234+```hoon
235+|%
236++$ example-gall-action
237+ $%
238+ [%view who=@p]
239+ [%stop-view who=@p]
240+ [%increment-remote who=@p]
241+ [%increment ~]
242+ ==
243+--
244+```
245+
246+### `mar/example-gall/action.hoon`
247+
248+```hoon
249+/- *example-gall
250+|_ act=example-gall-action
251+++ grab
252+ |%
253+ ++ noun example-gall-action
254+ --
255+--
256+```
257+
258+## Arms
259+
260+### `++on-init`
261+
262+Application initialisation
263+
264+`++on-init` is called when an application is first started. It is not a gate and
265+has no input.
266+
267+#### Returns
268+
269+```hoon
270+(quip card _this)
271+```
272+
273+List of cards and new agent
274+
275+#### Example
276+
277+```hoon
278+:: From reference agent.
279+:: Set local counter to 1 by default
280+::
281+++ on-init
282+ ^- (quip card _this)
283+ `this(local.sta 1)
284+:: From app/weather.hoon. This setup is typical of a landscape tile.
285+::
286+++ on-init
287+ :_ this
288+ :~ [%pass /bind/weather %arvo %e %connect [~ /'~weather'] %weather]
289+ :* %pass /launch/weather %agent [our.bol %launch] %poke
290+ %launch-action !>([%weather /weathertile '/~weather/js/tile.js'])
291+ ==
292+ ==
293+```
294+
295+### `++on-save`
296+
297+Expose state for saving.
298+
299+This arm is called immediately before the agent is upgraded. It packages the
300+permament state of the agent in a vase for the next version of the agent.
301+Unlike most handlers, this cannot produce effects. It is not a gate and has no input.
302+
303+#### Returns
304+
305+`vase` of permanent state.
306+
307+#### Example
308+
309+```hoon
310+:: From reference agent
311+::
312+:: Expose state for saving
313+::
314+++ on-save
315+ !>(state)
316+```
317+
318+### `++on-load`
319+
320+Application upgrade.
321+
322+This arm is called immediately after the agent is upgraded. It receives
323+a vase of the state of the previously-running version of the agent, obtained
324+from `+on-save`, which allows it to cleanly upgrade from the old agent.
325+
326+#### Accepts
327+
328+```hoon
329+=vase
330+```
331+
332+`vase` of previous state, from `++on-save`
333+
334+#### Returns
335+
336+```hoon
337+(quip card _this)
338+```
339+
340+List of cards and new agent
341+
342+#### Examples
343+
344+```hoon
345+:: From reference agent
346+::
347+:: Load old state and upgrade if neccessary
348+++ on-load
349+ |= old=vase
350+ ^- (quip card _this)
351+ =/ loaded=versioned-state
352+ !<(versioned-state old)
353+ ?- -.loaded
354+ %0
355+ `this(local local.loaded) :: Upgrade old state
356+ %1
357+ `this(state loaded)
358+ ==
359+```
360+
361+### `++on-poke`
362+
363+Handle application poke.
364+
365+This arm is called when the agent is "poked". The input is a cage, so
366+it's a pair of a mark and a dynamic vase.
367+
368+#### Accepts
369+
370+```hoon
371+[=mark =vase]
372+```
373+
374+`mark` is the mark of the poked data.
375+
376+`vase` is a vase with the poked data inside.
377+
378+#### Returns
379+
380+```hoon
381+(quip card _this)
382+```
383+
384+List of cards and new agent.
385+
386+#### Example
387+
388+```hoon
389+:: From reference agent.
390+::
391+:: Respond to poke
392+:: App can be poked in the dojo by running the following commands
393+:: Increment local counter
394+:: :example-gall &example-gall-action [%increment ~]
395+:: Increment ~zod's counter
396+:: :example-gall &example-gall-action [%increment-remote ~zod]
397+:: Subscribe to ~zod's counter
398+:: :example-gall &example-gall-action [%view ~zod]
399+:: Unsubscribe from ~zod's counter
400+:: :example-gall &example-gall-action [%stop-view ~zod]
401+::
402+++ on-poke
403+ |= [=mark =vase]
404+ ^- (quip card _this)
405+ :: Ensure poke is of mark %example-gall-action
406+ ?> =(mark %example-gall-action)
407+ =/ act=example-gall-action !<(example-gall-action vase)
408+ ?- act
409+ ::
410+ :: Increment local counter and send new counter to subscribers
411+ ::
412+ [%increment ~]
413+ :- [%give %fact ~[/local] %atom !>(+(local))]~
414+ this(local +(local))
415+ ::
416+ :: Send remote %increment poke
417+ ::
418+ [%increment-remote who=@p]
419+ :_ this
420+ :~ :*
421+ %pass
422+ /inc/(scot %p who.act)
423+ %agent
424+ [who.act %example-gall]
425+ %poke %example-gall-action !>([%increment ~])
426+ == ==
427+ ::
428+ :: Subscribe to a remote counter
429+ ::
430+ [%view who=@p]
431+ :_ this
432+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
433+ ::
434+ :: Unsubscribe from remote counter and remove from state
435+ ::
436+ [%stop-view who=@p]
437+ :_ this(remote (~(del by remote) who.act))
438+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
439+ ::
440+ ==
441+```
442+
443+### `++on-watch`
444+
445+Handle new subscriber.
446+
447+This arm is called when a program wants to subscribe to the agent on a
448+particular path. The agent may or may not need to perform setup steps
449+to intialize the subscription. It may produce a `%give`
450+`%subscription-result` to the subscriber to get it up to date, but after
451+this event is complete, it cannot give further updates to a specific
452+subscriber. It must give all further updates to all subscribers on a
453+specific path.
454+
455+If this arm crashes, then the subscription is immediately terminated.
456+More specifcally, it never started -- the subscriber will receive a
457+negative `%watch-ack`. You may also produce an explicit `%kick` to
458+close the subscription without crashing -- for example, you could
459+produce a single update followed by a `%kick`.
460+
461+#### Accepts
462+
463+```hoon
464+=path
465+```
466+
467+Path of new subscription.
468+
469+#### Returns
470+
471+```hoon
472+(quip card _this)
473+```
474+
475+List of cards and new agent.
476+
477+#### Example
478+
479+```hoon
480+:: From reference agent
481+::
482+:: Handle new subscription
483+::
484+:: When another ship subscribes to our counter, give them the current state of
485+:: the counter immediately
486+::
487+++ on-watch
488+ |= =path
489+ ^- (quip card _this)
490+ :_ this
491+ ?+ path on-watch:def
492+ ::
493+ [%local ~]
494+ [%give %fact ~ %atom !>(local)]~
495+ ==
496+```
497+
498+### `++on-leave`
499+
500+Handle unsubscribe.
501+
502+This arm is called when a program becomes unsubscribed to you.
503+Subscriptions may close because the subscriber intentionally
504+unsubscribed, but they also could be closed by an intermediary. For
505+example, if a subscription is from another ship which is currently
506+unreachable, Ames may choose to close the subscription to avoid queueing
507+updates indefinitely. If the program crashes while processing an
508+update, this may also generate an unsubscription. You should consider
509+subscriptions to be closable at any time.
510+
511+#### Accepts
512+
513+```hoon
514+=path
515+```
516+
517+Path of the closed subscription.
518+
519+#### Returns
520+
521+```hoon
522+(quip card _this)
523+```
524+
525+List of cards and new agent.
526+
527+#### Example
528+
529+```hoon
530+:: From reference agent. Prints a message when programs become unsubscribed.
531+++ on-leave
532+ |= =path
533+ ^- (quip card _this)
534+ ~& "Unsubscribe by: {<src.bowl>} on: {<path>}"
535+ `this
536+```
537+
538+### `++on-peek`
539+
540+Handle scry request.
541+
542+This arm is called when a program reads from the agent's "scry"
543+namespace, which should be referentially transparent. Unlike most
544+handlers, this cannot perform IO, and it cannot change the state. All
545+it can do is produce a piece of data to the caller, or not.
546+
547+#### Accepts
548+
549+```hoon
550+=path
551+```
552+
553+The path being scryed for.
554+
555+```hoon
556+:: Example scry to path mappings
557+::
558+.^(arch %gy /=example-gall=/remote)
559+:: Path will be /y/remote
560+.^(@ %gx /=example-gall=/local/atom)
561+:: Path will be /x/local
562+```
563+
564+#### Returns
565+
566+```hoon
567+(unit (unit cage))
568+```
569+
570+If this arm produces `[~ ~ data]`, then `data` is the value at the the
571+given path. If it produces `[~ ~]`, then there is no data at the given
572+path and never will be. If it produces `~`, then we don't know yet whether
573+there is or will be data at the given path. The head of the path is known as the
574+`care`. Requests with a care of `%x` should return a vase that matches or is
575+convertible to the mark at the end of the scry request. This mark is not
576+included in the path passed to `++on-peek`. Requests with a care of `%y` should
577+return a cage with a mark of `%arch` and a vase of `arch`.
578+
579+#### Example
580+
581+```hoon
582+:: From reference agent
583+::
584+:: Expose scry namespace
585+::
586+:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
587+:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
588+:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
589+:: remote counters
590+++ on-peek
591+ |= =path
592+ ^- (unit (unit cage))
593+ ?+ path [~ ~]
594+ ::
595+ :: Produce local counter
596+ ::
597+ [%x %local ~]
598+ ``[%atom !>(local)]
599+ ::
600+ :: Produce remote counter
601+ ::
602+ [%x %remote who=@ta ~]
603+ =* location i.t.t.path :: Ship name is third in the list
604+ =/ res
605+ (~(got by remote) (slav %p location))
606+ ``[%atom !>(res)]
607+ ::
608+ :: Produce listing of remote counters
609+ ::
610+ [%y %remote ~]
611+ =/ dir=(map @ta ~)
612+ %- molt :: Map from list of k-v pairs
613+ %+ turn :: iterate over list of k-v pairs
614+ ~(tap by remote) :: list of k-v pairs from map
615+ |= [who=@p *]
616+ [(scot %p who) ~]
617+ ``[%arch !>(`arch`[~ dir])]
618+ ==
619+```
620+
621+### `++on-agent`
622+
623+Handle `%pass` card
624+
625+This arm is called to handle responses to `%pass` cards to other agents.
626+It will be one of the following types of response:
627+
628+- `%poke-ack`: acknowledgment (positive or negative) of a poke. If the
629+ value is `~`, then the poke succeeded. If the value is `[~ tang]`,
630+ then the poke failed, and a printable explanation (eg a stack trace)
631+ is given in the `tang`.
632+
633+- `%watch-ack`: acknowledgment (positive or negative) of a subscription.
634+ If negative, the subscription is already ended (technically, it never
635+ started).
636+
637+- `%fact`: update from the publisher.
638+
639+- `%kick`: notification that the subscription has ended. This happens because
640+ either the target app passed a `%leave` note, or ames killed the subscription
641+ due to backpressure. Most of the time you will want to resubscribe. If you can
642+ no longer access the subscription you will get a negative `%watch-ack` and end
643+ your flow there.
644+
645+#### Accepts
646+
647+```hoon
648+[=wire =sign:agent:gall]
649+```
650+
651+`wire` is the wire from the `+gift` that triggered `++on-agent`
652+
653+`sign` is response for the gift.
654+
655+#### Returns
656+
657+```hoon
658+(quip card _this)
659+```
660+
661+#### Example
662+
663+```hoon
664+:: From reference agent
665+::
666+:: Handle sign from agent
667+::
668+++ on-agent
669+ |= [=wire =sign:agent:gall]
670+ ^- (quip card _this)
671+ ?- -.sign
672+ ::
673+ :: Print error if poke failed
674+ ::
675+ %poke-ack
676+ ?~ p.sign
677+ `this
678+ %- (slog u.p.sign)
679+ `this
680+ ::
681+ :: Print error if subscription failed
682+ ::
683+ %watch-ack
684+ ?~ p.sign
685+ `this
686+ =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
687+ %- (slog tank u.p.sign)
688+ `this
689+ ::
690+ :: Do nothing if unsubscribed
691+ ::
692+ %kick `this
693+ ::
694+ :: Update remote counter when we get a subscription update
695+ ::
696+ %fact
697+ :- ~
698+ ?. ?=(%atom p.cage.sign)
699+ this
700+ this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
701+ ==
702+```
703+
704+### `++on-arvo`
705+
706+Handle vane response
707+
708+This arm is called to handle responses for `%pass` cards to vanes.
709+
710+#### Accepts
711+
712+```hoon
713+ [=wire =sign:agent:gall]
714+```
715+
716+`wire` is the wire from the `++gift` that triggered `++on-arvo`.
717+
718+`sign` is the response from the vane. The list of possible responses from the
719+vanes is statically defined in sys/zuse.hoon (grep for `++ sign-arvo`).
720+
721+#### Returns
722+
723+```hoon
724+(quip card _this)
725+```
726+
727+List of cards and new agent.
728+
729+#### Example
730+
731+```hoon
732+:: From app/weather.hoon. Handles %bound, %wake and %http-response signs
733+++ on-arvo
734+ |= [=wire =sign-arvo]
735+ ^- (quip card:agent:gall _this)
736+ ?: ?=(%bound +<.sign-arvo)
737+ [~ this]
738+ ?: ?=(%wake +<.sign-arvo)
739+ =^ cards state
740+ (wake:wc wire error.sign-arvo)
741+ [cards this]
742+ ?: ?=(%http-response +<.sign-arvo)
743+ =^ cards state
744+ (http-response:wc wire client-response.sign-arvo)
745+ [cards this]
746+ (on-arvo:def wire sign-arvo)
747+::
748+:: From reference agent
749+::
750+:: Handle arvo signs
751+::
752+:: We never give any cards to arvo. Therefore we never need to handle any signs
753+:: from arvo. We use the default-agent library to avoid implementing this arm,
754+:: as gall apps must have all the arms specified in the agent:gall definition.
755+::
756+++ on-arvo on-arvo:def
757+```
758+
759+### `++on-fail`
760+
761+Handle error.
762+
763+If an error happens in `+on-poke`, the crash report goes into the
764+`%poke-ack` response. Similarly, if an error happens in
765+`+on-subscription`, the crash report goes into the `%watch-ack`
766+response. If a crash happens in any of the other handlers, the report
767+is passed into this arm.
768+
769+#### Accepts
770+
771+```hoon
772+[=term =tang]
773+```
774+
775+`term` is a cord describing the error.
776+
777+`tang` is a stack trace for the error.
778+
779+#### Returns
780+
781+```hoon
782+(quip card _this)
783+```
784+
785+List of cards and new agent
786+
787+#### Example
788+
789+```hoon
790+::
791+:: Handle error
792+::
793+:: Print errors when they happen
794+::
795+++ on-fail
796+ |= [=term =tang]
797+ ^- (quip card _this)
798+ %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
799+ `this
800+```
801+
802+## Agent Gifts
803+
804+Giving a gift takes the general form of
805+
806+```hoon
807+[%give =gift]
808+```
809+
810+### `%fact`
811+
812+Produce a subscription update.
813+
814+Produces a subscription update. A subscription update is a new piece of
815+subscription content for all subscribers on a given path.
816+
817+#### Structure
818+
819+```hoon
820+[%fact (list path) =cage]
821+```
822+
823+`(list path)` is a list of the paths to send the update on. If no path is
824+given, then the update is only given to the program that instigated the
825+request. Typical use of this mode is in `+on-watch` to give an initial update
826+to a new subscriber to get them up to date.
827+
828+`cage` is a cage of the subscription update.
829+
830+#### Example
831+
832+```hoon
833+:: From ++on-watch in reference agent.
834+::
835+:: Gives current local state to new subscribers.
836+[%give %fact ~ %atom !>(local.sta)]
837+
838+
839+:: From ++on-poke in reference agent
840+::
841+:: Gives incremented local state to any subscribers on /local
842+[%give %fact ~[/local] %atom !>(+(local))]
843+```
844+
845+### `%kick`
846+
847+Close subscription.
848+
849+Closes a subscription. A subscription close closes the subscription for all or
850+one subscribers on a given path.
851+
852+#### Structure
853+
854+```hoon
855+[%kick (unit path) (unit ship)]
856+```
857+
858+`(unit path)` is the path of the subscription being updated. If no path is
859+given, then the update is only given to the program that instigated the request.
860+Typical use of this mode would be in `+on-watch` to produce a single update to a
861+subscription then close the subscription.
862+
863+`(unit ship)` is the ship to close the subscription for. If no path is given,
864+then the subscription is closed for all subscribers.
865+
866+## Agent Notes
867+
868+Passing a agent note (a 'task') along a wire looks like so.
869+
870+```hoon
871+[%pass =wire %agent [=ship name=term] =task]
872+```
873+
874+`wire` is used to identify the response to the note.
875+
876+`ship` is the ship to pass the note to.
877+
878+`name` is the name of the agent that should receive the note.
879+
880+`task` is the task itself, described below.
881+
882+### `%poke`
883+
884+Poke an application.
885+
886+This note is passed to poke an application with a cage, a marked vase.
887+
888+#### Structure
889+
890+```hoon
891+[%poke =cage]
892+```
893+
894+`cage` is the marked data to poke the application with. It is a pair of a mark
895+and vase.
896+
897+#### Example
898+
899+```hoon
900+:: From ++on-poke in reference agent.
901+::
902+:: Sends an increment poke to the example-gall agent
903+:: on who.act.
904+:*
905+ %pass
906+ /inc/(scot %p who.act)
907+ %agent
908+ [who.act %example-gall]
909+ %poke %example-gall-action !>([%increment ~])
910+==
911+```
912+
913+### `%watch`
914+
915+Subscribe to an application.
916+
917+This note is given to subscribe to an application at a path
918+
919+#### Structure
920+
921+```hoon
922+[%watch =path]
923+```
924+
925+`path` is the path to be subscribed to.
926+
927+#### Example
928+
929+```hoon
930+:: From ++on-poke in reference agent.
931+::
932+:: Subscribes to the example-gall agent on who.act on the path /local
933+::
934+[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]
935+```
936+
937+### `%leave`
938+
939+Unsubscribe from an application.
940+
941+This note is passed to unsubscribe from an application. It should be passed on
942+the same wire that the corresponding `%watch` note for the subscription was
943+passed on.
944+
945+#### Structure
946+
947+```hoon
948+[%leave ~]
949+```
950+
951+#### Example
952+
953+```hoon
954+:: From ++on-poke in reference agent.
955+::
956+:: Unsubscribes from the example-gall agent on who.act
957+[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]
958+```
content/docs/arvo/gall/gall.mdnew file+558
@@ -0,0 +1,558 @@
1++++
2+title = "Overview"
3+weight = 1
4+template = "doc.html"
5+aliases = ["/docs/learn/arvo/gall/"]
6++++
7+
8+This document describes Gall, the Arvo userspace vane.
9+
10+# Agents
11+
12+Urbit code lives in the following basic categories:
13+
14+- Runtime (Nock interpreter, persistence engine, IO drivers, jets)
15+- Kernel vanes (managed by Arvo)
16+- Userspace agents (managed by Gall, permanent state)
17+- Userspace threads (managed by Spider, transient state)
18+
19+This lays out the framework for the third category: Agents.
20+
21+An agent is a piece of software that is primarily focused on maintaining
22+and distributing a piece of state with a defined structure. It exposes
23+an interface that lets programs read, subscribe to, and manipulate the
24+state. Every event happens in an atomic transaction, so the state is
25+never inconsistent. Since the state is permanent, when the agent is
26+upgraded with a change to the structure of the state, the developer
27+provides a migration function from the old state type to the new state
28+type.
29+
30+It's not too far off to think of an agent as simply a database with
31+developer-defined logic. But an agent is significantly less constrained
32+than a database. Databases are usually tightly constrained in one or
33+more ways because they need to provide certain guarantees (like
34+atomicity) or optimizations (like indexes). Urbit is a single-level
35+store, so atomicity comes for free. Many applications don't use
36+databases because they need relational indices; rather, they use them
37+for their guarantees around persistence. Some do need the indices,
38+though, and it's not hard to imagine an agent which provides a SQL-like
39+interface.
40+
41+On the other hand, an agent is also a lot like what many systems call a
42+"service". An agent is permanent and addressable -- a running program
43+can talk to an agent just by naming it. An agent can perform IO, unlike
44+most databases. This is a critical part of an agent: it performs IO
45+along the same transaction boundaries as changes to its state, so if an
46+effect happens, you know that the associated state change has happened.
47+You should be careful, though, to avoid creating implicit non-atomicity
48+-- eg if it comes into an inconsistent state pending a response to an IO
49+action.
50+
51+But the best way to think about an agent is as a state machine. Like a
52+state machine, any input could happen at any time, and it must react
53+coherently to that input. Ouput (effects) and the next state of the
54+machine are both pure functions of the previous state and the input
55+event. Of course, it's important to ensure there isn't an order of
56+events that could cause your agent to enter an inconsistent state.
57+
58+We often think of state machines as finite state machines, but of course
59+in this instance, the state is not actually finite (though it should be
60+definable in a regular recursive data type).
61+
62+## Specification
63+
64+An agent is defined as a [core](/docs/glossary/core/) with a set of [arms](/docs/glossary/arm/) to handle various
65+events. These handlers usually produce a list of effects and the next
66+state of the agent. The interface definition can be found in
67+`sys/lull.hoon`, which at the time of writing is:
68+
69+```hoon
70+++ agent
71+ =< form
72+ |%
73+ +$ step (quip card form)
74+ +$ card (wind note gift)
75+ +$ note
76+ $% [%arvo =note-arvo]
77+ [%agent [=ship name=term] =task]
78+ ==
79+ +$ task
80+ $% [%watch =path]
81+ [%watch-as =mark =path]
82+ [%leave ~]
83+ [%poke =cage]
84+ [%poke-as =mark =cage]
85+ ==
86+ +$ gift
87+ $% [%fact path=(unit path) =cage]
88+ [%kick path=(unit path) ship=(unit ship)]
89+ [%watch-ack p=(unit tang)]
90+ [%poke-ack p=(unit tang)]
91+ ==
92+ +$ sign
93+ $% [%poke-ack p=(unit tang)]
94+ [%watch-ack p=(unit tang)]
95+ [%fact =cage]
96+ [%kick ~]
97+ ==
98+ ++ form
99+ $_ ^|
100+ |_ bowl
101+ ++ on-init
102+ *(quip card _^|(..on-init))
103+ ::
104+ ++ on-save
105+ *vase
106+ ::
107+ ++ on-load
108+ |~ old-state=vase
109+ *(quip card _^|(..on-init))
110+ ::
111+ ++ on-poke
112+ |~ [mark vase]
113+ *(quip card _^|(..on-init))
114+ ::
115+ ++ on-watch
116+ |~ path
117+ *(quip card _^|(..on-init))
118+ ::
119+ ++ on-leave
120+ |~ path
121+ *(quip card _^|(..on-init))
122+ ::
123+ ++ on-peek
124+ |~ path
125+ *(unit (unit cage))
126+ ::
127+ ++ on-agent
128+ |~ [wire sign]
129+ *(quip card _^|(..on-init))
130+ ::
131+ ++ on-arvo
132+ |~ [wire sign-arvo]
133+ *(quip card _^|(..on-init))
134+ ::
135+ ++ on-fail
136+ |~ [term tang]
137+ *(quip card _^|(..on-init))
138+ --
139+```
140+
141+Here's a skeleton example of an implementation:
142+
143+```hoon
144+^- agent:gall
145+=| state=@
146+|_ bowl:gall
147++* this .
148+++ on-init
149+ `this
150+::
151+++ on-save
152+ !>(state)
153+::
154+++ on-load
155+ |= =old-state=vase
156+ `this(state !<(@ old-state-vase))
157+::
158+++ on-poke
159+ |= [=mark =vase]
160+ ~& > state=state
161+ ~& got-poked-with-data=mark
162+ =. state +(state)
163+ `this
164+::
165+++ on-watch
166+ |= path
167+ `this
168+::
169+++ on-leave
170+ |= path
171+ `this
172+::
173+++ on-peek
174+ |= path
175+ *(unit (unit cage))
176+::
177+++ on-agent
178+ |= [wire sign:agent:gall]
179+ `this
180+::
181+++ on-arvo
182+ |= [wire sign-arvo]
183+ `this
184+::
185+++ on-fail
186+ |= [term tang]
187+ `this
188+--
189+```
190+
191+We also supply a `default-agent` library, which is useful if you don't
192+want to handle some of the arms. Most of the above could also be
193+implemented as:
194+
195+```hoon
196+/+ default-agent
197+^- agent:gall
198+=| state=@
199+|_ =bowl:gall
200++* this .
201+ default ~(. (default-agent this %|) bowl)
202+::
203+++ on-init on-init:default
204+++ on-save on-save:default
205+++ on-load on-load:default
206+++ on-poke
207+ |= [=mark =vase]
208+ ~& > state=state
209+ ~& got-poked-with-data=mark
210+ =. state +(state)
211+ `this
212+::
213+++ on-watch on-watch:default
214+++ on-leave on-leave:default
215+++ on-peek on-peek:default
216+++ on-agent on-agent:default
217+++ on-arvo on-arvo:default
218+++ on-fail on-fail:default
219+--
220+```
221+
222+So, an agent is a core with 10 arms. The handlers correspond to
223+different sorts of input. We'll discuss each of these in detail, but
224+first a few general concepts.
225+
226+## Basic concepts
227+
228+### Interacting with an agent
229+
230+There are two basic ways programs can interact with an agent: you may
231+subscribe to data as described above, or you may "poke" an agent to send
232+it a command. Suppose there is an agent for a calendar service; then,
233+pokes would likely include `%create-event`, `%modify-event`,
234+`%delete-event`, and `%change-time-zone` (along with assocated data).
235+Subscription paths could include `/next-event` and `/all-events`.
236+
237+Agents generally conform to CQRS -- pokes may change state, but
238+subscriptions generally shouldn't. In practice, there may be state
239+changes required to properly initialize the subscription, but these
240+shouldn't change the essential state of the agent.
241+
242+### Cards
243+
244+Most of the handlers produce a `(quip card agent:gall)`, which is just
245+`[(list card) agent:gall]`. The first allows us to produce effects, and
246+the second allows us to maintain state.
247+
248+A card is one of two things: a `note` or a `gift`. You `%pass` `note`s
249+and you `%give` `gift`s. When you pass a `note`, you expect zero or more
250+responses; when you give a `gift`, you will not get a response. Since you
251+may get a response to a `note`, you tag it with a `wire` so that you can
252+identify the response.
253+
254+Thus, we say you "pass a `note` along a `wire`", or you "give a `gift`".
255+These phrases correspond to producing a card that looks like:
256+
257+```hoon
258+[%pass /my/wire a-note]
259+```
260+
261+or
262+
263+```hoon
264+[%give a-gift]
265+```
266+
267+When you give a `gift`, that's the end of the story, but when you pass a
268+`note`, you may get a response. If you do, then the response will come
269+tagged with the `wire` that you used to pass the `note`. It's generally
270+good practice to make your `wire`s fairly unique within your agent, since
271+otherwise you may not be able to distinguish the responses.
272+
273+#### Notes
274+
275+An agent may pass `note`s to either Arvo or another agent. If the `note` is
276+to another agent, then it should usually be one of these:
277+
278+```hoon
279+[%pass /my/wire %agent [our.bowl agent-name] %watch /a/path]
280+[%pass /my/wire %agent [our.bowl agent-name] %leave ~]
281+[%pass /my/wire %agent [our.bowl agent-name] %poke %foo-mark !>(poke-data)]
282+```
283+
284+Note that to unsubscribe to a `path`, you must send the unsubscription on
285+the same `wire` that sent for the original subscription. Don't subscribe
286+to separate `path`s along the same `wire`, because then you can't properly
287+distinguish them for cancelling (besides not being able to distinguish
288+the subscription updates). In other words, besides letting _you_
289+distinguish your `card`s, the `wire` also identifies requests for the system.
290+
291+If the `note` is not to another agent but to Arvo itself, then it is a
292+request to one of the vanes, which are kernel modules that provide
293+various system services, including IO. Here are some examples:
294+
295+```hoon
296+[%pass /my/wire %arvo %b %wait (add now.hid ~s10)]
297+```
298+
299+This is a request to the `%b` vane (Behn, the timer vane) to set a timer
300+for 10 seconds in the future. After 10 seconds, Behn will respond with
301+a `%wake` card, which you will recieve in `+on-arvo`. It will come back
302+on `/my/wire`.
303+
304+```hoon
305+=/ =path /(scot %p our.hid)/home/(scot %da now.hid)/my-file/txt
306+=/ contents=cage [%txt !>(~['text file line 1' 'line 2'])]
307+[%pass /my/wire %arvo %c %info (foal:space:userlib path contents)]
308+```
309+
310+This is a request to the `%c` vane (Clay, the filesystem vane) to write
311+a file to `/my-file/txt` in the home desk. You will not receive a
312+response to this `note`.
313+
314+```hoon
315+=/ =path /my-file/txt
316+=/ =moat [da+now.hid da+(add now.hid ~h1) path]
317+[%pass /my/wire %arvo %c %warp our.hid %home ~ %many & moat]
318+```
319+
320+This is a request to the `%c` vane to send us a `%writ` `card` whenever
321+`/my-file/txt` changes in the next hour. There may be many responses to
322+this note if the file changes many times.
323+
324+```hoon
325+=/ =request:http
326+ [%'GET' 'https://example.com' ~ ~]
327+[%pass /my/wire %arvo %i %request request *outbound-config:iris]
328+```
329+
330+This is a request to the `%i` vane (Iris, the HTTP client vane) to make
331+a GET HTTP request to example.com. The response will come as an
332+`%http-response` card.
333+
334+#### Gifts
335+
336+In contrast to the many possible `note`s, there are only two types of
337+`gift`s that an agent may give:
338+
339+```hoon
340+[%give %fact (unit path) =cage]
341+[%give %kick (unit path)]
342+```
343+
344+A subscription update is a new piece of subscription content for all
345+subscribers on a given `path`. If no `path` is given, then the update is
346+only given to the program that instigated this request. Typical use of
347+this mode is in `+on-watch` to give an initial update to a new
348+subscriber to get them up to date.
349+
350+A subscription close closes the subscription for all subscribers on a
351+given `path`. If no `path` is given, then the update is only given to the
352+program that instigated this request. Typical use of this mode would be
353+in `+on-watch` to produce a single update to a subscription then close
354+the subscription.
355+
356+### Vases and cages
357+
358+A `vase` is a piece of dynamic data. Structurally, it's a pair of an
359+explicit reification of a type and an untyped [noun](/docs/glossary/noun/). This lets us
360+represent a value which has a type that isn't known at compile time. A
361+vase has three operations:
362+
363+- `!>` is a unary rune that lifts a statically typed value to a
364+ dynamically-typed `vase`. For example, `!>('hi')` gives `[#t/@t q=26.984]`.
365+
366+- `!<` is a binary rune that takes a mold and a dynamically typed `vase`
367+ and reduces it to a statically typed value. If the `vase` does not in
368+ fact have the type of the mold you give it, then it nest-fails, else
369+ it produces `value`. For example, `!<(@t !>('hi'))` produces `'hi'` while `!<(^ !>('hi'))` causes a nest fail..
370+
371+- The compiler takes text and converts it to a `vase` of the compiled
372+ code. Agents shouldn't need this directly, but Gall uses this to
373+ compile agents to `vase`s, on which it calls `!<(agent:gall compiled-agent-vase)`.
374+
375+A `cage` is simply a pair of a mark and a vase. A mark is a textual tag
376+that should correspond to the particular dynamic type in the vase.
377+
378+In agents, we use vases to represent types which Gall doesn't know about
379+when it was compiled, but which nevertheless need to go outside the
380+agent. In practice, there are three common cases:
381+
382+- The data in a "poke" request is of a type that is defined by each
383+ agent, so it must by dynamic. This is the input to `++on-poke` as well
384+ as the cage in the `%poke` case of the `%agent` note.
385+
386+- The data in a subscription update is defined by each agent, so it must
387+ be dynamic. This is the cage in `%fact`, both when giving the update
388+ and in the input to `+on-agent`.
389+
390+- The state of an agent is also unique to each agent. Most of the time,
391+ Gall doesn't interact directly with agent's state, but when upgrading
392+ an agent, it must pass the state of the old version of the agent to
393+ the new version of the agent. This is the output of `+on-save` and
394+ the input to `+on-load`.
395+
396+### State
397+
398+In the definition of an agent, the entire core is wrapped with the `^|`
399+rune, which corresponds to the "iron" variance mode. This means it's
400+"contravariant" in the input, which allows Gall to write to the new bowl
401+on every event. It also means that the context of the core is opaque to
402+Gall, which means you can store state in your context in whatever
403+structure you want.
404+
405+This is why most of the handler arms produce not just a list of cards
406+but also a new `agent:gall`. Usually, this will be the "same" agent in
407+the sense that the code will be the same, but you may have changed the
408+state that's stored in its (opaque to Gall) context.
409+
410+The skeleton example above gives an example of keeping an atom as your
411+state. Define the state in the context of your agent core, then you can
412+change it with `=.` or `%=`, as long as you produce the new version of
413+the agent core.
414+
415+When you upgrade an agent, you need to extract the state from your
416+opaque context and produce it to Gall as a dynamically typed vase.
417+Usually, this will be easy: just call `!>` on whatever state you wish
418+to preserve. This is `+on-save`.
419+
420+When the new agent is about to be started, Gall will call it with
421+`+on-load` with the vase just produced above. This allows you to ingest
422+your old state and continue right where you left off.
423+
424+If the type of your state hasn't changed, you can just
425+
426+```hoon
427+=. state !<(state-type old-state-vase)
428+```
429+
430+If it has changed, then it should look more like:
431+
432+```hoon
433+=. state (upgrade-state !<(old-state-type old-state-vase))
434+```
435+
436+It's useful to tag your state with a version number so that the
437+`+upgrade-state` function can take a tagged union of all your old state
438+types and upgrade from any of them to the current state type. For
439+example, it may have the following structure:
440+
441+```hoon
442++$ old-state-types
443+ $% [%0 s=state-0]
444+ [%1 s=state-1]
445+ [%2 s=state-2]
446+ ==
447+++ upgrade-state
448+ |= old=old-state-types
449+ =? old ?=(%0 -.old)
450+ (state-0-to-1 s.old)
451+ =? old ?=(%1 -.old)
452+ (state-1-to-2 s.old)
453+ ?> ?=(%2 -.old)
454+ s.old
455+```
456+
457+### Bowl
458+
459+The core takes as input a `bowl`, which includes useful info like the
460+current ship, the current time, and a renewable source of entropy. This
461+information is available to any of the handlers.
462+
463+## Arms
464+
465+A description of each of the handler arms follows.
466+
467+### +on-init
468+
469+This arm is called once when the agent is started. It has no input and
470+lets you perform any initial IO.
471+
472+### +on-save
473+
474+This arm is called immediately before the agent is upgraded. It
475+packages the permament state of the agent in a `vase` for the next version
476+of the agent. Unlike most handlers, this cannot produce effects.
477+
478+### +on-load
479+
480+This arm is called immediately after the agent is upgraded. It receives
481+a `vase` of the state of the previously-running version of the agent,
482+which allows it to cleanly upgrade from the old agent.
483+
484+### +on-poke
485+
486+This arm is called when the agent is "poked". The input is a `cage`, so
487+it's a pair of a mark and a dynamic `vase`.
488+
489+### +on-watch
490+
491+This arm is called when a program wants to subscribe to the agent on a
492+particular `path`. The agent may or may not need to perform setup steps
493+to intialize the subscription. It may produce a `%give`
494+`%subscription-result` to the subscriber to get it up to date, but after
495+this event is complete, it cannot give further updates to a specific
496+subscriber. It must give all further updates to all subscribers on a
497+specific `path`.
498+
499+If this arm crashes, then the subscription is immediately terminated.
500+More specifcally, it never started -- the subscriber will receive a
501+negative `%watch-ack`. You may also produce an explicit `%kick` to
502+close the subscription without crashing -- for example, you could
503+produce a single update followed by a `%kick`.
504+
505+### +on-leave
506+
507+This arm is called when a program becomes unsubscribed to you.
508+Subscriptions may close because the subscriber intentionally
509+unsubscribed, but they also could be closed by an intermediary. For
510+example, if a subscription is from another ship which is currently
511+unreachable, Ames may choose to close the subscription to avoid queueing
512+updates indefinitely. If the program crashes while processing an
513+update, this may also generate an unsubscription. You should consider
514+subscriptions to be closable at any time.
515+
516+### +on-peek
517+
518+This arm is called when a program reads from the agent's "scry"
519+namespace, which should be referentially transparent. Unlike most
520+handlers, this cannot perform IO, and it cannot change the state. All
521+it can do is produce a piece of data to the caller, or not.
522+
523+If this arm produces `[~ ~ data]`, then `data` is the value at the the
524+given `path`. If it produces `[~ ~]`, then there is no data at the given
525+`path` and never will be. If it produces `~`, then we don't know yet
526+whether there is or will be data at the given `path`.
527+
528+### +on-agent
529+
530+This arm is called to handle responses to `%give` moves to other agents.
531+It will be one of the following types of response:
532+
533+- `%poke-ack`: acknowledgment (positive or negative) of a poke. If the
534+ value is `~`, then the poke succeeded. If the value is `[~ tang]`,
535+ then the poke failed, and a printable explanation (e.g. a stack trace)
536+ is given in the `tang`.
537+
538+- `%watch-ack`: acknowledgment (positive or negative) of a subscription.
539+ If negative, the subscription is already ended (technically, it never
540+ started).
541+
542+- `%fact`: update from the publisher.
543+
544+- `%kick`: notification that the subscription has ended.
545+
546+### +on-arvo
547+
548+This arm is called to handle responses to `%pass` `move`s to vanes. The
549+list of possible responses from the system is statically defined in
550+`sys/lull.hoon` (grep for `+$ sign-arvo`).
551+
552+### +on-fail
553+
554+If an error happens in `+on-poke`, the crash report goes into the
555+`%poke-ack` response. Similarly, if an error happens in
556+`+on-subscription`, the crash report goes into the `%watch-ack`
557+response. If a crash happens in any of the other handlers, the report
558+is passed into this arm.
content/docs/userspace/gall-guide.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Gall Guide"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+[**The Complete Guide to Gall and Userspace Apps on
8+Urbit**](https://github.com/timlucmiptev/gall-guide), or more colloquially
9+referred to as just "the Gall Guide," was contributed by a member of our
10+community named `~timluc-miptev`.
11+
12+Our plan is ultimately to make this part of the official documentation found
13+here, but for now, know that it has our official seal of approval and is
14+actively maintained.