on master help sign in
Merge pull request #1045 from tinnus-napbus/thread-docs-integration

Integrate thread docs

commit5abd2ffd03ce3da474329bc9f5c2a2d34290286d authorDavid Kerschner <david@tlon.io> dateWed 31 Mar 2021, 12:36 (6 years ago) parent8dce7a76137fd0
41 files changed+2453−257
_index.md+2−3 arvo/_index.md+1−1 arvo/ames/ames.md+1−1 arvo/gall/overview.md+12 arvo/overview.md+1−1 development/develop.md+6−6 glossary/aqua.md+1−1 glossary/gall.md+1−1 system-overview/arvo.md+1−1 userspace/_index.md+25 userspace/gall/_index.md+21 arvo/gall/gall-api.md → userspace/gall/gall-api.md arvo/gall/gall.md → userspace/gall/gall.md+2−237 arvo/gall/tutorial.md → userspace/gall/tutorial.md landscape/_index.md → userspace/landscape/_index.md+2−2 landscape/overview.md → userspace/landscape/overview.md+2−2 landscape/reference/_index.md → userspace/landscape/reference/_index.md+1−1 landscape/reference/graph-store.md → userspace/landscape/reference/graph-store.md userspace/overview.md+19 userspace/threads/_index.md+27 userspace/threads/basics/_index.md+29 userspace/threads/basics/bind.md+97 userspace/threads/basics/fundamentals.md+169 userspace/threads/basics/input.md+145 userspace/threads/basics/output.md+119 userspace/threads/basics/summary.md+75 userspace/threads/examples/_index.md+33 userspace/threads/examples/child-thread.md+237 userspace/threads/examples/get-json.md+126 userspace/threads/examples/main-loop.md+178 userspace/threads/examples/poke-agent.md+60 userspace/threads/examples/scry.md+70 userspace/threads/examples/take-fact.md+65 userspace/threads/gall/_index.md+29 userspace/threads/gall/poke-thread.md+116 userspace/threads/gall/start-thread.md+145 userspace/threads/gall/stop-thread.md+152 userspace/threads/gall/take-facts.md+184 userspace/threads/gall/take-result.md+132 userspace/threads/overview.md+81 userspace/threads/reference.md+86
_index.md+2−3
@@ -51,7 +51,6 @@ between Urbit and Unix.
5151
5252The workings of Azimuth, the decentralized ID system utilized by Urbit.
5353
54−### [Landscape (Web Client)](@/docs/landscape/_index.md)
54+### [Userspace](@/docs/userspace/_index.md)
5555
56−Developer guides to Landscape, the web client by which most users interact
57−with their ship.
56+Developer guides for Gall (the vane for controlling userspace apps), Landscape (the web client by which most users interact with their ship), and Threads (transient apps for IO).
arvo/_index.md+1−1
@@ -36,7 +36,7 @@ Eyre is our HTTP server. Unix sends HTTP messages to `%eyre`, and `%eyre` produc
3636
3737Ford is our build system. It handles resources and publishing.
3838
39−## [Gall](@/docs/arvo/gall/gall.md)
39+## [Gall](@/docs/arvo/gall/overview.md)
4040
4141Gall is the vane for controlling userspace apps.
4242
arvo/ames/ames.md+1−1
@@ -11,7 +11,7 @@ over it. When Unix receives a packet over the correct UDP port, it pipes
1111it straight into Ames for handling. Also, all packets sent over the
1212Ames network are sent by the Ames vane. Apps and vanes may use
1313Ames to directly send messages to other ships. In general, apps use
14−[Gall](@/docs/arvo/gall/gall.md) and [Clay](@/docs/arvo/clay/clay.md)
14+[Gall](@/docs/userspace/gall/gall.md) and [Clay](@/docs/arvo/clay/clay.md)
1515to communicate with other ships rather than using Ames
1616directly, but this isn't a requirement. Of course, Gall and Clay use
1717Ames behind the scenes to communicate across the network. Jael is the only other
arvo/gall/overview.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Overview"
3+weight = 1
4+template = "doc.html"
5+aliases = ["/docs/learn/arvo/gall/"]
6++++
7+
8+**Gall** is the application-management [vane](../vane). Userspace apps –⁠ daemons, really –⁠ are started, stopped, and sandboxed by Gall. Gall provides developers with a consistent interface for connecting their app to [Arvo](../arvo). It allows applications and other vanes to send messages to applications and subscribe to data streams. Messages coming into Gall are routed to the intended application, and the response comes back along the same route. If the intended target is on another [ship](../ship), Gall will route it behind the scenes through [Ames](../ames) to the other ship.
9+
10+Gall is located at `/home/sys/vane/gall.hoon` within Arvo.
11+
12+For more details, see the [userspace](@/docs/userspace/gall/gall.md) section.
arvo/overview.md+1−1
@@ -566,7 +566,7 @@ As of this writing, we have nine vanes, which each provide the following service
566566- [Eyre](@/docs/arvo/eyre/eyre.md): an http server. Unix sends http messages to `%eyre`, and `%eyre` produces http messages in response.
567567- [Ford](@/docs/arvo/ford/ford.md): a build system also utilized for marks
568568 (file types) and debugging.
569−- [Gall](@/docs/arvo/gall/gall.md): manages our userspace applications. `%gall` keeps state and manages subscribers.
569+- [Gall](@/docs/userspace/gall/gall.md): manages our userspace applications. `%gall` keeps state and manages subscribers.
570570- `Iris`: an http client.
571571- `Jael`: storage for Azimuth information.
572572
development/develop.md+6−6
@@ -13,7 +13,7 @@ contribute to. At a high level, you can:
1313- [Build clients](#clients), which use Urbit as their back-end to store data and
1414 interact with the network
1515- [Develop agents](#agents), or more precisely [*gall*
16− agents](@/docs/arvo/gall/gall.md), which are written in [Hoon](/docs/hoon/)
16+ agents](@/docs/userspace/gall/gall.md), which are written in [Hoon](/docs/hoon/)
1717 and can best be thought of as microservices
1818- [Contribute to Urbit's core](#core), which involves contributing to Urbit
1919 itself &mdash; either the operating system
@@ -27,7 +27,7 @@ throughout the docs.
2727
2828### Build Clients {#clients}
2929
30−Urbit ships with [Landscape](@/docs/landscape/overview.md), which can be thought
30+Urbit ships with [Landscape](@/docs/userspace/landscape/overview.md), which can be thought
3131of as its flagship client. Landscape can be broken into two different technical
3232components: there's the collection of [agents](#agents) that utilize the
3333Urbit for networking and data persistence, and the JavaScript client, which is
@@ -60,17 +60,17 @@ library called `shoe`, which you can learn more about
6060Gall agents can be best thought of as individual services with a
6161statically-typed interface and built-in database. They're written in
6262[Hoon](@/docs/hoon/overview.md) and all conform to a specific
63−[interface](@/docs/arvo/gall/gall-api.md) that's defined by the kernel vane
64−called [Gall](@/docs/arvo/gall/gall.md).
63+[interface](@/docs/userspace/gall/gall-api.md) that's defined by the kernel vane
64+called [Gall](@/docs/userspace/gall/gall.md).
6565
6666Applications built on Urbit utilize a collection of different agents, each of
6767which handle specific functionality. The [Landscape
68−architecture](@/docs/landscape/overview.md) is a good reference implementation
68+architecture](@/docs/userspace/landscape/overview.md) is a good reference implementation
6969to see how this pattern works in practice.
7070
7171If you want to learn how to build gall agents, your best bet is to first [learn
7272the Hoon programming language](@/docs/hoon/hoon-school/_index.md), and then follow that
73−up with the [Gall guide](@/docs/arvo/gall/tutorial.md).
73+up with the [Gall guide](@/docs/userspace/gall/tutorial.md).
7474
7575### Contribute to Urbit Core {#core}
7676
glossary/aqua.md+1−1
@@ -13,4 +13,4 @@ Aqua is jetted with the usual [Nock](../nock) interpreter and thus virtual ships
1313
1414### Further Reading
1515
16−- [The Gall tutorial](@/docs/arvo/gall/gall.md): A technical guide to the Gall vane.
16+- [The Gall tutorial](@/docs/userspace/gall/gall.md): A technical guide to the Gall vane.
glossary/gall.md+1−1
@@ -14,4 +14,4 @@ Gall is located at `/home/sys/vane/gall.hoon` within Arvo.
1414
1515- [The Hoon Tutorial](@/docs/hoon/hoon-school/_index.md): Our guide to learning the Hoon programming language that will give you the foundation necessary for app development.
1616 - [Lesson 2.7: Gall](@/docs/hoon/hoon-school/gall.md): A Hoon Tutorial lesson that explains how to write a simple Gall app.
17−- [The Gall tutorial](@/docs/arvo/gall/gall.md): A technical guide to the Gall vane.
17+- [The Gall tutorial](@/docs/userspace/gall/gall.md): A technical guide to the Gall vane.
system-overview/arvo.md+1−1
@@ -27,7 +27,7 @@ Arvo modules are also called 'vanes'. Arvo's vanes are:
2727 Also includes our typed functional build system.
2828- [Dill](@/docs/arvo/dill/dill.md): terminal driver.
2929- [Eyre](@/docs/arvo/eyre/eyre.md): HTTP server.
30−- [Gall](@/docs/arvo/gall/gall.md): application sandbox and manager.
30+- [Gall](@/docs/userspace/gall/gall.md): application sandbox and manager.
3131- [Iris](@/docs/arvo/iris/iris-api.md): HTTP client.
3232- [Jael](@/docs/arvo/jael/jael-api.md): Public and private key storage.
3333
userspace/_index.mdnew file+25
@@ -0,0 +1,25 @@
1++++
2+title = "Userspace"
3+weight = 350
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+Urbit's userspace is managed by Arvo's Gall vane.
10+
11+## [Overview](@/docs/userspace/overview.md)
12+
13+An overview of userspace in Urbit.
14+
15+## [Gall](@/docs/userspace/gall/gall.md)
16+
17+Resources on Gall which manages userspace applications.
18+
19+## [Landscape](@/docs/userspace/landscape/_index.md)
20+
21+Resources on the flagship web client Landcape, through which most users interact with their ship.
22+
23+## [Threads](@/docs/userspace/threads/_index.md)
24+
25+Resources on threads - monadic functions useful for complex IO.
userspace/gall/_index.mdnew file+21
@@ -0,0 +1,21 @@
1++++
2+title = "Gall"
3+weight = 40
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+Gall is the Arvo vane that manages userspace applications.
10+
11+## [Overview](@/docs/userspace/gall/gall.md)
12+
13+Overview of the Gall vane.
14+
15+## [Tutorial](@/docs/userspace/gall/tutorial.md)
16+
17+Tutorial for writing Gall agents.
18+
19+## [API Reference](@/docs/userspace/gall/gall-api.md)
20+
21+Reference information.
arvo/gall/gall-api.md → userspace/gall/gall-api.mdrenamed

The content is the same.

