on master help sign in
add gall reference docs (#753)
6d333f7Liam Fitzgerald
reference/gall.mdnew file+948
@@ -0,0 +1,948 @@
1+# Gall
2+
3+## Reference Agent
4+
5+This app stores a number for each user. You can increment your number, increment
6+someone else's number, start tracking someone else's number by poking. It
7+exposes a scry namespace to inspect everyone's number.
8+
9+### `app/example-gall.hoon`
10+
11+```hoon
12+:: Import sur/example-gall
13+/- *example-gall
14+:: Import lib/default-agent
15+/+ default-agent
16+|%
17++$ card card:agent:gall
18++$ note
19+ $%
20+ [%arvo =note-arvo]
21+ [%agent [=ship name=term] =task:agent:gall]
22+ ==
23++$ state-zero [%0 local=@ud]
24++$ state-one [%1 local=@ud remote=(map @p @ud)]
25++$ versioned-state
26+ $%
27+ state-zero
28+ state-one
29+ ==
30+--
31+=| state-one
32+=* state -
33+^- agent:gall
34+|_ =bowl:gall
35++* this .
36+ def ~(. (default-agent this %|) bowl)
37+::
38+:: Set local counter to 1 by default
39+++ on-init
40+ ^- (quip card _this)
41+ `this(local 1)
42+:: Expose state for saving
43+++ on-save
44+ !>(state)
45+::
46+:: Load old state and upgrade if neccessary
47+++ on-load
48+ |= old=vase
49+ ^- (quip card _this)
50+ =/ loaded=versioned-state
51+ !<(versioned-state old)
52+ ?- -.loaded
53+ %0
54+ `this(local local.loaded) :: Upgrade old state
55+ %1
56+ `this(state loaded)
57+ ==
58+::
59+:: Respond to poke
60+:: App can be poked in the dojo by running the following commands
61+:: Increment local counter
62+:: :example-gall &example-gall-action [%increment ~]
63+:: Increment ~zod's counter
64+:: :example-gall &example-gall-action [%increment-remote ~zod]
65+:: Subscribe to ~zod's counter
66+:: :example-gall &example-gall-action [%view ~zod]
67+:: Unsubscribe from ~zod's counter
68+:: :example-gall &example-gall-action [%stop-view ~zod]
69+::
70+++ on-poke
71+ |= [=mark =vase]
72+ ^- (quip card _this)
73+ :: Ensure poke is of mark %example-gall-action
74+ ?> =(mark %example-gall-action)
75+ =/ act=example-gall-action !<(example-gall-action vase)
76+ ?- act
77+ ::
78+ :: Increment local counter and send new counter to subscribers
79+ ::
80+ [%increment ~]
81+ :- [%give %fact `/local %atom !>(+(local))]~
82+ this(local +(local))
83+ ::
84+ :: Send remote %increment poke
85+ ::
86+ [%increment-remote who=@p]
87+ :_ this
88+ :~ :*
89+ %pass
90+ /inc/(scot %p who.act)
91+ %agent
92+ [who.act %example-gall]
93+ %poke %example-gall-action !>([%increment ~])
94+ == ==
95+ ::
96+ :: Subscribe to a remote counter
97+ ::
98+ [%view who=@p]
99+ :_ this
100+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
101+ ::
102+ :: Unsubscribe from remote counter and remove from state
103+ ::
104+ [%stop-view who=@p]
105+ :_ this(remote (~(del by remote) who.act))
106+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
107+ ::
108+ ==
109+::
110+:: Print on unsubscribe
111+::
112+++ on-leave
113+ |= =path
114+ ^- (quip card _this)
115+ ~& "Unsubscribed by: {<src.bowl>} on: {<path>}"
116+ `this
117+::
118+:: Handle new subscription
119+::
120+:: When another ship subscribes to our counter, give them the current state of
121+:: the counter immediately
122+::
123+++ on-watch
124+ |= =path
125+ ^- (quip card _this)
126+ :_ this
127+ :: Crash if we see a subscription we don't recognise
128+ ?+ path ~|("unexpected subscription" !!)
129+ ::
130+ [%local ~]
131+ [%give %fact ~ %atom !>(local)]~
132+ ==
133+::
134+:: Expose scry namespace
135+::
136+:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
137+:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
138+:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
139+:: remote counters
140+++ on-peek
141+ |= =path
142+ ^- (unit (unit cage))
143+ ?+ path [~ ~]
144+ ::
145+ :: Produce local counter
146+ ::
147+ [%x %local ~]
148+ ``[%atom !>(local)]
149+ ::
150+ :: Produce remote counter
151+ ::
152+ [%x %remote who=@ta ~]
153+ =* location i.t.t.path :: Ship name is third in the list
154+ =/ res
155+ (~(got by remote) (slav %p location))
156+ ``[%atom !>(res)]
157+ ::
158+ :: Produce listing of remote counters
159+ ::
160+ [%y %remote ~]
161+ =/ dir=(map @ta ~)
162+ %- molt :: Map from list of k-v pairs
163+ %+ turn :: iterate over list of k-v pairs
164+ ~(tap by remote) :: list of k-v pairs from map
165+ |= [who=@p *]
166+ [(scot %p who) ~]
167+ ``[%arch !>(`arch`[~ dir])]
168+ ==
169+::
170+:: Handle sign from agent
171+::
172+++ on-agent
173+ |= [=wire =sign:agent:gall]
174+ ^- (quip card _this)
175+ ?- -.sign
176+ ::
177+ :: Print error if poke failed
178+ ::
179+ %poke-ack
180+ ?~ p.sign
181+ `this
182+ %- (slog u.p.sign)
183+ `this
184+ ::
185+ :: Print error if subscription failed
186+ ::
187+ %watch-ack
188+ ?~ p.sign
189+ `this
190+ =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
191+ %- (slog tank u.p.sign)
192+ `this
193+ ::
194+ :: Do nothing if unsubscribed
195+ ::
196+ %kick `this
197+ ::
198+ :: Update remote counter when we get a subscription update
199+ ::
200+ %fact
201+ :- ~
202+ ?. ?=(%atom p.cage.sign)
203+ this
204+ this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
205+ ==
206+::
207+:: Handle arvo signs
208+::
209+:: We never give any cards to arvo. Therefore we never need to handle any signs
210+:: from arvo. We use the default-agent library to avoid implementing this arm,
211+:: as gall apps must have all the arms.
212+::
213+++ on-arvo on-arvo:def
214+::
215+:: Handle error
216+::
217+:: Print errors when they happen
218+::
219+++ on-fail
220+ |= [=term =tang]
221+ ^- (quip card _this)
222+ %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
223+ `this
224+--
225+
226+```
227+
228+### `sur/example-gall.hoon`
229+
230+```hoon
231+|%
232++$ example-gall-action
233+ $%
234+ [%view who=@p]
235+ [%stop-view who=@p]
236+ [%increment-remote who=@p]
237+ [%increment ~]
238+ ==
239+--
240+```
241+
242+### `mar/example-gall/action.hoon`
243+
244+```hoon
245+/- *example-gall
246+|_ act=example-gall-action
247+++ grab
248+ |%
249+ ++ noun example-gall-action
250+ --
251+--
252+```
253+
254+## Arms
255+
256+### `++on-init`
257+
258+Application initialisation
259+
260+`++on-init` is called when an application is first started. It is not a gate and
261+has no input.
262+
263+#### Returns
264+
265+```hoon
266+(quip card _this)
267+```
268+
269+List of cards and new agent
270+
271+#### Example
272+
273+```hoon
274+:: From reference agent.
275+:: Set local counter to 1 by default
276+::
277+++ on-init
278+ ^- (quip card _this)
279+ `this(local.sta 1)
280+:: From app/weather.hoon. This setup is typical of a landscape tile.
281+::
282+++ on-init
283+ :_ this
284+ :~ [%pass /bind/weather %arvo %e %connect [~ /'~weather'] %weather]
285+ :* %pass /launch/weather %agent [our.bol %launch] %poke
286+ %launch-action !>([%weather /weathertile '/~weather/js/tile.js'])
287+ ==
288+ ==
289+```
290+
291+### `++on-save`
292+
293+Expose state for saving.
294+
295+This arm is called immediately before the agent is upgraded. It packages the
296+permament state of the agent in a vase for the next version of the agent.
297+Unlike most handlers, this cannot produce effects. It is not a gate and has no input.
298+
299+#### Returns
300+
301+`vase` of permanent state.
302+
303+#### Example
304+
305+```hoon
306+:: From reference agent
307+::
308+:: Expose state for saving
309+::
310+++ on-save
311+ !>(state)
312+```
313+
314+### `++on-load`
315+
316+Application upgrade.
317+
318+This arm is called immediately after the agent is upgraded. It receives
319+a vase of the state of the previously-running version of the agent, obtained
320+from `+on-save`, which allows it to cleanly upgrade from the old agent.
321+
322+#### Accepts
323+
324+```hoon
325+=vase
326+```
327+
328+`vase` of previous state, from `++on-save`
329+
330+#### Returns
331+
332+```hoon
333+(quip card _this)
334+```
335+
336+List of cards and new agent
337+
338+#### Examples
339+
340+```hoon
341+:: From reference agent
342+::
343+:: Load old state and upgrade if neccessary
344+++ on-load
345+ |= old=vase
346+ ^- (quip card _this)
347+ =/ loaded=versioned-state
348+ !<(versioned-state old)
349+ ?- -.loaded
350+ %0
351+ `this(local local.loaded) :: Upgrade old state
352+ %1
353+ `this(state loaded)
354+ ==
355+```
356+
357+### `++on-poke`
358+
359+Handle application poke.
360+
361+This arm is called when the agent is "poked". The input is a cage, so
362+it's a pair of a mark and a dynamic vase.
363+
364+#### Accepts
365+
366+```hoon
367+[=mark =vase]
368+```
369+
370+`mark` is the mark of the poked data.
371+
372+`vase` is a vase with the poked data inside.
373+
374+#### Returns
375+
376+```hoon
377+(quip card _this)
378+```
379+
380+List of cards and new agent.
381+
382+#### Example
383+
384+```hoon
385+:: From reference agent.
386+::
387+:: Respond to poke
388+:: App can be poked in the dojo by running the following commands
389+:: Increment local counter
390+:: :example-gall &example-gall-action [%increment ~]
391+:: Increment ~zod's counter
392+:: :example-gall &example-gall-action [%increment-remote ~zod]
393+:: Subscribe to ~zod's counter
394+:: :example-gall &example-gall-action [%view ~zod]
395+:: Unsubscribe from ~zod's counter
396+:: :example-gall &example-gall-action [%stop-view ~zod]
397+::
398+++ on-poke
399+ |= [=mark =vase]
400+ ^- (quip card _this)
401+ :: Ensure poke is of mark %example-gall-action
402+ ?> =(mark %example-gall-action)
403+ =/ act=example-gall-action !<(example-gall-action vase)
404+ ?- act
405+ ::
406+ :: Increment local counter and send new counter to subscribers
407+ ::
408+ [%increment ~]
409+ :- [%give %fact `/local %atom !>(+(local))]~
410+ this(local +(local))
411+ ::
412+ :: Send remote %increment poke
413+ ::
414+ [%increment-remote who=@p]
415+ :_ this
416+ :~ :*
417+ %pass
418+ /inc/(scot %p who.act)
419+ %agent
420+ [who.act %example-gall]
421+ %poke %example-gall-action !>([%increment ~])
422+ == ==
423+ ::
424+ :: Subscribe to a remote counter
425+ ::
426+ [%view who=@p]
427+ :_ this
428+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
429+ ::
430+ :: Unsubscribe from remote counter and remove from state
431+ ::
432+ [%stop-view who=@p]
433+ :_ this(remote (~(del by remote) who.act))
434+ [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
435+ ::
436+ ==
437+```
438+
439+### `++on-watch`
440+
441+Handle new subscriber.
442+
443+This arm is called when a program wants to subscribe to the agent on a
444+particular path. The agent may or may not need to perform setup steps
445+to intialize the subscription. It may produce a `%give`
446+`%subscription-result` to the subscriber to get it up to date, but after
447+this event is complete, it cannot give further updates to a specific
448+subscriber. It must give all further updates to all subscribers on a
449+specific path.
450+
451+If this arm crashes, then the subscription is immediately terminated.
452+More specifcally, it never started -- the subscriber will receive a
453+negative `%watch-ack`. You may also produce an explicit `%kick` to
454+close the subscription without crashing -- for example, you could
455+produce a single update followed by a `%kick`.
456+
457+#### Accepts
458+
459+```hoon
460+=path
461+```
462+
463+Path of new subscription.
464+
465+#### Returns
466+
467+```hoon
468+(quip card _this)
469+```
470+
471+List of cards and new agent.
472+
473+#### Example
474+
475+```hoon
476+:: From reference agent
477+::
478+:: Handle new subscription
479+::
480+:: When another ship subscribes to our counter, give them the current state of
481+:: the counter immediately
482+::
483+++ on-watch
484+ |= =path
485+ ^- (quip card _this)
486+ :_ this
487+ ?+ path on-watch:def
488+ ::
489+ [%local ~]
490+ [%give %fact ~ %atom !>(local)]~
491+ ==
492+```
493+
494+### `++on-leave`
495+
496+Handle unsubscribe.
497+
498+This arm is called when a program becomes unsubscribed to you.
499+Subscriptions may close because the subscriber intentionally
500+unsubscribed, but they also could be closed by an intermediary. For
501+example, if a subscription is from another ship which is currently
502+unreachable, Ames may choose to close the subscription to avoid queueing
503+updates indefinitely. If the program crashes while processing an
504+update, this may also generate an unsubscription. You should consider
505+subscriptions to be closable at any time.
506+
507+#### Accepts
508+
509+```hoon
510+=path
511+```
512+
513+Path of the closed subscription.
514+
515+#### Returns
516+
517+```hoon
518+(quip card _this)
519+```
520+
521+List of cards and new agent.
522+
523+#### Example
524+
525+```hoon
526+:: From reference agent. Prints a message when programs become unsubscribed.
527+++ on-leave
528+ |= =path
529+ ^- (quip card _this)
530+ ~& "Unsubscribe by: {<src.bowl>} on: {<path>}"
531+ `this
532+```
533+
534+### `++on-peek`
535+
536+Handle scry request.
537+
538+This arm is called when a program reads from the agent's "scry"
539+namespace, which should be referentially transparent. Unlike most
540+handlers, this cannot perform IO, and it cannot change the state. All
541+it can do is produce a piece of data to the caller, or not.
542+
543+#### Accepts
544+
545+```hoon
546+=path
547+```
548+
549+The path being scryed for.
550+
551+```hoon
552+:: Example scry to path mappings
553+::
554+.^(arch %gy /=example-gall=/remote)
555+:: Path will be /y/remote
556+.^(@ %gx /=example-gall=/local/atom)
557+:: Path will be /x/local
558+```
559+
560+#### Returns
561+
562+```hoon
563+(unit (unit cage))
564+```
565+
566+If this arm produces `[~ ~ data]`, then `data` is the value at the the
567+given path. If it produces `[~ ~]`, then there is no data at the given
568+path and never will be. If it produces `~`, then we don't know yet whether
569+there is or will be data at the given path. The head of the path is known as the
570+`care`. Requests with a care of `%x` should return a vase that matches or is
571+convertible to the mark at the end of the scry request. This mark is not
572+included in the path passed to `++on-peek`. Requests with a care of `%y` should
573+return a cage with a mark of `%arch` and a vase of `arch`.
574+
575+#### Example
576+
577+```hoon
578+:: From reference agent
579+::
580+:: Expose scry namespace
581+::
582+:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
583+:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
584+:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
585+:: remote counters
586+++ on-peek
587+ |= =path
588+ ^- (unit (unit cage))
589+ ?+ path [~ ~]
590+ ::
591+ :: Produce local counter
592+ ::
593+ [%x %local ~]
594+ ``[%atom !>(local)]
595+ ::
596+ :: Produce remote counter
597+ ::
598+ [%x %remote who=@ta ~]
599+ =* location i.t.t.path :: Ship name is third in the list
600+ =/ res
601+ (~(got by remote) (slav %p location))
602+ ``[%atom !>(res)]
603+ ::
604+ :: Produce listing of remote counters
605+ ::
606+ [%y %remote ~]
607+ =/ dir=(map @ta ~)
608+ %- molt :: Map from list of k-v pairs
609+ %+ turn :: iterate over list of k-v pairs
610+ ~(tap by remote) :: list of k-v pairs from map
611+ |= [who=@p *]
612+ [(scot %p who) ~]
613+ ``[%arch !>(`arch`[~ dir])]
614+ ==
615+```
616+
617+### `++on-agent`
618+
619+Handle `%pass` card
620+
621+This arm is called to handle responses to `%pass` cards to other agents.
622+It will be one of the following types of response:
623+
624+- `%poke-ack`: acknowledgment (positive or negative) of a poke. If the
625+ value is `~`, then the poke succeeded. If the value is `[~ tang]`,
626+ then the poke failed, and a printable explanation (eg a stack trace)
627+ is given in the `tang`.
628+
629+- `%watch-ack`: acknowledgment (positive or negative) of a subscription.
630+ If negative, the subscription is already ended (technically, it never
631+ started).
632+
633+- `%fact`: update from the publisher.
634+
635+- `%kick`: notification that the subscription has ended. This happens because
636+ either the target app passed a `%leave` note, or ames killed the subscription
637+ due to backpressure. Most of the time you will want to resubscribe. If you can
638+ no longer access the subscription you will get a negative `%watch-ack` and end
639+ your flow there.
640+
641+#### Accepts
642+
643+```hoon
644+[=wire =sign:agent:gall]
645+```
646+
647+`wire` is the wire from the `+gift` that triggered `++on-agent`
648+
649+`sign` is response for the gift.
650+
651+#### Returns
652+
653+```hoon
654+(quip card _this)
655+```
656+
657+#### Example
658+
659+```hoon
660+:: From reference agent
661+::
662+:: Handle sign from agent
663+::
664+++ on-agent
665+ |= [=wire =sign:agent:gall]
666+ ^- (quip card _this)
667+ ?- -.sign
668+ ::
669+ :: Print error if poke failed
670+ ::
671+ %poke-ack
672+ ?~ p.sign
673+ `this
674+ %- (slog u.p.sign)
675+ `this
676+ ::
677+ :: Print error if subscription failed
678+ ::
679+ %watch-ack
680+ ?~ p.sign
681+ `this
682+ =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
683+ %- (slog tank u.p.sign)
684+ `this
685+ ::
686+ :: Do nothing if unsubscribed
687+ ::
688+ %kick `this
689+ ::
690+ :: Update remote counter when we get a subscription update
691+ ::
692+ %fact
693+ :- ~
694+ ?. ?=(%atom p.cage.sign)
695+ this
696+ this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
697+ ==
698+```
699+
700+### `++on-arvo`
701+
702+Handle vane response
703+
704+This arm is called to handle responses for `%pass` cards to vanes.
705+
706+#### Accepts
707+
708+```hoon
709+ [=wire =sign:agent:gall]
710+```
711+
712+`wire` is the wire from the `++gift` that triggered `++on-arvo`.
713+
714+`sign` is the response from the vane. The list of possible responses from the
715+vanes is statically defined in sys/zuse.hoon (grep for `++ sign-arvo`).
716+
717+#### Returns
718+
719+```hoon
720+(quip card _this)
721+```
722+
723+List of cards and new agent.
724+
725+#### Example
726+
727+```hoon
728+:: From app/weather.hoon. Handles %bound, %wake and %http-response signs
729+++ on-arvo
730+ |= [=wire =sign-arvo]
731+ ^- (quip card:agent:gall _this)
732+ ?: ?=(%bound +<.sign-arvo)
733+ [~ this]
734+ ?: ?=(%wake +<.sign-arvo)
735+ =^ cards state
736+ (wake:wc wire error.sign-arvo)
737+ [cards this]
738+ ?: ?=(%http-response +<.sign-arvo)
739+ =^ cards state
740+ (http-response:wc wire client-response.sign-arvo)
741+ [cards this]
742+ (on-arvo:def wire sign-arvo)
743+::
744+:: From reference agent
745+::
746+:: Handle arvo signs
747+::
748+:: We never give any cards to arvo. Therefore we never need to handle any signs
749+:: from arvo. We use the default-agent library to avoid implementing this arm,
750+:: as gall apps must have all the arms specified in the agent:gall definition.
751+::
752+++ on-arvo on-arvo:def
753+```
754+
755+### `++on-fail`
756+
757+Handle error.
758+
759+If an error happens in `+on-poke`, the crash report goes into the
760+`%poke-ack` response. Similarly, if an error happens in
761+`+on-subscription`, the crash report goes into the `%watch-ack`
762+response. If a crash happens in any of the other handlers, the report
763+is passed into this arm.
764+
765+#### Accepts
766+
767+```hoon
768+[=term =tang]
769+```
770+
771+`term` is a cord describing the error.
772+
773+`tang` is a stack trace for the error.
774+
775+#### Returns
776+
777+```hoon
778+(quip card _this)
779+```
780+
781+List of cards and new agent
782+
783+#### Example
784+
785+```hoon
786+::
787+:: Handle error
788+::
789+:: Print errors when they happen
790+::
791+++ on-fail
792+ |= [=term =tang]
793+ ^- (quip card _this)
794+ %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
795+ `this
796+```
797+
798+## Agent Gifts
799+
800+Giving a gift takes the general form of
801+
802+```hoon
803+[%give =gift]
804+```
805+
806+### `%fact`
807+
808+Produce a subscription update.
809+
810+Produces a subscription update. A subscription update is a new piece of
811+subscription content for all subscribers on a given path.
812+
813+#### Structure
814+
815+```hoon
816+[%fact (unit path) =cage]
817+```
818+
819+`(unit path)` is the path of the subscription being updated. If no path is
820+ given, then the update is only given to the program that instigated the
821+ request. Typical use of this mode is in `+on-watch` to give an initial update
822+ to a new subscriber to get them up to date.
823+
824+`cage` is a cage of the subscription update.
825+
826+#### Example
827+
828+```hoon
829+:: From ++on-watch in reference agent.
830+::
831+:: Gives current local state to new subscribers.
832+[%give %fact ~ %atom !>(local.sta)]
833+```
834+
835+### `%kick`
836+
837+Close subscription.
838+
839+Closes a subscription. A subscription close closes the subscription for all or
840+one subscribers on a given path.
841+
842+#### Structure
843+
844+```hoon
845+[%kick (unit path) (unit ship)]
846+```
847+
848+`(unit path)` is the path of the subscription being updated. If no path is
849+given, then the update is only given to the program that instigated the request.
850+Typical use of this mode would be in `+on-watch` to produce a single update to a
851+subscription then close the subscription.
852+
853+`(unit ship)` is the ship to close the subscription for. If no path is given,
854+then the subscription is closed for all subscribers.
855+
856+## Agent Notes
857+
858+Passing a agent note (a 'task') along a wire looks like so.
859+
860+```hoon
861+[%pass =wire %agent [=ship name=term] =task]
862+```
863+
864+`wire` is used to identify the response to the note.
865+
866+`ship` is the ship to pass the note to.
867+
868+`name` is the name of the agent that should receive the note.
869+
870+`task` is the task itself, described below.
871+
872+### `%poke`
873+
874+Poke an application.
875+
876+This note is passed to poke an application with a cage, a marked vase.
877+
878+#### Structure
879+
880+```hoon
881+[%poke =cage]
882+```
883+
884+`cage` is the marked data to poke the application with. It is a pair of a mark
885+and vase.
886+
887+#### Example
888+
889+```hoon
890+:: From ++on-poke in reference agent.
891+::
892+:: Sends an increment poke to the example-gall agent
893+:: on who.act.
894+:*
895+ %pass
896+ /inc/(scot %p who.act)
897+ %agent
898+ [who.act %example-gall]
899+ %poke %example-gall-action !>([%increment ~])
900+==
901+```
902+
903+### `%watch`
904+
905+Subscribe to an application.
906+
907+This note is given to subscribe to an application at a path
908+
909+#### Structure
910+
911+```hoon
912+[%watch =path]
913+```
914+
915+`path` is the path to be subscribed to.
916+
917+#### Example
918+
919+```hoon
920+:: From ++on-poke in reference agent.
921+::
922+:: Subscribes to the example-gall agent on who.act on the path /local
923+::
924+[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]
925+```
926+
927+### `%leave`
928+
929+Unsubscribe from an application.
930+
931+ This note is passed to unsubscribe from an application. It should be passed on
932+the same wire that the corresponding `%watch` note for the subscription was
933+passed on.
934+
935+#### Structure
936+
937+```hoon
938+[%leave ~]
939+```
940+
941+#### Example
942+
943+```hoon
944+:: From ++on-poke in reference agent.
945+::
946+:: Unsubscribes from the example-gall agent on who.act
947+[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]
948+```