Urbit Docs
  • What is Urbit?
  • Get on Urbit
  • Build on Urbit
    • Contents
    • Environment Setup
    • Hoon School
      • 1. Hoon Syntax
      • 2. Azimuth (Urbit ID)
      • 3. Gates (Functions)
      • 4. Molds (Types)
      • 5. Cores
      • 6. Trees and Addressing
      • 7. Libraries
      • 8. Testing Code
      • 9. Text Processing I
      • 10. Cores and Doors
      • 11. Data Structures
      • 12. Type Checking
      • 13. Conditional Logic
      • 14. Subject-Oriented Programming
      • 15. Text Processing II
      • 16. Functional Programming
      • 17. Text Processing III
      • 18. Generic and Variant Cores
      • 19. Mathematics
    • App School I
      • 1. Arvo
      • 2. The Agent Core
      • 3. Imports and Aliases
      • 4. Lifecycle
      • 5. Cards
      • 6. Pokes
      • 7. Structures and Marks
      • 8. Subscriptions
      • 9. Vanes
      • 10. Scries
      • 11. Failure
      • 12. Next Steps
      • Appendix: Types
    • App School II (Full-Stack)
      • 1. Types
      • 2. Agent
      • 3. JSON
      • 4. Marks
      • 5. Eyre
      • 6. React app setup
      • 7. React app logic
      • 8. Desk and glob
      • 9. Summary
    • Core Academy
      • 1. Evaluating Nock
      • 2. Building Hoon
      • 3. The Core Stack
      • 4. Arvo I: The Main Sequence
      • 5. Arvo II: The Boot Sequence
      • 6. Vere I: u3 and the Serf
      • 7. Vere II: The Loom
      • 8. Vanes I: Behn, Dill, Kahn, Lick
      • 9. Vanes II: Ames
      • 10. Vanes III: Eyre, Iris
      • 11. Vanes IV: Clay
      • 12. Vanes V: Gall and Userspace
      • 13. Vanes VI: Khan, Lick
      • 14. Vanes VII: Jael, Azimuth
    • Runtime
      • U3
      • Conn.c Guide
      • How to Write a Jet
      • API Overview by Prefix
      • C in Urbit
      • Cryptography
      • Land of Nouns
    • Tools
      • Useful Links
      • JS Libraries
        • HTTP API
      • Docs App
        • File Format
        • Index File
        • Suggested Structure
    • Userspace
      • Command-Line App Tutorial
      • Remote Scry
      • Unit Tests
      • Software Distribution
        • Software Distribution Guide
        • Docket File
        • Glob
      • Examples
        • Building a CLI App
        • Debugging Wrapper
        • Host a Website
        • Serving a JS Game
        • Ship Monitoring
        • Styled Text
  • Urbit ID
    • What is Urbit ID?
    • Azimuth Data Flow
    • Life and Rift
    • Urbit HD Wallet
    • Advanced Azimuth Tools
    • Custom Roller Tutorial
    • Azimuth.eth Reference
    • Ecliptic.eth Reference
    • Layer 2
      • L2 Actions
      • L2 Rollers
      • L2 Roller HTTP RPC-API
      • L2 Transaction Format
  • Urbit OS
    • What is Urbit OS?
    • Base
      • Hood
      • Threads
        • Basics Tutorial
          • Bind
          • Fundamentals
          • Input
          • Output
          • Summary
        • HTTP API Guide
        • Spider API Reference
        • Strandio Reference
        • Examples
          • Child Thread
          • Fetch JSON
          • Gall
            • Poke Thread
            • Start Thread
            • Stop Thread
            • Take Facts
            • Take Result
          • Main-loop
          • Poke Agent
          • Scry
          • Take Fact
    • Kernel
      • Arvo
        • Cryptography
        • Move Trace
        • Scries
        • Subscriptions
      • Ames
        • Ames API Reference
        • Ames Cryptography
        • Ames Data Types
        • Ames Scry Reference
      • Behn
        • Behn API Reference
        • Behn Examples
        • Behn Scry Reference
      • Clay
        • Clay API Reference
        • Clay Architecture
        • Clay Data Types
        • Clay Examples
        • Clay Scry Reference
        • Filesystem Hierarchy
        • Marks
          • Mark Examples
          • Using Marks
          • Writing Marks
        • Using Clay
      • Dill
        • Dill API Reference
        • Dill Data Types
        • Dill Scry Reference
      • Eyre
        • EAuth
        • Eyre Data Types
        • Eyre External API
        • Eyre Internal API
        • Eyre Scry Reference
        • Low-Level Eyre Guide
        • Noun channels
      • Gall
        • Gall API Reference
        • Gall Data Types
        • Gall Scry Reference
      • Iris
        • Iris API Reference
        • Iris Data Types
        • Iris Example
      • Jael
        • Jael API Reference
        • Jael Data Types
        • Jael Examples
        • Jael Scry Reference
      • Khan
        • Khan API Reference
        • Khan Data Types
        • Khan Example
      • Lick
        • Lick API Reference
        • Lick Guide
        • Lick Examples
        • Lick Scry Reference
  • Hoon
    • Why Hoon?
    • Advanced Types
    • Arvo
    • Auras
    • Basic Types
    • Cheat Sheet
    • Cryptography
    • Examples
      • ABC Blocks
      • Competitive Programming
      • Emirp
      • Gleichniszahlenreihe
      • Islands
      • Luhn Number
      • Minimum Path Sum
      • Phone Letters
      • Restore IP
      • Rhonda Numbers
      • Roman Numerals
      • Solitaire Cipher
      • Water Towers
    • Generators
    • Hoon Errors
    • Hoon Style Guide
    • Implementing an Aura
    • Irregular forms
    • JSON
    • Limbs and wings
      • Limbs
      • Wings
    • Mips (Maps of Maps)
    • Parsing Text
    • Runes
      • | bar · Cores
      • $ buc · Structures
      • % cen · Calls
      • : col · Cells
      • . dot · Nock
      • / fas · Imports
      • ^ ket · Casts
      • + lus · Arms
      • ; mic · Make
      • ~ sig · Hints
      • = tis · Subject
      • ? wut · Conditionals
      • ! zap · Wild
      • Constants (Atoms and Strings)
      • --, == · Terminators
    • Sail (HTML)
    • Serialization
    • Sets
    • Standard Library
      • 1a: Basic Arithmetic
      • 1b: Tree Addressing
      • 1c: Molds and Mold-Builders
      • 2a: Unit Logic
      • 2b: List Logic
      • 2c: Bit Arithmetic
      • 2d: Bit Logic
      • 2e: Insecure Hashing
      • 2f: Noun Ordering
      • 2g: Unsigned Powers
      • 2h: Set Logic
      • 2i: Map Logic
      • 2j: Jar and Jug Logic
      • 2k: Queue Logic
      • 2l: Container from Container
      • 2m: Container from Noun
      • 2n: Functional Hacks
      • 2o: Normalizing Containers
      • 2p: Serialization
      • 2q: Molds and Mold-Builders
      • 3a: Modular and Signed Ints
      • 3b: Floating Point
      • 3c: Urbit Time
      • 3d: SHA Hash Family
      • 3e: AES encryption (Removed)
      • 3f: Scrambling
      • 3g: Molds and Mold-Builders
      • 4a: Exotic Bases
      • 4b: Text Processing
      • 4c: Tank Printer
      • 4d: Parsing (Tracing)
      • 4e: Parsing (Combinators)
      • 4f: Parsing (Rule-Builders)
      • 4g: Parsing (Outside Caller)
      • 4h: Parsing (ASCII Glyphs)
      • 4i: Parsing (Useful Idioms)
      • 4j: Parsing (Bases and Base Digits)
      • 4k: Atom Printing
      • 4l: Atom Parsing
      • 4m: Formatting Functions
      • 4n: Virtualization
      • 4o: Molds
      • 5a: Compiler Utilities
      • 5b: Macro Expansion
      • 5c: Compiler Backend & Prettyprinter
      • 5d: Parser
      • 5e: Molds and mold builders
      • 5f: Profiling support
    • Strings
    • The Engine Pattern
    • Udon (Markdown-esque)
    • Vases
    • Zuse
      • 2d(1-5): To JSON, Wains
      • 2d(6): From JSON
      • 2d(7): From JSON (unit)
      • 2e(2-3): Print & Parse JSON
      • 2m: Ordered Maps
  • Nock
    • What is Nock?
    • Decrement
    • Definition
    • Fast Hints and Jets
    • Implementations
    • Specification
  • User Manual
    • Contents
    • Running Urbit
      • Cloud Hosting
      • Home Servers
      • Runtime Reference
      • Self-hosting S3 Storage with MinIO
    • Urbit ID
      • Bridge Troubleshooting
      • Creating an Invite Pool
      • Get an Urbit ID
      • Guide to Factory Resets
      • HD Wallet (Master Ticket)
      • Layer 2 for planets
      • Layer 2 for stars
      • Proxies
      • Using Bridge
    • Urbit OS
      • Basics
      • Configuring S3 Storage
      • Dojo Tools
      • Filesystem
      • Shell
      • Ship Troubleshooting
      • Star and Galaxy Operations
      • Updates
