diff --git a/main/pub/fab/site/hymn.hook b/main/pub/fab/site/hymn.hook index 43383a797..f8b80afb9 100644 --- a/main/pub/fab/site/hymn.hook +++ b/main/pub/fab/site/hymn.hook @@ -2,6 +2,7 @@ :: :::: :: +/= bod /^ manx /: /===/pub/src/doc/say/intro /psal/ /= sty /^ @t /: /===/pub/fab/site/styles /css/ :: :::: ~tomsyt-balsen @@ -14,18 +15,11 @@ ;body ;div(class "content container") ;div(class "page documentation") + ;+ bod ;h1(class "page-title"): Documentation - ;p ; If you want to build a deep understanding of how Urbit works, - ; start with Nock. If you would prefer to just try stuff - ; out, start with Arvo. - == ;p ; This documentation is a work in progress. Feedback and corrections ; are welcome. Pull requests are encouraged. The repo for this site ; lives ;{a(href "https://github.com/urbit/urbit.github.io") "here"}. - ; We would love your help in making this reference more useful. - == - ;p ; Arvo is still actively being changed and updated. - ; As Arvo development cools, more documentation will emerge. == ;ul ;li diff --git a/main/pub/fab/site/styles.css b/main/pub/fab/site/styles.css new file mode 100644 index 000000000..3743b5116 --- /dev/null +++ b/main/pub/fab/site/styles.css @@ -0,0 +1,596 @@ + + +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; +} + +html { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.5; +} +@media (min-width: 38rem) { + html { + font-size: 16px; + } +} + +body { + color: #515151; + background-color: #fff; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +/* No `:visited` state is required by default (browsers will use `a`) */ +a { + line-height: 1.1rem; + color: #555; + text-decoration: none; +} +li a, p a { + display: inline-block; + border-bottom: 2px solid #ccc; +} +/* `:focus` is linked to `:hover` for basic accessibility */ +a:hover, +a:focus { + text-decoration: underline; +} + +li a:hover, p a:hover, +li a:hover, p a:focus { + border-bottom: 2px solid #555; +} + +/* Headings */ +h1, h2, h3, h4, h5, h6 { + margin-bottom: .5rem; + font-weight: bold; + line-height: 1.25; + color: #313131; + text-rendering: optimizeLegibility; +} +h1 { + font-size: 1.2rem; +} +h2 { + margin-top: 1rem; + font-size: 1rem; +} +h3 { + margin-top: 1.5rem; + font-size: .9rem; +} +h4, h5, h6 { + margin-top: .9rem; + font-size: .9rem; + font-weight: 500; + letter-spacing: .03rem; +} + +/* Body text */ +p { + max-width: 42rem; + margin-top: 0; + margin-bottom: 1rem; +} + +strong { + color: #303030; +} + + +/* Lists */ +ul, ol, dl { + margin-top: 0; + margin-bottom: 1rem; +} + +dt { + font-weight: bold; +} +dd { + margin-bottom: .5rem; +} + +/* Misc */ +hr { + position: relative; + margin: 1.5rem 0; + border: 0; + border-top: 1px solid #eee; + border-bottom: 1px solid #fff; +} + +abbr { + font-size: 85%; + font-weight: bold; + color: #555; + text-transform: uppercase; +} +abbr[title] { + cursor: help; + border-bottom: 1px dotted #e5e5e5; +} + +/* Code */ +code, +pre, .codeblock { + font-family: Menlo, Monaco, "Courier New", monospace; +} +code { + padding: .25em .5em; + font-size: 90%; + background-color: #f9f9f9; + border-radius: none; +} +pre, .codeblock { + display: block; + margin-top: 0; + margin-bottom: 1rem; + padding: 1rem; + font-size: .9rem; + line-height: 1.4; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; + width: 42rem; + background-color: #f9f9f9; +} +pre code, .codeblock code { + padding: 0; + font-size: 90%; + color: inherit; + background-color: transparent; +} +.highlight { + margin-bottom: 1rem; + border-radius: none; +} +.highlight pre { + margin-bottom: 0; +} + +/* Quotes */ +blockquote { + padding: .5rem 1rem; + padding-left: 0; + max-width: 32rem; + margin: .8rem 0; + color: #7a7a7a; +} +blockquote p:last-child { + margin-bottom: 0; +} +@media (min-width: 30rem) { + blockquote { + padding-right: 5rem; + padding-left: 0; + } +} + +img { + display: block; + margin: 0 0 1rem; + border-radius: none; + min-width:100%; + max-width:100%; + height:auto; +} + +/* Tables */ +table { + margin-bottom: 1rem; + width: 100%; + border: 1px solid #e5e5e5; + border-collapse: collapse; +} +td, +th { + padding: .25rem .5rem; + border: 1px solid #e5e5e5; +} +tbody tr:nth-child(odd) td, +tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} + + +/* + * Custom type + * + * Extend paragraphs with `.lead` for larger introductory text. + */ + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + + +/* + * Messages + * + * Show alert messages to users. You may add it to single elements like a `
`, + * or to a parent if there are multiple elements to show. + */ + +.message { + margin-bottom: 1rem; + padding: 1rem; + color: #717171; + background-color: #f9f9f9; +} + + +/* + * Container + * + * Center the page content. + */ + +.container { + max-width: 42rem; + padding-left: 1rem; + padding-right: 1rem; + margin-left: auto; + margin-right: auto; +} + + +/* + * Masthead + * + * Super small header above the content for site name and short description. + */ + +.masthead { + padding-top: 1rem; + padding-bottom: 1rem; + margin-bottom: 3rem; +} +.masthead-title { + margin-top: 0; + margin-bottom: 0; + color: #505050; +} +.masthead-title a { + color: #505050; +} +.masthead-title small { + font-size: 75%; + font-weight: 400; + color: #c0c0c0; + letter-spacing: 0; +} + + +/* + * Posts and pages + * + * Each post is wrapped in `.post` and is used on default and post layouts. Each + * page is wrapped in `.page` and is only used on the page layout. + */ + +.page, +.subpage, +.post { + margin-top: 2rem; + margin-bottom: 4em; +} + +/* Blog post or page title */ +.page-title, +.post-title, +.post-title a { + color: #303030; +} + +/* Meta data line below post title */ +.post-date { + display: block; + margin-top: -.5rem; + margin-bottom: 1rem; + color: #9a9a9a; +} + +/* Related posts */ +.related { + padding-top: 2rem; + padding-bottom: 2rem; + border-top: 1px solid #eee; +} +.related-posts { + padding-left: 0; + list-style: none; +} +.related-posts h3 { + margin-top: 0; +} +.related-posts li small { + font-size: 75%; + color: #999; +} +.related-posts li a:hover { + color: #268bd2; + text-decoration: none; +} +.related-posts li a:hover small { + color: inherit; +} + + +/* + * Pagination + * + * Super lightweight (HTML-wise) blog pagination. `span`s are provide for when + * there are no more previous or next posts to show. + */ + +.pagination { + overflow: hidden; /* clearfix */ + margin-left: -1rem; + margin-right: -1rem; + font-family: "PT Sans", Helvetica, Arial, sans-serif; + color: #ccc; + text-align: center; +} + +/* Pagination items can be `span`s or `a`s */ +.pagination-item { + display: block; + padding: 1rem; + border: 1px solid #eee; +} +.pagination-item:first-child { + margin-bottom: -1px; +} + +/* Only provide a hover state for linked pagination items */ +a.pagination-item:hover { + background-color: #f5f5f5; +} + +@media (min-width: 30rem) { + .pagination { + margin: 3rem 0; + } + .pagination-item { + float: left; + width: 50%; + } + .pagination-item:first-child { + margin-bottom: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + } + .pagination-item:last-child { + margin-left: -1px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } +} + +.hll { background-color: #ffffcc } + + +.css .o, +.css .o + .nt, +.css .nt + .nt { color: #999; } + +.toggle { + display: none; +} +.subnav li.active .toggle, .toggle.active { + display: block; +} + +.setup .subnav li.active > a { + border-color: #000; + font-weight: bold; + color: #000; +} + +.sidebar-about { + height: 3rem; +} + +.sidebar-about h1 { + font-size: 1rem; + font-weight: 500; + display: inline-block +} + +.sidebar-about > a:focus, +.sidebar-about > a:hover { + border: none; + text-decoration: none; +} + +.sidebar-about h1.title { + border-bottom: 3px solid transparent; +} + +.sidebar-about h1.logo { + margin-top: .6rem; + margin-right: .6rem; + margin-left: -2rem; + margin-bottom: 0; + height: 1rem; + float: left; +} + +@media only screen and (max-width: 500px) { + .sidebar-about h1.logo { + margin-left: 0; + } +} + +img.logo { + width: 1.2rem; + height: 1.2rem; +} + +.sidebar-about p.lead { + font-size: .8rem; + font-weight: normal; +} + +.sidebar-nav { + margin: 0; + padding: 0; +} + +.sidebar-nav li > a { + border: none; + border-bottom: 3px solid #fff; +} + +.sidebar-about h1.title:focus, +.sidebar-about h1.title:hover, +.sidebar-nav li > a.active, +.sidebar-nav li > a:focus, +.sidebar-nav li > a:hover { + text-decoration: none; + border-bottom: 3px solid #555; +} + +.sidebar-about > a > img { + width: 30px; +} + +.sidebar-nav-item { + display: inline-block; + min-width: 13rem; + font-size: 1rem; +} + +.footer { + margin-bottom: 4rem; +} + +.footer .sidebar-nav-item { + margin-top: 4rem; +} + +ul,ol { + padding-left: 2rem; +} + +ol { + list-style-type: upper-roman; +} + +ul { + list-style-type: circle; +} + +ul.chat { + list-style-type: none; +} + +ul.chat li { + margin-bottom: 2rem; +} + +.doc-hoon h1, .doc-hoon h2 { + margin-top: 3rem; +} + +.documentation > ul { + list-style-type: none; + padding-left: 0; + float: left; +} + +.documentation ul > li { + float: left; + width: 13rem; +} + +code, .subnav > ul > li > ul { + font-family: "Menlo", "Courier New", courier, monospace; + color: inherit; +} + +.subnav > ul > li > ul { + font-size: .9rem; + overflow: hidden; + height: 0; + margin-right: 2rem; +} + +.subnav > ul > li.active > ul { + overflow: visible; + height: auto; +} + +.subnav > ul > li .section { + display: inline-block; +} + +.setup .subnav li > a.expand, .subnav > ul > li .expand { + font-size: .6rem; + border: 0; +} + +.setup .subnav li > a.expand:before, .subnav > ul > li .expand:before { + content: "\25B6"; + font-size: .6rem; +} + +.setup .subnav li > a.expand:before { + margin-right: .6rem; +} + +.setup .subnav li.active > a.expand:before, .subnav > ul > li.active .expand:before { + content: "\25BC"; + font-size: .6rem; +} + +.subnav, .subnav ul { + list-style-type: none; + padding: 0; + margin: 0 0 .6rem 0; +} + +.subnav ul > li > ul > li { + margin-bottom: .3rem; +} + +.subnav a.active { + font-size: 1rem; + font-weight: 700; + color: #333; + border-bottom: 2px solid #555; +} + +.page.setup .subnav .toggle { + margin: 1rem 0 2rem 1.6rem; +} + +@media only screen and (min-width: 54rem) { + .doc-hoon .subnav.arms a{ + font-size: .8rem; + } + .doc-hoon .subnav.runes, .doc-hoon .subnav.arms { + position: fixed; + top: 8rem; + left: 50%; + margin-left: -30rem; + overflow-y: scroll; + } + .subnav > ul > li > ul { + margin-right: 0; + } +} diff --git a/main/pub/fab/site/tut/arvo3/hymn.hook b/main/pub/fab/site/tut/arvo3/hymn.hook new file mode 100644 index 000000000..1c09ece97 --- /dev/null +++ b/main/pub/fab/site/tut/arvo3/hymn.hook @@ -0,0 +1,18 @@ +/= sty /^ @t /: /===/pub/fab/site/styles /css/ +/= bod /^ manx /: /===/pub/src/doc/say/arvo/app /psal/ +:: +:::: ~tomsyt-balsen + :: +;html + ;head + ;title: Urbit: Personal Cloud Computing + ;style:"{(trip sty)}" + == + ;body + ;div(class "content container") + ;div.subpage + ;+ bod + == + == + == +== diff --git a/main/pub/fab/site/tut/arvo4/hymn.hook b/main/pub/fab/site/tut/arvo4/hymn.hook new file mode 100644 index 000000000..496fded93 --- /dev/null +++ b/main/pub/fab/site/tut/arvo4/hymn.hook @@ -0,0 +1,18 @@ +/= sty /^ @t /: /===/pub/fab/site/styles /css/ +/= bod /^ manx /: /===/pub/src/doc/say/arvo/pub2 /psal/ +:: +:::: ~tomsyt-balsen + :: +;html + ;head + ;title: Urbit: Personal Cloud Computing + ;style:"{(trip sty)}" + == + ;body + ;div(class "content container") + ;div.subpage + ;+ bod + == + == + == +== diff --git a/main/pub/fab/site/tut/arvo5/hymn.hook b/main/pub/fab/site/tut/arvo5/hymn.hook new file mode 100644 index 000000000..6285c4a28 --- /dev/null +++ b/main/pub/fab/site/tut/arvo5/hymn.hook @@ -0,0 +1,18 @@ +/= sty /^ @t /: /===/pub/fab/site/styles /css/ +/= bod /^ manx /: /===/pub/src/doc/say/arvo/pub3 /psal/ +:: +:::: ~tomsyt-balsen + :: +;html + ;head + ;title: Urbit: Personal Cloud Computing + ;style:"{(trip sty)}" + == + ;body + ;div(class "content container") + ;div.subpage + ;+ bod + == + == + == +== diff --git a/main/pub/fab/site/tut/setup/hymn.hook b/main/pub/fab/site/tut/setup/hymn.hook new file mode 100644 index 000000000..6fa662268 --- /dev/null +++ b/main/pub/fab/site/tut/setup/hymn.hook @@ -0,0 +1,18 @@ +/= bod /^ manx /: /===/pub/src/doc/say/setup /psal/ +/= sty /^ @t /: /===/pub/fab/site/styles /css/ +:: +:::: ~tomsyt-balsen + :: +;html + ;head + ;title: Urbit: Personal Cloud Computing + ;style:"{(trip sty)}" + == + ;body + ;div(class "content container") + ;div.subpage + ;+ bod + == + == + == +== diff --git a/main/pub/src/doc/ref/vol4.md b/main/pub/src/doc/ref/vol4.md new file mode 100644 index 000000000..27511c000 --- /dev/null +++ b/main/pub/src/doc/ref/vol4.md @@ -0,0 +1,987 @@ +Ames +==== + +Ames is our networking protocol. + +data models +----------- + +###`++fort`, formal state + +``` +++ fort :: formal state + $: %0 :: version + gad=duct :: client interface + hop=@da :: network boot date + ton=town :: security + zac=(map ship corn) :: flows by server + == :: +``` + +This is the state of our vane. Anything that must be remembered between +calls to ames must be stored in this state. + +`%0` is the version of the ames state model itself. If the data model `++fort` +changes, then this number needs to be incremented, and an adapter must be +written to upgrade the old state into the new state. Note that this is the +version number of the model itself, not the contents. When the data changes, +there is of course no need to change this. + +`gad` is a `duct` over which we send `%send` cards to unix. This card is +initialized when unix sends a `%barn` card as vere starts up. Vere treats this +duct specially -- don't send anything weird over it. + +`hop` is the network boot date. This is set when the `%kick` card is sent by +vere on start up. + +`ton` is a `++town`, where we store all of our security/encryption state. Note +that this is shared across all ships on a pier. + +`zac` is a map of ships to `++corn`. This stores all the per-ship state. The +keys to this map are the ships on the current pier. + +###`++town`, all security state + +``` +++ town :: all security state + $: lit=@ud :: imperial modulus + any=@ :: entropy + urb=(map ship sufi) :: all keys and routes + fak=? :: + == :: +``` + +This is the security state of our pier. + +`lit` is unused. + +`any` is 256 bits of entropy. This entropy is used and updated in exactly two +places: when we send a `%junk` card, and when we generate a new symmetric key +in `++griz:lax:as:go`. When it is updated, it is updated by a SHA-256 hash of +the current time and the old value of the entropy. + +`urb` is a map of ships to `++sufi`. This is where we store all the per-ship +state for the pier. The keys to this map are the ships on the current pier. + +`fak` is true if we are on a fake network. This disables certain security +checks so that anyone may run a fake `~zod`. This is used only for development. +To use, run vere with the `-F` option (and the `-I ~zod` option for a fake +`~zod`). + +###`++sufi`, domestic host + +``` +++ sufi :: domestic host + $: hoy=(list ship) :: hierarchy + val=wund :: private keys + law=will :: server will + seh=(map hand ,[p=ship q=@da]) :: key cache + hoc=(map ship dore) :: neighborhood + == :: +``` + +This is the security state of a domestic server. + +`hoy` is a list of the ships directly above us in the hierarchy of ships. For +example, for `~hoclur-bicrel`, this would be `~tasruc` and `~tug`. See +`++sein`. + +`val` is a list of our private keys. + +`law` is our certificate, which is a list of the XXX + +`seh` + +`hoc` is a map of ships to `++dore`. The stores all the security informatoin +about foreign ships. The keys to this map are the neighbors (ships we have +been in contact with) of this domestic server. + +###`++wund`, private keys + +``` +++ wund (list ,[p=life q=ring r=acru]) :: mace in action +``` + +This is a list of our own private keys, indexed by life. The key itself is +the `++ring`, and the `++acru` is the encryption engine. We generate the +`++acru` from the private key by calling `++weur`. Thus, we can at any time +regenerate our `++wund` from a `++mace`. The current crypto is at the head of +the list and can be accessed with +`++sen:as:go`. + +###`++ring`, private key + +``` +++ ring ,@ :: private key +``` + +This is a private key. The first byte is reserved to identify the type of +cryptography. Lower-case means public key, upper-case means public key, and +the letter identifies which `++acru` to use. + +###`++pass`, public key + +``` +++ pass ,@ :: public key +``` + +This is a public key. The first byte is reserved to identify the type of +cryptography. Lower-case means public key, upper-case means public key, and +the letter identifies which `++acru` to use. + +###`++mace`, private secrets + +``` +++ mace (list ,[p=life q=ring]) :: private secrets +``` + +This is a list of the our private keys, indexed by life. From this we can +generate a `++wund` for actual use. + +###`++skin`, encoding stem + +``` +++ skin ?(%none %open %fast %full) :: encoding stem +``` + +This defines the type of encryption used for each message. `%none` refers +to messages sent in the clear, `%open` refers to signed messages, `%full` +refers to sealed messages, and `%fast` refers to symmetrically encrypted +messages. See `++acru` for details. + +###`++acru`, asymmetric cryptosuite + +``` +++ acru :: asym cryptosuite + $_ ^? |% :: opaque object + ++ as ^? :: asym ops + |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a + ++ sign |=([a=@ b=@] _@) :: certify as us + ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us + ++ tear |= [a=pass b=@] :: accept from a + *(unit ,[p=@ q=@]) :: + -- :: + ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft + ++ dy |+([a=@ b=@] _@) :: symmetric de, hard + ++ en |+([a=@ b=@] _@) :: symmetric en + ++ ex ^? :: export + |% ++ fig _@uvH :: fingerprint + ++ pac _@uvG :: default passcode + ++ pub *pass :: public key + ++ sec *ring :: private key + -- + ++ nu ^? :: reconstructors + |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed] + ++ nol |=(a=@ ^?(..nu)) :: from naked ring + ++ com |=(a=@ ^?(..nu)) :: from naked pass + -- + -- +``` + +This is an opaque interface for a general asymmetric cryptosuite. Any form +of asymmetric cryptography can be dropped in to be used instead of the default. +Right now, there are two cryptosuites, `++crua`, which is your standard RSA, +and `++crub`, which is elliptic curve crypto but is mostly stubbed out at the +moment. + +####`++as:acru`, asymmetric operations + +``` + ++ as ^? :: asym ops + |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a + ++ sign |=([a=@ b=@] _@) :: certify as us + ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us + ++ tear |= [a=pass b=@] :: accept from a + *(unit ,[p=@ q=@]) :: + -- :: +``` + +This is the core that defines the standard asymmetric cryptography +operations. + +`++seal:as:acru` allows us to send a message encrypted with someone's public +key so that only they may read it. If Alice seals a message with Bob's public +key, then she can be sure that Bob is the only one who can read it. This is +associated with the `++skin` `%full`. + +`++sign:as:acru` allows us to sign a message with our private key so that +others can verify that we sent the message. If Alice signs a message with her +private key, then Bob can verify with her public key that it was indeed Alice +who sent it. This is associated with the `++skin` `%open`. + +`++sure:as:acru` is the dual to `++sign:as:acru`. It allows us to verify that +a message we have received is indeed from the claimed sender. If Alice sends a +message with her private key, then Bob can use this arm to verify that it was +indeed Alice who sent it. This is associated with the `++skin` `%open`. + +`++tear:as:acru` is the dual to `++seal:as:acru`. It allows us to read a +message that we can be sure is only read by us. If Alice seals a message with +Bob's public key, then Bob can use this arm to read it. This is associated +with the `++skin` `%full`. + +####`++de:acru`, `++dy:acru`, and `++en:acru`, symmetric encryption/decryption + +``` + ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft + ++ dy |+([a=@ b=@] _@) :: symmetric de, hard + ++ en |+([a=@ b=@] _@) :: symmetric en +``` + +Symmetric encryption is associated with the `++skin` `%fast`. + +`++de:acru` decrypts a message with a symmetric key, returning `~` on failure +and `[~ u=data]` on success. + +`++dy:acru` decrypts a message with a symmetric key, crashing on failure. This +should almost always be defined as, and should always be semantically +equivalent to, `(need (de a b))`. + +`++en:acru` encrypts a message with a symmetric key. + +####`++ex:acru`, exporting data + +``` + ++ ex ^? :: export + |% ++ fig _@uvH :: fingerprint + ++ pac _@uvG :: default passcode + ++ pub *pass :: public key + ++ sec *ring :: private key + -- +``` + +`++fig:ex:acru` is our fingerprint, usually a hash of our public key. This is +used, for example, in `++zeno`, where every carrier owner's fingerprint is +stored so that we can ensure that carriers are indeed owned by their owners + +`++pac:ex:acru` is our default passcode, which is unused at present. + +`++pub:ex:acru` is the `++pass` form of our public key. + +`++sec:ex:acru` is the `++ring` form of our private key. + +####`++nu:acru`, reconstructors + +``` + ++ nu ^? :: reconstructors + |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed] + ++ nol |=(a=@ ^?(..nu)) :: from naked ring + ++ com |=(a=@ ^?(..nu)) :: from naked pass + -- +``` + +These arms allow us to reconstruct a `++acru` from basic data. + +`++pit:nu:acru` constructs a `++acru` from the width of our intended key and +seed entropy. This is usually used in the initial construction of the +`++acru`. + +`++nol:nu:acru` constructs a `++acru` from a "naked ring", meaning a `++ring` +without the initial byte identifying the type of crypto. There is often a +helper arm that that wraps this; see `++weur` for `++crua` and `++wear` for +`++crub`. + +`++com:nu:acru` constructs a `++acru` from a "naked pass", meaning a `++ring` +without the initial byte identifying the type of crypto. There is often a +helper arm that that wraps this; see `++haul` for `++crua` and `++hail` for +`++crub`. + +###`++will`, certificate + +``` +++ will (list deed) :: certificate +``` + +This is a list of deeds associated with the current ship. There should be +an item in this list for every ship from this point up in the hierarchy times +the number of lives that each ship has had. For example, ~hoclur-bicrel may +have a will with three items: one for itself, one for ~tasruc (who issued +~hoclur-bicrel's deed) and one for ~tug (who issued ~tasruc's deed). + +###`++deed`, identity + +``` +++ deed ,[p=@ q=step r=?] :: sig, stage, fake? +``` + +`p` is the signature of a particular deed, which is a signed copy of `q`. + +`q` is the stage in the identity. + +`r` is true if we're working on a fake network, where we don't check that the +carrier fingerprints are correct. This allows us to create fake networks for +development without interfering with the real network. + +###`++step`, identity stage + +``` +++ step ,[p=bray q=gens r=pass] :: identity stage +``` + +This is a single stage in our identity. Thus, this is specific to a single +life in a single ship. Everything in here may change between lives. + +`p` + +`q` + +`r` is the public key for this stage in the identity. + +###`++bray` + +``` +++ bray ,[p=life q=(unit life) r=ship s=@da] :: our parent us now +``` + +XXX + +###`++gens`, general identity + +``` +++ gens ,[p=lang q=gcos] :: general identity +``` + +`p` is the IETF language code for the preferred language of this identity. +This is unused at the moment, but in the future text should be localized based +on this. + +`q` is the description of the ship. + +###`++gcos`, identity description + +``` +++ gcos :: id description + $% [%czar ~] :: 8-bit ship + [%duke p=what] :: 32-bit ship + [%earl p=@t] :: 64-bit ship + [%king p=@t] :: 16-bit ship + [%pawn p=(unit ,@t)] :: 128-bit ship + == :: +``` + +This is the description of the identity of a ship. Most types of identity have +a `@t` field, which is their human-readable name. The identity of a `%duke` is +more involved. + +A `%czar`, a carrier, is a ship with an 8-bit address. Thus, there are only +256 carriers. These are at the top of the namespace hierarchy, and the +fingerprint of each carrier is stored in `++zeno`. These are the "senators" of +Urbit. + +A `%king`, a cruiser, is a ship with a 16-bit address. Thus, there are 65,536 +cruisers. Each carrier may issue 256 cruisers. These are the infrastructure +of Urbit. + +A `%duke`, a destroyer, is a ship with a 32-bit address. Thus, there are +4,294,967,296 destroyers. Each cruiser may issue 65,536 cruisers. These are +the individuals of Urbit. + +A `%earl`, a yacht, is a ship with a 64-bit address. Thus, there are +18,446,744,073,709,551,616 yachts. Each destroyer may issue 4,294,967,296 +yachts. These are the devices of Urbit. + +A `%pawn`, a submarine, is a ship with a 128-bit address. Thus, there are a +lot of submarines. The chance of random name collision is negligible, so +submarines are not issued by any ship. They must simply assert their presence, +and they are all considered children of ~zod. This is the underworld of Urbit, +where anonymity reigns supreme. + +###`++what`, logical destroyer identity + +``` +++ what :: logical identity + $% [%anon ~] :: anonymous + [%lady p=whom] :: female person () + [%lord p=whom] :: male person [] + [%punk p=sect q=@t] :: opaque handle "" + == :: +``` + +This is the logical identity of a destroyer. + +A `%anon` is a completely anonymous destroyer. The difference between this and +a submarine is that a submarine is ephemeral while a `%anon` destroyer is not. +Thus, we may not know who ~hoclur-bicrel is, but we do know that it's always +the same person. + +A `%lady` is a female person. The name used here should be a real name. + +A `%lord` is a male person. The name used here should be a real name. + +A `%punk` is a person who is identified only by a handle. + +###`++whom`, real person + +``` +++ whom ,[p=@ud q=govt r=sect s=name] :: year/govt/id +``` + +Ths is the information associated with a real person. It is mostly information +that could be observed with the briefest of interactions. + +`p` is the birth year. + +`q` is the location of a user, usually of the form "country/zip". + +`r` is the sect of the user. + +`s` is the real name of the person. + + +###`++govt` + +``` +++ govt path :: country/postcode +``` + +This is the location of the user, usually of the form "country/zip". + +###`++sect` + +``` +++ sect ?(%black %blue %red %orange %white) :: banner +``` + +XXX + +###`++name` + +``` +++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last +``` + +This is the given name, possible middle name/initial, possible nickname, and +surname of a user. + +packet format +------------- + +`++go`, PKI engine +------------------ + +###`++as`, per server + +####`++born`, register user + +#####`++lax`, per client + +`++pu`, packet pump +------------------- + +`++am`, protocol engine +----------------------- + +###`++um`, per server + +####`++ho`, per friend + +#####`++la`, per packet + +protocol vane +------------- + +#Batz + +Coming soon + +#Dill + +Coming soon + +#Clay + +Clay +==== + +Clay is our filesystem. + +data models +----------- + +###`++raft`, formal state + +``` +++ raft :: filesystem + $: fat=(map ship room) :: domestic + hoy=(map ship rung) :: foreign + ran=rang :: hashes + == :: +``` + +This is the state of our vane. Anything that must be remembered between calls +to clay must be stored in this state. + +`fat` is the set of domestic servers. This stores all the information that is +specfic to a particular ship on this pier. The keys to this map are the ships +on the current pier. + +`hoy` is the set of foreign servers that we know anything about. This stores +all the information that is specific to a particular foreign ship. The keys to +this map are all the ships whose filesystems we have attempted to access +through clay. + +`ran` is the store of all commits and deltas, keyed by hash. The is where all +the "real" data we know is stored; the rest is "just bookkeeping". + +###`++room`, filesystem per domestic ship + +``` +++ room :: fs per ship + $: hun=duct :: terminal duct + hez=(unit duct) :: sync duch + dos=(map desk dojo) :: native desk + == :: +``` + +This is the representation of the filesystem of a ship on our pier. + +`hun` is the duct that we use to send messages to dill to display notifications +of filesystem changes. Only `%note` gifts should be produced along this duct. +This is set by the `%init` kiss. + +`hez`, if present, is the duct we use to send sync messages to unix so that +they end up in the pier unix directory. Only `%ergo` gifts should be producd +along this duct. This is set by `%into` and `%invo` gifts. + +`dos` is a well-known operating system released in 1981. It is also the set of +desks on this ship, mapped to their data. + +###`++desk`, filesystem branch + +``` +++ desk ,@tas :: ship desk case spur +``` + +This is the name of a branch of the filesystem. The default desks are "arvo", +"main", and "try". More may be created by simply referencing them. Desks have +independent histories and states, and they may be merged into each other. + +###`++dojo`, domestic desk state + +``` +++ dojo ,[p=cult q=dome] :: domestic desk state +``` + +This is the all the data that is specific to a particular desk on a domestic +ship. `p` is the set of subscribers to this desk and `q` is the data in the +desk. + +###`++cult`, subscriptions + +``` +++ cult (map duct rave) :: subscriptions +``` + +This is the set of subscriptions to a particular desk. The keys are the ducts +from where the subscriptions requests came. The results will be produced along +these ducts. The values are a description of the requested information. + +###`++rave`, general subscription request + +``` +++ rave :: general request + $% [& p=mood] :: single request + [| p=moat] :: change range + == :: +``` + +This represents a subscription request for a desk. The request can be for +either a single item in the desk or else for a range of changes on the desk. + +###`++mood`, single subscription request + +``` +++ mood ,[p=care q=case r=path] :: request in desk +``` + +This represents a request for the state of the desk at a particular commit, +specfied by `q`. `p` specifies what kind of information is desired, and `r` +specifies the path we are requesting. + +###`++moat`, range subscription request + +``` +++ moat ,[p=case q=case] :: change range +``` + +This represents a request for all changes between `p` and `q`. Note that there +is currently no way to request to be notified only on changes to particular +paths in the filesystem. You must subscribe to the entire desk. + +###`++care`, clay submode + +``` +++ care ?(%u %v %w %x %y %z) :: clay submode +``` + +This specifies what type of information is requested in a subscription or a +scry. + +`%u` requests the `++rang` at the current moment. Because this information is +not stored for any moment other than the present, we crash if the `++case` is +not a `%da` for now. + +`%v` requests the `++dome` at the specified commit. + +`%w` requests the current revsion number of the desk. + +`%x` requests the file at a specified path at the specified commit. If there +is no node at that path or if the node has no contents (that is, if `q:ankh` is +null), then this produces null. + +`%y` requests a `++arch` of the specfied commit at the specified path. + +`%z` requests the `++ankh` of the specified commit at the specfied path. + +###`++arch`, shallow filesystem node + +``` +++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node +``` + +This is analogous to `++ankh` except that the we have neither our contents nor +the ankhs of our children. The other fields are exactly the same, so `p` is a +hash of the associated ankh, `u.q`, if it exists, is a hash of the contents of +this node, and the keys of `r` are the names of our children. `r` is a map to +null rather than a set so that the ordering of the map will be equivalent to +that of `r:ankh`, allowing efficient conversion. + +###`++case`, specifying a commit + +``` +++ case :: ship desk case spur + $% [%da p=@da] :: date + [%tas p=@tas] :: label + [%ud p=@ud] :: number + == :: +``` + +A commit can be referred to in three ways: `%da` refers to the commit that was +at the head on date `p`, `%tas` refers to the commit labeled `p`, and `%ud` +refers to the commit numbered `p`. Note that since these all can be reduced +down to a `%ud`, only numbered commits may be referenced with a `++case`. + +###`++dome`, desk data + +``` +++ dome :: project state + $: ang=agon :: pedigree + ank=ankh :: state + let=@ud :: top id + hit=(map ,@ud tako) :: changes by id + lab=(map ,@tas ,@ud) :: labels + == :: +``` + +This is the data that is actually stored in a desk. + +`ang` is unused and should be removed. + +`ank` is the current state of the desk. Thus, it is the state of the +filesystem at revison `let`. The head of a desk is always a numbered commit. + +`let` is the number of the most recently numbered commit. This is also the +total number of numbered commits. + +`hit` is a map of numerical ids to hashes of commits. These hashes are mapped +into their associated commits in `hut:rang`. In general, the keys of this map +are exactly the numbers from 1 to `let`, with no gaps. Of course, when there +are no numbered commits, `let` is 0, so `hit` is null. Additionally, each of +the commits is an ancestor of every commit numbered greater than this one. +Thus, each is a descendant of every commit numbered less than this one. Since +it is true that the date in each commit (`t:yaki`) is no earlier than that of +each of its parents, the numbered commits are totally ordered in the same way +by both pedigree and date. Of course, not every commit is numbered. If that +sounds too complicated to you, don't worry about it. It basically behaves +exactly as you would expect. + +`lab` is a map of textual labels to numbered commits. Note that labels can +only be applied to numbered commits. Labels must be unique across a desk. + +###`++ankh`, filesystem node + +``` +++ ankh :: fs node (new) + $: p=cash :: recursive hash + q=(unit ,[p=cash q=*]) :: file + r=(map ,@ta ankh) :: folders + == :: +``` + +This is a single node in the filesystem. This may be file or a directory or +both. In earth filesystems, a node is a file xor a directory. On mars, we're +inclusive, so a node is a file ior a directory. + +`p` is a recursive hash that depends on the contents of the this file or +directory and on any children. + +`q` is the contents of this file, if any. `p.q` is a hash of the contents +while `q.q` is the data itself. + +`r` is the set of children of this node. In the case of a pure file, this is +empty. The keys are the names of the children and the values are, recursively, +the nodes themselves. + +###`++cash`, ankh hash + +``` +++ cash ,@uvH :: ankh hash +``` + +This is a 128-bit hash of an ankh. These are mostly stored within ankhs +themselves, and they are used to check for changes in possibly-deep +hierarchies. + +###`++rung`, filesystem per neighbor ship + +``` +++ rung $: rus=(map desk rede) :: neighbor desks + == :: +``` + +This is the filesystem of a neighbor ship. The keys to this map are all the +desks we know about on their ship. + +###`++rede`, desk state + +``` +++ rede :: universal project + $: lim=@da :: complete to + qyx=cult :: subscribers + ref=(unit rind) :: outgoing requests + dom=dome :: revision state + == :: +``` + +This is our knowledge of the state of a desk, either foreign or domestic. + +`lim` is the date of the last full update. We only respond to requests for +stuff before this time. + +`qyx` is the list of subscribers to this desk. For domestic desks, this is +simply `p:dojo`, all subscribers to the desk, while in foreign desks this is +all the subscribers from our ship to the foreign desk. + +`ref` is the request manager for the desk. + +`dom` is the actual data in the desk. + +###`++rind`, request manager + +``` +++ rind :: request manager + $: nix=@ud :: request index + bom=(map ,@ud ,[p=duct q=rave]) :: outstanding + fod=(map duct ,@ud) :: current requests + haw=(map mood (unit)) :: simple cache + == :: +``` + +This is the request manager for a desk. + +`nix` is one more than the index of the most recent request. Thus, it is the +next available request number. + +`bom` is the set of outstanding requests. The keys of this map are some subset +of the numbers between 0 and one less than `nix`. The members of the map are +exactly those requests that have not yet been fully satisfied. + +`fod` is the same set as `bom`, but from a different perspective. In +particular, the values of `fod` are the same as the values of `bom`, and the +`p` out of the values of `bom` are the same as the keys of `fod`. Thus, we can +map ducts to their associated request number and `++rave`, and we can map +numbers to their associated duct and `++rave`. + +`haw` is a map from simple requests to their values. This acts as a cache for +requests that have already been made. Thus, the second request for a +particular `++mood` is nearly instantaneous. + +###`++rang`, data store + +``` +++ rang $: hut=(map tako yaki) :: + lat=(map lobe blob) :: + == :: +``` + +This is a set of data keyed by hash. Thus, this is where the "real" data is +stored, but it is only meaningful if we know the hash of what we're looking +for. + +`hut` is a map from hashes to commits. We often get the hashes from +`hit:dome`, which keys them by logical id. Not every commit has an id. + +`lat` is a map from hashes to the actual data. We often get the hashes from a +`++yaki`, a commit, which references this map to get the data. There is no +`++blob` in any `++yaki`. They are only accessible through this map. + +###`++tako`, commit reference + +``` +++ tako ,@ :: yaki ref +``` + +This is a hash of a `++yaki`, a commit. These are most notably used as the +keys in `hut:rang`, where they are associated with the actual `++yaki`, and as +the values in `hit:dome`, where sequential ids are associated with these. + +###`++yaki`, commit + +``` +++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit +``` + +This is a single commit. + +`p` is a list of the hashes of the parents of this commit. In most cases, this +will be a single commit, but in a merge there may be more parents. In theory, +there may be an arbitrary number of parents, but in practice merges have +exactly two parents. This may change in the future. For commit 1, there is no +parent. + +`q` is a map of the paths on a desk to the data at that location. If you +understand what a `++lobe` and a `++blob` is, then the type signature here +tells the whole story. + +`r` is the hash associated with this commit. + +`t` is the date at which this commit was made. + +###`++lobe`, data reference + +``` +++ lobe ,@ :: blob ref +``` + +This is a hash of a `++blob`. These are most notably used in `lat:rang`, where +they are associated with the actual `++blob`, and as the values in `q:yaki`, +where paths are associated with their data in a commit. + +###`++blob`, data + +``` +++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q + [%direct p=lobe q=* r=umph] :: + [%indirect p=lobe q=* r=udon s=lobe] :: + == :: +``` + +This is a node of data. In every case, `p` is the hash of the blob. + +`%delta` is the case where we define the data by a delta on other data. In +practice, the other data is always the previous commit, but nothing depends on +this. `q` is the hash of the parent blob, and `r` is the delta. + +`%direct` is the case where we simply have the data directly. `q` is the data +itself, and `r` is any preprocessing instructions. These almost always come +from the creation of a file. + +`%indirect` is both of the preceding cases at once. `q` is the direct data, +`r` is the delta, and `s` is the parent blob. It should always be the case +that applying `r` to `s` gives the same data as `q` directly (with the +prepreprocessor instructions in `p.r`). This exists purely for performance +reasons. This is unused, at the moment, but in general these should be created +when there are a long line of changes so that we do not have to traverse the +delta chain back to the creation of the file. + +###`++udon`, abstract delta + +``` +++ udon :: abstract delta + $: p=umph :: preprocessor + $= q :: patch + $% [%a p=* q=*] :: trivial replace + [%b p=udal] :: atomic indel + [%c p=(urge)] :: list indel + [%d p=upas q=upas] :: tree edit + == :: + == :: +``` + +This is an abstract change to a file. This is a superset of what would +normally be called diffs. Diffs usually refer to changes in lines of text +while we have the ability to do more interesting deltas on arbitrary data +structures. + +`p` is any preprocessor instructions. + +`%a` refers to the trival delta of a complete replace of old data with new +data. + +`%b` refers to changes in an opaque atom on the block level. This has very +limited usefulness, and is not used at the moment. + +`%c` refers to changes in a list of data. This is often lines of text, which +is your classic diff. We, however, will work on any list of data. + +`%d` refers to changes in a tree of data. This is general enough to describe +changes to any hoon noun, but often more special-purpose delta should be +created for different content types. This is not used at the moment, and may +in fact be unimplemented. + +###`++urge`, list change + +``` +++ urge |*(a=_,* (list (unce a))) :: list change +``` + +This is a parametrized type for list changes. For example, `(urge ,@t)` is a +list change for lines of text. + +###`++unce`, change part of a list. + +``` +++ unce |* a=_,* :: change part + $% [%& p=@ud] :: skip[copy] + [%| p=(list a) q=(list a)] :: p -> q[chunk] + == :: +``` + +This is a single change in a list of elements of type `a`. For example, `(unce ,@t)` is +a single change in a lines of text. + +`%&` means the next `p` lines are unchanged. + +`%|` means the lines `p` have changed to `q`. + +###`++umph`, preprocessing information + +``` +++ umph :: change filter + $| $? %a :: no filter + %b :: jamfile + %c :: LF text + == :: + $% [%d p=@ud] :: blocklist + == :: +``` + +This space intentionally left undocumented. This stuff will change once we get +a well-typed clay. + + +###`++upas`, tree change + +``` +++ upas :: tree change (%d) + $& [p=upas q=upas] :: cell + $% [%0 p=axis] :: copy old + [%1 p=*] :: insert new + [%2 p=axis q=udon] :: mutate! + == :: +``` + +This space intentionally left undocumented. This stuff is not known to work, +and will likely change when we get a well-typed clay. Also, this is not a +complicated type; it is not difficult to work out the meaning. + +#Eyre + +Coming soon + +#Ford + +Coming soon + +#Gall + +Coming soon diff --git a/main/pub/src/doc/say/arvo/app.md b/main/pub/src/doc/say/arvo/app.md new file mode 100644 index 000000000..c1395ee25 --- /dev/null +++ b/main/pub/src/doc/say/arvo/app.md @@ -0,0 +1,1379 @@ +#Application programming in Arvo + + +**NOTE - not everything in this doc matches current reality! +Where this is the case, reality must be changed to match.** + +ERRATUM: the beautiful ~/urb/SHIP... is not real. Reference +your piers in the normal way. + + +## Hello, world. + +Let's write a simple Arvo app, `foobug`. Start Urbit: + + vere + +From Unix, edit `~/urb/SHIP/main/app/foobug/core.hoon`, where +SHIP is your ship *without* the ~ (for me, `tasfyn-partyv`): + + !: + ::::::::: Foobug: a simple application. + :: + |_ [hid=hide vat=~] + ++ peek + |= [you=ship pax=path] + :- %hymn + ;html + ;head + ;title: Foobug! + == + ;body + ;p: Hello, world. + == + == + -- + +In your browser, go to the URL: + + https://SHIP.urbit.org/foobug + +Now you've written and executed your first Urbit app. + +(If you are running `vere` locally, you'll go faster, not to +mention ease up on our servers, by going direct: + + https://localhost:PORT/foobug + +where `PORT` is the HTTP port `vere` prints out when it starts, +usually `8080`.) + +Leave your browser open and resume editing `foobug/core.hoon`. +Change "Hello" to "Goodbye." Save the file. Then, look at your +browser... now you've upgraded your first Urbit app. + + +## Introductory concepts. + +Urbit apps are written in a funny little language called Hoon. +To be exact, you write an app named APPL by putting a Hoon program +in `~/urb/SHIP/main/APPL/core.hoon`. + +How do you start APPL? You don't. Urbit starts it. You also +don't restart it when you change the code; Urbit does that too. + +Urbit loads an application as soon as someone tries to use it; it +tracks dependencies as it builds, and reloads when its source, or +any other hot-linked code or data dependency, local or remote, +changes. + +Type consistency is never broken in this process - if the +app state changes type across the reload, the replacement +brings an adapter function. If the reboot fails, the old app +continues to run. And as you saw, we inject a script which +auto-reloads your application page. Just to be nice. + +And of course, Urbit is a single-level store, so Urbit +applications with live state are inherently persistent and live +forever (or at least, as long as your Urbit ship). Flushing +state to Urbit's %clay revision store - or even more drastically, +to a legacy database outside Urbit - may be desired but is not +required, not even (ideally) for mission-critical data. + + +## What we're doing here. + +Let's look at `foobug` in a little more detail. + +Our `core.hoon` file starts with this boilerplate opening: + + !: + ::::::::: Foobug: a simple application. + :: + +The `!:` enters debug mode. Within the opening, we produce a core +around the sample state + + |_ [hid=hide vat=~] + +This is where all the data in our application lives. `hid` is +the system's data, `vat` is our data. Right now, `vat` is empty, +because our application is trivial. + +Searching for where `hide` comes from, we find in `hoon.hoon`: + + ++ bone ,@ud :: opaque duct + ++ hide :: standard app state + $: $: our=ship :: owner/operator + app=term :: application name + == :: + sup=(map bone (pair ship path)) :: subscription set + $: act=@ud :: change number + eny=@uvI :: entropy + lat=@da :: date of last action + == == :: + +Everything above is easy to explain but `++bone`. Perhaps the +simplest analogy: a Unix file descriptor. + +But this approximation won't really hold up under the crazy stuff +we're about to do. Unfortunately, we can't explain apps without +`++hide`,`++hide` without `++bone` or `++bone` without Arvo. + +## Arvo for undergrads + +If you take an undergraduate OS class, you'll learn that there +are two kinds of general-purpose operating systems: communicating +sequential processes, and asynchronous event-driven actors. Unix +and Go are CSP models; Node and Arvo are event loops. + +Across this pair of equally legitimate alternatives, every +architectural feature has its equivalent. But most programmers +are more familiar with the CSP model. For instance: in a pure +event OS, what's the equivalent of a file descriptor? + +In Arvo the answer is something called a `++duct` - or in +userspace, `++bone`. The actual event data is a `++card`. A +`++move`, or action, is a `(pair duct card)` in + +If you understand ducts, bones +and cards, you understand Arvo. + +(Well, mostly. But it's worth noting that Arvo proper, not the +vanes which actually do stuff, but the stuff in hoon.hoon that +makes everything do stuff, is only about 600 lines of code.) + +Physically, a duct is just a list of a list of symbols. +Semantically, it's the *source* of an event - or even more +philosophically its *cause*. But why do we need a data structure +for this? Shouldn't the effects of an event be, in fact, +*independent* of its cause? + + +### Motivation + +Arvo is a *structured* event system, designed to avoid the usual +state of complex event networks: event spaghetti. In some ways +it seems more complicated than a simple standard approach. It +is, but the systems built on top of it are much simpler. + +"Event," at its worst, is an asynchronous synonym for "goto." +What is the difference between a `goto` and a `gosub`, anyway? +You may not know where your gosub goes. But at least you know it +will in some way return to its caller. Otherwise.. it's a goto. + +In a vanilla functional event system, your application is defined +as an object with methods, one of which is something like "do" - +taking an event, returning a list of side effects and a new +application object. One such side effect, in any reasonably +complex system, is to post an event. Alas, this design - while +admirable on a small or simple scale - in bigger systems enters a +pathological mode in which events pile up in a sort of cascading +event ping-pong. + +This often even works. But as with the old BASIC gotos, when it +doesn't, it's rather hard to figure out why. So we need a gosub, +as it were. A structured event model. Slightly less simple than +nothing, but still not exactly rocket science. + +This is slightly simplified from the actual code, but Arvo's +structured event system is built around these models: + + ++ card (pair term noun) :: event data + ++ duct (list (pair role wire)) :: event source + ++ gift card :: out result <-$ + ++ kiss card :: in request ->$ + ++ mold :: general action + $% [%give (lone gift)] :: + [%pass (pair wire note)] :: + == :: + ++ move (pair duct mold) :: traced action + ++ note (pair term noun) :: out request $-> + ++ noun ,* :: any noun + ++ role ,@tasD :: role byte + ++ term ,@tas :: symbolic name + ++ span ,@ta :: wire segment + ++ sign (pair term noun) :: in result $<- + ++ wire (list span) :: logical location + +What the heck is this stuff? + +Think about a function call in a normal procedural language, +and its physical representation in a stack frame. Wallace +Stevens showed us 24 ways of seeing a blackbird, but there are +only four ways of seeing a stack frame. It can be (a) the +arguments as seen by the caller, (b) the arguments as seen by the +callee, (c) the return value as seen by the callee, (d) the +return value as seen by the caller. + +In Arvo terms, (a) is a `++note`, (b) is a `++kiss`, (c) is +a `++sign`, and (d) is a `++gift`. + +You'll see that `++note` and `++sign` have a different shape from +`++kiss` and `++gift`. The extra `++term` in a note or a sign +identifies the `++role` of the Arvo actor, or `vane`, that we're +calling to or returning from respectively. + + +### Vanes + +A vane is a stateful actor within the Arvo kernel. You are +writing user-level apps; you are not writing Arvo vanes. +But your apps use vane services, are hosted by a vane (`%gall`), +and most important - follow the same general design pattern. + +A vane's function is defined by its `role`, or interface +contract. Te role is a single letter which defines the vane's +interface, and matches the first letter of the module that +implements it - like `e` for `%eyre`, or `c` for `%clay`. + +Eg, `%eyre` (source in `/===/arvo/eyre/hoon`) is a concrete +implementation of the `%e` interface, ie, HTTP. If you change +`eyre.hoon`, `:reload %eyre` will install the new server. + +The vanes at present: + + %a %ames packet networking + %b %batz command line + %c %clay revision control + %d %dill console + %e %eyre HTTP + %f %ford functional construction + %g %gall user-level applications + + +### Vane arms + +An Arvo vane exports this basic interface (again, simplified for +educational purposes): + + |% + ++ call :: accept request + |= [hen=duct hic=kiss] + ^- [p=(list move) q=_+>] !! + :: + ++ take :: handle response + |= [hen=duct way=wire sih=sign] + ^- [p=(list move) q=_+>] !! + -- + +Whereas a hypothetical unstructured Arvo might look like: + + |% + ++ do + |= car=card + ^- [p=(list card) q=_+>] !! + -- + +The vane hears that something happened. It answers with `p`, a +list of more things to make happen, and `q`, the new itself. +This is simpler than Arvo; a `goto` is simpler than a `gosub`. + +In Arvo, your vane exports two gates: `++call` for when another +vane calls you, `++take` for when someone you called returns. + +The vane hears that *one of two* things happened. Either it got +a request (a kiss) or a response (a sign). There is no third +kind of a thing; there is no strange furry thing halfway between +a kiss and a sign. + +Note that `++call` and `++take` produce the same product. This +remains `p`, a list of more things to make happen, and `q`, the +vane's new value. + +But now there are *two* kinds of `++move`, a `%give` and a +`%pass`. If you suspect that `%give` means "return" and `%pass` +means "call", you may be beginning to understand Arvo. But +first, deeper into ducts. + +Arvo's structured events are the dual of procedure calls, but its +ducts are one phenomenon for which there is no exact equivalent +in any language we know. Most procedural languages (sadly) do +not even expose their call stacks as user-level data structures. +The duct is not the full call stack, but something like a call +stack in which each frame is just the procedure name. + +But this is an inexact and meretricious analogy. Let's look +concretely at how Arvo uses `%give` and `%pass` to build ducts. + + +### Ducts, events and types + +Before we continue, it's essential to confess our sins in the +oversimplified models above. + +In actual Arvo, there is no `++card` model at all, and each vane +has its own definition of `++gift`, `++kiss`, `++note`, `++move` +and `++sign`. `++mold` is parameterized for your convenience +(don't use `%slip` or `%sick`, please). + +Why do we have vanes, after all? So they don't have to include +each other. No two large systems can. Thus, it is very much our +desire not to tangle all our vanes together - like a previous +version of Arvo in which *all events were jammed together as a +single `++card` model*. There were almost 100 fronds in this +kelp, and it was just as heinous as it sounds. + +Rather, every vane uses the type system to formally define the +gifts and notes it produces, and the kisses and signs it accepts. +Moreover, Arvo dynamically compiles every event application, and +thus actually uses these types to typecheck its events. Event +data is never, ever de-typed and then re-rectified. Signs and +notes even need to match the roles they come from / go to. + +The downside of this is that it often makes sense to copy card +models from vane to vane, eg, from a service provider to a +service user. Programmers should not feel the slightest +discomfort at this duplication. Anyway, you only need to copy +the API tiles that you actually use. + + +### Duct examples + +A duct is a `(list wire)` in which each `++wire` represents the +*cause* of a a `++call` or `++take` action. The head of each +wire in the duct is a vane role, except for the bottom wire - +which is `%$`, for kisses from Unix to Arvo. + +The rest of the wire represents an abstract location or *place* +within the vane of that role. What does this "place" mean? It +depends on the vane. + +Consider, for instance, the bottom wire in every duct - the +original cause of this event, which is always something that +happened at the Unix layer. But Unix is not just one big blob. +For `%$` wires, the place is the Unix event channel - often +quite directly corresponding to a file descriptor. + +For example, HTTP requests come not from `/$`, and not even from +`/$/http/`, but from (for instance) `/$/http/0vh.ephnu/1/2`, +where `0vh.ephnu` uniquely identifies the current process's HTTP +server instance, `1` is its first connection, and `2` is that +connection's first request. If we reboot the `vere` process, we +know we broke all the sockets of `0vh.ephnu`, which is obvious to +Unix but has to be explained to Arvo. + +Ascending up in this same example, we see the deeper duct + + :~ /g/~zod/foobug/s/peer/~zod/goof + /e/hoop/~zod/pidtyl-danpur-dozted-micsed/1/frog + /$/http/0vh.ephnu/1/2 + == + +From the `/g` and `/e`, we know that the Unix event was sent +first to `%eyre` and then to `%gall`, ie, we seem to be talking +via HTTP to one of our applications. + + +### Duct assembly + +How do we construct ducts? Let's unroll the internal structure +of `++move`. A move is either + + [p=duct q=[%give p=card]] + +or + + [p=duct q=[%pass p=wire q=[p=role q=card]]] + +From this move, we know exactly how Arvo will use what vane. +Suppose `%ford` produces a `%give` move with the duct above, +and the card `[%test ~]`. Where `vay` is `%gall` (`/g`), Arvo +will compute + + (take:vay t.p t.i.p [%f p.q]) + +where `t.p`, the rest of the popped duct, is + + :~ /e/hoop/~zod/pidtyl-danpur-dozted-micsed/1/frog + /$/http/0vh.ephnu/1/2 + == + +`t.i.p` is the location, `/~zod/foobug/s/peer/~zod/goof`, +`%f` is the returning vane (`%ford`), and `p.q` is the result +that `%ford` wants to return to `%gall`. + +Suppose `%gall` wants to call back into `%ford` from exactly the +same location, with the same card. It must produce the move + + [t.p %pass /~zod/foobug/s/peer/~zod/goof %f [%test ~]] + +Where `vay` is `%ford`, Arvo will call + + (call:vay p [%test ~]) + +`p`, of course, being the original duct above. + + +### Duct semantics: independence principle + +Recall the question we asked originally: if we don't intend to +let the programmer use the data in the duct, why is it there? +If we do intend to let the programmer use it, isn't that a +mistake? Isn't there a contradiction here? This duct system +seems reasonably straightforward. But gosh, what is it *for*? + +We now have a concrete answer to what a vane can do with a duct. +The first principle of responsible duct ownership: *a vane is not +allowed to make ducts*. The only ducts a vane may produce are +those that Arvo has passed it. Only Arvo makes ducts - like the +government with dollars. + +The second principle of responsible duct ownership: event +computations must not depend on duct contents. Actually, it is +always wrong to peek into ducts. You can, but don't. + +Naturally, the Hoon type system cannot enforce these contracts. +We enforce the duct handling principles at the vane level by +noting that installing alternate vanes is like putting +aftermarket chips in your engine or overclocking your CPU. +Ma'am, we're sorry, but your warranty is void. + +At the user level (ie, within `%gall`) we enforce the opacity of +ducts by... hiding them behind an opaque atom, the `++bone`. +It is impossible to imagine the variety of "weird machines" that +a malicious actor could otherwise contrive. The wild maelstrom +of event `goto` hell is never far beneath the unrippled surface +of Arvo. + + +### Duct semantics: fool's mate + +One very easy mistake to make is to confuse the call stack of +Arvo itself with the duct. These are often logically aligned, +but by no means always so. + +Recall the vane arms: + + |% + ++ call :: accept request + |= [hen=duct hic=kiss] + ^- [p=(list move) q=_+>] !! + :: + ++ take :: handle response + |= [hen=duct way=wire sih=sign] + ^- [p=(list move) q=_+>] !! + -- + +Each of `++call` and `++take` has `hen=duct` in its sample. +Again, `hen` represents the *logical cause* of this event. + +And the product of each contains a list of `++move`, which as we +recall is (fully expanded): + + $? [p=duct q=[%give p=card]] + [p=duct q=[%pass p=wire q=[p=role q=card]]] + == + +The fool's mate of Arvo is the illusion that, for a call or take +with some `hen` in the sample, `p` in each product move must be +the same duct as that `hen`. Obviously, if this were the case, +`(list mold)` rather than `(list move)` would be the product. + +(Using procedural equivalence, we can see how this error aligns +with the Arvo call stack, or rather something like it. Imagine +if a vane, instead of producing a move when it wanted to "call" +another vane, ie `%pass` to it, actually called it. The call +stack (in this very impractical Arvo) would match the duct.) + +But of course, it is quite common for `p`, the move duct, to +equal `hen`, the event duct. This gives us two categories of +`++move`, for every event: *cis* moves, for moves where `=(p +hen)`, and `*trans*` moves, for everything else. + + +### Duct semantics: cis and trans + +The assembly example above contains only *cis* moves, which are +the typical pattern of a simple synchronous service. In a single +turn of the Arvo main event loop, our HTTP request bounces from +`%eyre` to `%gall` to `%ford` and back again; the request +produces its own response. + +In an asynchronous system like Urbit, synchronous *cis* services +remain the most common form of interaction. But Urbit would be +super boring if it didn't come with a big helping of *trans*. + +Suppose, for instance, we modify the above request pattern. +`%eyre` sends an application request to `%gall`, and `%gall` to +`%ford`, but `%ford` needs some global state not in its cache, +and has to consult `%clay`. `%clay` recognizes the path as a +foreign one and asks `%ames` to send a network request on its +behalf. When the state becomes available, the remote server uses +`%ames` to give a response message back to our `%clay` - which +gives a (confusingly named) `%writ` card back to `%ford`, etc. + +The asynchrony, the *trans* event, in this service path belongs +to `%ames`, because `%ames` matches the outgoing message with +the message response, and sends the response back on the incoming +duct. This process is rather less obvious than it may seem. + +To be exact: when `++call` asks `%ames` to send a message, the +only moves produced *in this event* are a list of packets heading +to the Ethernet port. (Even then, we hardly would send all our +little packetses off at once.) + +Rather, the actual, direct or *cis* cause of the `move` that +responds from `%ames` back to `%clay` is, of course, a packet +that `%ames` gets from the network. How does it get back to +`%clay`? + +Obviously, the outgoing-message `++call` (caused by `%clay`) must +*save* its `hen` duct somewhere in the bowls of %ames, mapped to +a message GUID. When an incoming-packet `++call`, some +milliseconds, seconds, or for that matter months later, produces +a message that decodes to a responding GUID, `%ames` will emit +moves that respond to the original `hen`. + +If we labor much over this concept, which may be seem stone cold +obvious, note that *trans* moves are obviously the converse of +the common CSP concept of blocking requests. (Exercise for the +undergraduate reader: what is the event converse of deadlock?) + + + +### The case against CSP + +Under various names, the war between events and CSP has been +going on at least as long as that between Chevy and Ford, +Makita and Husqvarna, or emacs and vi. + +As in each of these cases, it's quite simple. CSP sucks. It +belongs in a museum of the 20th century, next to T-tops, East +Germany and Windows 3.1. + +Evidence point: every time a platform exports native threads, +which actually have a scheduler like, you know, actual threads, +someone builds "green threads" on top of it - ie, nonpreemptive +threads. One common hint that something you're doing sucks: +every time you do it, someone comes along and feels the need to +do it over in the opposite way. + +Moreover, "nonpreemptive threads" are, with all due respect, a +contradiction in terms. Sirs, you are already halfway to the +devil! I know what's under your "nonpreemptive threads." It's an +event system, isn't it? What else could it be? + +If your underlying event system is of the `goto` school, sure, +it probably pays to keep it under a prophylactic layer. It would +be possible to use the usual functional techniques to make it +look very much like our message event above "blocked," like a +green thread. It would be not much more than a layer of +obscurity, though. Unnecessary layers are considered harmful. + +The case against CSP is that *the state of a CSP system is not +well-defined at any regular point in time*. Eg, there is +(generally) no systematic or well-defined way of stopping a CSP +process and saving it to a file, even with some loss of work. +Not, in any CSP system, that it's impossible to implement a +tool that does this - but that there is generally no +straightforward definition of intermediate state, and certainly +no mapping from any such abstraction to actual internal data. + +This is where a true event system, not even pretending to be a +CSP machine, shines. Not only is its state precisely defined +between events (and if you have to halt an event computer within +an event, you can just throw away the computation) - its *data is +not mixed up with code*. + +Passive data - Hoon nouns without cores in them - is vastly +preferable in almost every context to active data. For example, +it is always a mistake to send active data over the network - +where it is not actively impossible, it is actively idiotic. +Also, it's a relatively common operation to throw away all your +code, while keeping all your data. The more the two are mixed +together, the more fun it is untwingling them apart. + +Note that when `%ames` saves the duct it got from `++call`, +*it is not saving code*. It is not saving a callback, a closure, +a promise or even a continuation. (Uncharitable mockers may +recall the long-running struggle of HN, written in the CSP Lisp +Arc, to manage the limited pool of continuations mapped to URLs, +resulting in the dreaded "expired link" error. This is because a +continuation contains a stack and is more apt than not to be as +big as a bus.) + + +### The case against events + +Obviously, asynchronous events are the future. It's clear that +when the CSP dinosaurs are in the museum, it'll be the event +loops who *visit* that museum. Nonetheless, a few architectural +quirks are worth noticing. + +One of these is that *asynchronous systems have no flow control*, +and as a result *congestion control is an end-to-end problem*. + +Obviously, flow control makes no sense if you can't block a +process. Or rather, the only thing that makes sense is *logical* +flow control. Logical flow control is, always and everywhere, +congestion control. + +End-to-end congestion control is a somewhat harder problem than +classic congestion control. On the downside, E2ECC requires +actual, active compliance with CC logic not just in the stack, +but by the end application. Also, heuristics are considerably +more difficult, because the roundtrip time for a packet that +completes a message includes not just network latency, but also +computation latency for the whole transaction, from business +logic to disk - a metric with considerable variance. + +One mitigating factor: E2ECC is not really a hard problem for +apps to solve. The closer the programmer is to the endpoint, the +easier it is to behave in a sane way. For example, if an app (a) +obeys a simple request-response structure in which only one +request is outstanding at a time, and (b) the size of the +requests is sane, the behavior of the app is sane. + +The first law of E2ECC is: don't try to talk to people who aren't +talking back to you. The second law of E2ECC is: if it is +absolutely necessary to keep buttonholing people who are not +responding, give a neighbor a break and at least practice +exponential backoff. For instance, if my ship has been trying to +send a message to your ship for, say, a year, it is appropriate +for me to send you a packet again, say, every six hours. + +As for the CC algorithms, we are still screwing around... + +And of course, threads (real threads, anyway) excel when it's +time to go parallel. There is an event converse of explicit +parallelism: implicit parallelism. In which we cleverly figure +out that we can use physical parallelism to compute our event +function, which is serial, using these multiple cores. This does +not seem incredibly hard - given the high stability of said event +function, arbitrary amounts of tedious hardcoding become possible. + +## From Arvo to `%gall`, kernel to user. + +The structured event logic which connects the vanes is in fact +repeated at two other layers. At the bottom, the interface Arvo +presents to Unix (or whatever native OS) makes Arvo itself look +like one big vane. + +And on top, `%gall` treats the apps it runs like little vanes. +These analogies are highly imprecise and all details differ. +Even the arm names differ. + +But a vane in this more abstract sense is any object that can (a) +accept requests (`++call`) and handle responses (`++take`), +generating a list of actions (`++move`) and a new state; (b) +expose a namespace (`++scry`); (c) reboot itself safely (`++load` +and `++stay`). So long as you understand all these concepts, +you understand both kernel and user programming in Arvo. + + +## The goals of `%gall`. + +Broadly speaking, `%gall` has two goals: (a) let `%gall` +apps consume and provide kernel vane services; (b) let `%gall` +apps define an event arena, similar to that of kernel Arvo, but +between apps and across the network. + +Thus in (a) we talk to an inner ring, and in (b) we stay in the +outer ring. Applying our CSP metaphor, the good old "system +call" can be recognized in (a), though the system-call model does +not work so well if the kernel wants to call application +services; (b) is obviously some sort of RPC, or at least IPC. + +(The main challenge in `%gall` is maintaining type integrity +without revalidation (except of course for network data), for +both (a) and (b). Even with the tools Hoon provides, this is +difficult. The best way to understand how it works is to read +the code, especially `++song`.) + + +## Back to our application. + +We're now in a position to explain `++hide`, the standard state. + +This is the `%gall` equivalent of Unix's "u area": the kernel state +specific to your application. `%gall` resets the hide every time +it calls you. You can change it or not; `%gall` does not notice. + + + ++ hide :: standard app state + $: $: our=ship :: owner/operator + app=term :: application name + == :: + sup=(map bone (pair ship path)) :: subscription set + pus=(jug path bone) :: noitpircsbus set + $: act=@ud :: change number + eny=@uvI :: entropy + lat=@da :: date of last action + == == :: + +Let's run quickly through the meaning of these legs: + +`our.hid` is the host identity, ie, ~SHIP or `~tasfyn-partyv`. +`app.hid` is the formal name of the application, ie, APPL or +`%foobug`. `our` and `app` never change. + +`sup.hid` is a map from a communication channel, or `bone`, to a +user identity and a subscription path. `pus.hid` maps each path +back to a set of bones. This internal `%gall` state is also +useful to your app, as we'll see soon. otherwise get sweaty +maintaining it. + +`act.hid` is the change number - ie, the number of times the +application's state (ie, `vat`) has changed in any way. +`lat.hid` is the date of the last change. `eny.hid` is at least +256 bits of entropy, not detectably reused after this +construction. + +`vat` is your application state. Your goal and ours is to +serve, preserve and improve it. `foobug` has nothing in +there right now, of course, but watch out! + + +## The application core. + +Your job as a programmer is to (a) define the `vat`, ie, your +state, and fill in the various arms of the core. + +Because `%gall` uses dynamic compilation on your core, there is +no strict tile that it has to match. In fact, %gall can even +decide how to call you based on what arms your core exports, a +very un-Hoon-like reflexive behavior. + +Below you'll find definitions of each standard arm. For your +convenience, they all have four letters and start with `p`. + + +## Application gates: `++peek`. + +`++peek` is the one gate in Foobug so far. Abstractly: + + ++ peek + |= [you=ship pax=path] + ^- [mark noun] !! + +## Example: `++peek`. + +A `noun` in our abstract arm definitions doesn't mean we don't +use the type system - it means each app uses it differently. +For instance, as we wrote above: + + ++ peek + |= [you=ship pax=path] + ^- [mark manx] + :- %hymn + ;html + ;title: Foobug! + ;body + ;p: Hello, world. + == + == + +`++peek` is simply a view function. `you` is the user doing +the viewing, and `pax` is a path which represents what she's +looking at. + +In the example so far, we ignore both `pax` and `you`. Actually, +The uses you make of `you` and `pax` are entirely up to you. +Broadly speaking, `pax` represents a path, place, channel, +folder, or other subcontext within your application. + +But what does `++peek` produce? A... `[mark manx]`? Alas, this +requires another small digression. + + +## Content types and XML; ++mark and ++manx. + +In `foobug`, the product of `++peek` is a cell `[mark manx]`: + + ++ mark term :: content type + ++ manx $|(@tas [t=marx c=marl]) :: XML node + ++ mane $|(@tas [@tas @tas]) :: XML name/space + ++ manx $|(@tas [t=marx c=marl]) :: XML node + ++ marl (list manx) :: XML node list + ++ mars ,[t=[n=%$ a=[i=[n=%$ v=tape] t=~]] c=~] :: XML cdata + ++ mart (list ,[n=mane v=tape]) :: XML attributes + ++ marx $|(@tas [n=mane a=mart]) :: XML tag + +`++manx` is not of course a complete and perfect representation +of XML. But in most cases, it will do. Sorry, XML. + +`++mark` is a *mark*, or simplified content type. We ditch the +elaborate and bizarre hierarchical scheme of MIME, and stick with +a flat terminal that in general should equal the Unix file +extension. `Marks` can also be called `protocols`, as they are +formats for typed data being sent over the network. + +Our marks here is `%hymn`, which is logically an HTML noun. +Right now the `%hymn` mark is just an arbitrary `manx`, though it +really should reflect the DTD to at least some level. + +(It is important to recognize that although we can and do +construct both a rectifier and a type (the type being just the +range of the rectifier) for any working mark, the type is often +more general than the marks. It is ideal for them to match +exactly. But while every noun within the marks must be within +the type, not every noun within the type is within the marks - +just as not every valid `++manx` is a proper HTML5 noun.) + +One useful service that the build vane, `%ford`, provides: +automatic rectification (conversion of untyped to typed nouns) of +marks, and automatic translation between them. + +For instance, your browser showed you "Hello, world" as the +above. This came across as an HTTP, ie MIME, response. We had +to translate %hymn into (flat textual) %html, then %html to +%mime. All of these are trivial translations, which makes their +implementations ideal for educational purposes: + + ~/=main=/sys/hymn/ref/gate/hoon + ~/=main=/sys/hymn/tan/html/gate/hoon + ~/=main=/sys/html/ref/gate/hoon + ~/=main=/sys/html/tan/mime/gate/hoon + ~/=main=/sys/mime/ref/gate/hoon + +As for the Hoon syntax used to build HTML (or any XML, although +Hoon interpolation is disabled for the special cases of +`