arvo/gall/gall.md → userspace/gall/gall.mdrenamed+2−237
@@ -5,8 +5,7 @@ template = "doc.html"
55aliases = ["/docs/learn/arvo/gall/"]
66+++
77
8−This document describes Gall, the Arvo userspace vane. It is split into two main
9−sections: Agents and [Threads](#threads).
8+This document describes Gall, the Arvo userspace vane.
109
1110# Agents
1211
@@ -15,7 +14,7 @@ Urbit code lives in the following basic categories:
1514- Runtime (Nock interpreter, persistence engine, IO drivers, jets)
1615- Kernel vanes (managed by Arvo)
1716- Userspace agents (managed by Gall, permanent state)
18−- Userspace imps (managed by Spider, transient state)
17+- Userspace threads (managed by Spider, transient state)
1918
2019This lays out the framework for the third category: Agents.
2120
@@ -558,237 +557,3 @@ If an error happens in `+on-poke`, the crash report goes into the
558557`+on-subscription`, the crash report goes into the `%watch-ack`
559558response. If a crash happens in any of the other handlers, the report
560559is passed into this arm.
561−
562−
563−# Threads
564−
565−As discussed in [Agents](#agents), Urbit code lives in the following basic
566−categories:
567−
568−- Runtime (Nock interpreter, persistence engine, IO drivers, jets)
569−- Kernel vanes (managed by Arvo)
570−- Userspace agents (managed by Gall, permanent state)
571−- Userspace threads (managed by Spider, transient state)
572−
573−This describes the last category: Threads.
574−
575−A thread is a monadic function that takes arguments and produces a
576−result. It may perform input and output while running, so it is not a
577−pure function. It may fail.
578−
579−An agent's strength is that it's permanent and bulletproof. All state
580−transitions are defined, and each action it performs is a transaction.
581−Code upgrades preserve existing state.
582−
583−An agent's weakness is complex input and output. Since each state
584−transition must be explicitly handled, the complexity of an agent
585−explodes with the amount of IO it handles. At best, this results in
586−long and complex code; at worst, unexpected states are mishandled,
587−corrupting permanent state.
588−
589−A thread's strength is that it can easily perform complex IO operations.
590−It uses what's often called the IO monad (plus the exception monad) to
591−provide a natural framework for IO.
592−
593−A thread's weakness is that it's impermanent and may fail unexpectedly.
594−In most of its intermediate states, it expects only a small number of
595−events (usually one), so if it receives anything it didn't expect, it
596−fails. When code is upgraded, it's impossible to upgrade a running
597−thread, so it fails.
598−
599−Thus, for anything that needs to be permament, use an agent. When you
600−need to do a long or complex sequence of IO operations, reduce that to a
601−single logical IO operation by spinning it out into a thread. If you
602−only change your agent's state in response to success of the thread, an
603−IO failure will never result in partially applied state changes.
604−
605−A thread may also be run from the dojo by prefixing its name with `-`
606−and giving it any arguments it requires. If alone, any result will be
607−printed to the screen; else the output may be piped into an agent or
608−other sinks.
609−
610−## Specification
611−
612−```hoon
613−+$ thread $-(vase _*form:(strand ,vase))
614−```
615−
616−A thread is a running strand. It receives an argument as a vase and may
617−prodduce a vase of a result.
618−
619−```hoon
620−+$ tid @tasession
621−+$ start-args
622− [parent=(unit tid) use=(unit tid) file=term =vase]
623−```
624−
625−To run a thread, poke Spider with mark `%spider-start` and a value of
626−type `start-args`. `parent` is an optional parent, `use` is an optional
627−id, `file` is the filename, and `vase` is the argument. If the parent
628−is specified (usually to the thread that spawned this thread), then
629−when the parent ends, the child will end too.
630−
631−A thread may succeed or fail. You may recieve the return value or be
632−notified of failure by subscribing to Spider at `/thread-result/[tid]`,
633−where `tid` is the same one you passed in `use`. Take care to create a
634−`tid` that will be unique from any other that may be created, for
635−example with:
636−
637−```hoon
638−(scot %ta (cat 3 'my-agent_' (scot %uv (sham eny))))`
639−```
640−
641−The `%fact` that comes back on this subscription will have mark either
642−`%thread-fail` or `%thread-done`. If it failed, the content will have
643−type `[term tang]` with an explanation of the error. If it succeeded,
644−the content will be whatever the thread produced.
645−
646−```hoon
647−+$ input [=tid =cage]
648−```
649−
650−You may poke a thread by poking Spider with `%spider-input`. `tid` is
651−the id of the thread you wish to poke, and `cage` is the data to poke it
652−with.
653−
654−You may subscribe to a thread by subscribing to Spider at
655−`/thread/[tid]/path`.
656−
657−You may stop a thread by poking Spider with `%spider-stop` and data
658−`[tid ?]`, where `tid` is the thread you wish to stop and the loobean
659−decides whether to quit nicely (suppresses printfs).
660−
661−## Writing threads
662−
663−A thread is just a function from a vase of arguments to a strand that
664−produces a vase of the result. We say "just" not because it's obvious
665−yet what that means but because it means we only need to explain how to
666−write strands, and threads are just a particular case.
667−
668−The type of a strand is defined in lib/strand, but you will rarely touch
669−those types directly. Most of the time, you will use two functions
670−`pure` and `bind` combined with any of the functions defined in
671−lib/strandio.
672−
673−### Strand fundamentals
674−
675−When writing strands, you almost always want to start by specializing
676−`strand` to your return type. A strand can produce any type, but you
677−must specify up front what type it will produce. By convention, we use
678−the variable `m` for this. For example, if you are going to produce a
679−`@ud`, use:
680−
681−```hoon
682−=/ m (strand ,@ud)
683−^- form:m
684−...
685−```
686−
687−Note that `m` is a core that has three arms:
688−
689−`+form` is the mold of the strand, suitable for `^-`.
690−
691−`+pure` produces a strand that does nothing except return a value. So,
692−`(pure:(strand ,@tas) %foo)` is a strand that produces `%foo` without
693−doing any IO. Thus, the most trivial thread is:
694−
695−```hoon
696−/- spider
697−/+ strandio
698−=, strand=strand:spider
699−^- thread:spider
700−|= vase
701−=/ m (strand ,vase)
702−^- form:m
703−(pure:m *vase)
704−```
705−
706−`+bind`, used with `;<`, takes two strands and runs one after the other,
707−letting you use the result of the first strand in the second. For
708−example:
709−
710−```hoon
711−;< num=@ud bind:m (pure:m 5)
712−(pure:m +(num))
713−```
714−
715−Has the same result as:
716−
717−```hoon
718−(pure:m 6)
719−```
720−
721−### Other useful functions
722−
723−There are many useful strand functions in lib/strandio and some other
724−libraries. For example:
725−
726−`+sleep` waits for the specified time.
727−
728−`+get-time` gets the current time.
729−
730−`+poke` pokes an agent.
731−
732−`+watch` subscribes to an agent.
733−
734−`+fetch-json` produces the JSON at a particular URL.
735−
736−`+retry` tries a strand repeatedly with exponential backoff until it
737−succeeeds.
738−
739−`+start-thread` starts another thread.
740−
741−`send-raw-card` sends any card.
742−
743−## Examples
744−
745−```hoon
746−/- spider
747−/+ strandio
748−=, strand=strand:spider
749−^- thread:spider
750−|= arg=vase
751−=/ m (strand ,vase)
752−^- form:m
753−=+ !<([arg=@dr ~] arg)
754−;< now-1=@da bind:m get-time:strandio
755−;< ~ bind:m (sleep:strandio arg)
756−;< now-2=@da bind:m get-time:strandio
757−(pure:m !>(`@dr`(sub now-2 now-1)))
758−```
759−
760−The first seven lines are the same boilerplate we saw before. After
761−that, it `!<`'s the argument to its expected type. It saves the current
762−time in `now-1`, sleeps how long the argument says to, then gets the
763−time again and produces the difference between the two times. This
764−number should be close to the argument you passed in, plus a little for
765−computation time. You can run this at the dojo with `-time ~s1`.
766−
767−```hoon
768−/- spider
769−/+ *ph-io
770−=, strand=strand:spider
771−^- thread:spider
772−|= args=vase
773−=/ m (strand ,vase)
774−;< ~ bind:m start-simple
775−;< ~ bind:m (raw-ship ~bud ~)
776−;< ~ bind:m (dojo ~bud "[%test-result (add 2 3)]")
777−;< ~ bind:m (wait-for-output ~bud "[%test-result 5]")
778−;< ~ bind:m end-simple
779−(pure:m *vase)
780−```
781−
782−This is uses `lib/ph/io` to run a pH test. Aqua and pH are described
783−[elsewhere](@/docs/hoon/guides/aqua.md), but if you've initialized Aqua by running `|start %aqua` and
784−`:aqua +solid`, then you can run `-ph-add` to execute this thread.
785−
786−It starts by running some virtualization initialization with
787−`start-simple`. Then, it boots a guest ship called ~bud, types a line
788−into the dojo, and waits for it to printed the expected output.
789−
790−It's easy to see how this building blocks could be combined to perform
791−complex tests. For example, you could start several ships and have them
792−`|hi` each other, sync from each other, or do anything else. Check out
793−`lib/ph/io` and `lib/ph/azimuth` for other useful functions in constructing
794−pH tests.
arvo/gall/tutorial.md → userspace/gall/tutorial.mdrenamed

The content is the same.

landscape/_index.md → userspace/landscape/_index.mdrenamed+2−2
@@ -9,10 +9,10 @@ insert_anchor_links = "right"
99While not technically part of Urbit, Landscape serves as a reference
1010implementation for how to build applications in user space.
1111
12−## [Landscape Architecture](@/docs/landscape/overview.md)
12+## [Landscape Architecture](@/docs/userspace/landscape/overview.md)
1313
1414An overview of how Landscape, our flagship client, is structured.
1515
16−## [API Reference](@/docs/landscape/reference/_index.md)
16+## [API Reference](@/docs/userspace/landscape/reference/_index.md)
1717
1818API documentation about specific agents that comprise Landscape.
landscape/overview.md → userspace/landscape/overview.mdrenamed+2−2
@@ -37,7 +37,7 @@ Landscape is composed of two primary parts: its backend, which runs as a suite o
3737### Backend
3838
3939The Landscape backend is implemented as a collection of long-running
40−microservices known as [Gall agents](@/docs/arvo/gall/gall.md). They can be divided into the following,
40+microservices known as [Gall agents](@/docs/userspace/gall/gall.md). They can be divided into the following,
4141though this is a simplification:
4242
4343- **Graph**: handles storing messages / posts in a non-relational database
@@ -152,7 +152,7 @@ Pinterest equivalent, a more private version of Facebook, a decentralized
152152Reddit, or an even more distributed version of Mastodon. You can read more about
153153graph-store by [viewing the
154154source](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/app/graph-store.hoon)
155−or reading our [API Reference](@/docs/landscape/reference/graph-store.md) documentation.
155+or reading our [API Reference](@/docs/userspace/landscape/reference/graph-store.md) documentation.
156156
157157The `%graph-store` may be accessed from foreign ships through the use of the
158158`%graph-pull-hook` and `%graph-push-hook`.
landscape/reference/_index.md → userspace/landscape/reference/_index.mdrenamed+1−1
@@ -6,6 +6,6 @@ template = "sections/docs/chapters.html"
66insert_anchor_links = "right"
77+++
88
9−## [Graph Store](@/docs/landscape/reference/graph-store.md)
9+## [Graph Store](@/docs/userspace/landscape/reference/graph-store.md)
1010
1111The primary data backend utilized by Landscape.
landscape/reference/graph-store.md → userspace/landscape/reference/graph-store.mdrenamed

The content is the same.

userspace/overview.mdnew file+19
@@ -0,0 +1,19 @@
1++++
2+title = "Overview"
3+weight = 2
4+template = "doc.html"
5++++
6+
7+Urbit's userspace is managed by Arvo's Gall vane.
8+
9+## [Gall](@/docs/userspace/gall/gall.md)
10+
11+Resources on Gall which manages userspace applications.
12+
13+## [Landscape](@/docs/userspace/landscape/_index.md)
14+
15+Resources on the flagship web client Landcape, through which most users interact with their ship.
16+
17+## [Threads](@/docs/userspace/threads/_index.md)
18+
19+Resources on threads - monadic functions useful for complex IO.
userspace/threads/_index.mdnew file+27
@@ -0,0 +1,27 @@
1++++
2+title = "Threads"
3+weight = 50
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+## [Overview](@/docs/userspace/threads/overview.md)
10+
11+Overview of threads.
12+
13+## [Basics](@/docs/userspace/threads/basics/_index.md)
14+
15+Tutorial and explanation of the basics of writing threads.
16+
17+## [Gall](@/docs/userspace/threads/gall/_index.md)
18+
19+Tutorial and explanation of interacting with threads from agents.
20+
21+## [Examples](@/docs/userspace/threads/examples/_index.md)
22+
23+A collection of example threads and how-tos.
24+
25+## [Reference](@/docs/userspace/threads/reference.md)
26+
27+Basic reference for interacting with threads via the Gall agent Spider.
userspace/threads/basics/_index.mdnew file+29
@@ -0,0 +1,29 @@
1++++
2+title = "Basics"
3+weight = 10
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+Tutorial and explanation of the basics of writing threads.
10+
11+## [Fundamentals](@/docs/userspace/threads/basics/fundamentals.md)
12+
13+Basic explanation of threads and usage of the strand arms `form` and `pure`.
14+
15+## [Bind](@/docs/userspace/threads/basics/bind.md)
16+
17+Using micgal (`;<`) and the strand arm `bind` to chain strands together.
18+
19+## [Input](@/docs/userspace/threads/basics/input.md)
20+
21+Information on what a strand takes.
22+
23+## [Output](@/docs/userspace/threads/basics/output.md)
24+
25+Information on what a strand produces.
26+
27+## [Summary](@/docs/userspace/threads/basics/summary.md)
28+
29+Summary of this information.
userspace/threads/basics/bind.mdnew file+97
@@ -0,0 +1,97 @@
1++++
2+title = "Bind"
3+weight = 2
4+template = "doc.html"
5++++
6+
7+
8+Having looked at `form` and `pure`, we'll now look at the last `strand` arm `bind`. Bind is typically used in combination with micgal (`;<`).
9+
10+## Micgal
11+
12+Micgal takes four arguments like `spec hoon hoon hoon`. Given `;< a b c d`, it composes them like `((b ,a) c |=(a d))`. So, for example, these two expressions are equivalent:
13+
14+```hoon
15+;< ~ bind:m (sleep:strandio ~s2)
16+(pure:m !>(~))
17+```
18+
19+and
20+
21+```hoon
22+((bind:m ,~) (sleep:strandio ~s2) |=(~ (pure:m !>(~))))
23+```
24+
25+Micgal exists simply for readability. The above isn't too bad, but consider this:
26+
27+```hoon
28+;< a b c
29+;< d e f
30+;< g h i
31+j
32+```
33+...as opposed to this monstrosity: `((b ,a) c |=(a ((e ,d) f |=(d ((h ,g) i |=(g j))))))`
34+
35+## bind
36+
37+Bind by itself must be specialised like `(bind:m ,<type>)` and it takes two arguments:
38+
39+- The first argument is a function that returns the `form` of a strand which produces `<type>`.
40+- The second argument is a gate whose sample is `<type>` and which returns a `form`.
41+
42+Since you'll invariably use it in conjunction with micgal, the `<type>` in `;< <type> bind:m ...` will both specialise `bind` and specify the gate's sample.
43+
44+Bind calls the first function then, if it succeeded, calls the second gate with the result of the first as its sample. If the first function failed, it will instead just return an error message and not bother calling the next gate. So it's essentially "strand A then strand B".
45+
46+Since the second gate may itself contain another `;< <type> bind:m ...`, you can see how this allows you to glue together an arbitrarily large pipeline, where subsequent gates depend on the previous ones.
47+
48+## strandio
49+
50+`/lib/strandio/hoon` contains a large collection of useful, ready-made functions for use in threads. For example:
51+
52+- `sleep` waits for the specified time.
53+- `get-time` gets the current time.
54+- `poke` pokes an agent.
55+- `watch` subscribes to an agent.
56+- `fetch-json` produces the JSON at a particular URL.
57+- `retry` tries a strand repeatedly with exponential backoff until it succeeds.
58+- `start-thread` starts another thread.
59+- `send-raw-card` sends any card.
60+
61+...and many more.
62+
63+## Putting it together
64+
65+Here's a simple thread with a couple of `strandio` functions:
66+
67+```hoon
68+/- spider
69+/+ strandio
70+=, strand=strand:spider
71+^- thread:spider
72+|= arg=vase
73+=/ m (strand ,vase)
74+^- form:m
75+;< t=@da bind:m get-time:strandio
76+;< s=ship bind:m get-our:strandio
77+(pure:m !>([s t]))
78+```
79+
80+Save it as `/ted/mythread.hoon`, `|commit` it and run it with `-mythread`. You should see something like:
81+
82+```
83+> -mythread
84+[~zod ~2021.3.8..14.52.15..bdfe]
85+```
86+
87+## Analysis
88+
89+To use `strandio` functions we've imported the library with `/+ strandio`.
90+
91+`get-time` and `get-our` get the current time & ship from the bowl in `strand-input`. We'll discuss `strand-input` in more detail later.
92+
93+Note how we've specified the face and return type of each strand like `t=@da`, etc.
94+
95+You can see how `pure` has access to the results of previous strands in the pipeline. Note how we've wrapped `pure`'s argument in a `!>` because the thread must produce a `vase`.
96+
97+Next we'll look at `strand-input` in more detail.
userspace/threads/basics/fundamentals.mdnew file+169
@@ -0,0 +1,169 @@
1++++
2+title = "Fundamentals"
3+weight = 1
4+template = "doc.html"
5++++
6+
7+## Introduction
8+
9+A thread is like a transient gall agent. Unlike an agent, it can end and it can fail. The primary uses for threads are:
10+
11+1. Complex IO, like making a bunch of external API calls where each call depends on the last. Doing this in an agent significantly increases its complexity and the risk of a mishandled intermediary state corrupting permanent state. If you spin the IO out into a thread, your agent only has to make one call to the thread and receive one response.
12+2. Testing - threads are very useful for writing complex tests for your agents.
13+
14+Threads are managed by the gall agent called `spider`.
15+
16+## Thread location
17+
18+Threads live in the `ted` directory of your desk:
19+
20+```
21+%
22+├──app
23+├──gen
24+├──lib
25+├──mar
26+├──sur
27+├──sys
28+└──ted <-
29+ ├──foo
30+ │ └──bar.hoon
31+ └──baz.hoon
32+```
33+
34+From the dojo, `ted/baz.hoon` can be run with `-baz`, and `ted/foo/bar.hoon` with `-foo-bar`.
35+
36+**NOTE:** When the dojo sees the `-` prefix it automatically handles creating a thread ID, composing the argument, poking the `spider` gall agent and subscribing for the result. Running a thread from another context (eg. a gall agent) requires doing these things explicitly and is outside the scope of this particular tutorial.
37+
38+## Libraries and Structures
39+
40+There are three files that matter:
41+
42+- `/sur/spider/hoon` - this contains a few simple structures used by spider. It's not terribly useful except it imports libstrand, so you'll typically get `strand` from `spider`.
43+
44+- `/lib/strand/hoon` - this contains all the main functions and structures for strands (a thread is a running strand), and you'll refer to this fairly frequently.
45+
46+- `/lib/strandio/hoon` - this contains a large collection of ready-made functions for use in threads. You'll likely use many of these when you write threads, so it's very useful.
47+
48+## Thread definition
49+
50+`/sur/spider/hoon` defines a thread as:
51+
52+```hoon
53++$ thread $-(vase _*form:(strand ,vase))
54+```
55+
56+That is, a gate which takes a `vase` and returns the `form` of a `strand` that produces a `vase`. This is a little confusing and we'll look at each part in detail later. For now, note that the thread doesn't just produce a result, it actually produces a strand that takes input and produces output from which a result can be extracted. It works something like this:
57+
58+![thread diagram](https://pub.m.tinnus-napbus.xyz/thread-diagram.png "diagram of a thread")
59+
60+This is because threads typically do a bunch of I/O so it can't just immediately produce a result and end. Instead the strand will get some input, produce output, get some new input, produce new output, and so forth, until they eventually produce a `%done` with the actual final result.
61+
62+## Strands
63+
64+Strands are the building blocks of threads. A thread will typically compose multiple strands.
65+
66+A strand is a function of `strand-input:strand -> output:strand` and is defined in `/lib/strand/hoon`. You can see the details of `strand-input` [here](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/strand.hoon#L2-L21) and `output:strand` [here](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/strand.hoon#L23-L48). At this stage you don't need to know the nitty-gritty but it's helpful to have a quick look through. We'll discuss these things in more detail later.
67+
68+A strand is a core that has three important arms:
69+- `form` - the mold of the strand
70+- `pure` - produces a strand that does nothing except return a value
71+- `bind` - monadic bind, like `then` in javascript promises
72+
73+We'll discuss each of these arms later.
74+
75+A strand must be specialised to produce a particular type like `(strand ,<type>)`. As previously mentioned, a `thread` produces a `vase` so is specialised like `(strand ,vase)`. Within your thread you'll likely compose multiple strands which produce different types like `(strand ,@ud)`, `(strand ,[path cage])`, etc, but the thread itself will always come back to a `(strand ,vase)`.
76+
77+Strands are conventionally given the face `m` like:
78+
79+```hoon
80+=/ m (strand ,vase)
81+...
82+```
83+
84+**NOTE:** a comma prefix as in `,vase` is the irregular form of `^:` which is a gate that returns the sample value if it's of the correct type, but crashes otherwise.
85+
86+## Form and Pure
87+
88+### `form`
89+
90+The `form` arm is the mold of the strand, suitable for casting. The two other arms produce `form`s so you'll cast everything to this like:
91+
92+```hoon
93+=/ m (strand ,@ud)
94+^- form:m
95+...
96+```
97+
98+### `pure`
99+
100+Pure produces a strand that does nothing except return a value. So, `(pure:(strand ,@tas) %foo)` is a strand that produces `%foo` without doing any IO.
101+
102+We'll cover `bind` later.
103+
104+## A trivial thread
105+
106+```hoon
107+/- spider
108+=, strand=strand:spider
109+^- thread:spider
110+|= arg=vase
111+=/ m (strand ,vase)
112+^- form:m
113+(pure:m arg)
114+```
115+
116+The above code is a simple thread that just returns its argument, and it's a good boilerplate to start from.
117+
118+Save the above code as a file in `ted/mythread.hoon` and `|commit` it. Run it with `-mythread 'foo'`, you should see the following:
119+
120+
121+```
122+> -mythread 'foo'
123+[~ 'foo']
124+```
125+
126+**NOTE:** The dojo wraps arguments in a unit so that's why it's `[~ 'foo']` rather than just `foo`.
127+
128+## Analysis
129+
130+We'll go through it line-by line.
131+
132+```hoon
133+/- spider
134+=, strand=strand:spider
135+```
136+
137+First we import `/sur/spider/hoon` which includes `/lib/strand/hoon` and give give the latter the face `strand` for convenience.
138+
139+```hoon
140+^- thread:spider
141+```
142+
143+We make it a thread by casting it to `thread:spider`
144+
145+```hoon
146+|= arg=vase
147+```
148+
149+We create a gate that takes a vase, the first part of the previously mentioned thread definition.
150+
151+```hoon
152+=/ m (strand ,vase)
153+```
154+
155+Inside the gate we create our `strand` specialised to produce a `vase` and give it the canonical face `m`.
156+
157+```hoon
158+^- form:m
159+```
160+
161+We cast the output to `form` - the mold of the strand we created.
162+
163+```hoon
164+(pure:m arg)
165+```
166+
167+Finally we call `pure` with the gate input `arg` as its argument. Since `arg` is a `vase` it will return the `form` of a `strand` which produces a `vase`. Thus we've created a thread in accordance with its type definition.
168+
169+Next we'll look at the third arm of a strand: `bind`.
userspace/threads/basics/input.mdnew file+145
@@ -0,0 +1,145 @@
1++++
2+title = "Input"
3+weight = 3
4+template = "doc.html"
5++++
6+
7+The input to a `strand` is defined in `/lib/strand/hoon` as:
8+
9+```hoon
10++$ strand-input [=bowl in=(unit input)]
11+```
12+
13+When a thread is first started, spider will populate the `bowl` and provide it along with an `input` of `~`. If/when new input comes in (such as a poke, sign or watch) it will provide a new updated bowl along with the new input.
14+
15+For example, here's a thread that gets the time from the bowl, runs an IO-less function that takes one or two seconds to compute, and then gets the time again:
16+
17+```hoon
18+ /- spider
19+ /+ *strandio
20+ =, strand=strand:spider
21+ |%
22+ ++ ackermann
23+ |= [m=@ n=@]
24+ ?: =(m 0) +(n)
25+ ?: =(n 0) $(m (dec m), n 1)
26+ $(m (dec m), n $(n (dec n)))
27+ --
28+ ^- thread:spider
29+ |= arg=vase
30+ =/ m (strand ,vase)
31+ ^- form:m
32+ ;< t1=@da bind:m get-time
33+ =/ ack (ackermann 3 8)
34+ ;< t2=@da bind:m get-time
35+ (pure:m !>([t1 t2]))
36+```
37+
38+Since it never does any IO, `t1` and `t2` are the same: `[~2021.3.17..07.47.39..e186 ~2021.3.17..07.47.39..e186]`. However, if we replace the ackermann function with a 2 second `sleep` from strandio:
39+
40+```hoon
41+/- spider
42+/+ *strandio
43+=, strand=strand:spider
44+^- thread:spider
45+|= arg=vase
46+=/ m (strand ,vase)
47+^- form:m
48+;< t1=@da bind:m get-time
49+;< ~ bind:m (sleep ~s2)
50+;< t2=@da bind:m get-time
51+(pure:m !>([t1 t2]))
52+```
53+
54+...and run it again we get different values for `t1` and `t2`: `[~2021.3.17..07.50.28..8a5d ~2021.3.17..07.50.30..8a66]`. This is because `sleep` gets a `%wake` sign back from `behn`, so spider updates the time in the bowl along with it.
55+
56+Now let's look at the contents of `bowl` and `input` in detail:
57+
58+## bowl
59+
60+`bowl` is the following:
61+
62+```hoon
63++$ bowl
64+ $: our=ship
65+ src=ship
66+ tid=tid
67+ mom=(unit tid)
68+ wex=boat:gall
69+ sup=bitt:gall
70+ eny=@uvJ
71+ now=@da
72+ byk=beak
73+ ==
74+```
75+
76+- `our` - our ship
77+- `src` - ship where input is coming from
78+- `tid` - ID of this thread
79+- `mom` - parent thread if this is a child thread
80+- `wex` - outgoing subscriptions
81+- `sup` - incoming subscriptions
82+- `eny` - entropy
83+- `now` - current datetime
84+- `byk` - `[p=ship q=desk r=case]` path prefix
85+
86+There are a number of functions in `strandio` to access the `bowl` contents like `get-bowl`, `get-beak`, `get-time`, `get-our` and `get-entropy`.
87+
88+You can also write a function with a gate whose sample is `strand-input:strand` and access the bowl that way like:
89+
90+```hoon
91+/- spider
92+/+ strandio
93+=, strand=strand:spider
94+=>
95+|%
96+++ bowl-stuff
97+ =/ m (strand ,[boat:gall bitt:gall])
98+ ^- form:m
99+ |= tin=strand-input:strand
100+ `[%done [wex.bowl.tin sup.bowl.tin]]
101+--
102+^- thread:spider
103+|= arg=vase
104+=/ m (strand ,vase)
105+^- form:m
106+;< res=[boat:gall bitt:gall] bind:m bowl-stuff
107+(pure:m !>(res))
108+```
109+
110+## input
111+
112+`input` is defined in libstrand as:
113+
114+```hoon
115++$ input
116+ $% [%poke =cage]
117+ [%sign =wire =sign-arvo]
118+ [%agent =wire =sign:agent:gall]
119+ [%watch =path]
120+ ==
121+```
122+
123+- `%poke` incoming poke
124+- `%sign` incoming sign from arvo
125+- `%agent` incoming sign from a gall agent
126+- `%watch` incoming subscription
127+
128+Various functions in `strandio` will check `input` and conditionally do things based on its contents. For example, `sleep` sets a `behn` timer and then calls `take-wake` to wait for a `%wake` sign from behn:
129+
130+```hoon
131+++ take-wake
132+ |= until=(unit @da)
133+ =/ m (strand ,~)
134+ ^- form:m
135+ |= tin=strand-input:strand
136+ ?+ in.tin `[%skip ~]
137+ ~ `[%wait ~]
138+ [~ %sign [%wait @ ~] %behn %wake *]
139+ ?. |(?=(~ until) =(`u.until (slaw %da i.t.wire.u.in.tin)))
140+ `[%skip ~]
141+ ?~ error.sign-arvo.u.in.tin
142+ `[%done ~]
143+ `[%fail %timer-error u.error.sign-arvo.u.in.tin]
144+ ==
145+```
userspace/threads/basics/output.mdnew file+119
@@ -0,0 +1,119 @@
1++++
2+title = "Output"
3+weight = 4
4+template = "doc.html"
5++++
6+
7+A strand produces a `[(list card) <response>]`. The first part is a list of cards to be sent off immediately, and `<response>` is one of:
8+
9+- `[%wait ~]`
10+- `[%skip ~]`
11+- `[%cont self=(strand-form-raw a)]`
12+- `[%fail err=(pair term tang)]`
13+- `[%done value=a]`
14+
15+So, for example, if you feed `2 2` into the following function:
16+
17+```hoon
18+ |= [a=@ud b=@ud]
19+ =/ m (strand ,vase)
20+ ^- form:m
21+ =/ res !>(`@ud`(add a b))
22+ (pure:m res)
23+```
24+
25+The resulting strand won't just produce `[#t/@ud q=4]`, but rather `[~ %done [#t/@ud q=4]]`.
26+
27+**Note:** that spider doesn't actually return the codes themselves to thread subscribers, they're only used internally to manage the flow of the thread.
28+
29+Since a strand is a function from the previously discussed `strand-input` to the output discussed here, you can compose a valid strand like:
30+
31+```hoon
32+|= strand-input:strand
33+[~ %done 'foo']
34+```
35+
36+So this is a valid thread:
37+
38+```hoon
39+/- spider
40+=, strand=strand:spider
41+^- thread:spider
42+|= arg=vase
43+=/ m (strand ,vase)
44+^- form:m
45+|= strand-input:strand
46+[~ %done arg]
47+```
48+
49+As is this:
50+
51+```hoon
52+/- spider
53+=, strand=strand:spider
54+|%
55+++ my-function
56+ =/ m (strand ,@t)
57+ ^- form:m
58+ |= strand-input:strand
59+ [~ %done 'foo']
60+--
61+^- thread:spider
62+|= arg=vase
63+=/ m (strand ,vase)
64+^- form:m
65+;< msg=@t bind:m my-function
66+(pure:m !>(msg))
67+```
68+
69+As is this:
70+
71+```hoon
72+/- spider
73+=, strand=strand:spider
74+^- thread:spider
75+|= arg=vase
76+=/ m (strand ,vase)
77+^- form:m
78+|= strand-input:strand
79+=/ umsg !< (unit @tas) arg
80+?~ umsg
81+[~ %fail %no-arg ~]
82+=/ msg=@tas u.umsg
83+?. =(msg %foo)
84+[~ %fail %not-foo ~]
85+[~ %done arg]
86+```
87+
88+Which works like:
89+
90+```
91+> -mythread
92+thread failed: %no-arg
93+> -mythread %bar
94+thread failed: %not-foo
95+> -mythread %foo
96+[~ %foo]
97+```
98+
99+Now let's look at the meaning of each of the response codes.
100+
101+### wait
102+
103+Wait tells spider not to move on from the current strand, and to wait for some new input. For example, `sleep:strandio` will return a `[%wait ~]` along with a card to start a behn timer. Spider passes the card to behn, and when behn sends a wake back to spider, the new input will be given back to `sleep` as a `%sign`. Sleep will then issue `[~ %done ~]` and (assuming it's in a `bind`) `bind` will proceed to the next strand.
104+
105+### skip
106+
107+Spider will normally treat a `%skip` the same as a `%wait` and just wait for some new input. When used inside a `main-loop:strandio`, however, it will instead tell `main-loop` to skip this function and try the next one with the same input. This is very useful when you want to call different functions depending on the mark of a poke or some other condition.
108+
109+### cont
110+
111+Cont means continue computation. When a `%cont` is issued, the issuing gate will be called again with the new value provided. Therefore `%cont` essentially creates a loop.
112+
113+### fail
114+
115+Fail says to end the thread here and don't call any subsequent strands. It includes an error message and optional traceback. When spider gets a `%fail` it will send a fact with mark `%thread-fail` containing the error and traceback to its subscribers, and then end the thread.
116+
117+### done
118+
119+Done means the computation was completed successfully and includes the result. When `spider` recieves a `%done` it will send the result it contains in a fact with a mark of `%thread-done` to subscribers and end the thread. When `bind` receives a `%done` it will extract the result and call the next gate with it.
userspace/threads/basics/summary.mdnew file+75
@@ -0,0 +1,75 @@
1++++
2+title = "Summary"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+That's basically all you need to know to write threads. The best way to get a good handle on them is just to experiment with some `strandio` functions. For information on running threads from gall agents, see [here](../index.md#gall) and for some examples see [here](../index.md#how-tos--examples).
8+
9+Now here's a quick recap of the main points covered:
10+
11+## Spider
12+
13+- is the gall agent that manages threads.
14+- Details of interacting with threads via spider can be seen [here](../reference.md).
15+
16+## Threads
17+- are like transient gall agents
18+- are used mostly to chain a series of IO operations
19+- can be used by gall agents to spin out IO operations
20+- live in the `ted` directory
21+- are managed by the gall agent `spider`
22+- take a `vase` and produce a `strand` which produces a `vase`
23+
24+#### Example
25+
26+```hoon
27+/- spider
28+=, strand=strand:spider
29+^- thread:spider
30+|= arg=vase
31+=/ m (strand ,vase)
32+^- form:m
33+(pure:m arg)
34+```
35+
36+## Strands
37+
38+- are the building blocks of threads
39+- take [this](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/strand.hoon#L2-L21) input and produce [this](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/strand.hoon#L23-L48) output.
40+- must be specialised to produce a particular type like `(strand ,@ud)`.
41+- are conventionally given the face `m`.
42+- are a core that has three main arms - `form`, `pure` and `bind`:
43+
44+#### form
45+- is the mold of the strand suitable for casting
46+- is the type returned by the other arms
47+#### pure
48+- simply returns the `form` of a `strand` that produces pure's argument without doing any IO
49+#### bind
50+- is used to chain strands together like javascript promises
51+- is used in conjunction with micgal (`;<`)
52+- must be specialised to a type like `;< <type> bind:m ...`
53+- takes two arguments. The first is a function that returns the `form` of a `strand` that produces `<type>`. The second is a gate whose sample is `<type>` and which returns a `form`.
54+- calls the first and then, if it succeeded, calls the second with the result of the first as its sample.
55+
56+## Strand input
57+
58+- looks like `[=bowl in=(unit input)]`
59+- `bowl` has things like `our`, `now`, `eny` and so forth
60+- `bowl` is populated once when the thread is first called and then every time it receives new input
61+- `input` contains any incoming pokes, signs and watches.
62+
63+## Strand output
64+
65+- contains `[cards=(list card:agent:gall) <response>]`
66+- `cards` are any cards to be sent immediately
67+- `<response>` is something like `[%done value]`, `[%fail err]`, etc.
68+- `%done` will contain the result
69+- responses are only used internally to manage the flow of the thread and are not returned to subscribers.
70+
71+## Strandio
72+
73+- is located in `/lib/strandio/hoon`
74+- contains a collection of ready-made functions for use in threads
75+- eg. `sleep`, `get-bowl`, `take-watch`, `poke`, `fetch-json`, etc.
userspace/threads/examples/_index.mdnew file+33
@@ -0,0 +1,33 @@
1++++
2+title = "Examples"
3+weight = 30
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+Collection of how-tos and examples for threads.
10+
11+## [Fetch JSON](@/docs/userspace/threads/examples/get-json.md)
12+
13+Get some JSON from an external website.
14+
15+## [Child Thread](@/docs/userspace/threads/examples/child-thread.md)
16+
17+Spawn and manage threads from within threads.
18+
19+## [Main-loop](@/docs/userspace/threads/examples/main-loop.md)
20+
21+Create a loop - useful for long-running threads and for trying the same input against multiple functions.
22+
23+## [Poke Agent](@/docs/userspace/threads/examples/poke-agent.md)
24+
25+Poke an agent from a thread.
26+
27+## [Scry](@/docs/userspace/threads/examples/scry.md)
28+
29+Scry example.
30+
31+## [Take Fact](@/docs/userspace/threads/examples/take-fact.md)
32+
33+Take a fact from arvo or an agent.
userspace/threads/examples/child-thread.mdnew file+237
@@ -0,0 +1,237 @@
1++++
2+title = "Child Thread"
3+weight = 2
4+template = "doc.html"
5++++
6+
7+Here's a simple example of a thread that starts another thread:
8+
9+### parent.hoon
10+
11+```hoon
12+/- spider
13+/+ *strandio
14+=, strand=strand:spider
15+^- thread:spider
16+|= arg=vase
17+=/ m (strand ,vase)
18+^- form:m
19+;< tid=tid:spider bind:m (start-thread %child)
20+(pure:m !>(~))
21+```
22+
23+### child.hoon
24+
25+```hoon
26+/- spider
27+/+ *strandio
28+=, strand=strand:spider
29+^- thread:spider
30+|= arg=vase
31+=/ m (strand ,vase)
32+^- form:m
33+%- (slog leaf+"foo" ~)
34+(pure:m !>(~))
35+```
36+
37+Save `parent.hoon` and `child.hoon` in `/ted`, `|commit %home` and run `-parent`. You should see something like:
38+
39+```
40+foo
41+> -parent
42+~
43+```
44+
45+`parent.hoon` just uses the `strandio` function `start-thread` to start `child.hoon`, and `child.hoon` just prints `foo` to the dojo. Since we got `foo` we can tell the second thread did, in fact, run.
46+
47+```hoon
48+;< tid=tid:spider bind:m (start-thread %child)
49+```
50+
51+See here how we gave `start-thread` the name of the thread to run. It returns the `tid` of the thread, which we could then use to poke it or whatever.
52+
53+`start-thread` handles creating the `tid` for the thread so is quite convenient.
54+
55+Note that threads we start this way will be a child of the thread that started them, and so will be killed when the parent thread ends.
56+
57+## Start thread and get its result
58+
59+If we want to actually get the result of the thread we started, it's slightly more complicated:
60+
61+### parent.hoon
62+
63+```hoon
64+/- spider
65+/+ *strandio
66+=, strand=strand:spider
67+^- thread:spider
68+|= arg=vase
69+=/ m (strand ,vase)
70+^- form:m
71+;< =bowl:spider bind:m get-bowl
72+=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
73+;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid])
74+;< ~ bind:m %- poke-our
75+ :* %spider
76+ %spider-start
77+ !>([`tid.bowl `tid %child !>(~)])
78+ ==
79+;< =cage bind:m (take-fact /awaiting/[tid])
80+;< ~ bind:m (take-kick /awaiting/[tid])
81+?+ p.cage ~|([%strange-thread-result p.cage %child tid] !!)
82+ %thread-done (pure:m q.cage)
83+ %thread-fail (strand-fail !<([term tang] q.cage))
84+==
85+```
86+
87+### child.hoon
88+
89+```hoon
90+/- spider
91+/+ *strandio
92+=, strand=strand:spider
93+=>
94+|%
95+++ url "https://www.whatsthelatestbasehash.com/"
96+--
97+^- thread:spider
98+|= arg=vase
99+=/ m (strand ,vase)
100+^- form:m
101+;< =cord bind:m (fetch-cord url)
102+=/ hash-as-cord `@t`(end [3 (sub (met 3 cord) 1)] cord)
103+=/ hash `@uv`(slav %uv hash-as-cord)
104+(pure:m !>(hash))
105+```
106+
107+`child.hoon` simply grabs the latest base hash from https://www.whatsthelatestbasehash.com/ and returns it.
108+
109+`parent.hoon` is a bit more complicated so we'll look at it line-by-line
110+
111+```hoon
112+;< =bowl:spider bind:m get-bowl
113+```
114+
115+First we grab the bowl
116+
117+```hoon
118+=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
119+```
120+
121+Then we generate a `tid` (thread ID) for the thread we're gonna start
122+
123+```hoon
124+;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid])
125+```
126+
127+We pre-emptively subscribe for the result. Spider sends the result at `/thread-result/<tid>` so that's where we subscribe.
128+
129+```hoon
130+;< ~ bind:m %- poke-our
131+ :* %spider
132+ %spider-start
133+ !>([`tid.bowl `tid %child !>(~)])
134+ ==
135+```
136+
137+Spider takes a poke with a mark %spider-start and a vase containing `[parent=(unit tid) use=(unit tid) file=term =vase]` to start a thread, where:
138+
139+* `parent` is an optional parent thread. In this case we say the parent is our tid. Specifying a parent means the child will be killed if the parent ends.
140+* `use` is the thread ID for the thread we're creating
141+* `file` is the filename of the thread we want to start
142+* `vase` is the vase it will be given as an argument when it's started
143+
144+```hoon
145+;< =cage bind:m (take-fact /awaiting/[tid])
146+```
147+
148+We wait for a fact which will be the result of the thread.
149+
150+```hoon
151+;< ~ bind:m (take-kick /awaiting/[tid])
152+```
153+
154+Spider will kick us from the subscription when it ends the thread so we also take that kick.
155+
156+```hoon
157+?+ p.cage ~|([%strange-thread-result p.cage %child tid] !!)
158+ %thread-done (pure:m q.cage)
159+ %thread-fail (strand-fail !<([term tang] q.cage))
160+==
161+```
162+
163+Finally we test whether the thread produced a `%thread-done` or a `%thread-fail`. These are the two possible marks produced by spider when it returns the results of a thread. A `%thread-done` will contain a vase with the result, and a `%thread-fail` will contain an error message and traceback, so we see which it is and then either produce the result with `pure` or trigger a `%thread-fail` with the error we got from the child.
164+
165+## Stop a thread
166+
167+### parent.hoon
168+
169+```hoon
170+/- spider
171+/+ *strandio
172+=, strand=strand:spider
173+^- thread:spider
174+|= arg=vase
175+=/ m (strand ,vase)
176+^- form:m
177+;< =bowl:spider bind:m get-bowl
178+=/ tid `@ta`(cat 3 'strand_' (scot %uv (sham %child eny.bowl)))
179+%- (slog leaf+"Starting child thread..." ~)
180+;< ~ bind:m %- poke-our
181+ :* %spider
182+ %spider-start
183+ !>([`tid.bowl `tid %child !>(~)])
184+ ==
185+;< ~ bind:m (sleep ~s5)
186+%- (slog leaf+"Stopping child thread..." ~)
187+;< ~ bind:m %- poke-our
188+ :* %spider
189+ %spider-stop
190+ !>([tid %.y])
191+ ==
192+;< ~ bind:m (sleep ~s2)
193+(pure:m !>("Done"))
194+```
195+
196+### child.hoon
197+
198+```hoon
199+/- spider
200+/+ *strandio
201+=, strand=strand:spider
202+=>
203+|%
204+++ looper
205+ =/ m (strand ,~)
206+ ^- form:m
207+ %- (main-loop ,~)
208+ :~ |= ~
209+ ^- form:m
210+ ;< ~ bind:m (sleep `@dr`(div ~s1 2))
211+ %- (slog leaf+"child thread" ~)
212+ (pure:m ~)
213+ ==
214+--
215+^- thread:spider
216+|= arg=vase
217+=/ m (strand ,vase)
218+^- form:m
219+;< ~ bind:m looper
220+(pure:m !>(~))
221+```
222+
223+`child.hoon` just prints to the dojo in a loop.
224+
225+`parent.hoon` starts `child.hoon`, and then pokes spider like:
226+
227+```hoon
228+;< ~ bind:m %- poke-our
229+ :* %spider
230+ %spider-stop
231+ !>([tid %.y])
232+ ==
233+```
234+
235+* `%spider-stop` is the mark that tells spider to kill a thread.
236+* `tid` is the tid of the thread to kill
237+* `%.y` tells spider to suppress traceback in the result of the killed thread. If you give it `%.n` it will include the traceback.
userspace/threads/examples/get-json.mdnew file+126
@@ -0,0 +1,126 @@
1++++
2+title = "Fetch JSON"
3+weight = 1
4+template = "doc.html"
5++++
6+
7+Grabbing JSON from some url is very easy.
8+
9+`strandio` includes the `fetch-json` function which will handle the http request and response parsing and just return unformatted json data.
10+
11+Here's a simple thread that will:
12+- grab JSON of the latest base-hash from https://www.whatsthelatestbasehash.com/latesthash.json
13+- grab JSON of a list of all base-hashes with version info from https://www.whatsthelatestbasehash.com/all.json
14+- format and cast them
15+- check `all.json` includes the latest base-hash
16+- print the details of the latest base-hash to the dojo
17+
18+### latest-hash.hoon
19+
20+```hoon
21+/- spider
22+/+ *strandio
23+=, strand=strand:spider
24+=>
25+|%
26+++ url-1 "https://www.whatsthelatestbasehash.com/latesthash.json"
27+++ url-2 "https://www.whatsthelatestbasehash.com/all.json"
28+++ latest-format
29+ =, dejs:format
30+ %- ot
31+ :~ ['hash' so]
32+ ['timestamp' so]
33+ ['last_five' so]
34+ ==
35+++ latest-sur
36+ $: hash=@t
37+ timestamp=@t
38+ last-five=@t
39+ ==
40+++ all-format
41+ =, dejs:format
42+ %- ar
43+ %- ot
44+ :~ ['hash' so]
45+ ['pill' bo]
46+ ['version' so]
47+ ['published' so]
48+ ['release' so]
49+ ==
50+++ all-sur
51+ $: hash=@t
52+ pill=?
53+ version=@t
54+ published=@t
55+ release=@t
56+ ==
57+--
58+^- thread:spider
59+|= arg=vase
60+=/ m (strand ,vase)
61+^- form:m
62+;< js-latest=json bind:m (fetch-json url-1)
63+;< js-all=json bind:m (fetch-json url-2)
64+=/ latest `latest-sur`(latest-format js-latest)
65+=/ all `(list all-sur)`(all-format js-all)
66+=/ res (skim all |=(a=all-sur =(hash.a hash.latest)))
67+?~ res
68+ %- (slog leaf+"Not Found" ~) (pure:m !>(~))
69+%- (slog leaf+"Hash: {(trip hash.i.res)}" ~)
70+%- (slog leaf+"Pill? {?:(pill.i.res "Yes" "No")}" ~)
71+%- (slog leaf+"Version: {(trip version.i.res)}" ~)
72+%- (slog leaf+"Published: {(trip published.i.res)}" ~)
73+%- (slog leaf+"Release: {(trip release.i.res)}" ~)
74+(pure:m !>(~))
75+```
76+
77+Save it as `/ted/latest-hash.hoon`, `|commit %home` and run it with `-latest-hash`. You should see something like:
78+
79+```
80+> -latest-hash
81+Hash: 0vj.dqqil.77m3k.a7v8d.mvrmi.8mavk.0a2nl.te6i6.cstfa.1ko6e.872gd
82+Pill? No
83+Version: v2.39
84+Published: ~2021.3.10..02.20.48
85+Release: https://github.com/urbit/urbit/releases/tag/urbit-os-v2.39
86+~
87+```
88+
89+## Analysis
90+
91+`fetch-json` takes a url as a tape, so we've added a core with the urls like:
92+
93+```hoon
94+=>
95+|%
96+++ url-1 "https://www.whatsthelatestbasehash.com/latesthash.json"
97+++ url-2 "https://www.whatsthelatestbasehash.com/all.json"
98+...
99+```
100+
101+...then just called `fetch-json` like:
102+
103+```hoon
104+;< js-latest=json bind:m (fetch-json url-1)
105+```
106+
107+We've added formatting and structure arms like:
108+
109+```hoon
110+++ latest-format
111+ =, dejs:format
112+ %- ot
113+ :~ ['hash' so]
114+ ['timestamp' so]
115+ ['last_five' so]
116+ ==
117+++ latest-sur
118+ $: hash=@t
119+ timestamp=@t
120+ last-five=@t
121+ ==
122+```
123+
124+...to turn it from `json` to a noun with faces. You can have a look at the JSON formatting functions under `dejs:format` in `zuse.hoon` for how to deal with the various json types.
125+
126+After that it's just some ordinary list logic and printing.
userspace/threads/examples/main-loop.mdnew file+178
@@ -0,0 +1,178 @@
1++++
2+title = "Main-loop"
3+weight = 3
4+template = "doc.html"
5++++
6+
7+`main-loop` is a useful function included in `strandio` that:
8+
9+1. lets you create a loop
10+2. lets you try the same input against multiple functions
11+3. queues input on `%skip` and then dequeues from the beginning on `%done`
12+
13+`main-loop` takes a list of functions as its argument but only moves to the next item in the list on a `[%fail %ignore ~]` (whose usage we'll describe in the second example). In other cases it restarts from the top, so providing multiple functions is only useful for trying the same input against multiple functions.
14+
15+## Create a loop
16+
17+This is useful if you want to (for example) take an arbitrary number of facts.
18+
19+Here's an example of a thread that subscribes to `graph-store` for updates and nicely prints the messages (an extremely basic chat reader):
20+
21+#### chat-watch.hoon
22+
23+```hoon
24+/- spider
25+/+ *strandio, *graph-store
26+=, strand=strand:spider
27+=>
28+|%
29+++ watcher
30+ =/ m (strand ,~)
31+ ^- form:m
32+ %- (main-loop ,~)
33+ :~ |= ~
34+ ^- form:m
35+ ;< =cage bind:m (take-fact /graph-store)
36+ =/ up=update !< update q.cage
37+ ?. ?=(%add-nodes -.q.up)
38+ (pure:m ~)
39+ =/ res=tape "{(scow %p entity.resource.q.up)}/{(scow %tas name.resource.q.up)}"
40+ =/ node-list `(list (pair index node))`~(tap by nodes.q.up)
41+ ?~ node-list
42+ (pure:m ~)
43+ ?: (gth (lent node-list) 1)
44+ %- (slog leaf+"{res}: <multi-node update skipped>" ~)
45+ (pure:m ~)
46+ =/ from=tape (scow %p author.post.q.i.node-list)
47+ =/ conts `(list content)`contents.post.q.i.node-list
48+ ?~ conts
49+ (pure:m ~)
50+ ?: (gth (lent conts) 1)
51+ %- (slog leaf+"{res}: [{from}] <mixed-type message skipped>" ~)
52+ (pure:m ~)
53+ ?. ?=(%text -.i.conts)
54+ %- (slog leaf+"{res}: [{from}] <non-text message skipped>" ~)
55+ (pure:m ~)
56+ =/ msg=tape (trip text.i.conts)
57+ %- (slog leaf+"{res}: [{from}] {msg}" ~)
58+ (pure:m ~)
59+ ==
60+--
61+^- thread:spider
62+|= arg=vase
63+=/ m (strand ,vase)
64+^- form:m
65+;< now=@da bind:m get-time
66+;< ~ bind:m (watch-our /graph-store %graph-store /updates)
67+;< ~ bind:m watcher
68+(pure:m !>(~))
69+```
70+
71+Save it in `/ted`, `|commit %home`, and run it with `-chat-watch`. Now try typing some messages in the chat and you should see them printed like:
72+
73+```
74+~zod/test-8488: [~zod] x
75+~zod/test-8488: [~zod] blah blah blah
76+~zod/test-8488: [~zod] foo
77+~zod/test-8488: [~zod] some text
78+~zod/test-8488: [~zod] .
79+```
80+
81+To stop this hit backspace and then run `:spider|kill`.
82+
83+First we subscribe to graph-store for updates with `watch-our`, then we call the watcher arm of the core we have added. Watcher just calls `main-loop`:
84+
85+```hoon
86+=/ m (strand ,~)
87+^- form:m
88+%- (main-loop ,~)
89+...
90+```
91+
92+...with a list of functions. In this case we've just given it one. Our function first calls `take-fact`:
93+
94+```hoon
95+;< =cage bind:m (take-fact /graph-store)
96+```
97+
98+...to receive the fact and then the rest is just processing & printing logic which isn't too important.
99+
100+Once this is done, main-loop will just call the same function again which will again wait for a fact and so on. So you see how it creates a loop. The only way to exit the loop is with a `%fail` or else by poking spider with a `%spider-stop` and the thread's `tid`.
101+
102+## Try input against multiple functions
103+
104+To try the same input against multiple function you must use another `strandio` function `handle`. Handle converts a `%skip` into a `[fail %ignore ~]`. When `main-loop` sees a `[fail %ignore ~]` it tries the next function in its list with the same input.
105+
106+Here are two files: `tester.hoon` and `tested.hoon`. Save them both to `/ted`, `|commit %home` and run `-tester`. You should see:
107+
108+```
109+> -tester
110+baz
111+~
112+```
113+
114+#### tester.hoon
115+
116+```hoon
117+/- spider
118+/+ *strandio
119+=, strand=strand:spider
120+^- thread:spider
121+|= arg=vase
122+=/ m (strand ,vase)
123+^- form:m
124+;< tid=tid:spider bind:m (start-thread %tested)
125+;< our=ship bind:m get-our
126+;< ~ bind:m %- poke
127+ :- [our %spider]
128+ [%spider-input !>([tid `cage`[%baz !>("baz")]])]
129+(pure:m !>(~))
130+```
131+
132+#### tested.hoon
133+
134+```hoon
135+/- spider
136+/+ *strandio
137+=, strand=strand:spider
138+=>
139+|%
140+++ looper
141+ =/ m (strand ,~)
142+ ^- form:m
143+ %- (main-loop ,~)
144+ :~ |= ~
145+ ^- form:m
146+ ;< =vase bind:m ((handle ,vase) (take-poke %foo))
147+ =/ msg=tape !<(tape vase)
148+ %- (slog leaf+"{msg}" ~)
149+ (pure:m ~)
150+ ::
151+ |= ~
152+ ^- form:m
153+ ;< =vase bind:m ((handle ,vase) (take-poke %bar))
154+ =/ msg=tape !<(tape vase)
155+ %- (slog leaf+"{msg}" ~)
156+ (pure:m ~)
157+ ::
158+ |= ~
159+ ^- form:m
160+ ;< =vase bind:m ((handle ,vase) (take-poke %baz))
161+ =/ msg=tape !<(tape vase)
162+ %- (slog leaf+"{msg}" ~)
163+ (pure:m ~)
164+ ==
165+--
166+^- thread:spider
167+|= arg=vase
168+=/ m (strand ,vase)
169+^- form:m
170+;< ~ bind:m looper
171+(pure:m !>(~))
172+```
173+
174+The first thread (tester.hoon) just starts the second thread and pokes it with a vase containing `"baz"` and the mark `%baz`.
175+
176+The second thread (tested.hoon) has a `main-loop` with a list of three `take-poke` strands. As you can see it's the third one expecting a mark of `%baz` but yet it still successfully prints the message. This is because it tried the previous two which each saw the wrong mark and said `%skip`.
177+
178+Notice we've wrapped the `take-poke`s in `handle` to convert the `%skip`s into `[%fail %ignore ~]`s, which `main-loop` takes to mean it should try the next function with the same input.
userspace/threads/examples/poke-agent.mdnew file+60
@@ -0,0 +1,60 @@
1++++
2+title = "Poke Agent"
3+weight = 4
4+template = "doc.html"
5++++
6+
7+Here's a thread that lets you post a message to a chat in graph-store:
8+
9+#### post-msg.hoon
10+
11+```hoon
12+/- spider
13+/+ *strandio, *graph-store, *resource
14+=, strand=strand:spider
15+=>
16+|%
17+++ make-post
18+ |= [our=ship now=@da res=resource msg=@t]
19+ ^- cage
20+ ::
21+ =/ =post *post
22+ =: author.post our
23+ index.post ~[now]
24+ time-sent.post now
25+ contents.post ~[[%text msg]]
26+ ==
27+ ::
28+ :- %graph-update
29+ !> ^- update
30+ :+ %0 now
31+ :+ %add-nodes res
32+ %- ~(gas by *(map index node))
33+ ~[[~[now] [post ~[%empty]]]]
34+--
35+^- thread:spider
36+|= arg=vase
37+=/ m (strand ,vase)
38+=/ uarg !< (unit (pair resource @t)) arg
39+?~ uarg
40+ (strand-fail %no-arg ~)
41+=/ res p.u.uarg
42+=/ msg q.u.uarg
43+^- form:m
44+;< our=@p bind:m get-our
45+;< now=@da bind:m get-time
46+;< ~ bind:m (poke [our %graph-push-hook] (make-post our now res msg))
47+(pure:m !>(~))
48+```
49+
50+Save it in `/ted`, `|commit`, and run it like:
51+
52+```
53+-post-msg [~zod %foo-9955] 'some message'
54+```
55+
56+(obviously change the channel name to whatever you have)
57+
58+## Analysis
59+
60+Pretty simple, just use `on-poke` with an argument of `[ship term] cage` where `term` is the agent and `cage` is whatever the particular agent expects.
userspace/threads/examples/scry.mdnew file+70
@@ -0,0 +1,70 @@
1++++
2+title = "Scry"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+Here's an example of a thread that scries ames for the IP address & port of a ship and nicely prints it:
8+
9+#### get-ip.hoon
10+
11+```hoon
12+/- spider
13+/+ strandio
14+=, strand=strand:spider
15+=, strand-fail=strand-fail:libstrand:spider
16+|%
17+++ process-lanes
18+ |= [target=@p lanes=(list lane:ames)]
19+ =/ m (strand ,~)
20+ ^- form:m
21+ ?~ `(list lane:ames)`lanes
22+ %- (slog leaf+"No route for {(scow %p target)}." ~)
23+ (pure:m ~)
24+ =/ lroute (skip lanes |=(a=lane:ames -.a))
25+ ?~ lroute
26+ %- (slog leaf+"No direct route for {(scow %p target)}." ~)
27+ (pure:m ~)
28+ =/ ip +:(scow %if p.i.lroute)
29+ =/ port (skip (scow %ud (cut 5 [1 1] p.i.lroute)) |=(a=@tD =(a '.')))
30+ %- (slog leaf+"{ip}:{port}" ~)
31+ (pure:m ~)
32+--
33+^- thread:spider
34+|= arg=vase
35+=/ m (strand ,vase)
36+^- form:m
37+=/ utarget !< (unit @p) arg
38+?~ utarget
39+ (strand-fail %no-arg ~)
40+=/ target u.utarget
41+;< lanes=(list lane:ames) bind:m (scry:strandio (list lane:ames) /ax//peers/(scot %p target)/forward-lane)
42+;< ~ bind:m (process-lanes target lanes)
43+(pure:m !>(~))
44+```
45+
46+**Note:** Pretty useless on a fake ship.
47+
48+Save as `ted/get-ip.hoon`, `|commit %home`, and run it with `-get-ip ~bitbet-bolbel`. You should see something like:
49+
50+```
51+34.83.113.220:60659
52+```
53+
54+## Analysis
55+
56+Here we use the `strandio` function `scry` which takes an argument of `[mold path]` where:
57+
58+- `mold` is the return type of the scry
59+- `path` is the scry path formatted like:
60+ 1. vane letter and care
61+ 2. desk if scrying arvo or agent if scrying a gall agent
62+ 3. rest of path
63+
64+In our case the mold is `(list lane:ames)` and the path is `/ax//peers/(scot %p target)/forward-lane` like:
65+
66+```hoon
67+;< lanes=(list lane:ames) bind:m (scry:strandio (list lane:ames) /ax//peers/(scot %p target)/forward-lane)
68+```
69+
70+After that we just process the result in `++ process-lanes` and print it.
userspace/threads/examples/take-fact.mdnew file+65
@@ -0,0 +1,65 @@
1++++
2+title = "Take Fact"
3+weight = 6
4+template = "doc.html"
5++++
6+
7+Taking a fact from an agent, arvo or whatever is easy. First you subscribe using `watch:strandio` or `watch-our:strandio`, then you use `take-fact:strandio` to receive the fact. Here's an example that takes an update from `graph-store` and prints the message to the dojo:
8+
9+#### print-msg.hoon
10+
11+```hoon
12+/- spider
13+/+ *strandio, *graph-store
14+=, strand=strand:spider
15+=>
16+|%
17+++ take-update
18+ =/ m (strand ,~)
19+ ^- form:m
20+ ;< =cage bind:m (take-fact /graph-store)
21+ =/ =update !< update q.cage
22+ ?. ?=(%add-nodes -.q.update)
23+ (pure:m ~)
24+ =/ nodes=(list [=index =node]) ~(tap by nodes.q.update)
25+ ?~ nodes
26+ (pure:m ~)
27+ =/ contents=(list content) contents.post.node.i.nodes
28+ ?~ contents
29+ (pure:m ~)
30+ ?. ?=(%text -.i.contents)
31+ (pure:m ~)
32+ =/ msg (trip text.i.contents)
33+ %- (slog leaf+msg ~)
34+ (pure:m ~)
35+--
36+^- thread:spider
37+|= arg=vase
38+=/ m (strand ,vase)
39+^- form:m
40+;< ~ bind:m (watch-our /graph-store %graph-store /updates)
41+;< ~ bind:m take-update
42+(pure:m !>(~))
43+```
44+
45+Create a chat on your fake zod if you don't have one already, then save it in `/ted`, `|commit %home`, and run `-print-msg`. Next, type some message in your chat and you'll see it printed in the dojo.
46+
47+## Analysis
48+
49+First we call `watch-our` to subscribe:
50+
51+```hoon
52+;< ~ bind:m (watch-our /graph-store %graph-store /updates)
53+```
54+
55+We've spun the next part out into its own core, but it's just a `take-fact` to receive the update:
56+
57+```hoon
58+ ;< =cage bind:m (take-fact /graph-store)
59+```
60+
61+The rest of the code is just to pull the message out of the complicate data structure returned by graph-store and isn't important.
62+
63+Spider will automatically leave the subscription once the thread finishes.
64+
65+Note that `take-fact` only takes a single fact, so you'd need one for each message you're expecting. Alternatively you can use `main-loop` to take an arbitrary number of facts.
userspace/threads/gall/_index.mdnew file+29
@@ -0,0 +1,29 @@
1++++
2+title = "Gall"
3+weight = 20
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+Tutorial and explanation of interacting with threads from a Gall agent.
10+
11+## [Start Thread](@/docs/userspace/threads/gall/start-thread.md)
12+
13+Start a thread from an agent.
14+
15+## [Take Result](@/docs/userspace/threads/gall/take-result.md)
16+
17+Subscribe for thread result from an agent.
18+
19+## [Take Facts](@/docs/userspace/threads/gall/take-facts.md)
20+
21+Subscribe for facts sent from a running thread.
22+
23+## [Stop Thread](@/docs/userspace/threads/gall/stop-thread.md)
24+
25+Stop a thread from an agent.
26+
27+## [Poke Thread](@/docs/userspace/threads/gall/poke-thread.md)
28+
29+Poke a running thread from an agent.
userspace/threads/gall/poke-thread.mdnew file+116
@@ -0,0 +1,116 @@
1++++
2+title = "Poke Thread"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+Here's a modified agent that pokes our thread. I've replaced some off the previous stuff because it was getting a little unwieldly.
8+
9+#### thread-starter.hoon
10+
11+```hoon
12+/+ default-agent, dbug
13+=* card card:agent:gall
14+%- agent:dbug
15+^- agent:gall
16+|_ =bowl:gall
17++* this .
18+ def ~(. (default-agent this %|) bowl)
19+::
20+++ on-init on-init:def
21+++ on-save on-save:def
22+++ on-load on-load:def
23+++ on-poke
24+ |= [=mark =vase]
25+ ^- (quip card _this)
26+ ?+ mark (on-poke:def mark vase)
27+ %noun
28+ ?+ q.vase (on-poke:def mark vase)
29+ (pair term term)
30+ =/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))
31+ =/ ta-now `@ta`(scot %da now.bowl)
32+ =/ start-args [~ `tid p.q.vase !>(q.q.vase)]
33+ :_ this
34+ :~
35+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %watch /thread-result/[tid]]
36+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-start !>(start-args)]
37+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-input !>([tid %foo !>(q.q.vase)])]
38+ ==
39+ ==
40+ ==
41+++ on-watch on-watch:def
42+++ on-leave on-leave:def
43+++ on-peek on-peek:def
44+++ on-agent
45+ |= [=wire =sign:agent:gall]
46+ ^- (quip card _this)
47+ ?+ -.wire (on-agent:def wire sign)
48+ %thread
49+ ?+ -.sign (on-agent:def wire sign)
50+ %fact
51+ ?+ p.cage.sign (on-agent:def wire sign)
52+ %thread-fail
53+ =/ err !< (pair term tang) q.cage.sign
54+ %- (slog leaf+"Thread failed: {(trip p.err)}" q.err)
55+ `this
56+ %thread-done
57+ ?: =(q.cage.sign *vase)
58+ %- (slog leaf+"Thread cancelled nicely" ~)
59+ `this
60+ =/ res (trip !<(term q.cage.sign))
61+ %- (slog leaf+"Result: {res}" ~)
62+ `this
63+ ==
64+ ==
65+ ==
66+++ on-arvo on-arvo:def
67+++ on-fail on-fail:def
68+--
69+```
70+
71+And here we've modified the thread to take the poke and return it as the result:
72+
73+#### test-thread.hoon
74+
75+```hoon
76+/- spider
77+/+ *strandio
78+=, strand=strand:spider
79+^- thread:spider
80+|= arg=vase
81+=/ m (strand ,vase)
82+^- form:m
83+;< vmsg=vase bind:m (take-poke %foo)
84+(pure:m vmsg)
85+```
86+
87+Save them, `|commit` and run it like `:thread-starter [%test-thread %blah]`. You should see:
88+
89+
90+```
91+Result: blah
92+> :thread-starter [%test-thread %blah]
93+```
94+
95+## Analysis
96+
97+In our agent we've added this card:
98+
99+```hoon
100+[%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-input !>([tid %foo !>(q.q.vase)])]
101+```
102+
103+To poke a particular thread you poke `%spider` with a mark of `%spider-input` and a vase of `[tid cage]` where:
104+
105+- `tid` is the thread you want to poke
106+- `cage` has whatever mark and vase of data you want to give the thread
107+
108+In our case we've given it a mark of `%foo` and a vase of whatever `term` we poked our agent with.
109+
110+In our thread we've added:
111+
112+```hoon
113+;< vmsg=vase bind:m (take-poke %foo)
114+```
115+
116+`take-poke` is a `strandio` function that just waits for a poke with the given mark and skips everything else. In this case we've specified a mark of `%foo`. Once our thread gets a poke with this mark it returns it as a result with `(pure:m vmsg)`. When our agent gets that it just prints it.
userspace/threads/gall/start-thread.mdnew file+145
@@ -0,0 +1,145 @@
1++++
2+title = "Start Thread"
3+weight = 1
4+template = "doc.html"
5++++
6+
7+Here's an example of a barebones gall agent that just starts a thread:
8+
9+#### thread-starter.hoon
10+
11+```hoon
12+/+ default-agent, dbug
13+=* card card:agent:gall
14+%- agent:dbug
15+^- agent:gall
16+|_ =bowl:gall
17++* this .
18+ def ~(. (default-agent this %|) bowl)
19+::
20+++ on-init on-init:def
21+++ on-save on-save:def
22+++ on-load on-load:def
23+++ on-poke
24+ |= [=mark =vase]
25+ ^- (quip card _this)
26+ ?+ mark (on-poke:def mark vase)
27+ %noun
28+ ?+ q.vase (on-poke:def mark vase)
29+ (pair term term)
30+ =/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))
31+ =/ ta-now `@ta`(scot %da now.bowl)
32+ =/ start-args [~ `tid p.q.vase !>(q.q.vase)]
33+ :_ this
34+ :~
35+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-start !>(start-args)]
36+ ==
37+ ==
38+ ==
39+++ on-watch on-watch:def
40+++ on-leave on-leave:def
41+++ on-peek on-peek:def
42+++ on-agent
43+ |= [=wire =sign:agent:gall]
44+ ^- (quip card _this)
45+ ?+ -.wire (on-agent:def wire sign)
46+ %thread
47+ ?+ -.sign (on-agent:def wire sign)
48+ %poke-ack
49+ ?~ p.sign
50+ %- (slog leaf+"Thread started successfully" ~)
51+ `this
52+ %- (slog leaf+"Thread failed to start" u.p.sign)
53+ `this
54+ ==
55+ ==
56+++ on-arvo on-arvo:def
57+++ on-fail on-fail:def
58+--
59+```
60+
61+And here's a minimal thread to test it with:
62+
63+#### test-thread.hoon
64+
65+```hoon
66+/- spider
67+=, strand=strand:spider
68+^- thread:spider
69+|= arg=vase
70+=/ m (strand ,vase)
71+^- form:m
72+|= strand-input:strand
73+?+ q.arg [~ %fail %not-foo ~]
74+ %foo
75+ [~ %done arg]
76+==
77+```
78+
79+Save them as `/app/thread-starter.hoon` and `/ted/test-thread.hoon` respectively, `|commit %home`, and start the app with `|start %thread-starter`.
80+
81+Now you can poke it with a pair of thread name and argument like:
82+
83+```
84+:thread-starter [%test-thread %foo]
85+```
86+
87+You should see `Thread started successfully`.
88+
89+Now try poking it with `[%fake-thread %foo]`, you should see something like:
90+
91+```
92+Thread failed to start
93+/app/spider/hoon:<[355 5].[355 60]>
94+[%no-file-for-thread %fake-thread]
95+/app/spider/hoon:<[354 5].[355 60]>
96+/app/spider/hoon:<[353 3].[359 19]>
97+/app/spider/hoon:<[350 3].[359 19]>
98+/app/spider/hoon:<[346 3].[359 19]>
99+/app/spider/hoon:<[343 3].[359 19]>
100+/app/spider/hoon:<[341 3].[359 19]>
101+/app/spider/hoon:<[340 3].[359 19]>
102+/app/spider/hoon:<[336 3].[359 19]>
103+/app/spider/hoon:<[335 3].[359 19]>
104+/app/spider/hoon:<[202 24].[202 68]>
105+/app/spider/hoon:<[200 7].[207 9]>
106+/app/spider/hoon:<[199 5].[208 17]>
107+/app/spider/hoon:<[197 5].[208 17]>
108+/app/spider/hoon:<[196 5].[208 17]>
109+/sys/vane/gall/hoon:<[1.370 9].[1.370 37]>
110+```
111+
112+## Analysis
113+
114+We can ignore the input logic, here's the important part:
115+
116+```hoon
117+=/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))
118+=/ ta-now `@ta`(scot %da now.bowl)
119+=/ start-args [~ `tid p.q.vase !>(q.q.vase)]
120+:_ this
121+:~
122+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-start !>(start-args)]
123+==
124+```
125+
126+You can generate a tid any way you like, just make sure it's unique. Here we just use the hash of some entropy prefixed with `thread_`.
127+
128+Then it's just a poke to `%spider` with the mark `%spider-start` and a vase containing [start-args](../reference.md#start-thread). Spider will then respond with a `%poke-ack` with a `(unit tang)` which will be `~` if it started successfully or else contain an error and a traceback if it failed. Here we test for this and print the result:
129+
130+```hoon
131+++ on-agent
132+ |= [=wire =sign:agent:gall]
133+ ^- (quip card _this)
134+ ?+ -.wire (on-agent:def wire sign)
135+ %thread
136+ ?+ -.sign (on-agent:def wire sign)
137+ %poke-ack
138+ ?~ p.sign
139+ %- (slog leaf+"Thread started successfully" ~)
140+ `this
141+ %- (slog leaf+"Thread failed to start" u.p.sign)
142+ `this
143+ ==
144+ ==
145+```
userspace/threads/gall/stop-thread.mdnew file+152
@@ -0,0 +1,152 @@
1++++
2+title = "Stop Thread"
3+weight = 4
4+template = "doc.html"
5++++
6+
7+Here we've added one last card to `on-poke` to stop the thread and a little extra to `on-agent` to print things for demonstrative purposes.
8+
9+#### thread-starter.hoon
10+
11+```hoon
12+/+ default-agent, dbug
13+=* card card:agent:gall
14+%- agent:dbug
15+^- agent:gall
16+|_ =bowl:gall
17++* this .
18+ def ~(. (default-agent this %|) bowl)
19+::
20+++ on-init on-init:def
21+++ on-save on-save:def
22+++ on-load on-load:def
23+++ on-poke
24+ |= [=mark =vase]
25+ ^- (quip card _this)
26+ ?+ mark (on-poke:def mark vase)
27+ %noun
28+ ?+ q.vase (on-poke:def mark vase)
29+ (pair term term)
30+ =/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))
31+ =/ ta-now `@ta`(scot %da now.bowl)
32+ =/ start-args [~ `tid p.q.vase !>(q.q.vase)]
33+ :_ this
34+ :~
35+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %watch /thread-result/[tid]]
36+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-start !>(start-args)]
37+ [%pass /thread/updates/[ta-now] %agent [our.bowl %spider] %watch /thread/[tid]/updates]
38+ [%pass /thread-stop/[ta-now] %agent [our.bowl %spider] %poke %spider-stop !>([tid %.y])]
39+ ==
40+ ==
41+ ==
42+++ on-watch on-watch:def
43+++ on-leave on-leave:def
44+++ on-peek on-peek:def
45+++ on-agent
46+ |= [=wire =sign:agent:gall]
47+ ^- (quip card _this)
48+ ?+ -.wire (on-agent:def wire sign)
49+ %thread
50+ ?+ -.sign (on-agent:def wire sign)
51+ %poke-ack
52+ ?~ p.sign
53+ %- (slog leaf+"Thread started successfully" ~)
54+ `this
55+ %- (slog leaf+"Thread failed to start" u.p.sign)
56+ `this
57+ ::
58+ %fact
59+ ?+ p.cage.sign (on-agent:def wire sign)
60+ %thread-fail
61+ =/ err !< (pair term tang) q.cage.sign
62+ %- (slog leaf+"Thread failed: {(trip p.err)}" q.err)
63+ `this
64+ %thread-done
65+ ?: =(q.cage.sign *vase)
66+ %- (slog leaf+"Thread cancelled nicely" ~)
67+ `this
68+ =/ res (trip !<(term q.cage.sign))
69+ %- (slog leaf+"Result: {res}" ~)
70+ `this
71+ %update
72+ =/ msg !< tape q.cage.sign
73+ %- (slog leaf+msg ~)
74+ `this
75+ ==
76+ ==
77+ %thread-stop
78+ ?+ -.sign (on-agent:def wire sign)
79+ %poke-ack
80+ ?~ p.sign
81+ %- (slog leaf+"Thread cancelled successfully" ~)
82+ `this
83+ %- (slog leaf+"Thread failed to stop" u.p.sign)
84+ `this
85+ ==
86+ ==
87+++ on-arvo on-arvo:def
88+++ on-fail on-fail:def
89+--
90+```
91+
92+We've also added a `sleep` to the thread to keep it running for demonstration.
93+
94+#### test-thread.hoon
95+
96+```hoon
97+/- spider
98+/+ *strandio
99+=, strand=strand:spider
100+^- thread:spider
101+|= arg=vase
102+=/ m (strand ,vase)
103+^- form:m
104+;< =path bind:m take-watch
105+;< ~ bind:m (send-raw-card [%give %fact ~[path] %update !>("message 1")])
106+;< ~ bind:m %- send-raw-cards
107+ :~ [%give %fact ~[path] %update !>("message 2")]
108+ [%give %fact ~[path] %update !>("message 3")]
109+ [%give %fact ~[path] %update !>("message 4")]
110+ ==
111+;< ~ bind:m (send-raw-card [%give %kick ~[path] ~])
112+;< ~ bind:m (sleep ~m1)
113+|= strand-input:strand
114+?+ q.arg [~ %fail %not-foo ~]
115+ %foo
116+ [~ %done arg]
117+==
118+```
119+
120+Save these, `|commit`, and run with `:thread-starter [%test-thread %foo]`. You should see:
121+
122+```
123+Thread started successfully
124+message 1
125+message 2
126+message 3
127+message 4
128+Thread cancelled successfully
129+Thread cancelled nicely
130+```
131+
132+Now, try changing the vase in our new card from `!>([tid %.y])` to `!>([tid %.n])`. Save, `|commit`, and run again. You should see:
133+
134+```
135+Thread started successfully
136+message 1
137+message 2
138+message 3
139+message 4
140+Thread cancelled successfully
141+Thread failed: cancelled
142+```
143+
144+## Analysis
145+
146+The card we've added to our agent:
147+
148+```hoon
149+[%pass /thread-stop/[ta-now] %agent [our.bowl %spider] %poke %spider-stop !>([tid %.y])]
150+```
151+
152+...pokes spider with mark `%spider-stop` and a vase containing the tid of the thread we want to stop and a `?`. The `?` specifies whether to end it nicely or not. If `%.y` it will end with `%thread-done` and a `*vase` bunted vase. If `%.n` it will end with `%thread-fail` and a vase containing `[term tang]` where `term` is `%cancelled` and `tang` is `~`. You can see the difference in our tests above.
userspace/threads/gall/take-facts.mdnew file+184
@@ -0,0 +1,184 @@
1++++
2+title = "Take Facts"
3+weight = 3
4+template = "doc.html"
5++++
6+
7+Most of the time you'll just want the final result like how we did previously. Sometimes, though, you might want to send out facts while the thread runs rather than just at the end.
8+
9+Here we've added another card to subscribe for any facts sent by the thread and some small changes to `on-agent`:
10+
11+#### thread-starter.hoon
12+
13+```hoon
14+/+ default-agent, dbug
15+=* card card:agent:gall
16+%- agent:dbug
17+^- agent:gall
18+|_ =bowl:gall
19++* this .
20+ def ~(. (default-agent this %|) bowl)
21+::
22+++ on-init on-init:def
23+++ on-save on-save:def
24+++ on-load on-load:def
25+++ on-poke
26+ |= [=mark =vase]
27+ ^- (quip card _this)
28+ ?+ mark (on-poke:def mark vase)
29+ %noun
30+ ?+ q.vase (on-poke:def mark vase)
31+ (pair term term)
32+ =/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))
33+ =/ ta-now `@ta`(scot %da now.bowl)
34+ =/ start-args [~ `tid p.q.vase !>(q.q.vase)]
35+ :_ this
36+ :~
37+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %watch /thread-result/[tid]]
38+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-start !>(start-args)]
39+ [%pass /thread/updates/[ta-now] %agent [our.bowl %spider] %watch /thread/[tid]/updates]
40+ ==
41+ ==
42+ ==
43+++ on-watch on-watch:def
44+++ on-leave on-leave:def
45+++ on-peek on-peek:def
46+++ on-agent
47+ |= [=wire =sign:agent:gall]
48+ ^- (quip card _this)
49+ ?+ -.wire (on-agent:def wire sign)
50+ %thread
51+ ?+ -.sign (on-agent:def wire sign)
52+ %poke-ack
53+ ?~ p.sign
54+ %- (slog leaf+"Thread started successfully" ~)
55+ `this
56+ %- (slog leaf+"Thread failed to start" u.p.sign)
57+ `this
58+ ::
59+ %fact
60+ ?+ p.cage.sign (on-agent:def wire sign)
61+ %thread-fail
62+ =/ err !< (pair term tang) q.cage.sign
63+ %- (slog leaf+"Thread failed: {(trip p.err)}" q.err)
64+ `this
65+ %thread-done
66+ =/ res (trip !<(term q.cage.sign))
67+ %- (slog leaf+"Result: {res}" ~)
68+ `this
69+ %update
70+ =/ msg !< tape q.cage.sign
71+ %- (slog leaf+msg ~)
72+ `this
73+ ==
74+ ==
75+ ==
76+++ on-arvo on-arvo:def
77+++ on-fail on-fail:def
78+--
79+```
80+
81+We've also made some changes to the thread:
82+
83+#### test-thread.hoon
84+
85+```hoon
86+/- spider
87+/+ *strandio
88+=, strand=strand:spider
89+^- thread:spider
90+|= arg=vase
91+=/ m (strand ,vase)
92+^- form:m
93+;< =path bind:m take-watch
94+;< ~ bind:m (send-raw-card [%give %fact ~[path] %update !>("message 1")])
95+;< ~ bind:m %- send-raw-cards
96+ :~ [%give %fact ~[path] %update !>("message 2")]
97+ [%give %fact ~[path] %update !>("message 3")]
98+ [%give %fact ~[path] %update !>("message 4")]
99+ ==
100+;< ~ bind:m (send-raw-card [%give %kick ~[path] ~])
101+|= strand-input:strand
102+?+ q.arg [~ %fail %not-foo ~]
103+ %foo
104+ [~ %done arg]
105+==
106+```
107+
108+Save & `|commit`, then run `:thread-starter [%test-thread %foo]`. You should see:
109+
110+```
111+Thread started successfully
112+message 1
113+message 2
114+message 3
115+message 4
116+Result: foo
117+```
118+
119+Now try `:thread-starter [%test-thread %bar]`. You should see:
120+
121+```
122+Thread started successfully
123+message 1
124+message 2
125+message 3
126+message 4
127+Thread failed: not-foo
128+```
129+
130+## Analysis
131+
132+In our agent's `on-poke` arm we've added another card to subscribe to `/thread/[tid]/updates`:
133+
134+```hoon
135+[%pass /thread/updates/[ta-now] %agent [our.bowl %spider] %watch /thread/[tid]/updates]
136+```
137+
138+**Note:** In practice you'll want to include some kind of tag in the wire so you can differentiate particular threads and subscriptions and test for it in `on-agent`.
139+
140+Threads always send facts on `/thread/[tid]/some-path`. The thread itself will see the incoming subscription on `/some-path` though, not the full thing.
141+
142+In the thread we've first added:
143+
144+```hoon
145+;< =path bind:m take-watch
146+```
147+
148+...to take the subscription. Without something like this to handle the incoming `%watch`, spider will reject the subscription.
149+
150+Then we've added:
151+
152+```hoon
153+;< ~ bind:m (send-raw-card [%give %fact ~[path] %update !>("message 1")])
154+;< ~ bind:m %- send-raw-cards
155+ :~ [%give %fact ~[path] %update !>("message 2")]
156+ [%give %fact ~[path] %update !>("message 3")]
157+ [%give %fact ~[path] %update !>("message 4")]
158+ ==
159+```
160+
161+...to send some facts out to subscribers. Here we've used both `send-raw-card` and `send-raw-cards` to demonstrate both ways.
162+
163+**Note:** in practice you'd probably want to send facts on a predetermined path and just test the path of the incoming subscription rather than just accepting anything.
164+
165+Finally we've added:
166+
167+```hoon
168+;< ~ bind:m (send-raw-card [%give %kick ~[path] ~])
169+```
170+
171+...to kick subscribers. This is important because, unlike on `/thread-result`, spider will not automatically kick subscribers when the thread ends. You have to do it explicitly so your agent doesn't accumulate wires with repeated executions.
172+
173+Back in our agent: In the `on-agent` arm we've added:
174+
175+```hoon
176+ %update
177+=/ msg !< tape q.cage.sign
178+%- (slog leaf+msg ~)
179+`this
180+```
181+
182+... to take the facts and print them.
183+
184+One last thing: Notice how when we gave the thread an argument of `%bar` and made it fail, we still got the facts we sent. This is because such cards are sent immediately as the thread runs, they don't depend on the final result.
userspace/threads/gall/take-result.mdnew file+132
@@ -0,0 +1,132 @@
1++++
2+title = "Take Result"
3+weight = 2
4+template = "doc.html"
5++++
6+
7+Here we've added an extra card to subscribe for the result and a couple of lines in on-agent to test if it succeeded:
8+
9+#### thread-starter.hoon
10+
11+```hoon
12+/+ default-agent, dbug
13+=* card card:agent:gall
14+%- agent:dbug
15+^- agent:gall
16+|_ =bowl:gall
17++* this .
18+ def ~(. (default-agent this %|) bowl)
19+::
20+++ on-init on-init:def
21+++ on-save on-save:def
22+++ on-load on-load:def
23+++ on-poke
24+ |= [=mark =vase]
25+ ^- (quip card _this)
26+ ?+ mark (on-poke:def mark vase)
27+ %noun
28+ ?+ q.vase (on-poke:def mark vase)
29+ (pair term term)
30+ =/ tid `@ta`(cat 3 'thread_' (scot %uv (sham eny.bowl)))
31+ =/ ta-now `@ta`(scot %da now.bowl)
32+ =/ start-args [~ `tid p.q.vase !>(q.q.vase)]
33+ :_ this
34+ :~
35+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %watch /thread-result/[tid]]
36+ [%pass /thread/[ta-now] %agent [our.bowl %spider] %poke %spider-start !>(start-args)]
37+ ==
38+ ==
39+ ==
40+++ on-watch on-watch:def
41+++ on-leave on-leave:def
42+++ on-peek on-peek:def
43+++ on-agent
44+ |= [=wire =sign:agent:gall]
45+ ^- (quip card _this)
46+ ?+ -.wire (on-agent:def wire sign)
47+ %thread
48+ ?+ -.sign (on-agent:def wire sign)
49+ %poke-ack
50+ ?~ p.sign
51+ %- (slog leaf+"Thread started successfully" ~)
52+ `this
53+ %- (slog leaf+"Thread failed to start" u.p.sign)
54+ `this
55+ ::
56+ %fact
57+ ?+ p.cage.sign (on-agent:def wire sign)
58+ %thread-fail
59+ =/ err !< (pair term tang) q.cage.sign
60+ %- (slog leaf+"Thread failed: {(trip p.err)}" q.err)
61+ `this
62+ %thread-done
63+ =/ res (trip !<(term q.cage.sign))
64+ %- (slog leaf+"Result: {res}" ~)
65+ `this
66+ ==
67+ ==
68+ ==
69+++ on-arvo on-arvo:def
70+++ on-fail on-fail:def
71+--
72+```
73+
74+#### test-thread.hoon
75+
76+```hoon
77+/- spider
78+=, strand=strand:spider
79+^- thread:spider
80+|= arg=vase
81+=/ m (strand ,vase)
82+^- form:m
83+|= strand-input:strand
84+?+ q.arg [~ %fail %not-foo ~]
85+ %foo
86+ [~ %done arg]
87+==
88+```
89+
90+Save these, `|commit` and then poke the app with `:thread-starter [%test-thread %foo]`. You should see:
91+
92+```
93+Thread started successfully
94+Result: foo
95+```
96+
97+Now try `:thread-starter [%test-thread %bar]`. You should see:
98+
99+```
100+Thread started successfully
101+Thread failed: not-foo
102+```
103+
104+## Analysis
105+
106+In `on-poke` we've added an extra card *before* the `%spider-start` poke to subscribe for the result:
107+
108+```hoon
109+[%pass /thread/[ta-now] %agent [our.bowl %spider] %watch /thread-result/[tid]]
110+```
111+
112+If successful the thread will return a cage with a mark of `%thread-done` and a vase containing the result.
113+
114+If the thread failed it will return a cage with a mark of `%thread-fail` and a vase containing `[term tang]` where `term` is an error message and `tang` is a traceback. In our case our thread fails with error `%not-foo` when its argument is not `%foo`.
115+
116+Note that spider will automatically `%kick` us from the subscription after ending the thread and returning the result.
117+
118+```hoon
119+ %fact
120+?+ p.cage.sign (on-agent:def wire sign)
121+ %thread-fail
122+ =/ err !< (pair term tang) q.cage.sign
123+ %- (slog leaf+"Thread failed: {(trip p.err)}" q.err)
124+ `this
125+ %thread-done
126+ =/ res (trip !<(term q.cage.sign))
127+ %- (slog leaf+"Result: {res}" ~)
128+ `this
129+==
130+```
131+
132+Here in on-agent we've added a test for `%thread-fail` or `%thread-done` and print the appropriate result.
userspace/threads/overview.mdnew file+81
@@ -0,0 +1,81 @@
1++++
2+title = "Overview"
3+weight = 1
4+template = "doc.html"
5++++
6+
7+As discussed in the [Gall](@/docs/userspace/gall/gall.md) section, Urbit code lives in the following basic
8+categories:
9+
10+- Runtime (Nock interpreter, persistence engine, IO drivers, jets)
11+- Kernel vanes (managed by Arvo)
12+- Userspace agents (managed by Gall, permanent state)
13+- Userspace threads (managed by Spider, transient state)
14+
15+This describes the last category: Threads.
16+
17+A thread is a monadic function that takes arguments and produces a
18+result. It may perform input and output while running, so it is not a
19+pure function. It may fail.
20+
21+An agent's strength is that it's permanent and bulletproof. All state
22+transitions are defined, and each action it performs is a transaction.
23+Code upgrades preserve existing state.
24+
25+An agent's weakness is complex input and output. Since each state
26+transition must be explicitly handled, the complexity of an agent
27+explodes with the amount of IO it handles. At best, this results in
28+long and complex code; at worst, unexpected states are mishandled,
29+corrupting permanent state.
30+
31+A thread's strength is that it can easily perform complex IO operations.
32+It uses what's often called the IO monad (plus the exception monad) to
33+provide a natural framework for IO.
34+
35+A thread's weakness is that it's impermanent and may fail unexpectedly.
36+In most of its intermediate states, it expects only a small number of
37+events (usually one), so if it receives anything it didn't expect, it
38+fails. When code is upgraded, it's impossible to upgrade a running
39+thread, so it fails.
40+
41+Thus, for anything that needs to be permament, use an agent. When you
42+need to do a long or complex sequence of IO operations, reduce that to a
43+single logical IO operation by spinning it out into a thread. If you
44+only change your agent's state in response to success of the thread, an
45+IO failure will never result in partially applied state changes.
46+
47+A thread may also be run from the dojo by prefixing its name with `-`
48+and giving it any arguments it requires. If alone, any result will be
49+printed to the screen; else the output may be piped into an agent or
50+other sinks.
51+
52+## Thread basics
53+
54+These docs walk through the fundamental things you need to know to write threads. They're focused on basic thread composition so don't touch on interacting with threads from gall agents and such. The included examples can all just be run from the dojo.
55+
56+1. [Thread Fundamentals](@/docs/userspace/threads/basics/fundamentals.md) - Basic information and overview of threads, strands, `form` & `pure`.
57+2. [Micgal and Bind](@/docs/userspace/threads/basics/bind.md) - Covers using micgal and `bind` to chain strands.
58+3. [Strand Input](@/docs/userspace/threads/basics/input.md) - What strands receive as input
59+4. [Strand Output](@/docs/userspace/threads/basics/output.md) - What strands produce
60+5. [Summary](@/docs/userspace/threads/basics/summary.md)
61+
62+## Gall
63+These docs walk through the basics of interacting with threads from gall agents.
64+
65+1. [Start a thread](@/docs/userspace/threads/gall/start-thread.md)
66+2. [Subscribe for result](@/docs/userspace/threads/gall/take-result.md)
67+3. [Subscribe for facts](@/docs/userspace/threads/gall/take-facts.md)
68+4. [Stop a thread](@/docs/userspace/threads/gall/stop-thread.md)
69+5. [Poke a thread](@/docs/userspace/threads/gall/poke-thread.md)
70+
71+## How-tos & Examples
72+
73+- [Grab some JSON from a URL](@/docs/userspace/threads/examples/get-json.md) - Here's an example of chaining a couple of external http requests for JSON.
74+- [Start a child thread](@/docs/userspace/threads/examples/child-thread.md) - Starting and managing child threads.
75+- [Main Loop](@/docs/userspace/threads/examples/main-loop.md) - Some notes and examples of the `strandio` function `main-loop`.
76+- [Poke an agent](@/docs/userspace/threads/examples/poke-agent.md) - Example of poking an agent from a thread.
77+- [Scry](@/docs/userspace/threads/examples/scry.md) - Scry arvo or an agent.
78+- [Take a fact](@/docs/userspace/threads/examples/take-fact.md) - Subscribe to an agent and receive a fact.
79+
80+## [Reference](@/docs/userspace/threads/reference.md)
81+Basic reference information. For usage of particular `strandio` functions just refer directly to `/lib/strandio/hoon` since they're largely self-explanatory.
userspace/threads/reference.mdnew file+86
@@ -0,0 +1,86 @@
1++++
2+title = "Reference"
3+weight = 50
4+template = "doc.html"
5++++
6+
7+## Spider
8+
9+- [Start a thread](#start-thread)
10+- [Stop a thread](#stop-thread)
11+- [Subscribe to thread result](#subscribe-to-thread-result)
12+- [Subscribe to thread](#subscribe-to-thread)
13+- [Poke a thread](#poke-thread)
14+
15+### Start thread
16+
17+Poke `spider` with mark `%spider-start` and a vase containing `start-args`:
18+
19+```hoon
20++$ start-args
21+ [parent=(unit tid) use=(unit tid) file=term =vase]
22+```
23+
24+Where:
25+
26+- `parent` - optional `tid` of parent thread if the thread is a child. If specified, the child thread will be killed with the parent thread ends.
27+- `use` - `tid` (thread ID) to give the new thread. Can be generated with something like `(scot %ta (cat 3 'my-agent_' (scot %uv (sham eny))))`. However you do it, make sure it's unique.
28+- `file` - name of the thread file in `/ted`. For example, if the thread you want to start is `/ted/foo/hoon` you'd specify `%foo`.
29+- `vase` - `vase` to be given to the thread when it's started. Can be whatever or just `!>(~)` if it doesn't need any args.
30+
31+#### Example
32+
33+```hoon
34+[%pass /some-path %agent [our.bowl %spider] %poke %spider-start !>([~ `tid %foo !>(~)])]
35+```
36+
37+### Stop thread
38+
39+Poke `spider` with mark `%spider-stop` and a vase containing `[tid ?]`, where:
40+
41+- `tid` - the `tid` of the thread you want to stop
42+- `?` - whether thread should end nicely. If `%.y` it'll end with mark `%thread-done` and the bunt value of a vase. If `%.n` it'll end with mark `%thread-fail` and a `[term tang]` where `term` is `%cancelled` and `tang` is `~`.
43+
44+#### Example
45+
46+```hoon
47+[%pass /some-path %agent [our.bowl %spider] %poke %spider-stop !>([tid %.y)]
48+```
49+
50+### Subscribe to thread result
51+
52+Spider will send the result on `/thread-result/[tid]` so you can subscribe there for the result. You should subscribe before starting the thread.
53+
54+The result will have a mark of either `%thread-fail` or `%thread-done`.
55+
56+- `%thread-fail` - has a vase containing a `[term tang]` where `term` is an error message and `tang` is a traceback.
57+- `%thread-done` - has a vase of the result of the thread.
58+
59+#### Example
60+
61+```hoon
62+[%pass /some-path %agent [our.bowl %spider] %watch /thread-result/[tid]]
63+```
64+
65+### Subscribe to thread
66+
67+You can subscribe to a thread on `/thread/[tid]/path`. Note this is for facts sent off by the thread while it's running, not the final result. The path depends on the particular thread.
68+
69+#### Example
70+
71+```hoon
72+[%pass /some-path %agent [our.bowl %spider] %watch /thread/[tid]/thread-path]
73+```
74+
75+### Poke Thread
76+
77+To poke a thread you poke spider with a mark of `%spider-input` and a vase of `[tid cage]`.
78+
79+- `tid` is the tid of the thread you want to poke
80+- `cage` is whatever mark and vase you want to poke it with
81+
82+#### Example
83+
84+```hoon
85+[%pass /some-path %agent [our.bowl %spider] %poke %spider-input !>([tid %foo !>('foooo')])]
86+```