Powered by GitBook

GitHub

  • Urbit ID
  • Urbit OS
  • Runtime

Resources

  • YouTube
  • Whitepaper
  • Awesome Urbit

Contact

  • X
  • Email
  • Gather
On this page
  • Introduction
  • Thread file location
  • Libraries
  • Thread definition
  • Strands
  • Form and Pure
  • +form
  • +pure
  • A trivial thread
  • Analysis
  • Inline Threads
Edit on GitHub
  1. Urbit OS
  2. Base
  3. Threads
  4. Basics Tutorial

Fundamentals

Introduction

A thread is like a transient gall agent. Unlike an agent, it can end and it can fail. The primary uses for threads are:

  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.

  2. Testing - threads are very useful for writing complex tests for your agents.

Threads are managed by the Gall agent called %spider. You can poke %spider directly, or you can pass a task to the Khan thread runner vane and let it handle %spider for you.

Threads can be run from a file in the /ted directory, or an "inline thread" can be passed directly to Khan from within your agent.

Thread file location

Thread files live in the ted directory of each desk. For example, in a desk named %sandbox:

%sandbox
├──app
├──gen
├──lib
├──mar
├──sur
└──ted <-
   ├──foo
   │  └──bar.hoon
   └──baz.hoon

From the dojo, ted/baz.hoon can be run with -sandbox!baz, and ted/foo/bar.hoon with -sandbox!foo-bar. Threads in the %base desk can just be run like -foo, but all others must have the format -desk!thread.

Libraries

There are two libraries that may be relevant:

  • /sur/spider/hoon - this contains a few simple structures used by %spider. It's only relevant if you're running thread files by poking %spider directly. If you're running them by passing a task to Khan as is typical, it can be ignored.

  • /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.

Thread definition

A thread is defined as a $-(vase shed:khan). That is, a gate that takes a $vase and produces a $shed:khan. A $shed:khan is 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:

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.

Strands

Strands are the building blocks of threads. A thread will typically compose multiple strands.

A strand is a function of $strand-input:rand to $output:strand:rand, the latter of which is a +strand-output-raw:rand initialized with a particular mold:

$strand-input:rand
+$  strand-input
  $+  strand-input
  [=bowl in=(unit input)]
$strand-output-raw:rand
++  strand-output-raw
    |*  a=mold
    $+  strand-output-raw
    $~  [~ %done *a]
    $:  cards=(list card)
        $=  next
        $%  [%wait ~]
            [%skip ~]
            [%cont self=(strand-form-raw a)]
            [%fail err=error]
            [%done value=a]
        ==
    ==

At this stage you don't need to know the nitty-gritty details but it's helpful to have a quick look through the +rand arm in lull.hoon. We'll discuss these things in more detail later.

A strand is a core that has three important arms:

  • +form - the mold of the strand

  • +pure - produces a strand that does nothing except return a value

  • +bind - monadic bind, like then in javascript promises

We'll discuss each of these arms later.

A strand must be specialised to produce a particular type like (strand:rand ,<type>). As previously mentioned, a thread produces a vase so is specialised like (strand:rand ,vase). Within your thread you'll likely compose multiple strands which produce different types like (strand:rand ,@ud), (strand:rand ,[path cage]), etc, but the thread itself will always come back to a (strand:rand ,vase).

Strands are conventionally given the face m like:

=/  m  (strand:rand ,vase)
...

NOTE: a comma prefix as in ,vase is the irregular form of ^: ketcol which produces a gate that returns the sample value if it's of the correct type, but crashes otherwise.

Form and Pure

+form

The +form arm is the mold of the strand, suitable for casting. The two other arms produce +forms so you'll cast everything to this like:

=/  m  (strand:rand ,@ud)
^-  form:m
...

+pure

Pure produces a strand that does nothing except return a value. So, (pure:(strand:rand ,@tas) %foo) is a strand that produces %foo without doing any IO.

We'll cover +bind later.

A trivial thread

|=  arg=vase
=/  m  (strand:rand ,vase)
^-  form:m
(pure:m arg)

The above code is a simple thread that just returns its argument, and it's a good boilerplate to start from.

Save the above code as a file in ted/mythread.hoon and |commit it. Run it with -mythread 'foo', you should see the following:

> -mythread 'foo'
[~ 'foo']

NOTE: The dojo wraps arguments in a unit so that's why it's [~ 'foo'] rather than just 'foo'.

Analysis

We'll go through it line-by line.

|=  arg=vase

We create a gate that takes a vase, the first part of the previously mentioned thread definition.

=/  m  (strand:rand ,vase)

Inside the gate we create our +strand specialised to produce a $vase and give it the canonical face m.

^-  form:m

We cast the output to form - the mold of the strand we created.

(pure:m arg)

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.

Inline Threads

While you can store threads as files in the /ted directory, you can also include threads directly in your Gall agent code and ask the Khan vane to run them.

While a stand-alone thread file is expected to be a $-(vase shed:khan), an inline thread is just a $shed:khan. That is, it doesn't take any initial argument argument. Instead, you can simply reference any data and functions available in its subject in the Gall agent.

Here's how a trivial inline thread that'll just return 123, a number pinned previously in the Gall agent, might look:

=/  dat=@ud  123
=/  =shed:khan
  =/  m  (strand:rand ,vase)
  ^-  form:m
  (pure:m !>(dat))

The $shed can then be passed to Kahn in card:

[%pass /thread %arvo %k %lard %mydesk shed]~

The result will come back into the ++on-arvo arm of the Gall agent in an %arow gift.

Next we'll look at the third arm of a strand: +bind.

PreviousBindNextInput

Last updated 1 day ago

thread diagram