on master help sign in
1067 files changed+60665−65819
since splitsnapshots
unifiedsplit
.gitignore+45−3 .gitmodules−3 .npmrc+1 .nvmrc+1 .prettierrc+5 README.markdown−3 README.md+58 _index.md−35 arvo/_index.md−113 arvo/ames.md−1938 arvo/behn.md−20 arvo/clay.md−2626 arvo/dill.md−24 arvo/eyre.md−717 arvo/ford.md−571 arvo/gall.md−2318 arvo/glossary.md−850 arvo/hall.md−1335 arvo/sail-and-udon.md−1234 arvo/ship-troubleshooting.md−174 azimuth/_index.md−5 azimuth/azimuth.md−12 azimuth/creating-an-invite-pool.md−41 azimuth/glossary.md−118 components/BackgroundImage.js+9 components/BasicPage.js+46 components/Contact.js+16 components/ContentArea.js+86 components/CopyLink.js+61 components/DocsSidebar.js+32 components/EventPreview.js+92 components/Footer.js+6 components/GrantPreview.js+63 components/GrantProgramOverview.js+59 components/Header.js+169 components/HighlightCard.js+22 components/JoinGroup.js+79 components/Meta.js+54 components/NewsletterSignup.js+38 components/Pagination.js+22 components/PostPreview.js+27 components/Sidebar.js+21 components/Snippets.js+111 components/TabCarousel.js+9 components/ecosystem/Badge.js+20 components/ecosystem/BasicPage.js+146 components/ecosystem/EcosystemSidebar.js+86 components/ecosystem/IndexCard.js+34 components/ecosystem/MetadataBlock.js+7 components/ecosystem/Post.js+107 components/ecosystem/SpotlightArchive.js+66 components/gateway/Description.js+19 components/gateway/Gateway404.js+29 components/gateway/GatewayHeader.js+29 components/gateway/Image.js+62 components/gateway/MetadataBlock.js+8 components/gateway/MetadataLink.js+14 components/gateway/ResourceCard.js+24 components/icons/Cross.js+11 components/index/BubbleLink.js+25 content/applications/_index.md+3 content/applications/~bacwyl-samweg/templeochess.md+22 content/applications/~datder-sonnet/hodl.md+16 content/applications/~disreb-winner-mittec/urbit-go.md+12 content/applications/~dister-dister-datryn-ribdun/campfire.md+12 content/applications/~dister-dister-sidnym-ladrut/quorum.md+17 content/applications/~dister-dozzod-bacdun/uqbar-suite.md+20 content/applications/~dister-dozzod-dalten/books.md+20 content/applications/~dister-dozzod-dalten/gora.md+24 content/applications/~dister-dozzod-dalten/keep.md+13 content/applications/~dister-dozzod-dalten/orca.md+17 content/applications/~dister-dozzod-dalten/peat.md+36 content/applications/~dister-dozzod-dalten/wrdu.md+15 content/applications/~donpub-datdux/forms.md+14 content/applications/~fabnev-hinmur/escape.md+16 content/applications/~fabnev-hinmur/handshake.md+14 content/applications/~finmep-lanteb/chess.md+14 content/applications/~haddef-sigwen/transit.md+14 content/applications/~hanfel-dovned/board.md+14 content/applications/~hanfel-dovned/pony.md+12 content/applications/~hanfel-dovned/slam.md+14 content/applications/~hanrut-sillet-dachus-tiprel/blog.md+16 content/applications/~larryx-woldyr/osmosis.md+12 content/applications/~larryx-woldyr/safe.md+12 content/applications/~larryx-woldyr/uniswap.md+12 content/applications/~larryx-woldyr/urbhue.md+18 content/applications/~lomder-librun/ballot.md+14 content/applications/~lomder-librun/realm.md+18 content/applications/~midlev-mindyr/astrolabe.md+30 content/applications/~midsum-salrux/faux.md+11 content/applications/~migmeg-fidlen-sillus-mallus/kenning.md+17 content/applications/~mister-dister-dozzod-dozzod/terminal.md+14 content/applications/~niblyx-malnus/gol-cli.md+15 content/applications/~nocsyx-lassul/silo.md+20 content/applications/~nocsyx-lassul/sphinx.md+20 content/applications/~nodmyn-dosrux/basket.md+34 content/applications/~nodmyn-dosrux/houston.md+17 content/applications/~nodmyn-dosrux/radio.md+15 content/applications/~nodmyn-dosrux/vita.md+20 content/applications/~norsyr-torryn/canvas.md+29 content/applications/~paldev/face.md+13 content/applications/~paldev/fafa.md+14 content/applications/~paldev/pals.md+15 content/applications/~paldev/picture.md+13 content/applications/~paldev/rumors.md+15 content/applications/~paldev/scooore.md+14 content/applications/~paldev/verse.md+13 content/applications/~pocwet/docs.md+17 content/applications/~pocwet/straw.md+13 content/applications/~ribben-donnyl/funes-notes.md+15 content/applications/~sitden-sonnet/channel.md+20 content/applications/~sogryp-dister-dozzod-dozzod/groups.md+40 content/applications/~sogryp-dister-dozzod-dozzod/talk.md+21 content/applications/~sortug/gate.md+27 content/applications/~sortug/trill.md+27 content/applications/~sortug/ufa.md+27 content/applications/~tiller-tolbus/membrane.md+14 content/applications/~tirrel/scene.md+14 content/applications/~tirrel/studio.md+21 content/applications/~worpet-bildet/portal.md+16 content/apprenticeships.md+38 content/articles/2022-09-24_urbit-courts-daos-crypto.md+10 content/articles/2022-09-24_urbit-is-web3-weird-and-wonderful.md+10 content/articles/2022-09-28_college-course-on-urbit.md+10 content/articles/2022-09-29_assembly-miami-dispatch.md+11 content/articles/2022-09-29_the-dream-of-digital-homesteading.md+10 content/articles/2022-10-04_a-more-beautiful-computer.md+11 content/articles/2022-10-13_my-weekend-with-the-martians.md+10 content/articles/2022-10-23_three-things.md+10 content/articles/2023-02-20_trailblazing-urbit-startup-makes-earth-shaking-acquisition.md+10 content/articles/2023-05-10_urbit-a-network-older-and-weirder-than-bitcoin.md+10 content/audits.md+22 content/bitcoin-wallet.md+60 content/bitcoin.md+125 content/blog/2019-10-3-roadmap.md+112 content/blog/2019-5-roadmap.md+103 content/blog/2020-to-2021.md+45 content/blog/20200929-state-of-urbit.md+72 content/blog/20201119-models-of-society.md+65 content/blog/2021-11-18-report-from-the-field.md+94 content/blog/2021-11-18-the-promise-and-paradox-of-decentralization.md+55 content/blog/a-founders-farewell.md+619 content/blog/a-topiary.md+38 content/blog/aesthetic-culture-1.md+103 content/blog/after-machine-war.md+40 content/blog/agency-daos.md+110 content/blog/an-email.md+84 content/blog/an-urbit-overview.md+215 content/blog/announcing-urbit-grants.md+49 content/blog/ares.md+51 content/blog/august-2022-grants-program.md+73 content/blog/azimuth-as-multipass.md+34 content/blog/azimuth-is-on-chain.md+107 content/blog/azimuth-security-bounty-program.md+40 content/blog/beliefs-and-principles.md+134 content/blog/bootstrapping-urbit-from-ethereum.md+394 content/blog/common-objections-to-urbit.md+725 content/blog/community-spotlight-the-portico.md+138 content/blog/convivial-networks.md+27 content/blog/creating-sigils.md+172 content/blog/desire-lines.md+35 content/blog/eliza.md+46 content/blog/events-series.md+53 content/blog/first-contract.md+289 content/blog/first-steps-towards-urbit-org.md+52 content/blog/ford-fusion.md+222 content/blog/foss-1.md+64 content/blog/foss-2.md+59 content/blog/gifts-q3-2020.md+72 content/blog/governance-of-urbit.md+43 content/blog/hackathon-results.md+59 content/blog/haleek-maul-interview.md+71 content/blog/hoon-4-lispers.md+764 content/blog/hosting-the-future.md+30 content/blog/immunology-for-the-internet-age.md+118 content/blog/infrastructural.md+73 content/blog/interim-constitution.md+145 content/blog/interplanetary_commerce.md+37 content/blog/introducing-os1.md+140 content/blog/introduction-to-the-combine-dao.md+46 content/blog/io-in-hoon.md+342 content/blog/iot.md+445 content/blog/landscape-a-portrait.md+89 content/blog/layer-2-faq.md+155 content/blog/magic.md+205 content/blog/metaphase.md+79 content/blog/on-christopher-alexander.md+70 content/blog/pin-the-face-that-launches-a-thousand-ships.md+146 content/blog/pki-maze.md+70 content/blog/platform-decay.md+50 content/blog/precepts-discussion.md+756 content/blog/precepts.md+341 content/blog/providers.md+82 content/blog/pseudonymous-reputation.md+64 content/blog/rollups.md+222 content/blog/security-and-continuity.md+60 content/blog/security-audit.md+153 content/blog/simple-durable-yours.md+48 content/blog/smart-home-of-the-future.md+60 content/blog/stable-arvo.md+93 content/blog/state-of-urbit.md+95 content/blog/the-100-year-computer.md+30 content/blog/the-dao-as-a-lesson-in-decentralized-governance.md+327 content/blog/the-missing-middle.md+50 content/blog/the-shape-of-dao-governance-to-come.md+103 content/blog/the-state-of-landscape.md+78 content/blog/the-understanding-urbit-podcast.md+22 content/blog/the-urbit-address-space.md+299 content/blog/tools-of-our-own.md+66 content/blog/toward-a-frozen-operating-system.md+260 content/blog/toward-a-new-clay.md+1012 content/blog/urbit-and-bitcoin.md+21 content/blog/urbit-and-the-blockchain.md+272 content/blog/urbit-creator-daos.md+74 content/blog/urbit-for-creators.md+47 content/blog/urbit-for-normies.md+175 content/blog/urbit-grants-and-mid-2019-gifts.md+49 content/blog/urbit-is-for-communities.md+92 content/blog/urbithost-interview.md+116 content/blog/using-urbit-in-2023.md+55 content/blog/value-of-address-space-pt1.md+144 content/blog/value-of-address-space-pt2.md+141 content/blog/value-of-address-space-pt3.md+117 content/blog/what-is-urbit-for.md+196 content/blog/why-hoon.md+274 content/blog/why-urbit-probably-does-not-need-a-blockchain.md+623 content/blog/your-last-computer.md+36 content/bounties.md+54 content/campus/_index.md+37 content/campus/blockchain-enthusiasts.md+35 content/campus/creatives.md+21 content/coinmarketcap.md+8 content/communities/urbit-austin.md+11 content/communities/urbit-berlin.md+16 content/communities/urbit-christchurch.md+13 content/communities/urbit-cph.md+11 content/communities/urbit-dc.md+19 content/communities/urbit-denver.md+19 content/communities/urbit-london.md+15 content/communities/urbit-mst.md+13 content/communities/urbit-ny.md+11 content/communities/urbit-paris.md+23 content/communities/urbit-seattle.md+14 content/communities/urbit-sf.md+15 content/ecosystem/spotlight/2022-august.md+44 content/ecosystem/spotlight/2022-december.md+40 content/ecosystem/spotlight/2022-november.md+42 content/ecosystem/spotlight/2022-october.md+41 content/ecosystem/spotlight/2022-september.md+45 content/ecosystem/spotlight/2023-february.md+48 content/ecosystem/spotlight/2023-june.md+40 content/ecosystem/spotlight/2023-may.md+50 content/events/2017-08-11-after-hours-bootstrapping-urbit-from-the-ethereum-blockchain.md+21 content/events/2017-09-22-after-hours-fun-with-arvo-the-urbit-os.md+20 content/events/2017-10-26-after-hours-designing-robust-human-systems.md+20 content/events/2017-11-16-after-hours-visiting-contributors.md+17 content/events/2018-01-26-urbit-irl-20181.md+18 content/events/2018-02-23-urbit-irl-20182.md+18 content/events/2018-03-11-20183-hoon-school.md+16 content/events/2018-03-23-urbit-irl-20183.md+18 content/events/2018-04-08-20184-hoon-school.md+16 content/events/2018-05-25-urbit-irl-20185.md+18 content/events/2018-08-03-after-hours-decentralized-web-summit.md+14 content/events/2018-08-17-urbit-irl-20188.md+20 content/events/2018-09-21-urbit-irl-20189.md+18 content/events/2018-10-10-urbit-zcash-blockchain-week.md+24 content/events/2018-12-20-after-hours-its-just-a-party-man.md+18 content/events/2019-03-01-after-hours-ask-galen-anything.md+20 content/events/2019-03-08-urbit-irl-austin-tx.md+16 content/events/2019-04-19-urbit-irl-20194.md+20 content/events/2019-05-17-urbit-irl-20195.md+18 content/events/2019-06-21-urbit-irl-20196.md+18 content/events/2019-07-19-urbit-irl-20197.md+20 content/events/2019-08-29-urbit-austin-20198.md+18 content/events/2019-10-04-urbit-irl-201910.md+20 content/events/2019-11-15-urbit-irl-201911.md+20 content/events/2019-12-13-urbit-irl-201912.md+28 content/events/2020-01-24-urbit-irl-20201.md+24 content/events/2020-02-28-urbit-irl-20202.md+22 content/events/2020-04-03-urbit-os1-launch-party.md+49 content/events/2020-10-09-urbit-hosting-launch-event.md+38 content/events/2020-11-05-developer-call-graph-store.md+24 content/events/2020-11-19-developer-call-bittorrent-tracking-on-urbit.md+22 content/events/2020-12-10-developer-call-injecting-external-services-into-urbit.md+24 content/events/2021-02-04-developer-call-architectural-idea-maze.md+23 content/events/2021-03-04-developer-call-scaling-azimuth.md+25 content/events/2021-03-18-developer-call-pressure-and-protolith.md+25 content/events/2021-04-01-developer-call-javascript-apps-on-urbit.md+25 content/events/2021-04-15-developer-call-software-distribution.md+34 content/events/2021-04-27-bitcoin-launch.md+27 content/events/2021-04-29-developer-call-real-time-communications-on-urbit.md+30 content/events/2021-05-13-developer-call-versioned-networking.md+26 content/events/2021-05-27-town-hall.md+54 content/events/2021-07-01-developer-call-runtime-future.md+25 content/events/2021-07-15-developer-call-yakshaving.md+25 content/events/2021-09-02-21q3-dc-meetup.md+22 content/events/2021-09-16-developer-call-azimuth-scaled.md+46 content/events/2021-09-24-urbit-outside.md+23 content/events/2021-10-07-developer-call-visor.md+38 content/events/2021-10-15-assembly.md+26 content/events/2021-10-16-assembly-keynote.md+14 content/events/2021-10-16-assembly-sw-dist-qa.md+14 content/events/2021-10-28-developer-call-hosting.md+33 content/events/2021-11-26-meetup-brisbane.md+30 content/events/2022-01-21-meetup-austin.md+16 content/events/2022-02-17-developer-call-building-developers.md+27 content/events/2022-03-24-developer-call-urbit-three-ways-with-quartus.md+26 content/events/2022-04-05-urbit-meetup-stockholm.md+30 content/events/2022-04-21-developer-call-uqbar-and-urbits-first-blockchain.md+24 content/events/2022-04-26-urbit-foundation-meetup-kingsnight-amsterdam.md+23 content/events/2022-05-06-urbit-weekend-kansas.md+20 content/events/2022-06-16-developer-call-urbits-new-terminal-stack-tlon copy.md+23 content/events/2022-06-16-developer-call-urbits-new-terminal-stack-tlon.md+24 content/events/2022-07-07-hackathon-hackfs.md+18 content/events/2022-07-08-urbit-fireside-chat-1.md+19 content/events/2022-07-21-developer-holium-community-os.md+25 content/events/2022-07-21-ethcc-paris-22-meetup.md+21 content/events/2022-07-22-urbit-outside-alta-plaza.md+22 content/events/2022-07-28-urbit-meetup-milano-22.md+22 content/events/2022-08-04-reassembly.md+31 content/events/2022-08-12-urbit-fireside-chat-2.md+20 content/events/2022-08-27-urbit-outside-alta-plaza.md+17 content/events/2022-09-08-developer-call-future-of-khan.md+25 content/events/2022-09-15-developer-call-IoT.md+27 content/events/2022-09-19-rabbit-hole-talk.md+19 content/events/2022-09-22-assembly.md+14 content/events/2022-10-13-devcon-bogotá-urbit-meetup-22.md+36 content/events/2022-11-01-developer-week.md+75 content/events/2022-11-19-urbit-irl.md+18 content/events/2022-19-10-developer-call-herd-dependency.md+25 content/events/2023-01-28-urbit-meetup-christchurch.md+21 content/events/2023-01-31-urbit-meetup-krakow.md+26 content/events/2023-02-23-urbit-meetup-berlin.md+27 content/events/2023-03-05-meetup-el-salvador.md+24 content/events/2023-03-25-urbit-meetup-christchurch.md+21 content/events/2023-04-18-urbit-lisbon.md+19 content/events/2023-04-27-urbit-meetup-berlin.md+27 content/events/2023-04-27_urbit-austin-meetup-consensus.md+16 content/events/2023-05-10_urbit-meetup-berlin.md+25 content/events/2023-05-14_urbit-meetup-london.md+23 content/events/2023-05-18_urbit-denver-meetup.md+19 content/events/2023-05-18_urbit-miami-meetup.md+20 content/events/2023-05-27_urbit-meetup-london.md+21 content/events/2023-05-27_urbit-meetup-mst.md+20 content/events/2023-06-03-urbit-meetup-christchurch.md+24 content/events/2023-06-08_urbit-meetup-berlin.md+25 content/events/2023-06-08_urbit-meetup-prague.md+39 content/events/2023-06-12-developer-week.md+95 content/events/2023-06-15_urbit-denver-meetup.md+19 content/events/2023-06-24-urbit-meetup-christchurch.md+24 content/events/2023-06-29-Urbit-Paris-Meetup-1.md+30 content/events/2023-07-01_urbit-meetup-mst.md+23 content/events/2023-07-20-Urbit-Paris-Meetup-ethcc.md+53 content/events/2023-08-16_reassembly.md+22 content/events/2023-10-28_urbit-assembly-lisboa.md+24 content/faq.md+267 content/fora.md+11 content/getting-started/_index.md+28 content/getting-started/cli.md+290 content/getting-started/cloud-hosting.md+468 content/getting-started/desktop.md+11 content/getting-started/get-id.md+113 content/getting-started/getting-around.md+55 content/getting-started/home-servers.md+27 content/getting-started/hosted.md+30 content/getting-started/hosting-providers.md+24 content/getting-started/installing-applications.md+39 content/getting-started/interfaces.md+10 content/getting-started/joining-groups.md+54 content/getting-started/self-host.md+33 content/gifts/sample.md+6 content/grants/2019/bitcoin-node-json-rpc-api-part-1.md+54 content/grants/2019/bitcoin-node-json-rpc-api-part-2.md+54 content/grants/2019/bitcoin-node-json-rpc-api-part-3.md+54 content/grants/2019/bitcoin-node-json-rpc-api-part-4.md+54 content/grants/2019/bitcoin-wallet-on-bridge.md+62 content/grants/2019/escape.md+46 content/grants/2019/gall-api-documentation.md+53 content/grants/2019/host-two-urbit-meetups-1.md+62 content/grants/2019/host-two-urbit-meetups-10.md+62 content/grants/2019/host-two-urbit-meetups-2.md+62 content/grants/2019/host-two-urbit-meetups-3.md+62 content/grants/2019/host-two-urbit-meetups-4.md+62 content/grants/2019/host-two-urbit-meetups-5.md+62 content/grants/2019/host-two-urbit-meetups-6.md+62 content/grants/2019/host-two-urbit-meetups-7.md+62 content/grants/2019/host-two-urbit-meetups-8.md+62 content/grants/2019/host-two-urbit-meetups-9.md+62 content/grants/2019/ragnarok-online-on-urbit.md+53 content/grants/2019/udon-syntax-highlighter.md+43 content/grants/2019/unit-tests-for-json-parsing.md+49 content/grants/2019/unit-tests-for-pure-algorithms.md+60 content/grants/2019/unit-tests-for-sha-functions.md+50 content/grants/2019/unit-tests-for-zuse-cryptographic-functions.md+52 content/grants/2020/a-book-about-urbit.md+84 content/grants/2020/a-network-enabled-spatial-database-and-demonstration-app.md+94 content/grants/2020/antechamber.md+106 content/grants/2020/art-by-urbit.md+31 content/grants/2020/bart-train-tracker-landscape-tile.md+50 content/grants/2020/bitcoin-full-node-provider-and-wallet.md+102 content/grants/2020/bitcoin-key-derivation.md+66 content/grants/2020/boston-t-train-tracker-landscape-tile.md+53 content/grants/2020/calendar-ui.md+55 content/grants/2020/calendar.md+115 content/grants/2020/content-saver.md+44 content/grants/2020/cta-train-tracker-landscape-tile.md+52 content/grants/2020/display-eth-data.md+55 content/grants/2020/docker-image-for-cloud-container-orchestration.md+49 content/grants/2020/ethereum-abi-parser.md+56 content/grants/2020/go-airlock-library.md+44 content/grants/2020/haskell-airlock-library.md+43 content/grants/2020/hoon-001-learner-efficiency-and-early-learner-resources.md+78 content/grants/2020/host-three-college-university-urbit-meetups-1.md+67 content/grants/2020/host-three-college-university-urbit-meetups-2.md+67 content/grants/2020/host-three-college-university-urbit-meetups-3.md+67 content/grants/2020/host-three-virtual-urbit-meetups.md+52 content/grants/2020/links-in-urbit-reference-docs.md+31 content/grants/2020/llelogram.md+55 content/grants/2020/matrices-in-hoon.md+58 content/grants/2020/matrixriotim-bridge-bot.md+42 content/grants/2020/open-street-maps-data-importation.md+52 content/grants/2020/staff-the-urbit-help-desk-1.md+64 content/grants/2020/staff-the-urbit-help-desk-2.md+64 content/grants/2020/staff-the-urbit-helpdesk-west.md+58 content/grants/2020/the-complete-guide-to-gall-and-landscape.md+85 content/grants/2020/tor-nodes-relay-search-tile.md+45 content/grants/2020/typescript-airlock-library.md+43 content/grants/2020/up-to-date-hoon-reference-card.md+30 content/grants/2020/urbian-a-customized-linux-distribution-for-urbit-appliances.md+88 content/grants/2020/urbit-event-series.md+92 content/grants/2020/urbit-explainer-video.md+35 content/grants/2020/urbit-http-api-for-kotlin.md+37 content/grants/2020/urbit-http-api-for-rust.md+55 content/grants/2020/urbit-http-interface-java-edition.md+66 content/grants/2020/urbit-http-library-for-ruby.md+42 content/grants/2020/urbit-online-meetup.md+30 content/grants/2020/urbit-ship-and-star-hosting-and-troubleshooting-docs.md+38 content/grants/2020/verifying-urbit-id-on-keybase.md+76 content/grants/2020/web-scraper.md+45 content/grants/2021/analytics-script.md+54 content/grants/2021/authenticate-with-urbit.md+36 content/grants/2021/azimuth-cli.md+164 content/grants/2021/bitcoin-wallet-maintenance.md+65 content/grants/2021/bridge-l2-revamp.md+57 content/grants/2021/clojure-urbit-client.md+113 content/grants/2021/comprehensive-local-server-and-mum-explanation-video.md+45 content/grants/2021/contacts.md+37 content/grants/2021/content-producer.md+40 content/grants/2021/cross-platform-desktop-urbit-app.md+96 content/grants/2021/cypherscope-bot.md+80 content/grants/2021/educational-guide-todomvc-urbit-edition.md+332 content/grants/2021/feed-aggregator.md+103 content/grants/2021/graph-store-documentation-guide.md+115 content/grants/2021/guide-to-s3.md+35 content/grants/2021/host-two-urbit-meetups-11.md+62 content/grants/2021/host-two-urbit-meetups-12.md+58 content/grants/2021/host-two-urbit-meetups-13.md+59 content/grants/2021/host-two-urbit-meetups-14.md+59 content/grants/2021/host-two-urbit-meetups-15.md+59 content/grants/2021/host-two-urbit-meetups-16.md+59 content/grants/2021/json-jet.md+51 content/grants/2021/login-with-urbit.md+84 content/grants/2021/machine-learning.md+122 content/grants/2021/market-interface.md+62 content/grants/2021/meetup-bom.md+118 content/grants/2021/minimal-urbit-os.md+58 content/grants/2021/native-urbit.md+30 content/grants/2021/network-explorer-data-pipeline-http-api.md+234 content/grants/2021/nuck-jet.md+59 content/grants/2021/overhaul-the-urbitorg-website.md+74 content/grants/2021/planet-sales.md+66 content/grants/2021/pokur.md+90 content/grants/2021/ra-debugging-tools.md+26 content/grants/2021/ra-page-tracking.md+34 content/grants/2021/ra-segfaults.md+32 content/grants/2021/ra-stack-overflow.md+32 content/grants/2021/search-in-groups.md+42 content/grants/2021/send-emails-to-a-mailing-list.md+78 content/grants/2021/smol-future-sustained-knowledge-sharing-and-marketing.md+97 content/grants/2021/speech-recognition.md+78 content/grants/2021/staff-the-urbit-helpdesk-east.md+58 content/grants/2021/static-site-generation.md+80 content/grants/2021/thread-documentation.md+85 content/grants/2021/translate-key-parts-of-urbitorg-into-german.md+31 content/grants/2021/translate-key-parts-of-urbitorg-into-korean.md+31 content/grants/2021/translate-key-parts-of-urbitorg-into-norwegian.md+32 content/grants/2021/translate-key-parts-of-urbitorg-into-spanish.md+31 content/grants/2021/try-urbit-website.md+33 content/grants/2021/twitter-uv-extension.md+67 content/grants/2021/ua-collaborative-text-editor.md+31 content/grants/2021/ua-filesharer.md+30 content/grants/2021/ua-heads-up-poker.md+35 content/grants/2021/ua-invoice-system.md+35 content/grants/2021/ua-marketplace.md+36 content/grants/2021/ucal-google-and-outlook-integration.md+85 content/grants/2021/urbit-api-for-elixir.md+38 content/grants/2021/urbit-community-concierge-east-coast-2q2021.md+36 content/grants/2021/urbit-community-concierge-east-coast.md+36 content/grants/2021/urbit-community-concierge-west-coast-2q2021.md+36 content/grants/2021/urbit-community-concierge-west-coast.md+36 content/grants/2021/urbit-http-api-for-emacs-elisp.md+39 content/grants/2021/urbit-http-api-for-python.md+46 content/grants/2021/urbit-irc-bridge.md+49 content/grants/2021/urbit-lfs-filehosting.md+68 content/grants/2021/urbit-notes.md+102 content/grants/2021/urbit-react-cookbook.md+47 content/grants/2021/uturn.md+38 content/grants/2021/uv-extension-library.md+44 content/grants/2021/video-content-manager.md+61 content/grants/2021/volt-lightning-on-urbit.md+313 content/grants/2021/webrtc-gall-agent-and-external-app.md+81 content/grants/2021/~home-urbit.md+119 content/grants/2022/abacus.md+56 content/grants/2022/app-engram.md+117 content/grants/2022/app-openbsd.md+53 content/grants/2022/app-store.md+159 content/grants/2022/app-urvault.md+41 content/grants/2022/app-uv-native-notificatons.md+42 content/grants/2022/apprenticeship-extending-bitcoin.md+76 content/grants/2022/apprenticeship-studio-collections.md+55 content/grants/2022/apprenticeship-studio-email.md+40 content/grants/2022/astrolabe.md+165 content/grants/2022/books-development.md+44 content/grants/2022/books.md+116 content/grants/2022/calendar-holium.md+53 content/grants/2022/chess-bounty.md+54 content/grants/2022/chronicle.md+63 content/grants/2022/communal-computing.md+130 content/grants/2022/cue.md+60 content/grants/2022/desk-import-export.md+102 content/grants/2022/digital-editor-MROB.md+50 content/grants/2022/digital-storefront.md+73 content/grants/2022/dusko-valve.md+81 content/grants/2022/eth-provider.md+65 content/grants/2022/eth-wallet.md+49 content/grants/2022/eyre-scry.md+72 content/grants/2022/faux.md+58 content/grants/2022/filesharer.md+100 content/grants/2022/full-stop.md+131 content/grants/2022/gather.md+87 content/grants/2022/general-web-permissions.md+36 content/grants/2022/gnosis-safe.md+56 content/grants/2022/go-urbit.md+64 content/grants/2022/gora-apprentice.md+61 content/grants/2022/herd.md+58 content/grants/2022/hoon-eval.md+56 content/grants/2022/hoon-markdown-library.md+52 content/grants/2022/http-server-driver.md+98 content/grants/2022/keep.md+119 content/grants/2022/knox.md+81 content/grants/2022/lexicon.md+69 content/grants/2022/lightning-development.md+201 content/grants/2022/loom-pointer-compression.md+62 content/grants/2022/meld-memory.md+55 content/grants/2022/membrane.md+98 content/grants/2022/middleware-apprentice.md+55 content/grants/2022/minesweeper.md+48 content/grants/2022/native-planet-2.md+90 content/grants/2022/nested-goals.md+162 content/grants/2022/notifications-protocol.md+64 content/grants/2022/olif.md+97 content/grants/2022/peat.md+66 content/grants/2022/persistent-memory.md+157 content/grants/2022/plug.md+165 content/grants/2022/pony-bounty.md+72 content/grants/2022/port-maintenance.md+72 content/grants/2022/port-to-hosting.md+56 content/grants/2022/profiling.md+74 content/grants/2022/qr-login.md+48 content/grants/2022/quorum.md+106 content/grants/2022/regex-library.md+114 content/grants/2022/seguro-phase-2.md+190 content/grants/2022/seguro-prototype.md+66 content/grants/2022/serving-the-people.md+101 content/grants/2022/slam.md+113 content/grants/2022/slaw-scot-jets.md+72 content/grants/2022/smart-lightbulb-controller.md+104 content/grants/2022/symmetric-routing.md+69 content/grants/2022/trail.md+168 content/grants/2022/trill-ufa.md+67 content/grants/2022/trove.md+94 content/grants/2022/urbit-forms.md+250 content/grants/2022/urbit-interface-framework.md+88 content/grants/2022/urbitswap.md+59 content/grants/2022/value-articles.md+54 content/grants/2022/volt-ui.md+54 content/grants/2022/whom.md+70 content/grants/2023/aera.md+50 content/grants/2023/app-metrics.md+74 content/grants/2023/blog-updates.md+64 content/grants/2023/bridge-grab-bag.md+35 content/grants/2023/community-meetups.md+37 content/grants/2023/did-rfp.md+26 content/grants/2023/elm.md+68 content/grants/2023/email-stella-fixa-rfp.md+29 content/grants/2023/eyre-noun-channels.md+42 content/grants/2023/generator-doccords.md+46 content/grants/2023/gh-concierge.md+42 content/grants/2023/git-on-clay.md+42 content/grants/2023/goals-2.md+64 content/grants/2023/hoon-linter.md+30 content/grants/2023/hoon-replit.md+45 content/grants/2023/issue-grab-bag.md+36 content/grants/2023/json-parser-suite.md+170 content/grants/2023/kNock-property-testing.md+71 content/grants/2023/lick.md+82 content/grants/2023/mapping-ids.md+106 content/grants/2023/network-weather.md+24 content/grants/2023/oauth2-stella-fixa-rfp.md+31 content/grants/2023/osmosis-client.md+48 content/grants/2023/pastebin-RFP.md+28 content/grants/2023/pastebin-proposal.md+33 content/grants/2023/portal-features-1.md+82 content/grants/2023/privacy-msg.md+89 content/grants/2023/quorum-2.md+84 content/grants/2023/replit.md+52 content/grants/2023/school-support-23q1.md+43 content/grants/2023/splitwise-rfp.md+26 content/grants/2023/splitwise.md+129 content/grants/2023/text-search.md+24 content/grants/2023/tinygrad.md+24 content/grants/2023/treesitter.md+71 content/grants/2023/turf.md+205 content/grants/2023/uc-concierge.md+42 content/grants/2023/update-mass.md+26 content/grants/2023/urbit-ninja-strike-team.md+38 content/grants/2023/urbit-react-docs.md+124 content/grants/2023/vere-eyre-cache.md+38 content/grants/2023/wiki-stella-fixa-rfp.md+26 content/groups/_index.md+3 content/groups/~bitbet-bolbel/urbit-community.md+14 content/groups/~bitdeg/assembly22.md+10 content/groups/~dalten/aera.md+10 content/groups/~dibref-labter/arbit.md+9 content/groups/~dister-dozzod-lapdeg/battery-payload.md+9 content/groups/~fabled-faster/new-york.md+10 content/groups/~fabled-faster/structure.md+10 content/groups/~fabled-faster/wind.md+10 content/groups/~famreb-todmec/the-combine-public.md+13 content/groups/~halbex-palheb/uf-public.md+10 content/groups/~hatryx-lastud/other-life.md+10 content/groups/~hiddev-dannut/new-hooniverse.md+11 content/groups/~hocwyn-tipwex/uqbar-event-horizon-forever.md+11 content/groups/~ladtem-filmyr/urbit-ny-week.md+193 content/groups/~lanlyd/terminal.md+8 content/groups/~lodsum-rilner/emil-graphics.md+10 content/groups/~martyr-sarlev-sarsen/assembly-hackers.md+10 content/groups/~matwet/networked-subject.md+11 content/groups/~middev/the-forge.md+10 content/groups/~mister-hilper-dozzod-dalten/quartus.md+10 content/groups/~napmer-rilnut/wet-brain.md+10 content/groups/~natnex-ronret/door-link.md+10 content/groups/~nibset-napwyn/tlon-public.md+10 content/groups/~poldec-tonteg/the-phantom-tollbooth.md+12 content/groups/~sillus-mallus/toki-pona.md+12 content/groups/~sitbus-dapsup/urstralia.md+9 content/groups/~tirrel/the-marketplace.md+14 content/groups/~todset-partug/urmetica.md+9 content/groups/~wacrep-lossul/encyclosphere.md+9 content/groups/~widbep-faltev/asheville.md+9 content/groups/~winder-dapsym/urchan.md+29 content/groups/~witbep-witbep/embark.md+11 content/highlights/highlight-1.md+6 content/highlights/highlight-2.md+6 content/highlights/highlight-3.md+6 content/ids/ballun-dilsup.md+7 content/ids/battus-datsun.md+10 content/ids/binnus.md+10 content/ids/bintud-bitnev.md+8 content/ids/bitbet-bolbel.md+4 content/ids/botbyn-dolrum.md+7 content/ids/datder-sonnet.md+13 content/ids/datnut-pollen.md+15 content/ids/datryn-ribdun.md+12 content/ids/datsyr-radser.md+12 content/ids/dopbet-larped.md+7 content/ids/fallyn-balfus.md+8 content/ids/finmep-lanteb.md+29 content/ids/forryd-ravtyn.md+6 content/ids/haddef-sigwen.md+12 content/ids/haldul-navsyr.md+7 content/ids/hocmed-lidrev.md+8 content/ids/lagrev-nocfep.md+8 content/ids/lanlyd.md+8 content/ids/mallus-fabres.md+12 content/ids/mastyr-bottec.md+10 content/ids/monnys-riphet.md+7 content/ids/nallux-dozryl.md+12 content/ids/nibtud-bidsyt.md+17 content/ids/panleg-padben.md+6 content/ids/pinsyt-nossub.md+18 content/ids/poldec-tonteg.md+14 content/ids/rabsef-bicrym.md+14 content/ids/ravmel-ropdyl.md+8 content/ids/rilfun-lidlen.md+8 content/ids/sarlev-sarsen.md+8 content/ids/sicdev-pilnup.md+8 content/ids/sitful-hatred.md+8 content/ids/sogrum-savluc.md+11 content/ids/tagdyl-ponwyn.md+10 content/ids/tambes-palped.md+10 content/ids/tiplec-lacnyx.md+6 content/ids/tobrun-tomnet.md+8 content/ids/topfet-parmed.md+6 content/ids/wicrum-wicrun.md+8 content/ids/wolref-podlex.md+8 content/marketplaces/azimuth-shop.md+11 content/marketplaces/lanlyd.md+19 content/marketplaces/mocbel-house.md+19 content/marketplaces/networked-subject.md+14 content/marketplaces/opensea.md+18 content/marketplaces/planet-market.md+26 content/marketplaces/urbit-live.md+13 content/marketplaces/urbitex.md+11 content/marketplaces/urbitme.md+11 content/marketplaces/wexpert-systems.md+13 content/organizations/assemblycapital.md+10 content/organizations/dalten.md+10 content/organizations/holium.md+10 content/organizations/labyrinthdao.md+10 content/organizations/mars-review-of-books.md+19 content/organizations/nativeplanet.md+10 content/organizations/quartus.md+22 content/organizations/reciprocal.md+13 content/organizations/sortug.md+10 content/organizations/third-earth.md+10 content/organizations/tirrel.md+12 content/organizations/tlon.md+12 content/organizations/uqbar.md+10 content/organizations/urbit-foundation.md+12 content/organizations/zorp.md+10 content/overview/_index.md+64 content/overview/interface.md+42 content/overview/people-history.md+73 content/overview/urbit-id.md+63 content/overview/urbit-os.md+45 content/podcasts/2018-11-18_a-digital-republic.md+19 content/podcasts/2019-11-11_urbit.md+9 content/podcasts/2020-03-23_a-new-computing-platform.md+17 content/podcasts/2020-03-23_technology-and-freedom.md+18 content/podcasts/2020-03-23_under-the-hood.md+15 content/podcasts/2020-03-24_urbit-id-and-the-network.md+13 content/podcasts/2020-03-26_built-to-last.md+21 content/podcasts/2020-03-26_urbit-and-bitcoin.md+15 content/podcasts/2020-04-05_tlon-operations.md+15 content/podcasts/2020-11-24_humane-computing.md+11 content/podcasts/2021-02-08_urbit.md+27 content/podcasts/2022-01-21_the-most-beautiful-computer.md+17 content/podcasts/2022-01-26_the-only-dignified-computer.md+17 content/podcasts/2022-02-01_100-year-computer.md+15 content/podcasts/2022-02-15_building-web3-products.md+20 content/podcasts/2022-02-21_most-correct-computer.md+17 content/podcasts/2022-02-27_the-combine.md+13 content/podcasts/2022-03-02_theory-of-the-egirl.md+17 content/podcasts/2022-03-04_nockin.md+18 content/podcasts/2022-03-08_urbit-blockchains.md+16 content/podcasts/2022-03-11_mars-review.md+12 content/podcasts/2022-03-13_alien-invasions.md+16 content/podcasts/2022-03-18_politics-of-urbit-governance.md+15 content/podcasts/2022-03-23_quantum-computing.md+15 content/podcasts/2022-04-07_in-lehmans-terms.md+12 content/podcasts/2022-04-19_robot-opera.md+11 content/podcasts/2022-05-21_diary-of-sam-frank.md+10 content/podcasts/2022-05-22_cincinnati-chili.md+10 content/podcasts/2022-06-04_market-bedshite.md+10 content/podcasts/2022-06-22_software-as-soulcraft.md+20 content/podcasts/2022-06-29_josh-lehman.md+30 content/podcasts/2022-07-04_enable-people-to-run-their-own-servers.md+116 content/podcasts/2022-08-04_middling.md+10 content/podcasts/2022-08-11_probing-questions.md+14 content/podcasts/2022-08-19_the-blind.md+9 content/podcasts/2022-08-26_the-harvard-finance-bro.md+12 content/podcasts/2022-09-14_insanely-bullish-on-urbit.md+13 content/podcasts/2022-09-21_the-worlds-best-crypto-investor.md+12 content/podcasts/2022-09-30-neal-davis-urbit-sentience-daos.md+33 content/podcasts/2022-10-04-reality-maximalism-josh-lehman.md+9 content/podcasts/2022-10-06_urbit-maxi-episode copy.md+9 content/podcasts/2022-12-22_epicenter-ted-blackman-gary-lieberman.md+11 content/podcasts/2023-01-05_lets-get-personal.md+9 content/podcasts/2023-01-19_crypto-metaphysics.md+9 content/podcasts/2023-01-24_reject-triviality.md+13 content/podcasts/2023-01-26_building-future-states-with-nation3.md+9 content/podcasts/2023-01-29_urbit-for-idiots.md+11 content/podcasts/2023-02-09_crypto-narratives-new-and-old.md+9 content/podcasts/2023-02-13_distributed-networked-computing.md+17 content/podcasts/2023-02-23_the-urbit-episode.md+9 content/podcasts/2023-03-09_reclaiming-web-1.md+9 content/podcasts/2023-03-23_how-to-invest-in-web3-like-a-cool-kid.md+9 content/podcasts/2023-03-28_pupusas-volcanoes-and-databases.md+9 content/podcasts/2023-04-03_legacy-internet-new-internet.md+15 content/podcasts/2023-04-06_the-ai-episode.md+9 content/podcasts/2023-04-11_its-urbits-all-the-way-down-with-dachus-tiprel.md+9 content/podcasts/2023-04-14_epicenter-tim-galebach.md+11 content/podcasts/2023-04-20_artificial-qintelligence.md+9 content/podcasts/2023-04-27_hoon-only-legal-ui-with-hastuc-dibtux.md+11 content/podcasts/2023-05-11_full-metal-urbit-with-mopfel-winrux.md+15 content/podcasts/2023-05-18_crypto-takes-flight.md+11 content/privacy.md+89 content/proposals.md+93 content/rfps.md+40 content/terms-of-service.md+69 content/updates/2016-10-6-update.md+264 content/updates/2016-5-16-roadmap.md+245 content/updates/2016-7-20-update.md+160 content/updates/2016-8-30-update.md+268 content/updates/2017-1-30-update.md+345 content/updates/2017-10-7-update.md+17 content/updates/2017-11-14-update.md+217 content/updates/2017-12-16-update.md+31 content/updates/2017-12-2-update.md+76 content/updates/2017-12-22-update.md+33 content/updates/2017-3-1-update.md+108 content/updates/2017-4-17-update.md+158 content/updates/2017-5-11-roadmap.md+234 content/updates/2017-8-11-update.md+109 content/updates/2017-9-23-update.md+25 content/updates/2017-9-29-update.md+17 content/updates/2018-1-13-update.md+28 content/updates/2018-1-6-update.md+38 content/updates/2018-10-12-update.md+62 content/updates/2018-10-24-update.md+40 content/updates/2018-11-20-update.md+55 content/updates/2018-11-6-update.md+47 content/updates/2018-12-18-update.md+59 content/updates/2018-2-17-update.md+39 content/updates/2018-2-24-update.md+32 content/updates/2018-2-5-update.md+26 content/updates/2018-2-9-update.md+41 content/updates/2018-3-24-update.md+57 content/updates/2018-3-5-update.md+32 content/updates/2018-4-14-update.md+57 content/updates/2018-4-7-update.md+41 content/updates/2018-5-16-update.md+50 content/updates/2018-5-23-update.md+64 content/updates/2018-5-29-update.md+17 content/updates/2018-5-30-update.md+78 content/updates/2018-6-14-update.md+71 content/updates/2018-6-21-update.md+60 content/updates/2018-6-6-update.md+81 content/updates/2018-7-13-update.md+67 content/updates/2018-7-20-update.md+58 content/updates/2018-7-3-update.md+66 content/updates/2018-7-30-update.md+64 content/updates/2018-8-23-update.md+85 content/updates/2018-8-30-update.md+57 content/updates/2018-8-8-update.md+59 content/updates/2018-9-11-update.md+61 content/updates/2019-11-06-update.md+42 content/updates/2019-12-06-update.md+42 content/updates/2019-2-11-update.md+39 content/updates/2019-2-25-update.md+35 content/updates/2019-2-26-network-update.md+39 content/updates/2019-2-4-update.md+29 content/updates/2019-3-11-update.md+29 content/updates/2019-3-27-update.md+21 content/updates/2019-3-4-update.md+48 content/updates/2019-4-11-update.md+29 content/updates/2019-5-10-update.md+17 content/updates/2019-5-17-update.md+21 content/updates/2019-5-31-update.md+31 content/updates/2019-6-14-update.md+30 content/updates/2019-7-25-update.md+40 content/updates/2020-02-06-update.md+46 content/updates/2020-04-04-update.md+26 content/updates/2020-06-15-update.md+51 content/updates/2020-07-27-update.md+37 content/updates/2020-09-30-update.md+65 content/updates/2020-10-29-update.md+49 content/updates/2020-12-01-update.md+68 content/updates/2021-01-15-update.md+60 content/updates/2021-02-19-update.md+81 content/updates/2021-04-01-update.md+89 content/updates/2021-05-05-update.md+70 content/updates/2021-06-16-update.md+79 content/voting-instructions.md+36 gnosis-safe.md+48 hoon/_index.md−24 hoon/cheat-sheet.md−28 hoon/hoon-expressions/_index.md−28 hoon/hoon-expressions/advanced.md−203 hoon/hoon-expressions/basic.md−177 hoon/hoon-expressions/irregular.md−258 hoon/hoon-expressions/limb/_index.md−18 hoon/hoon-expressions/limb/limb.md−71 hoon/hoon-expressions/limb/wing.md−44 hoon/hoon-expressions/rune/_index.md−72 hoon/hoon-expressions/rune/bar.md−636 hoon/hoon-expressions/rune/buc.md−393 hoon/hoon-expressions/rune/cen.md−471 hoon/hoon-expressions/rune/col.md−245 hoon/hoon-expressions/rune/constants.md−193 hoon/hoon-expressions/rune/dot.md−223 hoon/hoon-expressions/rune/ket.md−387 hoon/hoon-expressions/rune/lus.md−176 hoon/hoon-expressions/rune/mic.md−375 hoon/hoon-expressions/rune/sig.md−450 hoon/hoon-expressions/rune/terminators.md−79 hoon/hoon-expressions/rune/tis.md−490 hoon/hoon-expressions/rune/wut.md−551 hoon/hoon-expressions/rune/zap.md−203 hoon/hoon-tutorial/_index.md−55 hoon/hoon-tutorial/ackermann.md−32 hoon/hoon-tutorial/arms-and-cores.md−490 hoon/hoon-tutorial/atoms-auras-and-simple-cell-types.md−779 hoon/hoon-tutorial/bank-account.md−82 hoon/hoon-tutorial/caesar.md−347 hoon/hoon-tutorial/conditionals.md−75 hoon/hoon-tutorial/doors.md−506 hoon/hoon-tutorial/egg-timer.md−121 hoon/hoon-tutorial/fibonacci.md−63 hoon/hoon-tutorial/gall.md−81 hoon/hoon-tutorial/gates.md−273 hoon/hoon-tutorial/generators.md−601 hoon/hoon-tutorial/hoon-syntax.md−329 hoon/hoon-tutorial/iron-polymorphism.md−91 hoon/hoon-tutorial/lead-polymorphism.md−157 hoon/hoon-tutorial/libraries.md−185 hoon/hoon-tutorial/list-of-numbers.md−134 hoon/hoon-tutorial/lists.md−336 hoon/hoon-tutorial/molds.md−59 hoon/hoon-tutorial/nouns.md−483 hoon/hoon-tutorial/recursion.md−196 hoon/hoon-tutorial/setup.md−108 hoon/hoon-tutorial/structures-and-complex-types.md−357 hoon/hoon-tutorial/the-subject-and-its-legs.md−657 hoon/hoon-tutorial/trees-sets-and-maps.md−323 hoon/hoon-tutorial/type-checking-and-type-inference.md−644 hoon/hoon-tutorial/type-polymorphism.md−578 hoon/library/1a.md−680 hoon/library/1b.md−273 hoon/library/1c.md−421 hoon/library/2a.md−449 hoon/library/2b.md−1293 hoon/library/2c.md−1251 hoon/library/2d.md−373 hoon/library/2e.md−276 hoon/library/2f.md−437 hoon/library/2g.md−105 hoon/library/2h.md−798 hoon/library/2i.md−1059 hoon/library/2j.md−272 hoon/library/2k.md−399 hoon/library/2l.md−111 hoon/library/2m.md−308 hoon/library/2n.md−427 hoon/library/2o.md−187 hoon/library/2p.md−242 hoon/library/2q.md−375 hoon/library/3a.md−858 hoon/library/3b.md−5889 hoon/library/3c.md−649 hoon/library/3d.md−821 hoon/library/3e.md−9 hoon/library/3f.md−723 hoon/library/3g.md−386 hoon/library/4a.md−217 hoon/library/4b.md−994 hoon/library/4c.md−364 hoon/library/4d.md−100 hoon/library/4e.md−471 hoon/library/4f.md−1195 hoon/library/4g.md−179 hoon/library/4h.md−962 hoon/library/4i.md−1054 hoon/library/4j.md−1656 hoon/library/4k.md−276 hoon/library/4l.md−608 hoon/library/4m.md−434 hoon/library/4n.md−447 hoon/library/4o.md−782 hoon/library/5a.md−7 hoon/library/5b.md−7 hoon/library/5c.md−7 hoon/library/5d.md−7 hoon/library/5e.md−7 hoon/library/5f.md−176 hoon/library/5g.md−7 hoon/library/_index.md−1733 hoon/library/table-of-contents.md−1730 hoon/library/zuse.md−10 hoon/style.md−475 hoon/troubleshooting.md−182 hoon/workbook/_index.md−17 hoon/workbook/bomb.md−140 hoon/workbook/digits.md−113 hoon/workbook/eightball.md−158 hoon/workbook/traffic-light.md−155 lib/buildGlossary.js+59 lib/buildPageTree.js+111 lib/cache.js+90 lib/constants.js+129 lib/hooks.js+71 lib/lib.js+251 lib/rss.js+95 next.config.js+26 nock/_index.md−26 nock/definition.md−186 nock/example.md−362 nock/explanation.md−601 nock/implementations.md−2322 package-lock.json+5276 package.json+58 pages/404.js+33 pages/[slug].js+48 pages/_app.js+85 pages/api/dev-search.js+8 pages/api/ops-search.js+8 pages/api/roadmap-search.js+8 pages/api/search.js+45 pages/api/sigil.js+60 pages/api/urbit-org-search.js+45 pages/applications/[[...application]].js+206 pages/applications/submit.js+143 pages/articles/[slug].js+84 pages/bitcoin.js+98 pages/blog.js+131 pages/blog/[slug].js+118 pages/campus/[[...slug]].js+312 pages/communities/[slug].js+87 pages/decentralized-discord.js+291 pages/ecosystem/index.js+416 pages/ecosystem/spotlight/[slug].js+69 pages/events.js+181 pages/events/[slug].js+173 pages/getinvolved.js+58 pages/getting-started/[[...slug]].js+314 pages/grants.js+401 pages/grants/[slug].js+270 pages/grants/apprenticeships.js+29 pages/grants/bounties.js+28 pages/grants/proposals.js+29 pages/grants/rfps.js+29 pages/groups/[[...group]].js+136 pages/groups/submit.js+152 pages/ids/[id].js+241 pages/ids/submit.js+170 pages/index.js+430 pages/marketplaces/[slug].js+84 pages/organizations/[slug].js+179 pages/overview/[[...slug]].js+147 pages/podcasts/[slug].js+84 pages/trial-over.js+35 pages/trial.js+129 pages/updates.js+87 pages/updates/[slug].js+126 postcss.config.js+6 public/images/android-chrome-192x192.png public/images/android-chrome-512x512.png public/images/apple-touch-icon.png public/images/favicon-16x16.png public/images/favicon-32x32.png public/images/favicon.ico public/images/planet-l2-claim.gif public/images/planet-l2-migration.gif public/images/planet-l2-transactions.png public/images/sound.svg+5 scripts/date_to_string_upgrade.js+43 scripts/event_date_upgrade.js+51 tailwind.config.js+19 vercel.json+271 vere/_index.md−36 vere/api.md−1040 vere/c.md−114 vere/jetting.md−770 vere/nouns.md−477 vere/runtime.md−44 weights.sh−23
.gitignore+45−3
@@ -1,4 +1,46 @@
1−# OS
1+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+# dependencies
4+/node_modules
5+/.pnp
6+.pnp.js
7+
8+# testing
9+/coverage
10+
11+# next.js
12+/.next/
13+/out/
14+.next
15+
16+# production
17+/build
18+/cache
19+
20+# misc
221.DS_Store
3−# etc
4−*.swn
22+*.pem
23+
24+# debug
25+npm-debug.log*
26+yarn-debug.log*
27+yarn-error.log*
28+
29+# local env files
30+.env
31+.env.local
32+.env.development.local
33+.env.test.local
34+.env.production.local
35+
36+# vercel
37+.vercel
38+
39+# editors
40+/.nova/
41+
42+# rss
43+public/rss.xml
44+
45+yarn.lock
46+
.gitmodulesdeleted−3
@@ -1,3 +0,0 @@
1−[submodule "docs/hoon/workbook"]
2− path = docs/hoon/workbook
3− url = git@github.com:urbit/hoon-workbook.git
.npmrcnew file+1
@@ -0,0 +1 @@
1+unsafe-perm = true
.nvmrcnew file+1
@@ -0,0 +1 @@
1+14
.prettierrcnew file+5
@@ -0,0 +1,5 @@
1+{
2+ "tabWidth": 2,
3+ "useTabs": false,
4+ "printWidth": 80
5+}
README.markdowndeleted−3
@@ -1,3 +0,0 @@
1−# Urbit Docs
2−
3−Urbit documentation as it appears on [urbit.org](https://urbit.org/docs/).
README.mdnew file+58
@@ -0,0 +1,58 @@
1+The website for Urbit is maintained by the Urbit Foundation and the Urbit community. Issues and contributions are welcome.
2+
3+## Getting Started
4+
5+1. Fork the [Urbit site repository](https://github.com/urbit/urbit.org).
6+
7+2. [Create a local clone](https://help.github.com/articles/cloning-a-repository/) of your fork.
8+
9+3. Navigate to the `urbit.org` directory and install Node 14 using [nvm](https://github.com/nvm-sh/nvm):
10+
11+ ```shell
12+ cd urbit.org
13+ nvm install 14
14+ ```
15+ You can then run `nvm use` whenever in the repository (or automate it with a script - see [here](https://github.com/nvm-sh/nvm#deeper-shell-integration)).
16+
17+4. Install our dependencies:
18+
19+ ```shell
20+ npm install
21+ ```
22+
23+ If running an arm64 Mac (M1 or later), you may need to install some dependencies to compile canvas, one of our dependencies. Assuming you have [Homebrew](https://brew.sh):
24+
25+ ```shell
26+ arch -arm64 brew install pkg-config cairo pango libpng jpeg giflib librsvg
27+ ```
28+
29+5. Run the development server:
30+
31+ ```shell
32+ npm run dev
33+ # or
34+ yarn dev
35+ ```
36+
37+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
38+
39+To learn more about contributing, see GitHub's [documentation](https://docs.github.com/en/get-started/quickstart/contributing-to-projects).
40+
41+## Framework and Library Documentation
42+
43+To learn more about Next.js, take a look at the following resources:
44+
45+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
46+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
47+
48+To learn more about Tailwind CSS, take a look at the docs:
49+
50+- [Tailwind CSS Docs](https://tailwindcss.com/docs) - Docs
51+
52+## Deployment
53+
54+We deploy using Vercel. All pull requests will show a deployment preview via the same.
55+
56+## Upgrades
57+
58+The `/scripts` contains scripts used to programmatically upgrade site content data.
_index.mddeleted−35
@@ -1,35 +0,0 @@
1−+++
2−title = "Docs"
3−template = "sections/docs.html"
4−+++
5−Welcome to the documentation for the Urbit project, including the Azimuth identity layer, the Arvo operating system, and the Hoon programming language. This documentation is maintained by [Tlon](https://tlon.io) in a public [Github repository](https://github.com/urbit/docs). Issues and contributions are welcome.
6−
7−## Getting Started
8−
9−The following three guides will help get you started on Urbit.
10−
11−### [Install Urbit](/install)
12−
13−Urbit isn't ready for serious use yet, but it's available to try out. If you have an Urbit identity, you can follow this step-by-step guide to get your point's _keyfile_, which you need to boot your ship. Then you can install Urbit and join the community.
14−
15−### [Operator's Manual](/operations)
16−
17−The Operator's Manual will show you how to perform everyday functions on your Urbit.
18−
19−### [Developer's Guide](/develop)
20−
21−This guide will teach you how set up an Urbit development environment.
22−
23−## Technical Documentation
24−
25−The documentation proper is contained on the sidebar of this page. It's meant for those interested in development on Urbit, and it's sorted by section:
26−
27−- [Arvo](../arvo) is the Urbit operating system. If you're interested in finding out about the architecture of the system, check out this section.
28−
29−- [Azimuth](../arvo) is the Urbit identity layer. To use Urbit, you need an identity that is secured by Azimuth.
30−
31−- [Hoon](../hoon) is the functional programming language used to build Urbit. This section contains tutorials that will help you build proficiency in the language.
32−
33−- [Nock](../nock) is the low-level language Hoon compiles to. If you want to understand that absolute fundamentals of Urbit, this section will be of help.
34−
35−- [Vere](../vere) is the Nock interpreter that acts as the layer between Urbit and whatever system (MacOS, Linux, BSD) is running it.
arvo/_index.mddeleted−113
@@ -1,113 +0,0 @@
1−+++
2−title = "Arvo"
3−weight = 1
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−aliases = ["/docs/learn/arvo/"]
7−+++
8−Arvo is Urbit's functional operating system, written in [Hoon](@/docs/hoon/_index.md). It's composed of modules called _vanes_:
9−
10−## [Ames](@/docs/arvo/ames.md)
11−
12−Ames is the name of our network and the vane that communicates over it. It's an encrypted P2P network composed of instances of the Arvo operating system.
13−
14−## [Behn](@/docs/arvo/behn.md)
15−
16−Behn is our timer. It allows vanes and applications to set and timer events, which are managed in a simple priority queue.
17−
18−## [Clay](@/docs/arvo/clay.md)
19−
20−Clay is our filesystem and revision-control system.
21−
22−## [Dill](@/docs/arvo/dill.md)
23−
24−Dill is our terminal driver. Unix sends keyboard events to dill from the terminal, and dill produces terminal output.
25−
26−## [Eyre](@/docs/arvo/eyre.md)
27−
28−Eyre is our HTTP server. Unix sends HTTP messages to `%eyre`, and `%eyre` produces HTTP messages in response.
29−
30−## [Ford](@/docs/arvo/ford.md)
31−
32−Ford is our build system. It handles resources and publishing.
33−
34−## [Gall](@/docs/arvo/gall.md)
35−
36−Gall is the vane for controlling userspace apps.
37−
38−### [Hall](@/docs/arvo/hall.md)
39−
40−Hall isn't a vane, but an important Gall app that functions as the Urbit messaging protocol.
41−
42−## Principles
43−
44−At a high level `%arvo` takes a mess of Unix I/O events and turns them into something clean and structured for the programmer.
45−
46−`%arvo` is designed to avoid the usual state of complex event networks: event spaghetti. We keep track of every event's cause so that we have a clear causal chain for every computation. At the bottom of every chain is a Unix I/O event, such as a network request, terminal input, file sync, or timer event. We push every step in the path the request takes onto the chain until we get to the terminal cause of the computation. Then we use this causal stack to route results back to the caller.
47−
48−### Ducts
49−
50−The `%arvo` causal stack is called a `++duct`. This is represented simply as a list of paths, where each path represents a step in the causal chain. The first element in the path is the first letter of whichever vane handled that step in the computation, or the empty span for Unix.
51−
52−Here's a duct that was recently observed in the wild:
53−
54−```
55−~[
56− /g/a/~zod/4_shell_terminal/u/time
57− /g/a/~zod/shell_terminal/u/child/4/main
58− /g/a/~zod/terminal/u/txt
59− /d/term-mess
60− //term/1
61−]
62−```
63−
64−This is the duct the timer vane receives when "timer" sample app asks the timer vane to set a timer. This is also the duct over which the response is produced at the specified time. Unix sent a terminal keystroke event (enter), and Arvo routed it to `%dill` (our terminal), which passed it on to the `%gall` app terminal, which sent it to shell, its child, which created a new child (with process id 4), which on startup asked the timer vane to set a timer.
65−
66−The timer vane saves this duct, so that when the specified time arrives and Unix sends a wakeup event to the timer vane, it can produce the response on the same duct. This response is routed to the place we popped off the top of the duct, i.e. the time app. This app produces the text "ding", which falls down to the shell, which drops it through to the terminal. Terminal drops this down to dill, which converts it into an effect that Unix will recognize as a request to print "ding" to the screen. When dill produces this, the last path in the duct has an
67−initial element of the empty span, so this is routed to Unix, which applies the effects.
68−
69−This is a call stack, with a crucial feature: the stack is a first-class citizen. You can respond over a duct zero, one, or many times. You can save ducts for later use. There are definitely parallels to Scheme-style continuations, but simpler and with more structure.
70−
71−### Making Moves
72−
73−If ducts are a call stack, then how do we make calls and produce results? Arvo processes "moves" which are a combination of message data and metadata. There are two types of moves. A `%pass` move is analogous to a call:
74−
75−```
76−[duct %pass return-path=path vane-name=@tD data=card]
77−```
78−
79−Arvo pushes the return path (preceded by the first letter of the vane name) onto the duct and sends the given data, a card, to the vane we specified. Any response will come along the same duct with the path `return-path`.
80−
81−A `%give` move is analogous to a return:
82−
83−```
84−[duct %give data=card]
85−```
86−
87−Arvo pops the top path off the duct and sends the given card back to the caller.
88−
89−### Vanes
90−
91−As shown above, we use Arvo proper to route and control the flow of moves. However, Arvo proper is rarely directly responsible for processing the event data that directly causes the desired outcome of a move. This event data is contained within a card, which is simply a `(pair term noun)`. Instead, Arvo proper passes the card off to one of its vanes, which each present an interface to clients for a particular well-defined, stable, and general-purpose piece of functionality.
92−
93−As of this writing, we have seven vanes, which each provide the following services:
94−
95−- `%ames`: the name of both our network and the vane that communicates over it.
96−- `%behn`: a simple timer.
97−- `%clay`: our version-controlled, referentially- transparent, and global filesystem.
98−- `%dill`: a terminal driver. Unix sends keyboard events to `%dill` from either the console or telnet, and `%dill` produces terminal output.
99−- `%eyre`: an http server. Unix sends http messages to `%eyre`, and `%eyre` produces http messages in response.
100−- `%ford`: handles resources and publishing.
101−- `%gall`: manages our userspace applications. `%gall` keeps state and manages subscribers.
102−
103−### Cards
104−
105−Cards are the vane-specific portion of a move. Each vane defines a protocol for interacting with other vanes (via Arvo) by defining four types of cards: tasks, gifts, notes, and signs.
106−
107−When one vane is `%pass`ed a card in its `++task` (defined in zuse), Arvo activates the `++call` gate with the card as its argument. To produce a result, the vane `%give`s one of the cards defined in its `++gift`. If the vane needs to request something of another vane, it `%pass`es it a `++note` card. When that other vane returns a result, Arvo activates the `++take` gate of the initial vane with one of the cards defined in its `++sign`.
108−
109−In other words, there are only four ways of seeing a move: (1) as a request seen by the caller, which is a ++note. (2) that same request as seen by the callee, a `++task`. (3) the response to that first request as seen by the callee, a `++gift`. (4) the response to the first request as seen by the caller, a `++sign`.
110−
111−When a `++task` card is passed to a vane, Arvo calls its `++call` gate, passing it both the card and its duct. This gate must be defined in every vane. It produces two things in the following order: a list of moves and a possibly modified copy of its context. The moves are used to interact with other vanes, while the new context allows the vane to save its state. The next time Arvo activates the vane it will have this context as its subject.
112−
113−This overview has detailed how to pass a card to a particular vane. To see the cards each vane can be `%pass`ed as a `++task` or return as a `++gift` (as well as the semantics tied to them), each vane's public interface is explained in detail in its respective overview.
arvo/ames.mddeleted−1938
@@ -1,1938 +0,0 @@
1−+++
2−title = "Ames"
3−weight = 1
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/ames/"]
6−+++
7−Our networking protocol.
8−
9−`%ames` is the name of both our network and the vane that communicates
10−over it. When Unix receives a packet over the correct UDP port, it pipes
11−it straight into `%ames` for handling. Also, all packets sent over the
12−`%ames` network are sent by the `%ames` vane. Apps and vanes may use
13−`%ames` to directly send messages to other ships. In general, apps use
14−gall and clay to communicate with other ships rather than using `%ames`
15−directly, but this isn't a requirement. Of course, gall and clay use
16−`%ames` behind the scenes to communicate across the network. These are
17−the only two vanes that use `%ames`.
18−
19−`%ames` includes several significant components. Although the actual
20−crypto algorithms are defined in zuse, they're used extensively in
21−`%ames` for encrypting and decrypting packets. Congestion control and
22−routing is handled entirely in `%ames`. Finally, the actual `%ames`
23−protocol itself, including how to route incoming packets to the correct
24−vane or app, is defined in `%ames`.
25−
26−## Commentary
27−
28−`%ames` is our networking protocol.
29−
30−First we give commentary on the code, the algorithms involved, and the
31−protocol. We trace through the code touched when a packet is sent,
32−received, acknowledged, and that acknowledgment applied. This is fairly
33−comprehensive, and contains many implementation details, but if you
34−understand this, then you understand `%ames`.
35−
36−If you've scrolled down this page, you may be intimidated by the amount
37−of Hoon code, especially if you are new to the language. Don't be afraid
38−of it, you don't have to read any of it if you don't want to -- every
39−interesting action the code takes is explained in plain English. In
40−fact, if you are new to the language, this may be a good learning
41−opportunity. Even if you don't understand every line of Hoon code,
42−you'll hopefully be able to follow most lines. By the time you've worked
43−through this, you'll have seen many common patterns and best practices.
44−Hoon, much more than other languages, is best learned by reading and
45−understanding large quantities of existing code. In this way, it is
46−similar to learning a natural language. All of this code is in
47−`arvo/ames.hoon`.
48−
49−After the commentary, we have reference documentation for all the data
50−structures that are specific to `%ames`. If you see a data structure or
51−a variable used that you don't recognize, search for it in the code, and
52−it's very likely defined in one of these data structures. We recommend
53−that another tab is kept open for easy access to the data structure
54−reference documentation. The code for these is split between
55−`arvo/ames.hoon` and `arvo/zuse.hoon`.
56−
57−The Lifecycle of a Packet (or, How a Packet Becomes Law)
58−
59−---
60−
61−Here, we will trace a packet as it makes its way through ames. There are
62−actually two pathways through ames: the legacy path through `%want`, and
63−the modern way, entered through `%wont`, with full end-to-end
64−acknowledgments. Here we will only trace the modern way, though much of
65−the path is the same for both.
66−
67−When an app (or a vane) wishes to send a packet to another ship, it must
68−send a `%wont` card:
69−
70−```hoon
71− [%wont p=sock q=path r=*] :: e2e send message
72−```
73−
74−This card takes three arguments. The `p` is a `sock`, that is, a pair of
75−two ships, the first of which is the sender and the second is the
76−receiver. But wait, you ask, why do I get to decide who is the sender?
77−Can I fake like I'm someone else? The reason is that there are
78−potentially multiple ships on the same pier, and the kernel can send a
79−message from any of them. If you attempt to send a message from a ship
80−not on your pier, then ames will refuse to send it. If you hack around
81−in your own copy of ames to go ahead and send it anyway, then the other
82−ship will reject it because your key is bad. Only send messages from
83−yourself.
84−
85−The `q` is a path, representing the place on the other side that you
86−want to receive your message. It is approximately equivalent to a port
87−number. Messages on the same path are guaranteed to arrive in the same
88−order as they were sent. No such guarantees are made across paths.
89−
90−The `r` is the actual data that you are sending. As the type implies,
91−this can be an arbitrary noun, and it will be transferred to the
92−receiver exactly as-is, in a well-typed way. Of course, this is data
93−that is sent over the wire, so be careful not to send anything too
94−massive unless you're willing to wait.
95−
96−But enough about the interface. Grepping in ames.hoon for `%wont`, we
97−find that it appears in `++knob`. We see that we go
98−directly into `++wise:am`.
99−
100−```hoon
101− ++ wise :: wise:am
102− |= [soq=sock hen=duct cha=path val=* ete=?] :: send a statement
103− ^- [p=(list boon) q=fort]
104− zork:zank:(wool:(ho:(um p.soq) q.soq) hen cha val ete)
105−```
106−
107−The inputs to this gate are exactly the sort of thing you'd expect. In
108−particular, everything in the `%wont` gate is here plus the calling duct
109−so that we know where to send the acknowledgment and `ete` to determine
110−if we're going to do the modern end-to-end acknowledgments.
111−
112−The actual line of code looks intimidating, but it's really not all that
113−bad. Working from the inside out, the call to `++um` sets up our
114−domestic server, and the call to `++ho` sets up our knowledge about the
115−neighbor we're sending to. From the outside, `++zork` and `++zank` just
116−apply the changes made to our `++um` and `++am` cores, respectively. If
117−you're familiar with the common idiom of `++abet`, that's all this is.
118−The code predates the widespread usage of that name.
119−
120−The interesting part, then, is in `++wool:ho:um:am`. Let's look at the
121−code.
122−
123−```hoon
124− ++ wool :: wool:ho:um:am
125− |= [hen=duct cha=path val=* ete=?] :: send a statement
126− ^+ +>
127− =+ ^= rol ^- rill
128− =+ rol=(~(get by ryl.bah) cha)
129− ?~(rol *rill u.rol)
130− =+ sex=sed.rol
131− :: ~& [%tx [our her] cha sex]
132− =. ryl.bah
133− %+ ~(put by ryl.bah) cha
134− rol(sed +(sed.rol), san (~(put by san.rol) sex hen))
135− =+ cov=[p=p:sen:gus q=clon:diz]
136− %+ wind [cha sex]
137− ?: ete
138− [%bund q.cov cha sex val]
139− [%bond q.cov cha sex val]
140−```
141−
142−This is slightly more complicated, but it's still not all that bad. Our
143−inputs, at least, are fairly obvious.
144−
145−If you glance at the code for a second, you'll see that
146−`++wind:ho:um:am` seems to be able to send a message, or `++meal:ames`, given
147−a `++soup`. This gate, then, just sets up the things we need to for
148−`++wind` to do its job.
149−
150−We first get `rol`, which is a `++rill:ames`, that is, a particular outbound
151−stream. This stream is specific to the path on which we're sending. If
152−the path hasn't been used before, then we create it. We let `sex` be the
153−number of messages we've already sent on this path.
154−
155−Then, we update the outbound stream by incrementing the number of
156−messages sent and placing an entry in `san.rol` that associates the
157−message number with the `duct` that sent the message. This allows us to
158−give the acknowledgment to the one who sent the message.
159−
160−We let `cov` be the current life of our crypto and our neighbor's
161−crypto. At the moment, we only need our neighbor's life, which we put
162−into the meal.
163−
164−Finally, we call `++wind:ho:um:am` with the `++soup` of the path and
165−message number and the `++meal:ames` of the payload itself. For end-to-end
166−acknowledged messages, we use `%bund`.
167−
168−```hoon
169− [%bund p=life q=path r=@ud s=*] :: e2e message
170−```
171−
172−Looking at how we create the `%bund`, we can easily see what each field
173−is for.
174−
175−Following the trail a little further, we go to `++wind:ho:um:am`.
176−
177−```hoon
178− ++ wind :: wind:ho:um:am
179− |= [gom=soup ham=meal]
180− :: ~& [%wind her gom]
181− ^+ +>
182− =^ wyv diz (zuul:diz now ham)
183− =^ feh puz (whap:puz now gom wyv)
184− (busk xong:diz feh)
185−```
186−
187−`++wind` does three things: it (1) encodes the message into a list of
188−possibly-encrypted packets, (2) puts the message into the packet pump,
189−and (3) sends any packets that are ready to be sent. Yes, our nice
190−little linear run of each gate calling exactly one other interesting
191−gate is over. We'll go in order here.
192−
193−`++zuul:lax:as:go` is the what converts a `++meal:ames` into a list of
194−actual, 1KB packets.
195−
196−```hoon
197− ++ zuul :: zuul:lax:as:go
198− |= [now=@da ham=meal] :: encode message
199− ^- [p=(list rock) q=_+>]
200− =< weft
201− ++ wasp :: null security
202− ++ weft :: fragment message
203− ++ wisp :: generate message
204−```
205−
206−For organizational purposes, `++zuul` constructs an internal core with
207−three arms. `++wasp` encodes the meal into an atom with no encryption.
208−`++wisp` encodes a meal with possible encryption (else it simply calls
209−`++wasp`). `++weft` takes the result of `++wisp` and splits it into
210−actual packets.
211−
212−```hoon
213− ++ wasp :: null security
214− ^-([p=skin q=@] [%none (jam ham)])
215−```
216−
217−This simply jams the meal, wrapping it with the `skin` of `%none`,
218−meaning no encryption.
219−
220−Since `++wisp` is a little long, we'll go through it line-by-line.
221−
222−```hoon
223− ++ wisp :: generate message
224− ^- [[p=skin q=@] q=_..wisp]
225−```
226−
227−`++wisp` produces a pair of a `skin` and an atom, which is the meal
228−encoded as a single atom and possibly encrypted.
229−
230−```hoon
231− ?: =(%carp -.ham)
232− [wasp ..wisp]
233−```
234−
235−If the meal that we're encoding is a `%carp`, then we don't encrypt it.
236−A `%carp` meal is a partial meal, used when a message is more than 1KB.
237−Since the entire message is already encrypted, we don't need to encrypt
238−each packet individually again.
239−
240−```hoon
241− ?: !=(~ yed.caq.dur)
242− ?> ?=(^ yed.caq.dur)
243− :_ ..wisp
244− :- %fast
245− %^ cat 7
246− p.u.yed.caq.dur
247− (en:r:cluy q.u.yed.caq.dur (jam ham))
248−```
249−
250−If we have a symmetric key set up with this neighbor, then we simply use
251−it. The skin `%fast` is used to indicate a symmetric key.
252−
253−```hoon
254− ?: &(=(~ lew.wod.dur) |(=(%back -.ham) =(%buck -.ham)))
255− [wasp ..wisp]
256−```
257−
258−If we do not yet have our neighbor's will, then there is no way that we
259−can seal the message so that only they may read it. If what we're
260−sending is an acknowledgment, then we go ahead and just send it in the
261−clear.
262−
263−```hoon
264− =^ tuy +>.$
265− ?:(=(~ lew.wod.dur) [*code +>.$] (griz now))
266−```
267−
268−If we don't have our neighbor's will, then we "encrypt" with a key of 0.
269−If we do have their will, then we generate a new symmetric key that we
270−will propose.
271−
272−```hoon
273− :_ ..wisp
274− =+ yig=sen
275− =+ bil=law.saf :: XX send whole will
276− =+ hom=(jam ham)
277−```
278−
279−`yig` will be the life and engine for our current crypto. `bil` is our
280−will. `hom` is the meal encoded as a single atom.
281−
282−```hoon
283− ?: =(~ lew.wod.dur)
284− :- %open
285− %^ jam
286− [~ `life`p.yig]
287− bil
288− (sign:as:q.yig tuy hom)
289−```
290−
291−If we do not have our neighbor's will, then we send our current life
292−along with our will and the message. The message itself is "signed" with
293−a key of 0.
294−
295−```hoon
296− :- %full
297− =+ cay=cluy
298− %^ jam
299− [`life`p.cay `life`p.yig]
300− bil
301− (seal:as:q.yig pub:ex:r.cay tuy hom)
302− -- :: --zuul:lax:as:go
303−```
304−
305−If we do have our neighbor's will, then we send our perception of their
306−current life, our current life, our will, and the message. The message
307−is sealed with their public key so that only they can read our message.
308−
309−Once we have the message encoded as an atom, `++weft` goes to work.
310−
311−```hoon
312− ++ weft :: fragment message
313− ^- [p=(list rock) q=_+>.$]
314− =^ gim ..weft wisp
315− :_ +>.$
316− ^- (list rock)
317−```
318−
319−We're going to produce a list of the packets to send. First, we use the
320−aforementioned `++wisp` to get the message as an atom.
321−
322−```hoon
323− =+ wit=(met 13 q.gim)
324− ?< =(0 wit)
325−```
326−
327−`wit` is the number of 1KB (2\^13 bit) blocks in the message. We assert
328−that there is at least one block.
329−
330−```hoon
331− ?: =(1 wit)
332− =+ yup=(spit [our her] p.gim q.gim)
333− [yup ~]
334−```
335−
336−If there is exactly one block, then we just call `++spit` to turn the
337−message into a packet. We'll explain what `++spit` does momentarily.
338−
339−```hoon
340− =+ ruv=(rip 13 q.gim)
341− =+ gom=(shaf %thug q.gim)
342− =+ inx=0
343−```
344−
345−If there is more than one block, then we rip it into blocks in `ruv`.
346−`gom` is a hash of the message, used as an id. `inx` is the number of
347−packets we've already made.
348−
349−```hoon
350− |- ^- (list rock)
351− ?~ ruv ~
352− =+ ^= vie
353− %+ spit
354− [our her]
355− wasp(ham [%carp (ksin p.gim) inx wit gom i.ruv])
356− :- vie
357− $(ruv t.ruv, inx +(inx))
358−```
359−
360−Here we package each block into a packet with `++spit` and produce the
361−list of packets.
362−
363−```hoon
364− ++ spit :: cake to packet
365− |= kec=cake ^- @
366− =+ wim=(met 3 p.p.kec)
367− =+ dum=(met 3 q.p.kec)
368− =+ yax=?:((lte wim 2) 0 ?:((lte wim 4) 1 ?:((lte wim 8) 2 3)))
369− =+ qax=?:((lte dum 2) 0 ?:((lte dum 4) 1 ?:((lte dum 8) 2 3)))
370− =+ wix=(bex +(yax))
371− =+ vix=(bex +(qax))
372− =+ bod=:(mix p.p.kec (lsh 3 wix q.p.kec) (lsh 3 (add wix vix) r.kec))
373− =+ tay=(ksin q.kec)
374− %+ mix
375− %+ can 0
376− :~ [3 1]
377− [20 (mug bod)]
378− [2 yax]
379− [2 qax]
380− [5 tay]
381− ==
382− (lsh 5 1 bod)
383−```
384−
385−This is how we turn a message into a real packet. This has the
386−definition of the packet format.
387−
388−`wim` is the length of the sending ship, and `dum` is the length of the
389−receiving ship. There are only five possibilities for each of those,
390−corresponding to carriers, cruisers, destroyers, yachts, and submarines.
391−These are encoded in `yax` and `qax` as 0, 0, 1, 2, and 3, respectively.
392−Thus, `wix` and `vix` are the number of bytes that must be reserved for
393−the ship names in a packet.
394−
395−Next, we construct `bod` by simply concatenating the sending ship, the
396−receiving ship, and the body of the message. Then, we get the encryption
397−mechanism from `++skin:ames`, which may be a 0, 1, 2, or 3, and put it in
398−`tay`.
399−
400−Next, we concatenate together, bit by bit, some final metadata. We use
401−three bits for our protocol number, which is incremented modulo eight
402−when there is a continuity breach or the protocol changes. We use the
403−final twenty bits of a hash of the body (which, we suppose, makes it a
404−twenty bit hash) for error-checking. We use two bits to tell how much
405−room is used in the body for the sending ship, and another two bits for
406−the receiving ship. Finally, we use five bits to store the encryption
407−type. Note that since there are only two bits worth of encryption types,
408−there are three unused bits here. This adds up to 32 bits of header
409−data. Finally, we concatenate this onto the front of the packet. Thus,
410−we can summarize the packet header format as follows.
411−
412−```
413− 0 1 2 3
414− 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
415− +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
416− |Proto| Hash of Body |yax|qax| Crypto |
417− +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
418−```
419−
420−After this, there are `yax` bits of the sender name, `qax` bits of the
421−receiver name, and up to 8192 bits of data. Thus, the maximum size of a
422−packet is achieved in a message between two submarines with 8192 bits of
423−data. This will require 32+128+128+8192 = 8480 bits, or 1060 bytes.
424−
425−This concludes our discussion of `++zuul:lax:as:go`. If you recall from
426−`++wind:ho:um:am`, the list of packets from `++zuul` is passed into
427−`++whap:pu` to update the packet pump and get any packets that can be
428−sent immediately.
429−
430−```hoon
431− ++ whap :: whap:pu
432− |= [now=@da gom=soup wyv=(list rock)] :: send a message
433− ^- [(list rock) _+>]
434− =. pyz (~(put by pyz) gom (lent wyv))
435− =. +>
436− |- ^+ +>.^$
437− ?~ wyv +>.^$
438− %= $
439− wyv t.wyv
440− nus +(nus)
441− diq (~(put by diq) (shaf %flap i.wyv) nus)
442− puq (~(put to puq) [nus `soul`[gom 0 | ~2000.1.1 i.wyv]])
443− ==
444− (harv now)
445−```
446−
447−First, we put into `pyz` the id for this message and the number of its
448−packets that have not yet been acknowledged, which is of course the
449−total number of packets since we haven't even sent the packets.
450−
451−For every packet, we change three things in the state (`++shed:ames`) of our
452−packet pump: (1) we increment `nus`, the number of packets sent; (2) we
453−put the packet number into `diq` keyed by a hash of the packet; and (3)
454−we put the packet into the packet queue, with the basic metadata of its
455−id `gom`, 0 transmissions, not live yet, last sent in the year 2000, and
456−the packet itself.
457−
458−Finally, we harvest the packet pump.
459−
460−```hoon
461− ++ harv :: harv:pu
462− |= now=@da :: harvest queue
463− ^- [(list rock) _+>]
464− ?: =(~ puq) [~ +>(rtn ~)]
465− ?. (gth caw nif) [~ +>]
466− =+ wid=(sub caw nif)
467− =| rub=(list rock)
468− =< abet =< apse
469− |%
470−```
471−
472−`++harv` contains a core for most of its work. The meat is in `++apse`.
473−First, though, it sets itself up. If there aren't any packets in the
474−queue, then we simply do nothing except set `rtn`, our next timeout, to
475−nil because we don't have any packets that may need to be retransmitted.
476−If we have more live (that is, sent and unacknowledged) packets than our
477−window size, then we don't do anything.
478−
479−Otherwise, we let `wid` be the width of our remaining packet window, and
480−we initialize `rub` to nil. `rub` will be the list of packets that are
481−ready to be sent. We then call `++apse` and pass the result to `++abet`.
482−`++apse` decides which packets are ready to be sent.
483−
484−```hoon
485− ++ apse
486− ^+ .
487− ?~ puq .
488− ?: =(0 wid) .
489− => rigt =< left
490− ?> ?=(^ puq)
491− ?: =(0 wid) .
492− ?. =(| liv.q.n.puq) .
493− :: ~& [%harv nux.q.n.puq p.n.puq]
494− %_ .
495− wid (dec wid)
496− rub [pac.q.n.puq rub]
497− nif +(nif)
498− liv.q.n.puq &
499− nux.q.n.puq +(nux.q.n.puq)
500− lys.q.n.puq now
501− ==
502−```
503−
504−If there are no remaining packets to send, or if we've filled the packet
505−window, do nothing. We call `++rigt` and `++left` to process the left
506−and right branches of the packet queue.
507−
508−Now we assert that the queue is not empty, and we again check that we
509−haven't filled the packet window. We will operate on the head of the
510−queue. If the packet is live, then do nothing. Otherwise, we go ahead
511−and send it.
512−
513−To send, we (1) decrement `wid`, our packet window width; (2) cons the
514−packet onto the `rub`, which will be returned as the list of packets to
515−send; (3) increment `nif`, the number of live packets; (4) set the
516−packet to be live; (5) increment the number of transmissions of the
517−packet; and (6) set the last sent time of the packet to now.
518−
519−```hoon
520− ++ left
521− ?> ?=(^ puq)
522− ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq])))
523− ++ rigt
524− ?> ?=(^ puq)
525− ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig])))
526−```
527−
528−These do exactly what you would expect: they traverse the packet queue
529−so that `++apse` gets called recursively through it.
530−
531−Finally, `++abet` gets called, which resolves the changes.
532−
533−```hoon
534− ++ abet
535− ?~ rub [~ +>.$]
536− [(flop rub) +>.$(rtn [~ (add rto now)])]
537−```
538−
539−This returns the packets that we wish to send, and it updates the
540−timeout so that we know when to try resending unacknowledged packets.
541−
542−This concludes our discussion of `++whap:pu`. To finish
543−`++wind:ho:um:am`, we just need to delve into `++busk:ho:um:am`. But
544−wait, in the call to `++busk`, the first argument is `xong:diz`. What is
545−this? This, my dear reader, is one more detour, this time into
546−`++xong:lax:as:go`.
547−
548−```hoon
549− ++ xong :: xong:lax:as:go
550− ^- (list ship) :: route unto
551− =+ [fro=xen too=xeno]
552− =+ ^= oot ^- (list ship)
553− =| oot=(list ship)
554− |- ^+ oot
555− ?~ too ~
556− ?: (lien fro |=(a=ship =(a i.too))) ~
557− [i.too $(too t.too)]
558− :: ~& [%xong-to [our her] (weld oot ?>(?=(^ fro) t.fro))]
559− (weld oot ?>(?=(^ fro) t.fro))
560−```
561−
562−This gets the list of intermediate ships needed to get a packet from us
563−to our neighbor. First, we get `fro` and `too`, the "canons" of ourself
564−and our neighbor, respectively.
565−
566−What is this "canon", you ask? A canon is simply a ship plus its
567−"ancestors", as defined by `++sein:title`. For example, the canon of
568−`~hoclur-bicrel` is:
569−
570−```
571− ~hoclur-bicrel/try=> (saxo:title ~hoclur-bicrel)
572− ~[~hoclur-bicrel ~tasruc ~tug]
573−```
574−
575−If we follow the algorithm in `++xong`, we see that we are simply
576−creating a list of ships that form a path from our neighbor to ourself.
577−Essentially, we look through the canon of our neighbor until we find
578−something in our own cannon -- a common ancestor. Or, if we are from
579−different carriers, then there is no common ancestor. We then weld this
580−onto the tail of our own canon. In the end, this is simply a list of
581−possible ships to try to route via to get to our neighbor, ordered by
582−preferability (that is, closeness to our neighbor). We will end up
583−trying, in order, to find a lane to these.
584−
585−Now, we can finally get to `++busk:ho:um:am`.
586−
587−```hoon
588− ++ busk :: busk:ho:um:am
589− |= [waz=(list ship) pax=(list rock)] :: send packets
590− %_ +>
591− bin
592− |- ^+ bin
593− ?~ pax bin
594− $(pax t.pax, bin (weld (flop (wist:diz now waz ~ i.pax)) bin))
595− ==
596−```
597−
598−Thankfully, `++busk` is fairly simple. We go through the list of packets
599−and convert them to `++boon:ames`s with `++wist:lax:as:go`. These boons are
600−placed into `bin`, and they end up getting processed by `++clop` (this
601−happens in `++knob`).
602−
603−```hoon
604− ++ wist :: wist:lax:as:go
605− |= $: now=@da :: route via
606− waz=(list ,@p)
607− ryn=(unit lane)
608− pac=rock
609− ==
610− ^- (list boon)
611− ?: =(our her) [[%ouzo *lane pac] ~]
612− ?~ waz ~
613− =+ dyr=?:(=(her i.waz) dur (gur i.waz))
614− ?. ?& !=(our i.waz)
615− ?=(^ lun.wod.dyr)
616− ==
617− $(waz t.waz)
618− :_ ?: ?=(%ix -.u.lun.wod.dyr)
619− $(waz t.waz)
620− ~
621− :+ %ouzo u.lun.wod.dyr
622− ?: &(=(i.waz her) =(~ ryn)) pac
623− =+ mal=(jam `meal`[%fore her ryn pac])
624− %- spit
625− ^- cake
626− :* [our i.waz]
627− ?~ yed.caq.dyr [%none mal]
628− :- %fast
629− %^ cat 7
630− p.u.yed.caq.dyr
631− (en:crub:crypto q.u.yed.caq.dyr mal)
632− ==
633−```
634−
635−This takes a sample of the current time, the list of ships that we just
636−generated, a lane if we already know it, and the packet itself.
637−
638−First, if we are sending a message to ourself, then we simply create a
639−`%ouzo` boon with a bunted lane. Otherwise, if there are no routing
640−candidates, there is nothing we can do, so we return nil.
641−
642−Next, we get the `++dore:ames` of the first routing candidate. If we're looking
643−at the neighbor to whom we're trying to send the message, then we simply
644−use the `++dore:ames` that we already have. Otherwise, we get a default `++dore:ames`.
645−
646−If we're the first routing candidate, or if we have don't have a lane to
647−this candidate, then we skip this candidate and move on to the next one.
648−
649−If we have only a provisional ip address, then we try to send on it, but
650−we also try to send on later routing candidates as well. Otherwise, we
651−only send on this one candidate.
652−
653−Finally, we create the actual `%ouzo` boon. The lane is the one from our
654−`++dore:ames`. If we're sending it directly to our intended recipient, and we
655−haven't been told to use a specific lane, then we just send the packet
656−directly. Otherwise, we wrap it in a little `%fore` meal, telling the
657−intermediary to whom we wish it to be sent. If we have already set up a
658−symmetric key with the intermediary, then we encrypt it with that.
659−Otherwise, we send it in the clear.
660−
661−Now, if you recall, we have traced all the way through from the
662−beginning when, in `++knob`, the `%wont` card was handled by a call to
663−`++wise`. There is only one more step before the packet is finally sent.
664−Looking in `++knob`, we see that the resultant list of boons is passed
665−into `++clop`, which will execute the correct actions and return a list
666−of moves. In `++clop`, we see the handling of each specific boon. The
667−one we are interested in is `%ouzo`, since that is the only one we have
668−sent thus far.
669−
670−```hoon
671− %ouzo
672− :: ~& [%send now p.bon `@p`(mug (shaf %flap q.bon))]
673− :_ fox
674− [[gad.fox [%give %send p.bon q.bon]] ~]
675−```
676−
677−Very simply, we give a `%send` gift along the special duct that goes
678−straight into the bowels of unix. This is the last stop before we drop
679−into vere, and later libuv. And then... the world.
680−
681−The packet, after its creation, embarks on a journey across physical
682−time and space into the great unknown. Hurtling through fiber-optic
683−cables at hundreds of thousands of kilometers per second, it finally
684−arrives at our neighbor's network adapter. The adapter tells unix, unix
685−tells libuv, libuv tells vere, and vere sends a `%hear` task to ames.
686−And now we reenter the kernel.
687−
688−The `%hear` task goes straight to `++knob`, just as did the `%wont` task
689−earlier.
690−
691−```hoon
692− %hear
693− (~(gnaw am [now fox]) %good p.kyz q.kyz)
694−```
695−
696−Here, though, we call `++gnaw:am` to process the packet. The arguments
697−to `++gnaw` are the same as those to the `%hear` task: the lane on which
698−the packet was received and the packet itself. The other argument is
699−just `%good`, which is a `++cape:ames` saying that we expect the packet to
700−succeed. If a formal error occurs, then since we have a transactional
701−event system, the `%hear` event will never be considered to have
702−actually happened, and unix will send a `%hole` task so that we may send
703−a negative acknowledgment.
704−
705−```hoon
706− ++ gnaw :: gnaw:am
707− |= [kay=cape ryn=lane pac=rock] :: process packet
708− ^- [p=(list boon) q=fort]
709− ?. =(2 (end 0 3 pac)) [~ fox]
710− =+ kec=(bite pac)
711− ?: (goop p.p.kec) [~ fox]
712− ?. (~(has by urb.ton.fox) q.p.kec)
713− [~ fox]
714− =< zork
715− =< zank
716− %- ~(chew la:(ho:(um q.p.kec) p.p.kec) kay ryn %none (shaf %flap pac))
717− [q.kec r.kec]
718−```
719−
720−First, we check the protocol number. If it is not correct, then we
721−simply ignore the packet entirely. Otherwise, we parse the packet with
722−`++bite`, which converts a packet atom into a `++cake:ames`, that is, a triple
723−of the `sock` (pair of sender and receiver), the `skin` (encryption
724−type), and the data.
725−
726−```hoon
727− ++ bite :: packet to cake
728− |= pac=rock ^- cake
729− =+ [mag=(end 5 1 pac) bod=(rsh 5 1 pac)]
730− =+ :* vez=(end 0 3 mag) :: protocol version
731− chk=(cut 0 [3 20] mag) :: checksum
732− wix=(bex +((cut 0 [23 2] mag))) :: width of receiver
733− vix=(bex +((cut 0 [25 2] mag))) :: width of sender
734− tay=(cut 0 [27 5] mag) :: message type
735− ==
736− ?> =(2 vez)
737− ?> =(chk (end 0 20 (mug bod)))
738− :+ [(end 3 wix bod) (cut 3 [wix vix] bod)]
739− (kins tay)
740− (rsh 3 (add wix vix) bod)
741−```
742−
743−This is exactly the inverse of `++spit`. Note that here we check both
744−the protocol number and the hash, crashing on error. Remember that a
745−crash will result in a negative acknowledgment being sent.
746−
747−Continuing in `++gnaw`, we see that if the intended recipient is not on
748−our pier, then we drop the packet.
749−
750−If we've gotten this far, then we wish to process the packet. Recall
751−that `++ho` and `++um` set up the domestic server and foreign client
752−cores, respectively, and that `++zork` and `++zank` resolve any changes
753−to these cores.
754−
755−The new stuff here, then, is the `++la` core and the `++chew` arm. The
756−`++la` sets up a core for this particular packet, containing the current
757−success/failure `++cape:ames`, the lane it was sent on, the encryption type,
758−and a hash of the packet, used as an id.
759−
760−`++chew` is called with the encryption type and the message itself. It
761−contains a little helper core inside of it, which starts immediately
762−with `++apse`.
763−
764−```hoon
765− ++ apse
766− ^+ +>.$
767− =+ oub=bust:puz
768− =+ neg==(~ yed.caq.dur.diz)
769− =. +>.$ east
770− =+ eng==(~ yed.caq.dur.diz)
771− =+ bou=bust:puz
772− =. bin
773− ?. &(oub !bou) bin
774− :_(bin [%wine [our her] " is ok"])
775− =. bin
776− ?. &(neg !eng) bin
777− :_(bin [%wine [our her] " is your neighbor"])
778− +>.$
779−```
780−
781−First, we let `oub` be true if our neighbor hasn't been responding to us
782−for more than sixteen seconds. Let `neg` be true if we haven't yet
783−proposed a symmetric key, meaning that we haven't yet corresponded with
784−this ship, so they are not our neighbor. Next, we run `++east`, which
785−we'll go into in just a minute.
786−
787−We now do the same two checks and store the results in `eng` and `bou`.
788−If our neighbor has, like the prodigal son, returned after an extended
789−absence, then we send a `%wine` boon as the proverbial fatted calf,
790−which is simply printed out to the console. Likewise, if we are meeting
791−one with whom we have never had the pleasure of acquainting ourselves,
792−we send a message to the console to that effect.
793−
794−We skipped over `++east`, which contains the meat of the processing. It
795−first decrypts the message, then calls `++chow:la:ho:um:am` with the
796−resultant meal. We'll go through each of the four cases in turn, but
797−first since each one calls `++bilk:pu`, we'll take a brief detour.
798−
799−```hoon
800− ++ bilk :: bilk:pu
801− |= now=@da :: inbound packet
802− ^+ +>
803− =+ trt=(mul 2 rtt)
804− %= +>.$
805− rue [~ now]
806− rto trt
807− rtn ?~(puq ~ [~ (add now trt)])
808− ==
809−```
810−
811−This updates the timing information in our packet pump. `rue`, the last
812−time we have heard from this neighbor, is set to now. `rto`, the
813−retransmit timeout is set to twice the current ping time, and if there
814−is anything in the packet queue, then we reset the next timeout, since
815−we've just heard a message.
816−
817−Back to `++east`.
818−
819−```hoon
820− %none
821− =. puz (bilk:puz now)
822− (chow ((hard meal) (cue msg)))
823−```
824−
825−The simplest case is when the encryption type is `%none`. We first call
826−`++bilk` to update the packet pump, then we cue (unjam) the message into
827−a meal. We hard cast it into a meal -- if the cast fails, then we do
828−want to crash since someone is sending us malformed data. Finally, we
829−send the result to `++chow` for interpretation and handling.
830−
831−```hoon
832− %fast
833− =+ [mag=`hand`(end 7 1 msg) bod=(rsh 7 1 msg)]
834− =+ dey=(kuch:diz mag)
835− ?~ dey
836− ~& [%bad-key her mag]
837− +>.$ :: ignore unknown key
838− =. puz (bilk:puz now)
839− =^ key diz u.dey
840− (chow(aut sin) ((hard meal) (cue (dy:q:sen:gus key bod))))
841−```
842−
843−For symmetric encryption, we first get the `++hand`, which is the hash of
844−the symmetric key. We pass it to `++kuch:lax:as:go`, which returns the
845−key if we either have used it before or we have proposed it. If we have
846−proposed it, then we change its status from proposed to real. If
847−`++kuch` fails, then we drop the packet and print out a `%bad-key`
848−message.
849−
850−Otherwise, we call `++bilk` as before to update the packet pump and pass
851−into `++chow` the decrypted data.
852−
853−```hoon
854− %full
855− =+ mex=((hard ,[p=[p=life q=life] q=will r=@]) (cue msg))
856− =. diz (deng:diz q.mex)
857− =+ wug=cluy:diz
858− ?> =(q.p.mex p.wug)
859− =+ gey=(sev:gus p.p.mex)
860− =+ mes=(need (tear:as:q.gey pub:ex:r.wug r.mex))
861− =. diz (wasc:diz p.mes)
862− =. puz (bilk:puz now)
863− (west(msg q.mes))
864−```
865−
866−For sealed asymmetric encryption, we first take off the the layer of
867−data that gives us the life and will of our neighbor, and we apply try
868−to extend their former will with the new data. `++deng` will fail if
869−this is impossible.
870−
871−Next, we get our most current understanding of our neighbor's crypto,
872−and we verify that it's the same life as what they're sending. Then, we
873−get our own crypto from `++sev` and decrypt the message with the public
874−key from our neighbor's crypto. We register the proposed symmetric key,
875−update the packet pump, and call `++west`, which simply casts the
876−message to a meal and calls `++chow`, reporting any error.
877−
878−```hoon
879− %open
880− =+ mex=((hard ,[p=[~ q=life] q=will r=@]) (cue msg))
881− =. diz (deng:diz q.mex)
882− =+ wug=cluy:diz
883− ?> =(q.p.mex p.wug)
884− =+ mes=(need (sure:as:r.wug *code r.mex))
885− =. puz (bilk:puz now)
886− (west(msg mes))
887−```
888−
889−Finally, for signed asymmetric encryption, we, as before, take off the
890−layer of data that gives us the life and will of our neighbor. This
891−time, of course, we do not get our own crypto -- only that of our
892−neighbor.
893−
894−The rest you have seen. We call `++deng` to extend the will, we verify
895−that their crypto life is what we think it ought to be, we "decrypt" the
896−data, we update the packet pump, and we call `++west` to call `++chow`.
897−
898−```hoon
899− ++ chow :: chow:la:ho:um:am
900− |= fud=meal :: interpret meal
901− ^+ +>
902− =. diz ?:(=(%none aut) diz (wast:diz ryn))
903− (dine fud)
904−```
905−
906−Here, if the message was encrypted at all, then we call
907−`++wast:lax:as:go`, which simply updates the lane (route) to our
908−neighbor (unless we're given a provisional route). This ensures that we
909−always have the most direct possible path to them.
910−
911−We've been handling this meal for so long, we've almost forgotten what
912−we want to do with it. The telos is of any meal to be dined on. We will
913−choose out the cases here that are important to our current
914−investigation.
915−
916−```hoon
917− %fore
918− =+ ^= lyn ^- lane
919− ?~ q.fud ryn
920− ?. ?=(%if -.u.q.fud) u.q.fud
921− [%ix +.u.q.fud]
922− :: u.q.fud
923− ?: =(our p.fud)
924− (emit %mead lyn r.fud)
925− =+ zid=(myx:gus p.fud)
926− (emir (wist:zid now xong:zid [~ lyn] r.fud))
927−```
928−
929−Forwarding is the simplest case, since we've seen all the arms before,
930−except perhaps `++emit` and `++emir`, which simply take a boon or list
931−of boons respectively and queue them up to be handled when the core
932−resolves. If we're told to forward a packet to ourselves, then we emit a
933−`%mead` boon which simply sends another `%hear` task to ourselves with
934−the data. Otherwise, we try to find a route to the recipient, as before.
935−
936−```hoon
937− %carp
938− =+ zol=(~(get by olz.weg) s.fud)
939− ?^ zol cock(kay u.zol)
940− =^ neb nys.weg
941− =+ neb=(~(get by nys.weg) s.fud)
942− ?^ neb [u.neb nys.weg]
943− =+ neb=`bait`[(kins p.fud) 0 r.fud ~]
944− [neb (~(put by nys.weg) s.fud neb)]
945− ?> (lth q.fud p.r.neb)
946− ?> =((kins p.fud) p.neb)
947− ?> =(r.fud p.r.neb)
948− =+ doy=`(unit ,@)`(~(get by q.r.neb) q.fud)
949− ?^ doy cock
950− => ^+ . %= .
951− q.r.neb (~(put by q.r.neb) q.fud t.fud)
952− q.neb +(q.neb)
953− ==
954− :: ~& [%carp q.fud s.fud q.neb p.r.neb]
955− ?: =(q.neb p.r.neb)
956− =: nys.weg (~(del by nys.weg) s.fud)
957− olz.weg (~(put by olz.weg) s.fud kay)
958− ==
959− (golf p.neb r.neb)
960− =. +>.$ cock
961− +>.$(nys.weg (~(put by nys.weg) s.fud neb))
962−```
963−
964−Here, we have received a partial message, and we're just assembling the
965−individual packets into a message. Most of this code is fairly
966−algorithmic, so we'll just hit the high points. In the beginning, we
967−check if we've already received this message, and if so, we resend the
968−acknowledgment. Remember, "always ack a dupe, never ack an ack".
969−
970−In `nys.weg` we keep track of an incoming set of partial packets,
971−indexed by the `flap` hash that comes with every packet. We check to see
972−if we have already received this partial message, and if so we
973−acknowledge it. Otherwise, we put it in `nys.weg` unless this is the
974−last message, in which case we ack the last partial message, move the
975−complete message into `olz.weg`, and call `++golf`, which assembles the
976−message and calls `++chew`, to start the dance again with the complete
977−message.
978−
979−```hoon
980− %bund
981− :: ~& [%bund q.fud r.fud]
982− ?> =(p:sen:gus p.fud)
983− (deer q.fud r.fud ?-(kay %dead ~, %good [~ s.fud]))
984−```
985−
986−What if we're just receiving a regular old, garden variety message? We
987−call `++deer` with the data from the message. If we already know that
988−the message processing will fail (that is, if we got a `%hole` card from
989−unix rather than a `%hear` card), then we don't even send the data at
990−all. Remember, if a packet fails to process, it's as if it never even
991−arrived, except that we send a negative acknowledgment.
992−
993−```hoon
994− ++ deer :: deer:la:ho:um:am
995− |= [cha=path num=@ud dut=(unit)] :: interpret message
996− ^+ +>
997− =+ rum=(fall (~(get by raz.bah) cha) *race)
998− %= +>.$
999− +>
1000− ?. (gte num did.rum) :: always ack a dup
1001− (cook (~(get by bum.rum) num) cha ~ ryn dam)
1002− ?: dod.rum
1003− (coat cha rum(mis (~(put by mis.rum) num [kay ryn dam dut])))
1004− %= +>.+>.$
1005− raz.bah
1006− %+ ~(put by raz.bah) cha
1007− rum(mis (~(put by mis.rum) num [kay ryn dam dut]))
1008− ==
1009− ==
1010−```
1011−
1012−First, we get the race for this particular triple of sender, receiver,
1013−and path, creating it if it doesn't exist. If we've already acked the
1014−message, then we resend the ack. Note that `did.rum` is the number of
1015−packets we acknowledged, positively or negatively while `bum.rum` is a
1016−map of message numbers to negative acknowledgments. Thus, if a message
1017−number is less than `did.rum`, then if it's in `bum.rum` then it was
1018−negatively acknowledged, otherwise it's positively acknowledged. Thus, we
1019−are constant in space with the number of successful messages and linear
1020−in the number of failed messages. We'll document `++cook` later on, but
1021−suffice it to say that it sends an acknowledgment. It is to end-to-end
1022−acknowledgments what `++cock` is to packet-level acknowledgments.
1023−
1024−If we are still processing a message (that is, `dod.rum` is false), then
1025−we simply put this message in the map of misordered packets to be
1026−processed when their time comes. "Processing a message" in this case
1027−means that we've received the message and notified the correct
1028−application, but we're still waiting for the application-level
1029−acknowledgment.
1030−
1031−Otherwise, we're ready for a packet, so we process it.
1032−
1033−```hoon
1034− ++ coat :: coat:ho:um:am
1035− |= [cha=path rum=race] :: update input race
1036− ^+ +>
1037− =+ cun=(~(get by mis.rum) did.rum)
1038− ?~ cun
1039− +>.$(raz.bah (~(put by raz.bah) cha rum))
1040− ?. =(%good p.u.cun) +>.$
1041− ?> ?=(^ s.u.cun)
1042− %= +>.$
1043− raz.bah (~(put by raz.bah) cha rum(dod |))
1044− bin
1045− :_ bin
1046− :^ %mulk
1047− [our her]
1048− `soap:ames`[[p:sen:gus clon:diz] cha did.rum]
1049− u.s.u.cun
1050− ==
1051−```
1052−
1053−First, we grab the message we want to process and store it in `cun`. If
1054−it's a good packet, then we change `dod.rum` to false, meaning that
1055−we're in the middle of processing a packet and should not start
1056−processing another one. We also put a `%mulk` boon into the queue so
1057−that, when it all resolves, we send a mesage to the intended recipient
1058−application. The boon contains the sender, the receiver, the identity of
1059−the message, and the message itself.
1060−
1061−This bubbles up all the way back to `++knob`, where we were handling the
1062−`%hear` card. Following the logic in `++knob`, we can see that the boons
1063−get sent into `++clop` to be turned into actual arvo-level moves. We've
1064−been here before, if you recall, when we handled the `%cake` boon to
1065−send a message. Now, we're handling the `%mulk` boon, which is
1066−unfortunately slightly more complicated.
1067−
1068−```hoon
1069− %mulk
1070− :: ~& [%mulk p.bon q.bon]
1071− ?> ?=([@ @ *] q.q.bon)
1072− ?> ?=(%q i.q.q.bon)
1073− ?+ i.t.q.q.bon
1074− ~& %mulk-bad
1075− :_ fox
1076− :~ :- (claw p.p.bon)
1077− [%sick %wart p.bon i.t.q.q.bon t.t.q.q.bon r.bon]
1078− ==
1079− %ge :: %gall request
1080− ?> ?=([@ ~] t.t.q.q.bon)
1081− =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon))
1082− =+ ^= pax
1083− :+ (scot %p p.p.bon)
1084− (scot %p q.p.bon)
1085− q.q.bon
1086− :_ fox [hen %pass pax %g %rote p.bon app r.bon]~
1087− %gh :: %gall response
1088− ?> ?=([@ ~] t.t.q.q.bon)
1089− =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon))
1090− =+ ^= pax
1091− :+ (scot %p p.p.bon)
1092− (scot %p q.p.bon)
1093− q.q.bon
1094− :_ fox [hen %pass pax %g %roth p.bon app r.bon]~
1095− ==
1096−```
1097−
1098−We're dispatching messages based on the prefix of their path. Since only
1099−`%gall` apps use end-to-end acknowledgments at the moment, every path
1100−must have at least two elements, and the first one must be `%q`. Beyond
1101−that, we handle the `/q/ge` and `/q/gh` cases for gall requests and
1102−responses, respectively.
1103−
1104−In both cases, we require the next term in the path to be the name of
1105−the intended recipient `%gall` app. Thus, a message to `/q/ge/talk` for
1106−example, will send a message to the talk app.
1107−
1108−We then send a message to the app itself. The message is either a
1109−`%rote` or a `%roth` for a request and a response, respectively. The
1110−content is the `rook` or `roon` that was sent (stored in `r.bon`), but
1111−we don't actually handle that at all here. That's completely a
1112−`%gall`-level thing. We're just the messenger.
1113−
1114−Notice the path we send this over. We encode the sender, the receiver,
1115−and the path over which it was sent. This fully specifies the `race` so
1116−that when the app gives us the acknowledgment we know where to send it.
1117−
1118−We now have another interlude. We have entrusted our precious data, so
1119−carefully guarded and guided from the app on that far-away ship, to our
1120−local app. It has the ability to do whatever it pleases with it. It may
1121−take a significant amount of time to process. When the message has been
1122−handled by this app, though, it must produce an acknowledgment. Our
1123−final task is to deliver this acknowledgment to the sending app.
1124−
1125−We should describe here what exactly these oft-mentioned acknowledgments
1126−actually consist of. There are two kinds of acknowledgments: positive
1127−and negative. A positive acknowledgment contains no data other than its
1128−existence. A negative acknowledgment may optionally include a reason for
1129−said negativity. Formally, a negative acknowledgment is an `ares`, which
1130−is a unit pair of a term and a list of tanks. If this is null, this is
1131−simply a failure with no associated information. If the pair exists, the
1132−term is a short error code that is usually both human and computer
1133−readable. For example, if you try to send a message to a valid `%gall`
1134−app that doesn't have any `++poke` to handle it, then `%gall` will give
1135−a negative acknowledgment with error term `%poke-find-fail`. The list of
1136−tanks is a human-readable description of the error. This often contains
1137−a stack trace. At any rate, all this information is returned to the
1138−sending app on the other end of the wire.
1139−
1140−After this brief interlude, our story resumes in `++knap`, where we
1141−receive responses. In particular, a `%mean` indicates a negative
1142−acknowledgment while a `%nice` indicates a positive acknowledgment.
1143−
1144−```hoon
1145− ?(%mean %nice)
1146− ?> ?=([@ @ @ *] tea)
1147− =+ soq=[(slav %p i.tea) (slav %p i.t.tea)]
1148− =+ pax=t.t.tea
1149− =+ ^= fuy
1150− =< zork =< zank
1151− %^ ~(rack am [now fox]) soq pax
1152− ?-(+<.sih %mean `p.+.sih, %nice ~)
1153− => %_(. fox q.fuy)
1154− =| out=(list move)
1155− |- ^- [p=(list move) q=_+>.^$]
1156− ?~ p.fuy
1157− [(flop out) +>.^$]
1158− =^ toe fox (clop now hen i.p.fuy)
1159− $(p.fuy t.p.fuy, out (weld (flop toe) out))
1160−```
1161−
1162−Recall the format of the path we sent the message on, and you'll
1163−understand why `soq` and `pax` are the sender/receiver pair and path on
1164−which the message was sent. The rest of this is structured much like
1165−`++knob`, so we call `++rack:am` and send the resulting boons to
1166−`++clop`. Business as usual.
1167−
1168−```hoon
1169− ++ rack :: rack:am
1170− |= [soq=sock cha=path cop=coop] :: e2e ack
1171− =+ oh=(ho:(um p.soq) q.soq)
1172− =. oh (cook:oh cop cha ~)
1173− (cans:oh cha)
1174−```
1175−
1176−First, we set up `++um` and `++ho`, as we've done twice before, for our
1177−domestic and foreign servers, respectively. The other two things are
1178−new, though. Well, `++cook` is not actually new, but we delayed the
1179−explanation saying only that it sends an acknowledgment. The time has
1180−come.
1181−
1182−```hoon
1183− ++ cook :: cook:ho:um:am
1184− |= [cop=coop cha=path ram=(unit ,[ryn=lane dam=flap])]
1185− ^+ +> :: acknowledgment
1186− =+ rum=(need (~(get by raz.bah) cha))
1187− =+ lat=(~(get by mis.rum) did.rum)
1188− ?: &(?=(~ lat) ?=(~ ram)) ~&(%ack-late-or-redundant +>.$)
1189− =+ ^- [ryn=lane dam=flap]
1190− ?^ ram [ryn.u.ram dam.u.ram]
1191− ?< ?=(~ lat)
1192− [q r]:u.lat
1193− =. raz.bah
1194− ?^ ram raz.bah
1195− %+ ~(put by raz.bah) cha
1196− rum(dod &, bum ?~(cop bum.rum (~(put by bum.rum) did.rum u.cop)))
1197− =^ roc diz (zuul:diz now [%buck cop dam ~s0])
1198− (busk(diz (wast:diz ryn)) xong:diz roc)
1199−```
1200−
1201−If we are acknowledging a message that we have already acked, the `ram`
1202−will contain the new lane and flap to send the duplicate ack to. This
1203−happens if we call `++cook` in `++deer`, but it doesn't happen from
1204−`++rack`. If there is no message waiting to be acknowledged and we're
1205−not given an explicit lane and flap (that is, we're not sending a
1206−duplicate ack), then the app must have sent us multiple acknowledgments.
1207−We do the only sensible thing we can do and drop all acknowledgments
1208−after the first, printing a message. This is, in fact, an error, so it
1209−could be argued that we ought to crash. Whatever you do, don't depend on
1210−this not crashing.
1211−
1212−First, we grab the race specified by the given path, and we get the most
1213−recent in-order message, which must be the one which is being
1214−acknowledged.
1215−
1216−Then, we decide which lane/flap to respond on/to. Basically, in the
1217−usual case we respond on the lane through which the initial message was
1218−sent, which is stored along with the other packet information in
1219−`mis.rum`, since it has to be remembered across calls to ames. However,
1220−if we receive a duplicate message, then we must respond to the new
1221−message. It's quite possible the reason the other acknowledgment didn't
1222−get returned was that the lane between the ships was broken.
1223−
1224−At any rate, we update the race by saying that we've finished processing
1225−this packet (unless we're sending a duplicate ack) and, if we're sending
1226−a negative acknowledgment, putting the negative ack into `bum.rum` so
1227−that we can resend it if necessary.
1228−
1229−We encode our new message, updating the packet pump, with `++zuul`, as
1230−before, and we send it off with `++busk`, routed via `++wast` to one of
1231−the ships in `++xong`. Of course, in practice, we don't even look at the
1232−ships in `++xong` because we already have a lane directly to our
1233−neighbor (the one over which they sent their message to us).
1234−
1235−We glossed over the actual message we're sending back. We're sending a
1236−`%buck` meal, which is an acknowledgment. The `cop` specifies whether
1237−this is a positive or a negative ack, `dam` specifies the message we're
1238−acknowledging, and the `~s0` is a placeholder for the processing time
1239−required. This time is neither calculated (though it is hopefully
1240−obvious how to do so) nor used at present, but this information may be
1241−used in the future for improved congestion control. Since the round-trip
1242−time for an end-to-end acknowledged packet includes the processing time
1243−on the other end, most common congestion control algorithms will stumble
1244−when some messages take much longer to process than others. As noted,
1245−though, this is simply an opportunity for improvement -- our congestion
1246−control algorithms are relatively naive at the moment.
1247−
1248−Recall that `++busk` calls `++wist` to put the actual `%ouzo` boon in
1249−the queue, which gets handled by `++clop` to actually send the message.
1250−This is the same pipeline as sending any other message, so we'll refer
1251−you to the explanation above if you've forgotten it.
1252−
1253−The last thing we need to do on this ship is move on to the next packet
1254−in the queue if there is one. If you recall, in `++rack` after the call
1255−to `++cook` there was a call to `++cans:ho:um:am`.
1256−
1257−```hoon
1258− ++ cans :: cans:ho:um:am
1259− |= cha=path
1260− =+ rum=(need (~(get by raz.bah) cha))
1261− =. rum
1262− %= rum
1263− did +(did.rum)
1264− mis (~(del by mis.rum) did.rum)
1265− ==
1266− (coat cha rum)
1267−```
1268−
1269−This is very simple. We increment the number of packets that we've
1270−acknowledged on this race and we delete the packet that we just
1271−acknowledged from the set of misordered packets.
1272−
1273−Then, we call `++coat` again to process the next packet if we've already
1274−received it. And that's it for this.
1275−
1276−The acknowledgment now travels the same path that its forebearer, the
1277−original message, once tread, but this time not into the great unknown.
1278−The weary traveler is seeking out its familial roots, finding the app
1279−from whom sprung forth the original message way back in paragraph three.
1280−When it arrives at the network adapter of its ancestors, the adapter
1281−tells unix, unix tells libuv, libuv tells vere, and vere sends a `%hear`
1282−task to ames. Once more into the kernel.
1283−
1284−The `%hear` task is handled in `++knob` as before, leading to `++gnaw`,
1285−going over to `++chew`, `++apse`, `++chow`, and eventualy to `++dine`.
1286−We've seen most of the cases in `++dine`, but we haven't yet looked at
1287−the handling of this `%buck` meal.
1288−
1289−```hoon
1290− %buck
1291− =. +> ?.(=(%full aut) +> cock) :: finish key exch
1292− +>(..la (tock p.fud q.fud r.fud))
1293−```
1294−
1295−We send a packet level acknowledgment if we're finishing a key exchange,
1296−else we call `++tock` to process the acknowledgment.
1297−
1298−This will get a little involved, so if you don't much care about how
1299−exactly an acknowledgment happens, just know that the result gets gifted
1300−as a `%woot` card back to the app who sent it. For those brave souls who
1301−wish to see this thing through to the end, it's once more into the
1302−breach.
1303−
1304−```hoon
1305− ++ tock :: tock:ho:um:am
1306− |= [cop=coop fap=flap cot=@dr] :: e2e ack by hash
1307− ^+ +>
1308− =^ yoh puz (bick:puz now fap)
1309− =. +>.$
1310− ?~ p.yoh +>.$
1311− =^ hud +>.$
1312− (done p.u.p.yoh q.u.p.yoh)
1313− ?~ hud +>.$
1314− %= +>.$
1315− bin
1316− :_ bin
1317− `boon`[%cake [our her] [[p:sen:gus clon:diz] u.p.yoh] cop u.hud]
1318− ==
1319− (busk xong:diz q.yoh)
1320−```
1321−
1322−We're going to work through this one a little backwards since it's
1323−mostly fairly simple except the call to `++bick:pu`. In fact, we'll just
1324−skip `++bick` for the moment and finish the rest.
1325−
1326−If `++bick` succesfully acks the message, then we call `++done`.
1327−
1328−```hoon
1329− ++ done :: done:ho:um:am
1330− |= [cha=path num=@ud] :: complete outgoing
1331− ^- [(unit duct) _+>]
1332− =+ rol=(need (~(get by ryl.bah) cha))
1333− =+ rix=(~(get by san.rol) num)
1334− ?~ rix [~ +>.$]
1335− :- rix
1336− %_ +>.$
1337− ryl.bah
1338− (~(put by ryl.bah) cha rol(san (~(del by san.rol) num)))
1339− ==
1340−```
1341−
1342−This very simply gets the rill (the outgoing counterpart to a race, if
1343−you recall), pulls out of the map of outstanding messages the duct over
1344−which the original message was sent, and produces this duct while
1345−deleting that entry from the map of outstanding messages.
1346−
1347−Going back to `++tock`, we now have the duct we need to return the
1348−result over. We do the very sensible thing and put a `%cake` boon in the
1349−queue to be processed later by `++clop`.
1350−
1351−In `q.yoh` we have a list of messages that may need to be sent, which we
1352−pass to `++busk` to send, as usual. When an acknowledgment arrives, that
1353−may trigger other messages immediately. This often happens when sending
1354−more messages than the width of the logical window since for congestion
1355−control reasons another message cannot be sent until some of the earlier
1356−ones have been acknowledged.
1357−
1358−We'll look at the processing of the `%cake` boon in `++clop` before we
1359−get back to talking about `++bick`.
1360−
1361−```hoon
1362− %cake
1363− :_ fox
1364− :~ [s.bon %give %woot q.p.bon r.bon]
1365− ==
1366−```
1367−
1368−We very simply give, along the duct we found above, a `%woot` card with
1369−the ship who sent us the ack and the ack itself. This allows the
1370−application to decide what to do about the result. In case of a failure,
1371−we usually either resend the message or display it to the user.
1372−Sometimes, we recognize the error term and handle it internally. In any
1373−case, the decision of how to handle the acknowledgment is entirely up to
1374−the application. Our job is done.
1375−
1376−Well, except that we skipped `++bick:pu`. Let's go back to that.
1377−
1378−```hoon
1379− ++ bick :: bick:pu
1380− |= [now=@da fap=flap] :: ack by hash
1381− ^- [[p=(unit soup) q=(list rock)] _+>]
1382− =+ sun=(~(get by diq) fap)
1383− ?~ sun
1384− [[~ ~] +>.$]
1385− =. diq (~(del by diq) fap)
1386− =^ gub +>.$ (bock now u.sun)
1387− =^ yop +>.$ (harv now)
1388− [[gub yop] +>.$]
1389−```
1390−
1391−If you recall, in `++whap:pu` we created the packet pump's
1392−representation of the message, which included putting the message into
1393−`diq`, which maps from packet hashes to packet sequence numbers. Thus,
1394−`u.sun` is the sequence number of this particular message.
1395−
1396−We delete this message from `diq` since we have now received an ack for
1397−it. We call `++bock` to perform the ack by sequence number. We call
1398−`++harv` to harvest the packet queue, sending any messages that are now
1399−able to be sent.
1400−
1401−In `++bock`, there are three arms we haven't seen before: `++bine`,
1402−`+wept`, and `++beet`. We'll describe each of these before we get to
1403−`++bock`. `++bine` looks scariest.
1404−
1405−```hoon
1406− ++ bine :: bine:pu
1407− |= [now=@da num=@ud] :: apply ack
1408− ^- [(unit soup) _+>]
1409− ?~ puq !!
1410− ?. =(num p.n.puq)
1411− ?: (gth num p.n.puq)
1412− =+ lef=$(puq l.puq)
1413− [-.lef +.lef(puq [n.puq puq.lef r.puq])]
1414− =+ rig=$(puq r.puq)
1415− [-.rig +.rig(puq [n.puq l.puq puq.rig])]
1416− =: rtt ?. &(liv.q.n.puq =(1 nux.q.n.puq)) rtt
1417− =+ gap=(sub now lys.q.n.puq)
1418− :: ~& [%bock-trip num (div gap (div ~s1 1.000))]
1419− (div (add (mul 2 rtt) gap) 3)
1420− nif (sub nif !liv.q.n.puq)
1421− ==
1422− =+ lez=(dec (need (~(get by pyz) gom.q.n.puq)))
1423− =^ gub pyz
1424− ?: =(0 lez)
1425− [[~ gom.q.n.puq] (~(del by pyz) gom.q.n.puq)]
1426− [~ (~(put by pyz) gom.q.n.puq lez)]
1427− :- gub
1428− +>.$(puq ~(nap to puq))
1429−```
1430−
1431−The first few lines are simply looking through the packet queue until we
1432−find the correct packet to ack. This is basic queue manipulation that
1433−operates directly on the treap structure of the queue. If you understand
1434−treap queues, the logic is easy to follow. Otherwise, just trust us that
1435−by the time we get to the `=:`, the packet with sequence number `num` is
1436−on the top of the packet queue (that is, at `n.puq`).
1437−
1438−We first update the round-trip time. If the packet is either not alive
1439−or had to be transmitted more than once, then we don't have any reliable
1440−way of calculating the round-trip time since we're unsure of exactly
1441−which transmission was acknowledged. Otherwise, the round-trip time is
1442−the difference between now and when the packet was last sent. We set
1443−`rtt` by a little weighted average where the previous smoothed RTT is
1444−weighted twice as much as the RTT of the current packet. Thus,
1445−`(2*rtt+gap)/3`. This gives us a nice smooth RTT that is somewhat
1446−resilient to outlier data while still being responsive to our
1447−ever-changing world.
1448−
1449−If the packet wasn't already dead, then we decrement the number of live
1450−packets, which may allow more packets to be sent.
1451−
1452−We decrement the number of unacknowledged packets in our `pyz` for this
1453−particular message. If you recall, this was set in `++whap` to the
1454−number of packets required to send a message.
1455−
1456−If that was the last packet in the messge that needed to be acked, then
1457−we delete the messgae reference from `pyz` and produce the id of the
1458−message. Otherwise, we simply update `pyz` with the new number of
1459−unacked messages. In either case, we remove the packet from the packet
1460−queue.
1461−
1462−```hoon
1463− ++ wept :: wept:pu
1464− |= [fip=@ud lap=@ud] :: fip thru lap-1
1465− =< abet =< apse
1466− |%
1467− ++ abet +>.$
1468− ++ apse
1469− ^+ .
1470− ?~ puq .
1471− ?: (lth p.n.puq fip) ?~(l.puq . left)
1472− ?: (gte p.n.puq lap) ?~(r.puq . rigt)
1473− => rigt =< left
1474− ?> ?=(^ puq)
1475− ?.(liv.q.n.puq . .(nif (dec nif), liv.q.n.puq |))
1476− ::
1477− ++ left
1478− ?> ?=(^ puq)
1479− ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq])))
1480− ++ rigt
1481− ?> ?=(^ puq)
1482− ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig])))
1483− --
1484−```
1485−
1486−The algorithm is a simple case of traversing the packet queue.
1487−Essentialy, we mark as dead all packets in the queue between `fip` and
1488−`(dec lap)`. We also update `nif`, the number of live packets. Lest you
1489−mourn too much the passing of these packets, know that they shall soon
1490−rise again. Recall that in `++bick` after the call to `++bock` we call
1491−`++harv`. This will resend the packets that have just been labeled dead.
1492−
1493−```hoon
1494− ++ beet :: beet:pu
1495− ^+ . :: advance unacked
1496− =- +(nep ?~(foh nus u.foh))
1497− ^= foh
1498− |- ^- (unit ,@ud)
1499− ?~ puq ~
1500− ?: (lte p.n.puq nep) $(puq l.puq)
1501− =+ rig=$(puq r.puq)
1502− ?^(rig rig [~ p.n.puq])
1503−```
1504−
1505−Here we search for the next expected packet number. Basically, we search
1506−the queue for the leftmost packet whose number is greater than the
1507−current `nep`. If we don't find any such packet, we just use the total
1508−number of packets sent.
1509−
1510−We can now dive into `++bock`, our last arm.
1511−
1512−```hoon
1513− ++ bock :: bock:pu
1514− |= [now=@da num=@ud] :: ack by sequence
1515− ^- [(unit soup) _+>]
1516− =^ gym +> (bine now num)
1517− :- gym
1518− ?: (gth num nep)
1519− =+ cam=(max 2 (div caw 2))
1520− :: ~& [%bock-hole num nep cam]
1521− beet:(wept(nep num, cag cam, caw cam) nep num)
1522− =. caw ?: (lth caw cag) +(caw)
1523− (add caw !=(0 (mod (mug now) caw)))
1524− ?: =(num nep)
1525− :: ~& [%bock-fine num nif caw cag]
1526− beet
1527− :: ~& [%bock-fill num nif caw cag]
1528− +>.$
1529−```
1530−
1531−First, we call `++bine` to apply the ack to the packet pump information.
1532−We produce `gym`, which, if it exists, is the id of the packet that was
1533−acked. If we received an ack for a packet later than the one we
1534−expected, then we halve the logical packet window and kill all the
1535−earlier packets so that they may be resent.
1536−
1537−Otherwise, we possibly increase the congestion window. If the window is
1538−less than the congestion threshold, then we increment the size of the
1539−window. Otherwise, we only increment one out of every `caw` times.
1540−
1541−If we received an ack for the packet we expected, then we simply advance
1542−`nep` with `++beet`. If we received an ack for a packet earlier than we
1543−expected, we do nothing.
1544−
1545−It may be hard to believe, but we are, in fact, done. The message has
1546−been sent, received, acknowledged, and the acknowledgment has been
1547−returned to the original sender. We hope it's clear that, while the
1548−process has been somewhat involved, the algorithms are not all that
1549−complicated. If you've read this far, you know `%ames`. The only other
1550−code involves initialization, timeouts, and the like.
1551−
1552−Below, we give detailed reference documentation for the data models
1553−involved.
1554−
1555−## Data Models
1556−
1557−### `++sufi:ames`, domestic host
1558−
1559−```hoon
1560− ++ sufi :: domestic host
1561− $: hoy=(list ship) :: hierarchy
1562− val=wund :: private keys
1563− law=will :: server will
1564− seh=(map hand ,[p=ship q=@da]) :: key cache
1565− hoc=(map ship dore) :: neighborhood
1566− == ::
1567−```
1568−
1569−This is the security state of a domestic server.
1570−
1571−`hoy` is a list of the ships directly above us in the hierarchy of
1572−ships. For example, for `~hoclur-bicrel`, this would be `~tasruc` and
1573−`~tug`. See `++sein:title`.
1574−
1575−`val` is a list of our private keys.
1576−
1577−`law` is our certificate, which is a list of the XXX
1578−
1579−`seh`
1580−
1581−`hoc` is a map of ships to `++dore:ames`. The stores all the security
1582−information about foreign ships. The keys to this map are the neighbors
1583−(ships we have been in contact with) of this domestic server.
1584−
1585−### `++wund:ames`, private keys
1586−
1587−```hoon
1588− ++ wund (list ,[p=life q=ring r=acru]) :: mace in action
1589−```
1590−
1591−This is a list of our own private keys, indexed by life. The key itself
1592−is the `++ring`, and the `++acru:ames` is the encryption engine. We generate
1593−the `++acru:ames` from the private key by calling `++weur`. Thus, we can at
1594−any time regenerate our `++wund:ames` from a `++mace:ames`. The current crypto is
1595−at the head of the list and can be accessed with `++sen:as:go`.
1596−
1597−### `++ring`, private key
1598−
1599−```hoon
1600− ++ ring ,@ :: private key
1601−```
1602−
1603−This is a private key. The first byte is reserved to identify the type
1604−of cryptography. Lower-case means public key, upper-case means public
1605−key, and the letter identifies which `++acru:ames` to use.
1606−
1607−### `++pass`, public key
1608−
1609−```hoon
1610− ++ pass ,@ :: public key
1611−```
1612−
1613−This is a public key. The first byte is reserved to identify the type of
1614−cryptography. Lower-case means public key, upper-case means public key,
1615−and the letter identifies which `++acru:ames` to use.
1616−
1617−### `++mace:ames`, private secrets
1618−
1619−```hoon
1620− ++ mace (list ,[p=life q=ring]) :: private secrets
1621−```
1622−
1623−This is a list of the our private keys, indexed by life. From this we
1624−can generate a `++wund:ames` for actual use.
1625−
1626−### `++skin:ames`, encoding stem
1627−
1628−```hoon
1629− ++ skin ?(%none %open %fast %full) :: encoding stem
1630−```
1631−
1632−This defines the type of encryption used for each message. `%none`
1633−refers to messages sent in the clear, `%open` refers to signed messages,
1634−`%full` refers to sealed messages, and `%fast` refers to symmetrically
1635−encrypted messages. See `++acru:ames` for details.
1636−
1637−### `++acru:ames`, asymmetric cryptosuite
1638−
1639−```hoon
1640− ++ acru :: asym cryptosuite
1641− $_ ^? |% :: opaque object
1642− ++ as ^? :: asym ops
1643− |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
1644− ++ sign |=([a=@ b=@] _@) :: certify as us
1645− ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
1646− ++ tear |= [a=pass b=@] :: accept from a
1647− *(unit ,[p=@ q=@]) ::
1648− -- ::
1649− ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
1650− ++ dy |+([a=@ b=@] _@) :: symmetric de, hard
1651− ++ en |+([a=@ b=@] _@) :: symmetric en
1652− ++ ex ^? :: export
1653− |% ++ fig _@uvH :: fingerprint
1654− ++ pac _@uvG :: default passcode
1655− ++ pub *pass :: public key
1656− ++ sec *ring :: private key
1657− --
1658− ++ nu ^? :: reconstructors
1659− |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
1660− ++ nol |=(a=@ ^?(..nu)) :: from naked ring
1661− ++ com |=(a=@ ^?(..nu)) :: from naked pass
1662− --
1663− --
1664−```
1665−
1666−This is an opaque interface for a general asymmetric cryptosuite. Any
1667−form of asymmetric cryptography can be dropped in to be used instead of
1668−the default. Right now, there is one cryptosuite: `++crub:crypto:crypto`,
1669−which is elliptic-curve cryptography.
1670−
1671−#### `++as:acru:ames`, asymmetric operations
1672−
1673−```hoon
1674− ++ as ^? :: asym ops
1675− |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
1676− ++ sign |=([a=@ b=@] _@) :: certify as us
1677− ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
1678− ++ tear |= [a=pass b=@] :: accept from a
1679− *(unit ,[p=@ q=@]) ::
1680− -- ::
1681−```
1682−
1683−This is the core that defines the standard asymmetric cryptography
1684−operations.
1685−
1686−`++seal:as:acru:ames` allows us to send a message encrypted with someone's
1687−public key so that only they may read it. If Alice seals a message with
1688−Bob's public key, then she can be sure that Bob is the only one who can
1689−read it. This is associated with the `++skin:ames` `%full`.
1690−
1691−`++sign:as:acru:ames` allows us to sign a message with our private key so
1692−that others can verify that we sent the message. If Alice signs a
1693−message with her private key, then Bob can verify with her public key
1694−that it was indeed Alice who sent it. This is associated with the
1695−`++skin:ames` `%open`.
1696−
1697−`++sure:as:acru:ames` is the dual to `++sign:as:acru:ames`. It allows us to verify
1698−that a message we have received is indeed from the claimed sender. If
1699−Alice sends a message with her private key, then Bob can use this arm to
1700−verify that it was indeed Alice who sent it. This is associated with the
1701−`++skin:ames` `%open`.
1702−
1703−`++tear:as:acru:ames` is the dual to `++seal:as:acru:ames`. It allows us to read a
1704−message that we can be sure is only read by us. If Alice seals a message
1705−with Bob's public key, then Bob can use this arm to read it. This is
1706−associated with the `++skin:ames` `%full`.
1707−
1708−#### `++de:acru:ames`, `++dy:acru:ames`, and `++en:acru:ames`, symmetric encryption/decryption
1709−
1710−```hoon
1711− ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
1712− ++ dy |+([a=@ b=@] _@) :: symmetric de, hard
1713− ++ en |+([a=@ b=@] _@) :: symmetric en
1714−```
1715−
1716−Symmetric encryption is associated with the `++skin:ames` `%fast`.
1717−
1718−`++de:acru:ames` decrypts a message with a symmetric key, returning `~` on
1719−failure and `[~ u=data]` on success.
1720−
1721−`++dy:acru:ames` decrypts a message with a symmetric key, crashing on
1722−failure. This should almost always be defined as, and should always be
1723−semantically equivalent to, `(need (de a b))`.
1724−
1725−`++en:acru:ames` encrypts a message with a symmetric key.
1726−
1727−#### `++ex:acru:ames`, exporting data
1728−
1729−```hoon
1730− ++ ex ^? :: export
1731− |% ++ fig _@uvH :: fingerprint
1732− ++ pac _@uvG :: default passcode
1733− ++ pub *pass :: public key
1734− ++ sec *ring :: private key
1735− --
1736−```
1737−
1738−`++fig:ex:acru:ames` is our fingerprint, usually a hash of our public key.
1739−This is used, for example, in `++zeno`, where every carrier owner's
1740−fingerprint is stored so that we can ensure that carriers are indeed
1741−owned by their owners
1742−
1743−`++pac:ex:acru:ames` is our default passcode, which is unused at present.
1744−
1745−`++pub:ex:acru:ames` is the `++pass` form of our public key.
1746−
1747−`++sec:ex:acru:ames` is the `++ring` form of our private key.
1748−
1749−#### `++nu:acru:ames`, reconstructors
1750−
1751−```hoon
1752− ++ nu ^? :: reconstructors
1753− |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
1754− ++ nol |=(a=@ ^?(..nu)) :: from naked ring
1755− ++ com |=(a=@ ^?(..nu)) :: from naked pass
1756− --
1757−```
1758−
1759−These arms allow us to reconstruct a `++acru:ames` from basic data.
1760−
1761−`++pit:nu:acru:ames` constructs a `++acru:ames` from the width of our intended key
1762−and seed entropy. This is usually used in the initial construction of
1763−the `++acru:ames`.
1764−
1765−`++nol:nu:acru:ames` constructs a `++acru:ames` from a "naked ring", meaning a
1766−`++ring` without the initial byte identifying the type of crypto.
1767−
1768−`++com:nu:acru:ames` constructs a `++acru:ames` from a "naked pass", meaning a
1769−`++ring` without the initial byte identifying the type of crypto.
1770−
1771−### `++will`, certificate
1772−
1773−```hoon
1774− ++ will (list deed) :: certificate
1775−```
1776−
1777−This is a list of deeds associated with the current ship. There should
1778−be an item in this list for every ship from this point up in the
1779−hierarchy times the number of lives that each ship has had. For example,
1780−\~hoclur-bicrel may have a will with three items: one for itself, one
1781−for \~tasruc (who issued \~hoclur-bicrel's deed) and one for \~tug (who
1782−issued \~tasruc's deed).
1783−
1784−### `++deed`, identity
1785−
1786−```hoon
1787− ++ deed ,[p=@ q=step r=?] :: sig, stage, fake?
1788−```
1789−
1790−`p` is the signature of a particular deed, which is a signed copy of
1791−`q`.
1792−
1793−`q` is the stage in the identity.
1794−
1795−`r` is true if we're working on a fake network, where we don't check
1796−that the carrier fingerprints are correct. This allows us to create fake
1797−networks for development without interfering with the real network.
1798−
1799−### `++step:ames`, identity stage
1800−
1801−```hoon
1802− ++ step ,[p=bray q=gens r=pass] :: identity stage
1803−```
1804−
1805−This is a single stage in our identity. Thus, this is specific to a
1806−single life in a single ship. Everything in here may change between
1807−lives.
1808−
1809−`p`
1810−
1811−`q`
1812−
1813−`r` is the public key for this stage in the identity.
1814−
1815−### `++bray:ames`
1816−
1817−```hoon
1818− ++ bray ,[p=life q=(unit life) r=ship s=@da] :: our parent us now
1819−```
1820−
1821−XXX
1822−
1823−### `++gens:ames`, general identity
1824−
1825−```hoon
1826− ++ gens ,[p=lang q=gcos] :: general identity
1827−```
1828−
1829−`p` is the IETF language code for the preferred language of this
1830−identity. This is unused at the moment, but in the future text should be
1831−localized based on this.
1832−
1833−`q` is the description of the ship.
1834−
1835−### `++gcos:ames`, identity description
1836−
1837−```hoon
1838− ++ gcos :: id description
1839− $% [%czar ~] :: 8-bit ship
1840− [%duke p=what] :: 32-bit ship
1841− [%earl p=@t] :: 64-bit ship
1842− [%king p=@t] :: 16-bit ship
1843− [%pawn p=(unit ,@t)] :: 128-bit ship
1844− == ::
1845−```
1846−
1847−This is the description of the identity of a ship. Most types of
1848−identity have a `@t` field, which is their human-readable name. The
1849−identity of a `%duke` is more involved.
1850−
1851−A `%czar`, a carrier, is a ship with an 8-bit address. Thus, there are
1852−only 256 carriers. These are at the top of the namespace hierarchy, and
1853−the fingerprint of each carrier is stored in `++zeno`. These are the
1854−"senators" of Urbit.
1855−
1856−A `%king`, a cruiser, is a ship with a 16-bit address. Thus, there are
1857−65,536 cruisers. Each carrier may issue 256 cruisers. These are the
1858−infrastructure of Urbit.
1859−
1860−A `%duke`, a destroyer, is a ship with a 32-bit address. Thus, there are
1861−4,294,967,296 destroyers. Each cruiser may issue 65,536 cruisers. These
1862−are the individuals of Urbit.
1863−
1864−A `%earl`, a yacht, is a ship with a 64-bit address. Thus, there are
1865−18,446,744,073,709,551,616 yachts. Each destroyer may issue
1866−4,294,967,296 yachts. These are the devices of Urbit.
1867−
1868−A `%pawn`, a submarine, is a ship with a 128-bit address. Thus, there
1869−are a lot of submarines. The chance of random name collision is
1870−negligible, so submarines are not issued by any ship. They must simply
1871−assert their presence, and they are all considered children of \~zod.
1872−This is the underworld of Urbit, where anonymity reigns supreme.
1873−
1874−### `++what:ames`, logical destroyer identity
1875−
1876−```hoon
1877− ++ what :: logical identity
1878− $% [%anon ~] :: anonymous
1879− [%lady p=whom] :: female person ()
1880− [%lord p=whom] :: male person []
1881− [%punk p=sect q=@t] :: opaque handle ""
1882− == ::
1883−```
1884−
1885−This is the logical identity of a destroyer.
1886−
1887−A `%anon` is a completely anonymous destroyer. The difference between
1888−this and a submarine is that a submarine is ephemeral while a `%anon`
1889−destroyer is not. Thus, we may not know who \~hoclur-bicrel is, but we
1890−do know that it's always the same person.
1891−
1892−A `%lady` is a female person. The name used here should be a real name.
1893−
1894−A `%lord` is a male person. The name used here should be a real name.
1895−
1896−A `%punk` is a person who is identified only by a handle.
1897−
1898−### `++whom:ames`, real person
1899−
1900−```hoon
1901− ++ whom ,[p=@ud q=govt r=sect s=name] :: year/govt/id
1902−```
1903−
1904−Ths is the information associated with a real person. It is mostly
1905−information that could be observed with the briefest of interactions.
1906−
1907−`p` is the birth year.
1908−
1909−`q` is the location of a user, usually of the form "country/zip".
1910−
1911−`r` is the sect of the user.
1912−
1913−`s` is the real name of the person.
1914−
1915−### `++govt:ames`
1916−
1917−```hoon
1918− ++ govt path :: country/postcode
1919−```
1920−
1921−This is the location of the user, usually of the form "country/zip".
1922−
1923−### `++sect:ames`
1924−
1925−```hoon
1926− ++ sect ?(%black %blue %red %orange %white) :: banner
1927−```
1928−
1929−XXX
1930−
1931−### `++name:ames`
1932−
1933−```hoon
1934− ++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last
1935−```
1936−
1937−This is the given name, possible middle name/initial, possible nickname,
1938−and surname of a user.
arvo/behn.mddeleted−20
@@ -1,20 +0,0 @@
1−+++
2−title = "Behn"
3−weight = 2
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/behn/"]
6−+++
7−Our simple timer.
8−
9−It allows vanes and applications to set and timer events, which are
10−managed in a simple priority queue. `%behn` produces effects to start
11−the unix timer, and when the requested `%behn` passes, unix sends wake
12−events to `%behn`, which time routes back to original sender. We don't
13−guarantee that a timer event will happen at exactly the `%behn` it was
14−set for, or even that it'll be particularly close. A timer event is a
15−request to not be woken until after the given time.
16−
17−`%eyre` uses `%behn` for timing out sessions, and `%clay` uses `%behn`
18−for keeping track of time-specified file requests. `%ames` should
19−probably use `%behn` to keep track of things like network timeouts and
20−retry timing, but it currently uses its own alarm system.
arvo/clay.mddeleted−2626
@@ -1,2626 +0,0 @@
1−+++
2−title = "Clay"
3−weight = 3
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/clay/"]
6−+++
7−Our filesystem.
8−
9−`%clay` is version-controlled, referentially-transparent, and global.
10−While this filesystem is stored in `%clay`, it is mirrored to Unix for
11−convenience. Unix tells `%clay`s whenever a file changes in the Unix
12−copy of the filesystem so that the change may be applied. `%clay` tells
13−unix whenever an app or vane changes the filesystem so that the change
14−can be effected in Unix. Apps and vanes may use `%clay` to write to the
15−filesystem, query it, and subscribe to changes in it. Ford and gall use
16−`%clay` to serve up apps and web pages.
17−
18−`%clay` includes three components. First is the filesystem/version
19−control algorithms, which are mostly defined in `++ze` and `++zu` in
20−zuse. Second is the write, query, and subscription logic. Finally, there
21−is the logic for communicating requests to, and receiving requests from,
22−foreign ships.
23−
24−## Architecture
25−
26−Clay is the primary filesystem for the arvo operating system,
27−which is the core of an urbit. The architecture of clay is
28−intrinsically connected with arvo, but we assume no knowledge of
29−either arvo or urbit. We will point out only those features of
30−arvo that are necessary for an understanding of clay, and we will
31−do so only when they arise.
32−
33−The first relevant feature of arvo is that it is a deterministic
34−system where input and output are defined as a series of events
35−and effects. The state of arvo is simply a function of its event
36−log. None of the effects from an event are emitted until the
37−event is entered in the log and persisted, either to disk or
38−another trusted source of persistence, such as a Kafka cluster.
39−Consequently, arvo is a single-level store: everything in its
40−state is persistent.
41−
42−In a more traditional OS, everything in RAM can be erased at any
43−time by power failure, and is always erased on reboot. Thus, a
44−primary purpose of a filesystem is to ensure files persist across
45−power failures and reboots. In arvo, both power failures and
46−reboots are special cases of suspending computation, which is
47−done safely since our event log is already persistent. Therefore,
48−clay is not needed in arvo for persistence. Why, then, do we have a
49−filesystem? There are two answers to this question.
50−
51−First, clay provides a filesystem tree, which is a convenient
52−user interface for some applications. Unix has the useful concept
53−of virtual filesystems, which are used for everything from direct
54−access to devices, to random number generators, to the /proc
55−tree. It is easy and intuitive to read from and write to a
56−filesystem tree.
57−
58−Second, clay has a distributed revision-control system baked into
59−it. Traditional filesystems are not revision controlled, so
60−userspace software -- such as git -- is written on top of them to
61−do so. clay natively provides the same functionality as modern
62−DVCSes, and more.
63−
64−clay has two other unique properties that we'll cover later on:
65−it supports typed data and is referentially transparent.
66−
67−### Revision Control
68−
69−Every urbit has one or more "desks", which are independently
70−revision-controlled branches. Each desk contains its own mark
71−definitions, apps, doc, and so forth.
72−
73−Traditionally, an urbit has at least a base and a home desk. The
74−base desk has all the system software from the distribution. the
75−home desk is a fork of base with all the stuff specific to the
76−user of the urbit.
77−
78−A desk is a series of numbered commits, the most recent of which
79−represents the current state of the desk. A commit is composed of
80−(1) an absolute time when it was created, (2) a list of zero or
81−more parents, and (3) a map from paths to data.
82−
83−Most commits have exactly one parent, but the initial commit on a
84−desk may have zero parents, and merge commits have more than one
85−parent.
86−
87−The non-meta data is stored in the map of paths to data. It's
88−worth noting that no constraints are put on this map, so, for
89−example, both /a/b and /a/b/c could have data. This is impossible
90−in a traditional Unix filesystem since it means that /a/b is both
91−a file and a directory. Conventionally, the final element in the
92−path is its mark -- much like a filename extension in Unix. Thus,
93−/doc/readme.md in Unix is stored as /doc/readme/md in urbit.
94−
95−The data is not stored directly in the map; rather, a hash of the
96−data is stored, and we maintain a master blob store. Thus, if the
97−same data is referred to in multiple commits (as, for example,
98−when a file doesn't change between commits), only the hash is
99−duplicated.
100−
101−In the master blob store, we either store the data directly, or
102−else we store a diff against another blob. The hash is dependent
103−only on the data within and not on whether or not it's stored
104−directly, so we may on occasion rearrange the contents of the
105−blob store for performance reasons.
106−
107−Recall that a desk is a series of numbered commits. Not every
108−commit in a desk must be numbered. For example, if the base desk
109−has had 50 commits since home was forked from it, then a merge
110−from base to home will only add a single revision number to home,
111−although the full commit history will be accessible by traversing
112−the parentage of the individual commits.
113−
114−We do guarantee that the first commit is numbered 1, commits are
115−numbered consecutively after that (i.e. there are no "holes"),
116−the topmost commit is always numbered, and every numbered commit
117−is an ancestor of every later numbered commit.
118−
119−There are three ways to refer to particular commits in the
120−revision history. Firstly, one can use the revision number.
121−Secondly, one can use any absolute time between the one numbered
122−commit and the next (inclusive of the first, exclusive of the
123−second). Thirdly, every desk has a map of labels to revision
124−numbers. These labels may be used to refer to specific commits.
125−
126−Additionally, clay is a global filesystem, so data on other urbit
127−is easily accessible the same way as data on our local urbit. In
128−general, the path to a particular revision of a desk is
129−/~urbit-name/desk-name/revision. Thus, to get /try/readme/md
130−from revision 5 of the home desk on ~sampel-sipnym, we refer to
131−/~sampel-sipnym/home/5/try/readme/md. Clay's namespace is thus
132−global and referentially transparent.
133−
134−XXX reactivity here?
135−
136−### A Typed Filesystem
137−
138−Since clay is a general filesystem for storing data of arbitrary
139−types, in order to revision control correctly it needs to be
140−aware of types all the way through. Traditional revision control
141−does an excellent job of handling source code, so for source code
142−we act very similar to traditional revision control. The
143−challenge is to handle other data similarly well.
144−
145−For example, modern VCSs generally support "binary files", which
146−are files for which the standard textual diffing, patching, and
147−merging algorithms are not helpful. A "diff" of two binary files
148−is just a pair of the files, "patching" this diff is just
149−replacing the old file with the new one, and "merging"
150−non-identical diffs is always a conflict, which can't even be
151−helpfully annotated. Without knowing anything about the structure
152−of a blob of data, this is the best we can do.
153−
154−Often, though, "binary" files have some internal structure, and
155−it is possible to create diff, patch, and merge algorithms that
156−take advantage of this structure. An image may be the result of a
157−base image with some set of operations applied. With algorithms
158−aware of this set of operations, not only can revision control
159−software save space by not having to save every revision of the
160−image individually, these transformations can be made on parallel
161−branches and merged at will.
162−
163−Suppose Alice is tasked with touching up a picture, improving the
164−color balance, adjusting the contrast, and so forth, while Bob
165−has the job of cropping the picture to fit where it's needed and
166−adding textual overlay. Without type-aware revision control,
167−these changes must be made serially, requiring Alice and Bob to
168−explicitly coordinate their efforts. With type-aware revision
169−control, these operations may be performed in parallel, and then
170−the two changesets can be merged programmatically.
171−
172−Of course, even some kinds of text files may be better served by
173−diff, patch, and merge algorithms aware of the structure of the
174−files. Consider a file containing a pretty-printed JSON object.
175−Small changes in the JSON object may result in rather significant
176−changes in how the object is pretty-printed (for example, by
177−addding an indentation level, splitting a single line into
178−multiple lines).
179−
180−A text file wrapped at 80 columns also reacts suboptimally with
181−unadorned Hunt-McIlroy diffs. A single word inserted in a
182−paragraph may push the final word or two of the line onto the
183−next line, and the entire rest of the paragraph may be flagged as
184−a change. Two diffs consisting of a single added word to
185−different sentences may be flagged as a conflict. In general,
186−prose should be diffed by sentence, not by line.
187−
188−As far as the author is aware, clay is the first generalized,
189−type-aware revision control system. We'll go into the workings
190−of this system in some detail.
191−
192−### Marks
193−
194−Central to a typed filesystem is the idea of types. In clay, we
195−call these "marks". A mark is a file that defines a type,
196−conversion routines to and from the mark, and diff, patch, and
197−merge routines.
198−
199−For example, a `%txt` mark may be a list of lines of text, and it
200−may include conversions to `%mime` to allow it to be serialized
201−and sent to a browswer or to the unix filesystem. It will also
202−include Hunt-McIlroy diff, patch, and merge algorithms.
203−
204−A `%json` mark would be defined as a json object in the code, and
205−it would have a parser to convert from `%txt` and a printer to
206−convert back to `%txt`. The diff, patch, and merge algorithms are
207−fairly straightforward for json, though they're very different
208−from the text ones.
209−
210−More formally, a mark is a core with three arms, `++grab`,
211−`++grow`, and `++grad`. In `++grab` is a series of functions to
212−convert from other marks to the given mark. In `++grow` is a
213−series of functions to convert from the given mark to other
214−marks. In `++grad` is `++diff`, `++pact`, `++join`, and `++mash`.
215−
216−The types are as follows, in an informal pseudocode:
217−
218−```
219− ++ grab:
220− ++ mime: <mime> -> <mark-type>
221− ++ txt: <txt> -> <mark-type>
222− ...
223− ++ grow:
224− ++ mime: <mark-type> -> <mime>
225− ++ txt: <mark-type> -> <txt>
226− ...
227− ++ grad
228− ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
229− ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
230− ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
231− ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
232−```
233−
234−These types are basically what you would expect. Not every mark
235−has each of these functions defined -- all of them are optional
236−in the general case.
237−
238−In general, for a particular mark, the `++grab` and `++grow` entries
239−(if they exist) should be inverses of each other.
240−
241−In `++grad`, `++diff` takes two instances of a mark and produces
242−a diff of them. `++pact` takes an instance of a mark and patches
243−it with the given diff. `++join` takes two diffs and attempts to
244−merge them into a single diff. If there are conflicts, it
245−produces null. `++mash` takes two diffs and forces a merge,
246−annotating any conflicts.
247−
248−In general, if `++diff` called with A and B produces diff D, then
249−`++pact` called with A and D should produce B. Also, if `++join`
250−of two diffs does not produce null, then `++mash` of the same
251−diffs should produce the same result.
252−
253−Alternately, instead of `++diff`, `++pact`, `++join`, and
254−`++mash`, a mark can provide the same functionality by defining
255−`++sted` to be the name of another mark to which we wish to
256−delegate the revision control responsibilities. Then, before
257−running any of those functions, clay will convert to the other
258−mark, and convert back afterward. For example, the `%hoon` mark
259−is revision-controlled in the same way as `%txt`, so its `++grad`
260−is simply `++sted %txt`. Of course, `++txt` must be defined in
261−`++grow` and `++grab` as well.
262−
263−Every file in clay has a mark, and that mark must have a
264−fully-functioning `++grad`. Marks are used for more than just
265−clay, and other marks don't need a `++grad`, but if a piece of
266−data is to be saved to clay, we must know how to revision-control
267−it.
268−
269−Additionally, if a file is to be synced out to unix, then it must
270−have conversion routines to and from the `%mime` mark.
271−
272−## Using clay
273−
274−### Reading and Subscribing
275−
276−When reading from Clay, there are three types of requests. A
277−`%sing` request asks for data at single revsion. A `%next`
278−request asks to be notified the next time there's a change to
279−given file. A `%many` request asks to be notified on every
280−change in a desk for a range of changes.
281−
282−For `%sing` and `%next`, there are generally three things to be
283−queried. A `%u` request simply checks for the existence of a
284−file at a path. A `%x` request gets the data in the file at a
285−path. A `%y` request gets a hash of the data in the file at the
286−path combined with all its children and their data. Thus, `%y`
287−of a node changes if it or any of its children change.
288−
289−A `%sing` request is fulfilled immediately if possible. If the
290−requested revision is in the future, or is on another ship for
291−which we don't have the result cached, we don't respond
292−immediately. If the requested revision is in the future, we wait
293−until the revision happens before we respond to the request. If
294−the request is for data on another ship, we pass on the request
295−to the other ship. In general, Clay subscriptions, like most
296−things in Urbit, aren't guaranteed to return immediately.
297−They'll return when they can, and they'll do so in a
298−referentially transparent manner.
299−
300−A `%next` request checks query at the given revision, and it
301−produces the result of the query the next time it changes, along
302−with the revsion number when it changes. Thus, a `%next` of a
303−`%u` is triggered when a file is added or deleted, a `%next` of a
304−`%x` is triggered when a file is added, deleted, or changed, and
305−a `%next` of a `%y` is triggered when a file or any of its
306−children is added, deleted, or changed.
307−
308−A `%many` request is triggered every time the given desk has a
309−new revision. Unlike a `%next`, a `%many` has both a start and
310−an end revsion, after which it stops returning. For `%next`, a
311−single change is reported, and if the caller wishes to hear of
312−the next change, it must resubscribe. For `%many`, every revsion
313−from the start to the end triggers a response. Since a `%many`
314−request doesn't ask for any particular data, there aren't `%u`,
315−`%x`, and `%y` versions for it.
316−
317−### Unix sync
318−
319−One of the primary functions of clay is as a convenient user
320−interface. While tools exist to use clay from within urbit, it's
321−often useful to be able to treat clay like any other filesystem
322−from the Unix perspective -- to "mount" it, as it were.
323−
324−From urbit, you can run `|mount /path/to/directory %mount-point`,
325−and this will mount the given clay directory to the mount-point
326−directory in Unix. Every file is converted to `%mime` before it's
327−written to Unix, and converted back when read from Unix. The
328−entire directory is watched (a la Dropbox), and every change is
329−committed once you run `|commit %mount-point`.
330−
331−### Merging
332−
333−Merging is a fundamental operation for a distributed revision
334−control system. At their root, clay's merges are similar to
335−git's, but with some additions to accomodate typed data. There
336−are seven different merge strategies.
337−
338−Throughout our discussion, we'll say that the merge is from
339−Alice's desk to Bob's. Recall that a commit is a date (for all
340−new commits this will be the current date), a list of parents,
341−and the data itself.
342−
343−A `%init` merge should be used iff it's the first commit to a
344−desk. The head of Alice's desk is used as the number 1 commit to
345−Bob's desk. Obviously, the ancestry remains intact through
346−traversing the parentage of the commit even though previous
347−commits are not numbered for Bob's desk.
348−
349−A `%this` merge means to keep what's in Bob's desk, but join the
350−ancestry. Thus, the new commit has the head of each desk as
351−parents, but the data is exactly what's in Bob's desk. For those
352−following along in git, this is the 'ours' merge strategy, not
353−the '--ours' option to the 'recursive' merge strategy. In other
354−words, even if Alice makes a change that does not conflict with
355−Bob, we throw it away. It's Bob's way or the highway.
356−
357−A `%that` merge means to take what's in Alice's desk, but join
358−the ancestry. This is the reverse of `%this`.
359−
360−A `%fine` merge is a "fast-forward" merge. This succeeds iff one
361−head is in the ancestry of the other. In this case, we use the
362−descendant as our new head.
363−
364−For `%meet`, `%mate`, and `%meld` merges, we first find the most
365−recent common ancestor to use as our merge base. If we have no
366−common ancestors, then we fail. If we have more than one most
367−recent common ancestor, then we have a criss-cross situation,
368−which should be handled delicately. At present, we delicately
369−throw up our hands and give up, but something akin to git's
370−'recursive' strategy should be implemented in the future.
371−
372−There's a functional inclusion ordering on `%fine`, `%meet`,
373−`%mate`, and `%meld` such that if an earlier strategy would have
374−succeeded, then every later strategy will produce the same
375−result. Put another way, every earlier strategy is the same as
376−every later strategy except with a restricted domain.
377−
378−A `%meet` merge only succeeds if the changes from the merge base
379−to Alice's head (hereafter, "Alice's changes") are in different
380−files than Bob's changes. In this case, the parents are both
381−Alice's and Bob's heads, and the data is the merge base plus
382−Alice's changed files plus Bob's changed files.
383−
384−A `%mate` merge attempts to merge changes to the same file when
385−both Alice and bob change it. If the merge is clean, we use it;
386−otherwise, we fail. A merge between different types of changes --
387−for example, deleting a file vs changing it -- is always a
388−conflict. If we succeed, the parents are both Alice's and Bob's
389−heads, and the data is the merge base plus Alice's changed files
390−plus Bob's changed files plus the merged files.
391−
392−A `%meld` merge will succeed even if there are conflicts. If
393−there are conflicts in a file, then we use the merge base's
394−version of that file, and we produce a set of files with
395−conflicts. The parents are both Alice's and Bob's heads, and the
396−data is the merge base plus Alice's changed files plus Bob's
397−changed files plus the successfully merged files plus the merge
398−base's version of the conflicting files.
399−
400−That's the extent of the merge options in clay proper. In
401−userspace there's a final option `%auto`, which is the most
402−common. `%auto` checks to see if Bob's desk exists, and if it
403−doesn't we use a `%init` merge. Otherwise, we progressively try
404−`%fine`, `%meet`, and `%mate` until one succeeds.
405−
406−If none succeed, we merge Bob's desk into a scratch desk. Then,
407−we merge Alice's desk into the scratch desk with the `%meld`
408−option to force the merge. For each file in the produced set of
409−conflicting files, we call the `++mash` function for the
410−appropriate mark, which annotates the conflicts if we know how.
411−
412−Finally, we display a message to the user informing them of the
413−scratch desk's existence, which files have annotated conflicts,
414−and which files have unannotated conflicts. When the user has
415−resolved the conflicts, they can merge the scratch desk back into
416−Bob's desk. This will be a `%fine` merge since Bob's head is in
417−the ancestry of the scratch desk.
418−
419−### Autosync
420−
421−Tracking and staying in sync with another desk is another
422−fundamental operation. We call this "autosync". This doesn't mean
423−simply mirroring a desk, since that wouldn't allow local changes.
424−We simply want to apply changes as they are made upstream, as
425−long as there are no conflicts with local changes.
426−
427−This is implemented by watching the other desk, and, when it has
428−changes, merging these changes into our desk with the usual merge
429−strategies.
430−
431−Note that it's quite reasonable for two desks to be autosynced to
432−each other. This results in any change on one desk being mirrored
433−to the other and vice versa.
434−
435−Additionally, it's fine to set up an autosync even if one desk,
436−the other desk, or both desks do not exist. The sync will be
437−activated when the upstream desk comes into existence and will
438−create the downstream desk if needed.
439−
440−## Commentary
441−
442−The first part of this section will be reference documentation for the data
443−types used by our filesystem. In fact, as a general guide, we recommend
444−reading and attempting to understand the data structures used in any
445−Hoon code before you try to read the code itself. Although complete
446−understanding of the data structures is impossible without seeing them
447−used in the code, an 80% understanding greatly clarifies the code. As
448−another general guide, when reading Hoon, it rarely pays off to
449−understand every line of code when it appears. Try to get the gist of
450−it, and then move on. The next time you come back to it, it'll likely
451−make a lot more sense.
452−
453−After a description of the data models, we'll give an overview of the
454−interface that vanes and applications can use to interact with the
455−filesystem.
456−
457−Finally, we'll dive into the code and the algorithms themselves. You
458−know, the fun part.
459−
460−### Data Models
461−
462−As you're reading through this section, remember you can always come
463−back to this when you run into these types later on. You're not going to
464−remember everything the first time through, but it is worth reading, or
465−at least skimming, this so that you get a rough idea of how our state is
466−organized.
467−
468−The types that are certainly worth reading are `++raft`, `++room`,
469−`++dome:clay`, `++ankh:clay`, `++rung:clay`, `++rang:clay`, `++blob:clay`, `++yaki:clay`, and `++nori:clay`
470−(possibly in that order). All in all, though, this section isn't too
471−long, so many readers may wish to quickly read through all of it. If you
472−get bored, though, just skip to the next section. You can always come
473−back when you need to.
474−
475−### `++raft`, formal state
476−
477−```hoon
478− ++ raft :: filesystem
479− $: fat=(map ship room) :: domestic
480− hoy=(map ship rung) :: foreign
481− ran=rang :: hashes
482− == ::
483−```
484−
485−This is the state of our vane. Anything that must be remembered between
486−calls to clay is stored in this state.
487−
488−`fat` is the set of domestic servers. This stores all the information
489−that is specfic to a particular ship on this pier. The keys to this map
490−are the ships on the current pier. all the information that is specific
491−to a particular foreign ship. The keys to this map are all the ships
492−whose filesystems we have attempted to access through clay.
493−
494−`ran` is the store of all commits and deltas, keyed by hash. The is
495−where all the "real" data we know is stored; the rest is "just
496−bookkeeping".
497−
498−#### `++room`, filesystem per domestic ship
499−
500−```hoon
501− ++ room :: fs per ship
502− $: hun=duct :: terminal duct
503− hez=(unit duct) :: sync duch
504− dos=(map desk dojo) :: native desk
505− == ::
506−```
507−
508−This is the representation of the filesystem of a ship on our pier.
509−
510−`hun` is the duct we use to send messages to dill to display
511−notifications of filesystem changes. Only `%note` gifts should be
512−produced along this duct. This is set by the `%init` kiss.
513−
514−`hez`, if present, is the duct we use to send sync messages to unix so
515−that they end up in the pier unix directory. Only `%ergo` gifts should
516−be producd along this duct. This is set by `%into` and `%invo` kisses.
517−
518−`dos` is a well-known operating system released in 1981. It is also the
519−set of desks on this ship, mapped to their data.
520−
521−#### `++desk`, filesystem branch
522−
523−```hoon
524− ++ desk ,@tas :: ship desk case spur
525−```
526−
527−This is the name of a branch of the filesystem. The default desks are
528−"arvo", "main", and "try". More may be created by simply referencing
529−them. Desks have independent histories and states, and they may be
530−merged into each other.
531−
532−### `++dojo`, domestic desk state
533−
534−```hoon
535− ++ dojo ,[p=cult q=dome] :: domestic desk state
536−```
537−
538−This is the all the data that is specific to a particular desk on a
539−domestic ship. `p` is the set of subscribers to this desk and `q` is the
540−data in the desk.
541−
542−#### `++cult`, subscriptions
543−
544−```hoon
545− ++ cult (map duct rave) :: subscriptions
546−```
547−
548−This is the set of subscriptions to a particular desk. The keys are the
549−ducts from where the subscriptions requests came. The results will be
550−produced along these ducts. The values are a description of the
551−requested information.
552−
553−#### `++rave:clay`, general subscription request
554−
555−```hoon
556− ++ rave :: general request
557− $% [& p=mood] :: single request
558− [| p=moat] :: change range
559− == ::
560−```
561−
562−This represents a subscription request for a desk. The request can be
563−for either a single item in the desk or else for a range of changes on
564−the desk.
565−
566−### `++rove`, stored general subscription request
567−
568−```hoon
569− ++ rove (each mood moot) :: stored request
570−```
571−
572−When we store a request, we store subscriptions with a little extra
573−information so that we can determine whether new versions actually
574−affect the path we're subscribed to.
575−
576−#### `++mood:clay`, single subscription request
577−
578−```hoon
579− ++ mood ,[p=care q=case r=path] :: request in desk
580−```
581−
582−This represents a request for the state of the desk at a particular
583−commit, specfied by `q`. `p` specifies what kind of information is
584−desired, and `r` specifies the path we are requesting.
585−
586−#### `++moat:clay`, range subscription request
587−
588−```hoon
589− ++ moat ,[p=case q=case r=path] :: change range
590−```
591−
592−This represents a request for all changes between `p` and `q` on path
593−`r`. You will be notified when a change is made to the node referenced
594−by the path or to any of its children.
595−
596−### `++moot`, stored range subscription request
597−
598−```hoon
599− ++ moot ,[p=case q=case r=path s=(map path lobe)] ::
600−```
601−
602−This is just a `++moat:clay` plus a map of paths to lobes. This map
603−represents the data at the node referenced by the path at case `p`, if
604−we've gotten to that case (else null). We only send a notification along
605−the subscription if the data at a new revision is different than it was.
606−
607−### `++care:clay`, clay submode
608−
609−```hoon
610− ++ care ?(%u %v %w %x %y %z) :: clay submode
611−```
612−
613−This specifies what type of information is requested in a subscription
614−or a scry.
615−
616−`%u` requests the `++rang:clay` at the current moment. Because this
617−information is not stored for any moment other than the present, we
618−crash if the `++case:clay` is not a `%da` for now.
619−
620−`%v` requests the `++dome:clay` at the specified commit.
621−
622−`%w` requests the revsion number of the desk.
623−
624−`%x` requests the file at a specified path at the specified commit. If
625−there is no node at that path or if the node has no contents (that is,
626−if `q:ankh` is null), then this produces null.
627−
628−`%y` requests a `++arch` of the specfied commit at the specified path.
629−
630−`%z` requests the `++ankh` of the specified commit at the specfied path.
631−
632−### `++arch`, shallow filesystem node
633−
634−```hoon
635− ++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node
636−```
637−
638−This is analogous to `++ankh:clay` except that the we have neither our
639−contents nor the ankhs of our children. The other fields are exactly the
640−same, so `p` is a hash of the associated ankh, `u.q`, if it exists, is a
641−hash of the contents of this node, and the keys of `r` are the names of
642−our children. `r` is a map to null rather than a set so that the
643−ordering of the map will be equivalent to that of `r:ankh`, allowing
644−efficient conversion.
645−
646−#### `++case:clay`, specifying a commit
647−
648−```hoon
649− ++ case :: ship desk case spur
650− $% [%da p=@da] :: date
651− [%tas p=@tas] :: label
652− [%ud p=@ud] :: number
653− == ::
654−```
655−
656−A commit can be referred to in three ways: `%da` refers to the commit
657−that was at the head on date `p`, `%tas` refers to the commit labeled
658−`p`, and `%ud` refers to the commit numbered `p`. Note that since these
659−all can be reduced down to a `%ud`, only numbered commits may be
660−referenced with a `++case:clay`.
661−
662−#### `++dome:clay`, desk data
663−
664−```hoon
665− ++ dome :: project state
666− $: ang=agon :: pedigree
667− ank=ankh :: state
668− let=@ud :: top id
669− hit=(map ,@ud tako) :: changes by id
670− lab=(map ,@tas ,@ud) :: labels
671− == ::
672−```
673−
674−This is the data that is actually stored in a desk.
675−
676−`ang` is unused and should be removed.
677−
678−`ank` is the current state of the desk. Thus, it is the state of the
679−filesystem at revison `let`. The head of a desk is always a numbered
680−commit.
681−
682−`let` is the number of the most recently numbered commit. This is also
683−the total number of numbered commits.
684−
685−`hit` is a map of numerical ids to hashes of commits. These hashes are
686−mapped into their associated commits in `hut:rang:clay`. In general, the keys
687−of this map are exactly the numbers from 1 to `let`, with no gaps. Of
688−course, when there are no numbered commits, `let` is 0, so `hit` is
689−null. Additionally, each of the commits is an ancestor of every commit
690−numbered greater than this one. Thus, each is a descendant of every
691−commit numbered less than this one. Since it is true that the date in
692−each commit (`t:yaki`) is no earlier than that of each of its parents,
693−the numbered commits are totally ordered in the same way by both
694−pedigree and date. Of course, not every commit is numbered. If that
695−sounds too complicated to you, don't worry about it. It basically
696−behaves exactly as you would expect.
697−
698−`lab` is a map of textual labels to numbered commits. Note that labels
699−can only be applied to numbered commits. Labels must be unique across a
700−desk.
701−
702−#### `++ankh`, filesystem node
703−
704−```hoon
705− ++ ankh :: fs node (new)
706− $: p=cash :: recursive hash
707− q=(unit ,[p=cash q=*]) :: file
708− r=(map ,@ta ankh) :: folders
709− == ::
710−```
711−
712−This is a single node in the filesystem. This may be file or a directory
713−or both. In earth filesystems, a node is a file xor a directory. On
714−mars, we're inclusive, so a node is a file ior a directory.
715−
716−`p` is a recursive hash that depends on the contents of the this file or
717−directory and on any children.
718−
719−`q` is the contents of this file, if any. `p.q` is a hash of the
720−contents while `q.q` is the data itself.
721−
722−`r` is the set of children of this node. In the case of a pure file,
723−this is empty. The keys are the names of the children and the values
724−are, recursively, the nodes themselves.
725−
726−#### `++cash`, ankh hash
727−
728−```hoon
729− ++ cash ,@uvH :: ankh hash
730−```
731−
732−This is a 128-bit hash of an ankh. These are mostly stored within ankhs
733−themselves, and they are used to check for changes in possibly-deep
734−hierarchies.
735−
736−#### `++rung`, filesystem per neighbor ship
737−
738−```hoon
739− ++ rung $: rus=(map desk rede) :: neighbor desks
740− == ::
741−```
742−
743−This is the filesystem of a neighbor ship. The keys to this map are all
744−the desks we know about on their ship.
745−
746−#### `++rede`, desk state
747−
748−```hoon
749− ++ rede :: universal project
750− $: lim=@da :: complete to
751− qyx=cult :: subscribers
752− ref=(unit rind) :: outgoing requests
753− dom=dome :: revision state
754− == ::
755−```
756−
757−This is our knowledge of the state of a desk, either foreign or
758−domestic.
759−
760−`lim` is the date of the last full update. We only respond to requests
761−for stuff before this time.
762−
763−`qyx` is the list of subscribers to this desk. For domestic desks, this
764−is simply `p:dojo`, all subscribers to the desk, while in foreign desks
765−this is all the subscribers from our ship to the foreign desk.
766−
767−`ref` is the request manager for the desk. For domestic desks, this is
768−null since we handle requests ourselves.
769−
770−`dom` is the actual data in the desk.
771−
772−#### `++rind`, request manager
773−
774−```hoon
775− ++ rind :: request manager
776− $: nix=@ud :: request index
777− bom=(map ,@ud ,[p=duct q=rave]) :: outstanding
778− fod=(map duct ,@ud) :: current requests
779− haw=(map mood (unit)) :: simple cache
780− == ::
781−```
782−
783−This is the request manager for a foreign desk.
784−
785−`nix` is one more than the index of the most recent request. Thus, it is
786−the next available request number.
787−
788−`bom` is the set of outstanding requests. The keys of this map are some
789−subset of the numbers between 0 and one less than `nix`. The members of
790−the map are exactly those requests that have not yet been fully
791−satisfied.
792−
793−`fod` is the same set as `bom`, but from a different perspective. In
794−particular, the values of `fod` are the same as the values of `bom`, and
795−the `p` out of the values of `bom` are the same as the keys of `fod`.
796−Thus, we can map ducts to their associated request number and `++rave:clay`,
797−and we can map numbers to their associated duct and `++rave:clay`.
798−
799−`haw` is a map from simple requests to their values. This acts as a
800−cache for requests that have already been made. Thus, the second request
801−for a particular `++mood:clay` is nearly instantaneous.
802−
803−#### `++rang:clay`, data store
804−
805−```hoon
806− ++ rang $: hut=(map tako yaki) ::
807− lat=(map lobe blob) ::
808− == ::
809−```
810−
811−This is a set of data keyed by hash. Thus, this is where the "real" data
812−is stored, but it is only meaningful if we know the hash of what we're
813−looking for.
814−
815−`hut` is a map from hashes to commits. We often get the hashes from
816−`hit:dome:clay`, which keys them by logical id. Not every commit has an id.
817−
818−`lat` is a map from hashes to the actual data. We often get the hashes
819−from a `++yaki`, a commit, which references this map to get the data.
820−There is no `++blob:clay` in any `++yaki:clay`. They are only accessible through
821−this map.
822−
823−#### `++tako:clay`, commit reference
824−
825−```hoon
826− ++ tako ,@ :: yaki ref
827−```
828−
829−This is a hash of a `++yaki:clay`, a commit. These are most notably used as
830−the keys in `hut:rang:clay`, where they are associated with the actual
831−`++yaki:clay`, and as the values in `hit:dome:clay`, where sequential ids are
832−associated with these.
833−
834−#### `++yaki:clay`, commit
835−
836−```hoon
837− ++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit
838−```
839−
840−This is a single commit.
841−
842−`p` is a list of the hashes of the parents of this commit. In most
843−cases, this will be a single commit, but in a merge there may be more
844−parents. In theory, there may be an arbitrary number of parents, but in
845−practice merges have exactly two parents. This may change in the future.
846−For commit 1, there is no parent.
847−
848−`q` is a map of the paths on a desk to the data at that location. If you
849−understand what a `++lobe:clay` and a `++blob:clay` is, then the type signature
850−here tells the whole story.
851−
852−`r` is the hash associated with this commit.
853−
854−`t` is the date at which this commit was made.
855−
856−#### `++lobe:clay`, data reference
857−
858−```hoon
859− ++ lobe ,@ :: blob ref
860−```
861−
862−This is a hash of a `++blob:clay`. These are most notably used in `lat:rang:clay`,
863−where they are associated with the actual `++blob:clay`, and as the values in
864−`q:yaki:clay`, where paths are associated with their data in a commit.
865−
866−#### `++blob:clay`, data
867−
868−```hoon
869− ++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q
870− [%direct p=lobe q=* r=umph] ::
871− [%indirect p=lobe q=* r=udon s=lobe] ::
872− == ::
873−```
874−
875−This is a node of data. In every case, `p` is the hash of the blob.
876−
877−`%delta` is the case where we define the data by a delta on other data.
878−In practice, the other data is always the previous commit, but nothing
879−depends on this. `q` is the hash of the parent blob, and `r` is the
880−delta.
881−
882−`%direct` is the case where we simply have the data directly. `q` is the
883−data itself, and `r` is any preprocessing instructions. These almost
884−always come from the creation of a file.
885−
886−`%indirect` is both of the preceding cases at once. `q` is the direct
887−data, `r` is the delta, and `s` is the parent blob. It should always be
888−the case that applying `r` to `s` gives the same data as `q` directly
889−(with the prepreprocessor instructions in `p.r`). This exists purely for
890−performance reasons. This is unused, at the moment, but in general these
891−should be created when there are a long line of changes so that we do
892−not have to traverse the delta chain back to the creation of the file.
893−
894−#### `++udon`, abstract delta
895−
896−```hoon
897− ++ udon :: abstract delta
898− $: p=umph :: preprocessor
899− $= q :: patch
900− $% [%a p=* q=*] :: trivial replace
901− [%b p=udal] :: atomic indel
902− [%c p=(urge)] :: list indel
903− [%d p=upas q=upas] :: tree edit
904− == ::
905− == ::
906−```
907−
908−This is an abstract change to a file. This is a superset of what would
909−normally be called diffs. Diffs usually refer to changes in lines of
910−text while we have the ability to do more interesting deltas on
911−arbitrary data structures.
912−
913−`p` is any preprocessor instructions.
914−
915−`%a` refers to the trival delta of a complete replace of old data with
916−new data.
917−
918−`%b` refers to changes in an opaque atom on the block level. This has
919−very limited usefulness, and is not used at the moment.
920−
921−`%c` refers to changes in a list of data. This is often lines of text,
922−which is your classic diff. We, however, will work on any list of data.
923−
924−`%d` refers to changes in a tree of data. This is general enough to
925−describe changes to any hoon noun, but often more special-purpose delta
926−should be created for different content types. This is not used at the
927−moment, and may in fact be unimplemented.
928−
929−#### `++urge`, list change
930−
931−```hoon
932− ++ urge |*(a=_,* (list (unce a))) :: list change
933−```
934−
935−This is a parametrized type for list changes. For example, `(urge ,@t)`
936−is a list change for lines of text.
937−
938−#### `++unce`, change part of a list.
939−
940−```hoon
941− ++ unce |* a=_,* :: change part
942− $% [%& p=@ud] :: skip[copy]
943− [%| p=(list a) q=(list a)] :: p -> q[chunk]
944− == ::
945−```
946−
947−This is a single change in a list of elements of type `a`. For example,
948−`(unce ,@t)` is a single change in a lines of text.
949−
950−`%&` means the next `p` lines are unchanged.
951−
952−`%|` means the lines `p` have changed to `q`.
953−
954−#### `++umph`, preprocessing information
955−
956−```hoon
957− ++ umph :: change filter
958− $| $? %a :: no filter
959− %b :: jamfile
960− %c :: LF text
961− == ::
962− $% [%d p=@ud] :: blocklist
963− == ::
964−```
965−
966−This space intentionally left undocumented. This stuff will change once
967−we get a well-typed clay.
968−
969−#### `++upas`, tree change
970−
971−```hoon
972− ++ upas :: tree change (%d)
973− $& [p=upas q=upas] :: cell
974− $% [%0 p=axis] :: copy old
975− [%1 p=*] :: insert new
976− [%2 p=axis q=udon] :: mutate!
977− == ::
978−```
979−
980−This space intentionally left undocumented. This stuff is not known to
981−work, and will likely change when we get a well-typed clay. Also, this
982−is not a complicated type; it is not difficult to work out the meaning.
983−
984−#### `++nori:clay`, repository action
985−
986−```hoon
987− ++ nori :: repository action
988− $% [& q=soba] :: delta
989− [| p=@tas] :: label
990− == ::
991−```
992−
993−This describes a change that we are asking clay to make to the desk.
994−There are two kinds of changes that may be made: we can modify files or
995−we can apply a label to a commit.
996−
997−In the `|` case, we will simply label the current commit with the given
998−label. In the `&` case, we will apply the given changes.
999−
1000−#### `++soba:clay`, delta
1001−
1002−```hoon
1003− ++ soba ,[p=cart q=(list ,[p=path q=miso])] :: delta
1004−```
1005−
1006−This describes a set of changes to make to a desk. The `cart` is simply
1007−a pair of the old hash and the new hash of the desk. The list is a list
1008−of changes keyed by the file they're changing. Thus, the paths are paths
1009−to files to be changed while `miso` is a description of the change
1010−itself.
1011−
1012−#### `++miso:clay`, ankh delta
1013−
1014−```hoon
1015− ++ miso :: ankh delta
1016− $% [%del p=*] :: delete
1017− [%ins p=*] :: insert
1018− [%mut p=udon] :: mutate
1019− == ::
1020−```
1021−
1022−There are three kinds of changes that may be made to a node in a desk.
1023−We can insert a file, in which case `p` is the contents of the new file.
1024−We can delete a file, in which case `p` is the contents of the old file.
1025−Finally, we can mutate that file, in which case the `udon` describes the
1026−changes we are applying to the file.
1027−
1028−#### `++mizu:clay`, merged state
1029−
1030−```hoon
1031− ++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state
1032−```
1033−
1034−This is the input to the `%merg` kiss, which allows us to perform a
1035−merge. The `p` is the number of the new head commit. The `q` is a map
1036−from numbers to commit hashes. This is all the new numbered commits that
1037−are to be inserted. The keys to this should always be the numbers from
1038−`let.dom` plus one to `p`, inclusive. The `r` is the maps of all the new
1039−commits and data. Since these are merged into the current state, no old
1040−commits or data need be here.
1041−
1042−#### `++riff:clay`, request/desist
1043−
1044−```hoon
1045− ++ riff ,[p=desk q=(unit rave)] :: request/desist
1046−```
1047−
1048−This represents a request for data about a particular desk. If `q`
1049−contains a `rave`, then this opens a subscription to the desk for that
1050−data. If `q` is null, then this tells clay to cancel the subscription
1051−along this duct.
1052−
1053−#### `++riot:clay`, response
1054−
1055−```hoon
1056− ++ riot (unit rant) :: response/complete
1057−```
1058−
1059−A riot is a response to a subscription. If null, the subscription has
1060−been completed, and no more responses will be sent. Otherwise, the
1061−`rant` is the produced data.
1062−
1063−#### `++rant:clay`, response data
1064−
1065−```hoon
1066− ++ rant :: namespace binding
1067− $: p=[p=care q=case r=@tas] :: clade release book
1068− q=path :: spur
1069− r=* :: data
1070− == ::
1071−```
1072−
1073−This is the data at a particular node in the filesystem. `p.p` specifies
1074−the type of data that was requested (and is produced). `q.p` gives the
1075−specific version reported (since a range of versions may be requested in
1076−a subscription). `r.p` is the desk. `q` is the path to the filesystem
1077−node. `r` is the data itself (in the format specified by `p.p`).
1078−
1079−### `++nako`, subscription response data
1080−
1081−```hoon
1082− ++ nako $: gar=(map ,@ud tako) :: new ids
1083− let=@ud :: next id
1084− lar=(set yaki) :: new commits
1085− bar=(set blob) :: new content
1086− == ::
1087−```
1088−
1089−This is the data that is produced by a request for a range of revisions
1090−of a desk. This allows us to easily keep track of a remote repository --
1091−all the new information we need is contained in the `nako`.
1092−
1093−`gar` is a map of the revisions in the range to the hash of the commit
1094−at that revision. These hashes can be used with `hut:rang:clay` to find the
1095−commit itself.
1096−
1097−`let` is either the last revision number in the range or the most recent
1098−revision number, whichever is smaller.
1099−
1100−`lar` is the set of new commits, and `bar` is the set of new content.
1101−
1102−## Public Interface
1103−
1104−As with all vanes, there are exactly two ways to interact with clay.
1105−`%clay` exports a namespace accessible through `.^`, which is described
1106−above under `++care:clay`. The primary way of interacting with clay, though,
1107−is by sending kisses and receiving gifts.
1108−
1109−```hoon
1110− ++ gift :: out result <-$
1111− $% [%ergo p=@p q=@tas r=@ud] :: version update
1112− [%note p=@tD q=tank] :: debug message
1113− [%writ p=riot] :: response
1114− == ::
1115− ++ kiss :: in request ->$
1116− $% [%info p=@p q=@tas r=nori] :: internal edit
1117− [%ingo p=@p q=@tas r=nori] :: internal noun edit
1118− [%init p=@p] :: report install
1119− [%into p=@p q=@tas r=nori] :: external edit
1120− [%invo p=@p q=@tas r=nori] :: external noun edit
1121− [%merg p=@p q=@tas r=mizu] :: internal change
1122− [%wart p=sock q=@tas r=path s=*] :: network request
1123− [%warp p=sock q=riff] :: file request
1124− == ::
1125−```
1126−
1127−There are only a small number of possible kisses, so it behooves us to
1128−describe each in detail.
1129−
1130−```hoon
1131− $% [%info p=@p q=@tas r=nori] :: internal edit
1132−
1133− [%into p=@p q=@tas r=nori] :: external edit
1134−```
1135−
1136−These two kisses are nearly identical. At a high level, they apply
1137−changes to the filesystem. Whenever we add, remove, or edit a file, one
1138−of these cards is sent. The `p` is the ship whose filesystem we're
1139−trying to change, the `q` is the desk we're changing, and the `r` is the
1140−request change. For the format of the requested change, see the
1141−documentation for `++nori:clay` above.
1142−
1143−When a file is changed in the unix filesystem, vere will send a `%into`
1144−kiss. This tells clay that the duct over which the kiss was sent is the
1145−duct that unix is listening on for changes. From within Arvo, though, we
1146−should never send a `%into` kiss. The `%info` kiss is exactly identical
1147−except it does not reset the duct.
1148−
1149−```hoon
1150− [%ingo p=@p q=@tas r=nori] :: internal noun edit
1151−
1152− [%invo p=@p q=@tas r=nori] :: external noun edit
1153−```
1154−
1155−These kisses are currently identical to `%info` and `%into`, though this
1156−will not always be the case. The intent is for these kisses to allow
1157−typed changes to clay so that we may store typed data. This is currently
1158−unimplemented.
1159−
1160−```hoon
1161− [%init p=@p] :: report install
1162−```
1163−
1164−Init is called when a ship is started on our pier. This simply creates a
1165−default `room` to go into our `raft`. Essentially, this initializes the
1166−filesystem for a ship.
1167−
1168−```hoon
1169− [%merg p=@p q=@tas r=mizu] :: internal change
1170−```
1171−
1172−This is called to perform a merge. This is most visibly called by
1173−:update to update the filesystem of the current ship to that of its
1174−sein. The `p` and `q` are as in `%info`, and the `r` is the description
1175−of the merge. See `++mizu:clay` above.
1176−
1177−XX
1178−`XX [%wake ~] :: timer activate XX`
1179−XX\
1180−XX This card is sent by unix at the time specified by `++doze`. This
1181−time is XX usually the closest time specified in a subscription request.
1182−When `%wake` is XX called, we update our subscribers if there have been
1183−any changes.
1184−
1185−```hoon
1186− [%wart p=sock q=@tas r=path s=*] :: network request
1187−```
1188−
1189−This is a request that has come across the network for a particular
1190−file. When another ship asks for a file from us, that request comes to
1191−us in the form of a `%wart` kiss. This is handled by trivially turning
1192−it into a `%warp`.
1193−
1194−```hoon
1195− [%warp p=sock q=riff] :: file request
1196−```
1197−
1198−This is a request for information about a particular desk. This is, in
1199−its most general form, a subscription, though in many cases it is the
1200−trivial case of a subscription -- a read. See `++riff:clay` for the format of
1201−the request.
1202−
1203−## Lifecycle of a Local Read
1204−
1205−There are two real types of interaction with a filesystem: you can read,
1206−and you can write. We'll describe each process, detailing both the flow
1207−of control followed by the kernel and the algorithms involved. The
1208−simpler case is that of the read, so we'll begin with that.
1209−
1210−When a vane or an application wishes to read a file from the filesystem,
1211−it sends a `%warp` kiss, as described above. Of course, you may request
1212−a file on another ship and, being a global filesystem, clay will happily
1213−produce it for you. That code pathway will be described in another
1214−section; here, we will restrict ourselves to examining the case of a
1215−read from a ship on our own pier.
1216−
1217−The kiss can request either a single version of a file node or a range
1218−of versions of a desk. Here, we'll deal only with a request for a single
1219−version.
1220−
1221−As in all vanes, a kiss enters clay via a call to `++call`. Scanning
1222−through the arm, we quickly see where `%warp` is handled.
1223−
1224−```hoon
1225− ?: =(p.p.q.hic q.p.q.hic)
1226− =+ une=(un p.p.q.hic now ruf)
1227− =+ wex=(di:une p.q.q.hic)
1228− =+ ^= wao
1229− ?~ q.q.q.hic
1230− (ease:wex hen)
1231− (eave:wex hen u.q.q.q.hic)
1232− =+ ^= woo
1233− abet:wao
1234− [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
1235−```
1236−
1237−We're following the familar patern of producing a list of moves and an
1238−updated state. In this case, the state is `++raft`.
1239−
1240−We first check to see if the sending and receiving ships are the same.
1241−If they're not, then this is a request for data on another ship. We
1242−describe that process later. Here, we discuss only the case of a local
1243−read.
1244−
1245−At a high level, the call to `++un` sets up the core for the domestic
1246−ship that contains the files we're looking for. The call to `++di` sets
1247−up the core for the particular desk we're referring to.
1248−
1249−After this, we perform the actual request. If there is no rave in the
1250−riff, then that means we are cancelling a request, so we call
1251−`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
1252−call `++abet:de` to resolve our various types of output into actual
1253−moves. We produce the moves we found above and the `++un` core resolved
1254−with `++pish:un` (putting the modified desk in the room) and `++abet:un`
1255−(putting the modified room in the raft).
1256−
1257−Much of this is fairly straightforward, so we'll only describe `++ease`,
1258−`++eave`, and `++abet:de`. Feel free to look up the code to the other
1259−steps -- it should be easy to follow.
1260−
1261−Although it's called last, it's usually worth examining `++abet` first,
1262−since it defines in what ways we can cause side effects. Let's do that,
1263−and also a few of the lines at the beginning of `++de`.
1264−
1265−```hoon
1266− =| yel=(list ,[p=duct q=gift])
1267− =| byn=(list ,[p=duct q=riot])
1268− =| vag=(list ,[p=duct q=gift])
1269− =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
1270− =| tag=(list ,[p=duct q=path c=note])
1271− |%
1272− ++ abet
1273− ^- [(list move) rede]
1274− :_ red
1275− ;: weld
1276− %+ turn (flop yel)
1277− |=([a=duct b=gift] [hun %give b])
1278− ::
1279− %+ turn (flop byn)
1280− |=([a=duct b=riot] [a %give [%writ b]])
1281− ::
1282− %+ turn (flop vag)
1283− |=([a=duct b=gift] [a %give b])
1284− ::
1285− %+ turn (flop say)
1286− |= [a=duct b=path c=ship d=[p=@ud q=riff]]
1287− :- a
1288− [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
1289− ::
1290− %+ turn (flop tag)
1291− |=([a=duct b=path c=note] [a %pass b c])
1292− ==
1293−```
1294−
1295−This is very simple code. We see there are exactly five different kinds
1296−of side effects we can generate.
1297−
1298−In `yel` we put gifts that we wish to be sent along the `hun:room` duct
1299−to dill. See the documentation for `++room` above. This is how we
1300−display messages to the terminal.
1301−
1302−In `byn` we put riots that we wish returned to subscribers. Recall that
1303−a riot is a response to a subscription. These are returned to our
1304−subscribers in the form of a `%writ` gift.
1305−
1306−In `vag` we put gifts along with the ducts on which to send them. This
1307−allows us to produce arbitrary gifts, but in practice this is only used
1308−to produce `%ergo` gifts.
1309−
1310−In `say` we put messages we wish to pass to ames. These messages are
1311−used to request information from clay on other piers. We must provide
1312−not only the duct and the request (the riff), but also the return path,
1313−the other ship to talk to, and the sequence number of the request.
1314−
1315−In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
1316−the only notes we pass here are `%wait` and `%rest` to the timer vane.
1317−
1318−Now that we know what kinds of side effects we may have, we can jump
1319−into the handling of requests.
1320−
1321−```hoon
1322− ++ ease :: release request
1323− |= hen=duct
1324− ^+ +>
1325− ?~ ref +>
1326− =+ rov=(~(got by qyx) hen)
1327− =. qyx (~(del by qyx) hen)
1328− (mabe rov (cury best hen))
1329− =. qyx (~(del by qyx) hen)
1330− |- ^+ +>+.$
1331− =+ nux=(~(get by fod.u.ref) hen)
1332− ?~ nux +>+.$
1333− %= +>+.$
1334− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
1335− fod.u.ref (~(del by fod.u.ref) hen)
1336− bom.u.ref (~(del by bom.u.ref) u.nux)
1337− ==
1338−```
1339−
1340−This is called when we're cancelling a subscription. For domestic desks,
1341−`ref` is null, so we're going to cancel any timer we might have created.
1342−We first delete the duct from our map of requests, and then we call
1343−`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
1344−have started a timer. We'll describe `++best` and `++mabe` momentarily.
1345−
1346−Although we said we're not going to talk about foreign requests yet,
1347−it's easy to see that for foreign desks, we cancel any outstanding
1348−requests for this duct and send a message over ames to the other ship
1349−telling them to cancel the subscription.
1350−
1351−```hoon
1352− ++ best
1353− |= [hen=duct tym=@da]
1354− %_(+> tag :_(tag [hen /tyme %t %rest tym]))
1355−```
1356−
1357−This simply pushes a `%rest` note onto `tag`, from where it will be
1358−passed back to arvo to be handled. This cancels the timer at the given
1359−duct (with the given time).
1360−
1361−```hoon
1362− ++ mabe :: maybe fire function
1363− |* [rov=rove fun=$+(@da _+>.^$)]
1364− ^+ +>.$
1365− %- fall :_ +>.$
1366− %- bind :_ fun
1367− ^- (unit ,@da)
1368− ?- -.rov
1369− %&
1370− ?. ?=(%da -.q.p.rov) ~
1371− `p.q.p.rov
1372− %|
1373− =* mot p.rov
1374− %+ hunt
1375− ?. ?=(%da -.p.mot) ~
1376− ?.((lth now p.p.mot) ~ [~ p.p.mot])
1377− ?. ?=(%da -.q.mot) ~
1378− ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
1379− ==
1380−```
1381−
1382−This decides whether the given request can only be satsified in the
1383−future. In that case, we call the given function with the time in the
1384−future when we expect to have an update to give to this request. This is
1385−called with `++best` to cancel timers and with `++bait` to start them.
1386−
1387−For single requests, we have a time if the request is for a particular
1388−time (which is assumed to be in the future). For ranges of requests, we
1389−check both the start and end cases to see if they are time cases. If so,
1390−we choose the earlier time.
1391−
1392−If any of those give us a time, then we call the given funciton with the
1393−smallest time.
1394−
1395−The more interesting case is, of course, when we're not cancelling a
1396−subscription but starting one.
1397−
1398−```hoon
1399− ++ eave :: subscribe
1400− |= [hen=duct rav=rave]
1401− ^+ +>
1402− ?- -.rav
1403− &
1404− ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
1405− ~& [%clay-fail p.q.p.rav %now now]
1406− !!
1407− =+ ver=(aver p.rav)
1408− ?~ ver
1409− (duce hen rav)
1410− ?~ u.ver
1411− (blub hen)
1412− (blab hen p.rav u.u.ver)
1413−```
1414−
1415−There are two types of subscriptions -- either we're requesting a single
1416−file or we're requesting a range of versions of a desk. We'll dicuss the
1417−simpler case first.
1418−
1419−First, we check that we're not requesting the `rang` from any time other
1420−than the present. Since we don't store that information for any other
1421−time, we can't produce it in a referentially transparent manner for any
1422−time other than the present.
1423−
1424−Then, we try to read the requested `mood:clay` `p.rav`. If we can't access
1425−the request data right now, we call `++duce` to put the request in our
1426−queue to be satisfied when the information becomes available.
1427−
1428−This case occurs when we make a request for a case whose (1) date is
1429−after the current date, (2) number is after the current number, or (3)
1430−label is not yet used.
1431−
1432−```hoon
1433− ++ duce :: produce request
1434− |= [hen=duct rov=rove]
1435− ^+ +>
1436− =. qyx (~(put by qyx) hen rov)
1437− ?~ ref
1438− (mabe rov (cury bait hen))
1439− |- ^+ +>+.$ :: XX why?
1440− =+ rav=(reve rov)
1441− =+ ^= vaw ^- rave
1442− ?. ?=([%& %v *] rav) rav
1443− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
1444− =+ inx=nix.u.ref
1445− %= +>+.$
1446− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
1447− nix.u.ref +(nix.u.ref)
1448− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
1449− fod.u.ref (~(put by fod.u.ref) hen inx)
1450− ==
1451−```
1452−
1453−The code for `++duce` is nearly the exact inverse of `++ease`, which in
1454−the case of a domestic desk is very simple -- we simply put the duct and
1455−rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
1456−Recall that `ref` is null for domestic desks and that `++mabe` fires the
1457−given function with the time we need to be woken up at, if we need to be
1458−woken up at a particular time.
1459−
1460−```hoon
1461− ++ bait
1462− |= [hen=duct tym=@da]
1463− %_(+> tag :_(tag [hen /tyme %t %wait tym]))
1464−```
1465−
1466−This sets an alarm by sending a `%wait` card with the given time to the
1467−timer vane.
1468−
1469−Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
1470−subscription. This occurs when we make (1) a `%x` request for a file
1471−that does not exist, (2) a `%w` request with a case that is not a
1472−number, or (3) a `%w` request with a nonempty path. The `++blub` is
1473−exactly what you would expect it to be.
1474−
1475−```hoon
1476− ++ blub :: ship stop
1477− |= hen=duct
1478− %_(+> byn [[hen ~] byn])
1479−```
1480−
1481−We notify the duct that we're cancelling their subscription since it
1482−isn't satisfiable.
1483−
1484−Otherwise, we have received the desired information, so we send it on to
1485−the subscriber with `++blab`.
1486−
1487−```hoon
1488− ++ blab :: ship result
1489− |= [hen=duct mun=mood dat=*]
1490− ^+ +>
1491− +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
1492−```
1493−
1494−The most interesting arm called in `++eave` is, of course, `++aver`,
1495−where we actually try to read the data.
1496−
1497−```hoon
1498− ++ aver :: read
1499− |= mun=mood
1500− ^- (unit (unit ,*))
1501− ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
1502− ~& [%clay-fail p.q.mun %now now]
1503− !!
1504− =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
1505− ?^ ezy ezy
1506− =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
1507− ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
1508−```
1509−
1510−We check immediately that we're not requesting the `rang` for any time
1511−other than the present.
1512−
1513−If this is a foreign desk, then we check our cache for the specific
1514−request. If either this is a domestic desk or we don't have the request
1515−in our cache, then we have to actually go read the data from our dome.
1516−
1517−We need to do two things. First, we try to find the number of the commit
1518−specified by the given case, and then we try to get the data there.
1519−
1520−Here, we jump into `arvo/zuse.hoon`, which is where much of the
1521−algorithmic code is stored, as opposed to the clay interface, which is
1522−stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
1523−
1524−```hoon
1525− ++ case-to-aeon :: case-to-aeon:ze
1526− |= lok=case :: act count through
1527− ^- (unit aeon)
1528− ?- -.lok
1529− %da
1530− ?: (gth p.lok lim) ~
1531− |- ^- (unit aeon)
1532− ?: =(0 let) [~ 0] :: avoid underflow
1533− ?: %+ gte p.lok
1534− =< t
1535− %- tako-to-yaki
1536− %- aeon-to-tako
1537− let
1538− [~ let]
1539− $(let (dec let))
1540− ::
1541− %tas (~(get by lab) p.lok)
1542− %ud ?:((gth p.lok let) ~ [~ p.lok])
1543− ==
1544−```
1545−
1546−We handle each type of `case:clay` differently. The latter two types are
1547−easy.
1548−
1549−If we're requesting a revision by label, then we simply look up the
1550−requested label in `lab` from the given dome. If it exists, that is our
1551−aeon; else we produce null, indicating the requested revision does not
1552−yet exist.
1553−
1554−If we're requesting a revision by number, we check if we've yet reached
1555−that number. If so, we produce the number; else we produce null.
1556−
1557−If we're requesting a revision by date, we check first if the date is in
1558−the future, returning null if so. Else we start from the most recent
1559−revision and scan backwards until we find the first revision committed
1560−before that date, and we produce that. If we requested a date before any
1561−revisions were committed, we produce `0`.
1562−
1563−The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
1564−
1565−```hoon
1566− ++ aeon-to-tako ~(got by hit)
1567−
1568− ++ tako-to-yaki ~(got by hut) :: grab yaki
1569−```
1570−
1571−We simply look up the aeon or tako in their respective maps (`hit` and
1572−`hut`).
1573−
1574−Assuming we got a valid version number, `++aver` calls
1575−`++read-at-aeon:ze`, which reads the requested data at the given
1576−revision.
1577−
1578−```hoon
1579− ++ read-at-aeon :: read-at-aeon:ze
1580− |= [oan=aeon mun=mood] :: seek and read
1581− ^- (unit)
1582− ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
1583− ?^(r.mun ~ [~ oan])
1584− (read:(rewind oan) mun)
1585−```
1586−
1587−If we're requesting the revision number with a case other than by
1588−number, then we go ahead and just produce the number we were given.
1589−Otherwise, we call `++rewind` to rewind our state to the given revision,
1590−and then we call `++read` to get the requested information.
1591−
1592−```hoon
1593− ++ rewind :: rewind:ze
1594− |= oan=aeon :: rewind to aeon
1595− ^+ +>
1596− ?: =(let oan) +>
1597− ?: (gth oan let) !! :: don't have version
1598− +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
1599−```
1600−
1601−If we're already at the requested version, we do nothing. If we're
1602−requesting a version later than our head, we are unable to comply.
1603−
1604−Otherwise, we get the hash of the commit at the number, and from that we
1605−get the commit itself (the yaki), which has the map of path to lobe that
1606−represents a version of the filesystem. We call `++checkout-ankh` to
1607−checkout the commit, and we replace `ank` in our context with the
1608−result.
1609−
1610−```hoon
1611− ++ checkout-ankh :: checkout-ankh:ze
1612− |= hat=(map path lobe) :: checkout commit
1613− ^- ankh
1614− %- cosh
1615− %+ roll (~(tap by hat) ~)
1616− |= [[pat=path bar=lobe] ank=ankh]
1617− ^- ankh
1618− %- cosh
1619− ?~ pat
1620− =+ zar=(lobe-to-noun bar)
1621− ank(q [~ (sham zar) zar])
1622− =+ nak=(~(get by r.ank) i.pat)
1623− %= ank
1624− r %+ ~(put by r.ank) i.pat
1625− $(pat t.pat, ank (fall nak _ankh))
1626− ==
1627−```
1628−
1629−Twice we call `++cosh`, which hashes a commit, updating `p` in an
1630−`ankh`. Let's jump into that algorithm before we describe
1631−`++checkout-ankh`.
1632−
1633−```hoon
1634− ++ cosh :: locally rehash
1635− |= ank=ankh :: NB v/unix.c
1636− ank(p rehash:(zu ank))
1637−```
1638−
1639−We simply replace `p` in the hash with the `cash` we get from a call to
1640−`++rehash:zu`.
1641−
1642−```hoon
1643− ++ zu !: :: filesystem
1644− |= ank=ankh :: filesystem state
1645− =| myz=(list ,[p=path q=miso]) :: changes in reverse
1646− =| ram=path :: reverse path into
1647− |%
1648− ++ rehash :: local rehash
1649− ^- cash
1650− %+ mix ?~(q.ank 0 p.u.q.ank)
1651− =+ axe=1
1652− |- ^- cash
1653− ?~ r.ank _@
1654− ;: mix
1655− (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
1656− $(r.ank l.r.ank, axe (peg axe 2))
1657− $(r.ank r.r.ank, axe (peg axe 3))
1658− ==
1659−```
1660−
1661−`++zu` is a core we set up with a particular filesystem node to traverse
1662−a checkout of the filesystem and access the actual data inside it. One
1663−of the things we can do with it is to create a recursive hash of the
1664−node.
1665−
1666−In `++rehash`, if this node is a file, then we xor the remainder of the
1667−hash with the hash of the contents of the file. The remainder of the
1668−hash is `0` if we have no children, else we descend into our children.
1669−Basically, we do a half SHA-256 of the xor of the axis of this child and
1670−the half SHA-256 of the xor of the name of the child and the hash of the
1671−child. This is done for each child and all the results are xored
1672−together.
1673−
1674−Now we return to our discussion of `++checkout-ankh`.
1675−
1676−We fold over every path in this version of the filesystem and create a
1677−great ankh out of them. First, we call `++lobe-to-noun` to get the raw
1678−data referred to be each lobe.
1679−
1680−```hoon
1681− ++ lobe-to-noun :: grab blob
1682− |= p=lobe :: ^- *
1683− %- blob-to-noun
1684− (lobe-to-blob p)
1685−```
1686−
1687−This converts a lobe into the raw data it refers to by first getting the
1688−blob with `++lobe-to-blob` and converting that into data with
1689−`++blob-to-noun`.
1690−
1691−```hoon
1692− ++ lobe-to-blob ~(got by lat) :: grab blob
1693−```
1694−
1695−This just grabs the blob that the lobe refers to.
1696−
1697−```hoon
1698− ++ blob-to-noun :: grab blob
1699− |= p=blob
1700− ?- -.p
1701− %delta (lump r.p (lobe-to-noun q.p))
1702− %direct q.p
1703− %indirect q.p
1704− ==
1705−```
1706−
1707−If we have either a direct or an indirect blob, then the data is stored
1708−right in the blob. Otherwise, we have to reconstruct it from the diffs.
1709−We do this by calling `++lump` on the diff in the blob with the data
1710−obtained by recursively calling the parent of this blob.
1711−
1712−```hoon
1713− ++ lump :: apply patch
1714− |= [don=udon src=*]
1715− ^- *
1716− ?+ p.don ~|(%unsupported !!)
1717− %a
1718− ?+ -.q.don ~|(%unsupported !!)
1719− %a q.q.don
1720− %c (lurk ((hard (list)) src) p.q.don)
1721− %d (lure src p.q.don)
1722− ==
1723− ::
1724− %c
1725− =+ dst=(lore ((hard ,@) src))
1726− %- roly
1727− ?+ -.q.don ~|(%unsupported !!)
1728− %a ((hard (list ,@t)) q.q.don)
1729− %c (lurk dst p.q.don)
1730− ==
1731− ==
1732−```
1733−
1734−This is defined in `arvo/hoon.hoon` for historical reasons which are
1735−likely no longer applicable. Since the `++umph` structure will likely
1736−change we convert clay to be a typed filesystem, we'll only give a
1737−high-level description of this process. If we have a `%a` udon, then
1738−we're performing a trivial replace, so we produce simply `q.q.don`. If
1739−we have a `%c` udon, then we're performing a list merge (as in, for
1740−example, lines of text). The merge is performed by `++lurk`.
1741−
1742−```hoon
1743− ++ lurk :: apply list patch
1744− |* [hel=(list) rug=(urge)]
1745− ^+ hel
1746− =+ war=`_hel`~
1747− |- ^+ hel
1748− ?~ rug (flop war)
1749− ?- -.i.rug
1750− &
1751− %= $
1752− rug t.rug
1753− hel (slag p.i.rug hel)
1754− war (weld (flop (scag p.i.rug hel)) war)
1755− ==
1756− ::
1757− |
1758− %= $
1759− rug t.rug
1760− hel =+ gur=(flop p.i.rug)
1761− |- ^+ hel
1762− ?~ gur hel
1763− ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
1764− war (weld q.i.rug war)
1765− ==
1766− ==
1767−```
1768−
1769−We accumulate our final result in `war`. If there's nothing more in our
1770−list of merge instructions (unces), we just reverse `war` and produce
1771−it. Otherwise, we process another unce. If the unce is of type `&`, then
1772−we have `p.i.rug` lines of no changes, so we just copy them over from
1773−`hel` to `war`. If the unice is of type `|`, then we verify that the
1774−source lines (in `hel`) are what we expect them to be (`p.i.rug`),
1775−crashing on failure. If they're good, then we append the new lines in
1776−`q.i.rug` onto `war`.
1777−
1778−And that's really it. List merges are pretty easy. Anyway, if you
1779−recall, we were discussing `++checkout-ankh`.
1780−
1781−```hoon
1782− ++ checkout-ankh :: checkout-ankh:ze
1783− |= hat=(map path lobe) :: checkout commit
1784− ^- ankh
1785− %- cosh
1786− %+ roll (~(tap by hat) ~)
1787− |= [[pat=path bar=lobe] ank=ankh]
1788− ^- ankh
1789− %- cosh
1790− ?~ pat
1791− =+ zar=(lobe-to-noun bar)
1792− ank(q [~ (sham zar) zar])
1793− =+ nak=(~(get by r.ank) i.pat)
1794− %= ank
1795− r %+ ~(put by r.ank) i.pat
1796− $(pat t.pat, ank (fall nak _ankh))
1797− ==
1798−```
1799−
1800−If the path is null, then we calculate `zar`, the raw data at the path
1801−`pat` in this version. We produce the given ankh with the correct data.
1802−
1803−Otherwise, we try to get the child we're looking at from our parent
1804−ankh. If it's already been created, this succeeds; otherwise, we simply
1805−create a default blank ankh. We place ourselves in our parent after
1806−recursively computing our children.
1807−
1808−This algorithm really isn't that complicated, but it may not be
1809−immediately obvious why it works. An example should clear everything up.
1810−
1811−Suppose `hat` is a map of the following information.
1812−
1813−```
1814− /greeting --> "customary upon meeting"
1815− /greeting/english --> "hello"
1816− /greeting/spanish --> "hola"
1817− /greeting/russian/short --> "привет"
1818− /greeting/russian/long --> "Здравствуйте"
1819− /farewell/russian --> "до свидания"
1820−```
1821−
1822−Furthermore, let's say that we process them in this order:
1823−
1824−```
1825− /greeting/english
1826− /greeting/russian/short
1827− /greeting/russian/long
1828− /greeting
1829− /greeting/spanish
1830− /farewell/russian
1831−```
1832−
1833−Then, the first path we process is `/greeting/english` . Since our path
1834−is not null, we try to get `nak`, but because our ankh is blank at this
1835−point it doesn't find anything. Thus, update our blank top-level ankh
1836−with a child `%greeting`. and recurse with the blank `nak` to create the
1837−ankh of the new child.
1838−
1839−In the recursion, we our path is `/english` and our ankh is again blank.
1840−We try to get the `english` child of our ankh, but this of course fails.
1841−Thus, we update our blank `/greeting` ankh with a child `english`
1842−produced by recursing.
1843−
1844−Now our path is null, so we call `++lobe-to-noun` to get the actual
1845−data, and we place it in the brand-new ankh.
1846−
1847−Next, we process `/greeting/russian/short`. Since our path is not null,
1848−we try to get the child named `%greeting`, which does exist since we
1849−created it earlier. We put modify this child by recursing on it. Our
1850−path is now `/russian/short`, so we look for a `%russian` child in our
1851−`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
1852−path is now `/short`, so we look for a `%short` child in our
1853−`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
1854−Now our path is null, so we set the contents of this node to `"привет"`,
1855−and we're done processing this path.
1856−
1857−Next, we process `/greeting/russian/long`. This proceeds similarly to
1858−the previous except that now the ankh for `/greeting/russian` already
1859−exists, so we simply reuse it rather than creating a new one. Of course,
1860−we still must create a new `/greeting/russian/long` ankh.
1861−
1862−Next, we process `/greeting`. This ankh already exists, so after we've
1863−recursed once, our path is null, and our ankh is not blank -- it already
1864−has two children (and two grandchildren). We don't touch those, though,
1865−since a node may be both a file and a directory. We just add the
1866−contents of the file -- "customary upon meeting" -- to the existing
1867−ankh.
1868−
1869−Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
1870−already exists, but it doesn't have a `%spanish` child, so we create
1871−that, taking care not to disturb the contents of the `/greeting` file.
1872−We put "hola" into the ankh and call it good.
1873−
1874−Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
1875−doesn't exist, so we create it. Clearly the newly-created ankh doesn't
1876−have any children, so we have to add a `%russian` child, and in this
1877−child we put our last content -- "до свидания".
1878−
1879−We hope it's fairly obvious that the order we process the paths doesn't
1880−affect the final ankh tree. The tree will be constructed in a very
1881−different order depending on what order the paths come in, but the
1882−resulting tree is independent of order.
1883−
1884−At any rate, we were talking about something important, weren't we? If
1885−you recall, that concludes our discussion of `++rewind`, which was
1886−called from `++read-at-aeon`. In summary, `++rewind` returns a context
1887−in which our current state is (very nearly) as it was when the specified
1888−version of the desk was the head. This allows `++read-at-aeon` to call
1889−`++read` to read the requested information.
1890−
1891−```hoon
1892− ++ read :: read:ze
1893− |= mun=mood :: read at point
1894− ^- (unit)
1895− ?: ?=(%v p.mun)
1896− [~ `dome`+<+<.read]
1897− ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
1898− ?^(r.mun ~ [~ let])
1899− ?: ?=(%w p.mun)
1900− =+ ^= yak
1901− %- tako-to-yaki
1902− %- aeon-to-tako
1903− let
1904− ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
1905− ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
1906− (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
1907−```
1908−
1909−If we're requesting the dome, then we just return that immediately.
1910−
1911−If we're requesting the revision number of the desk and we're not
1912−requesting it by number, then we just return the current number of this
1913−desk. Note of course that this was really already handled in
1914−`++read-at-aeon`.
1915−
1916−If we're requesting a `%w` with a specific revision number, then we do
1917−something or other with the commit there. It's kind of weird, and it
1918−doesn't seem to work, so we'll ignore this case.
1919−
1920−Otherwise, we descend into the ankh tree to the given path with
1921−`++descend-path:zu`, and then we handle specific request in `++query`.
1922−
1923−```hoon
1924− ++ descend-path :: descend recursively
1925− |= way=path
1926− ^+ +>
1927− ?~(way +> $(way t.way, +> (descend i.way)))
1928−```
1929−
1930−This is simple recursion down into the ankh tree. `++descend` descends
1931−one level, so this will eventually get us down to the path we want.
1932−
1933−```hoon
1934− ++ descend :: descend
1935− |= lol=@ta
1936− ^+ +>
1937− =+ you=(~(get by r.ank) lol)
1938− +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
1939−```
1940−
1941−`ram` is the path that we're at, so to descend one level we push the
1942−name of this level onto that path. We update the ankh with the correct
1943−one at that path if it exists; else we create a blank one.
1944−
1945−Once we've decscended to the correct level, we need to actually deal
1946−with the request.
1947−
1948−```hoon
1949− ++ query :: query:ze
1950− |= ren=?(%u %v %x %y %z) :: endpoint query
1951− ^- (unit ,*)
1952− ?- ren
1953− %u [~ `rang`+<+>.query]
1954− %v [~ `dome`+<+<.query]
1955− %x ?~(q.ank ~ [~ q.u.q.ank])
1956− %y [~ as-arch]
1957− %z [~ ank]
1958− ==
1959−```
1960−
1961−Now that everything's set up, it's really easy. If they're requesting
1962−the rang, dome, or ankh, we give it to them. If the contents of a file,
1963−we give it to them if it is in fact a file. If the `arch`, then we
1964−calculate it with `++as-arch`.
1965−
1966−```hoon
1967− ++ as-arch :: as-arch:ze
1968− ^- arch :: arch report
1969− :+ p.ank
1970− ?~(q.ank ~ [~ p.u.q.ank])
1971− |- ^- (map ,@ta ,~)
1972− ?~ r.ank ~
1973− [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
1974−```
1975−
1976−This very simply strips out all the "real" data and returns just our own
1977−hash, the hash of the file contents (if we're a file), and a map of the
1978−names of our immediate children.
1979−
1980−## Lifecycle of a Local Subscription
1981−
1982−A subscription to a range of revisions of a desk initially follows the
1983−same path that a single read does. In `++aver`, we checked the head of
1984−the given rave. If the head was `&`, then it was a single request, so we
1985−handled it above. If `|`, then we handle it with the following code.
1986−
1987−```hoon
1988− =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
1989− ?~ nab
1990− ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
1991− (duce hen (rive rav))
1992− =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
1993− ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
1994− (blub hen)
1995− =+ top=?~(huy let.dom u.huy)
1996− =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
1997− =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
1998− =. +>.$
1999− ?: =(sar ear) +>.$
2000− =+ fud=(~(make-nako ze lim dom ran) u.nab top)
2001− (bleb hen u.nab fud)
2002− ?^ huy
2003− (blub hen)
2004− =+ ^= ptr ^- case
2005− [%ud +(let.dom)]
2006− (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
2007− ==
2008−```
2009−
2010−Recall that `++case-to-aeon:ze` produces the revision number that a case
2011−corresponds to, if it corresponds to any. If it doesn't yet correspond
2012−to a revision, then it produces null.
2013−
2014−Thus, we first check to see if we've even gotten to the beginning of the
2015−range of revisions requested. If not, then we assert that we haven't yet
2016−gotten to the end of the range either, because that would be really
2017−strange. If not, then we immediately call `++duce`, which, if you
2018−recall, for a local request, simply puts this duct and rove into our
2019−cult `qyx`, so that we know who to respond to when the revision does
2020−appear.
2021−
2022−If we've already gotten to the first revision, then we can produce some
2023−content immediately. If we've also gotten to the final revision, and
2024−that revision is earlier than the start revision, then it's a bad
2025−request and we call `++blub`, which tells the subscriber that his
2026−subscription will not be satisfied.
2027−
2028−Otherwise, we find the data at the given path at the beginning of the
2029−subscription and at the last available revision in the subscription. If
2030−they're the same, then we don't send a notification. Otherwise, we call
2031−`++gack`, which creates the `++nako` we need to produce. We call
2032−`++bleb` to actually produce the information.
2033−
2034−If we already have the last requested revision, then we also tell the
2035−subscriber with `++blub` that the subscription will receive no further
2036−updates.
2037−
2038−If there will be more revisions in the subscription, then we call
2039−`++duce`, adding the duct to our subscribers. We modify the rove to
2040−start at the next revision since we've already handled all the revisions
2041−up to the present.
2042−
2043−We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
2044−`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
2045−we'll start with that.
2046−
2047−```hoon
2048− ++ bleb :: ship sequence
2049− |= [hen=duct ins=@ud hip=nako]
2050− ^+ +>
2051− (blab hen [%w [%ud ins] ~] hip)
2052−```
2053−
2054−We're given a duct, the beginning revision number, and the nako that
2055−contains the updates since that revision. We use `++blab` to produce
2056−this result to the subscriber. The case is `%w` with a revision number
2057−of the beginning of the subscription, and the data is the nako itself.
2058−
2059−We call `++lobes-at-path:ze` to get the data at the particular path.
2060−
2061−```hoon
2062− ++ lobes-at-path :: lobes-at-path:ze
2063− |= [oan=aeon pax=path] :: data at path
2064− ^- (map path lobe)
2065− ?: =(0 oan) ~
2066− %- mo
2067− %+ skim
2068− %. ~
2069− %~ tap by
2070− =< q
2071− %- tako-to-yaki
2072− %- aeon-to-tako
2073− oan
2074− |= [p=path q=lobe]
2075− ?| ?=(~ pax)
2076− ?& !?=(~ p)
2077− =(-.pax -.p)
2078− $(p +.p, pax +.pax)
2079− == ==
2080−```
2081−
2082−At revision zero, the theoretical common revision between all
2083−repositories, there is no data, so we produce null.
2084−
2085−We get the list of paths (paired with their lobe) in the revision
2086−referred to by the given number and we keep only those paths which begin
2087−with `pax`. Converting to a map, we now have a map from the subpaths at
2088−the given path to the hash of their data. This is simple and efficient
2089−to calculate and compare to later revisions. This allows us to easily
2090−tell if a node or its children have changed.
2091−
2092−Finally, we will describe `++make-nako:ze`.
2093−
2094−```hoon
2095− ++ make-nako :: gack a through b
2096− |= [a=aeon b=aeon]
2097− ^- [(map aeon tako) aeon (set yaki) (set blob)]
2098− :_ :- b
2099− =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
2100− %+ reachable-between-takos
2101− (~(get by hit) a) :: if a not found, a=0
2102− (aeon-to-tako b)
2103− ^- (map aeon tako)
2104− %- mo %+ skim (~(tap by hit) ~)
2105− |= [p=aeon *]
2106− &((gth p a) (lte p b))
2107−```
2108−
2109−We need to produce four things -- the numbers of the new commits, the
2110−number of the latest commit, the new commits themselves, and the new
2111−data itself.
2112−
2113−The first is fairly easy to produce. We simply go over our map of
2114−numbered commits and produce all those numbered greater than `a` and not
2115−greater than `b`.
2116−
2117−The second is even easier to produce -- `b` is clearly our most recent
2118−commit.
2119−
2120−The third and fourth are slightly more interesting, though not too
2121−terribly difficult. First, we call `++reachable-between-takos`.
2122−
2123−```hoon
2124− ++ reachable-between-takos
2125− |= [a=(unit tako) b=tako] :: pack a through b
2126− ^- [(set tako) (set lobe)]
2127− =+ ^= sar
2128− ?~ a ~
2129− (reachable-takos r:(tako-to-yaki u.a))
2130− =+ yak=`yaki`(tako-to-yaki b)
2131− %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
2132− |- ^- (set tako) :: walk onto sar
2133− ?: (~(has in sar) r.yak)
2134− ~
2135− =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
2136− %- ~(uni in ber)
2137− ^- (set tako)
2138− %+ roll p.yak
2139− |= [yek=tako bar=(set tako)]
2140− ^- (set tako)
2141− ?: (~(has in bar) yek) :: save some time
2142− bar
2143− %- ~(uni in bar)
2144− ^$(yak (tako-to-yaki yek))
2145−```
2146−
2147−We take a possible starting commit and a definite ending commit, and we
2148−produce the set of commits and the set of data between them.
2149−
2150−We let `sar` be the set of commits reachable from `a`. If `a` is null,
2151−then obviously no commits are reachable. Otherwise, we call
2152−`++reachable-takos` to calculate this.
2153−
2154−```hoon
2155− ++ reachable-takos :: reachable
2156− |= p=tako :: XX slow
2157− ^- (set tako)
2158− =+ y=(tako-to-yaki p)
2159− =+ t=(~(put in _(set tako)) p)
2160− %+ roll p.y
2161− |= [q=tako s=_t]
2162− ?: (~(has in s) q) :: already done
2163− s :: hence skip
2164− (~(uni in s) ^$(p q)) :: otherwise traverse
2165−```
2166−
2167−We very simply produce the set of the given tako plus its parents,
2168−recursively.
2169−
2170−Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
2171−the ending commit. With this, we create a set that is the union of `sar`
2172−and all takos reachable from `b`.
2173−
2174−We pass `sar` into `++new-lobes` to get all the lobes referenced by any
2175−tako referenced by `a`. The result is passed into `++new-lobes-takos` to
2176−do the same, but not recomputing those in already calculated last
2177−sentence. This produces the sets of takos and lobes we need.
2178−
2179−```hoon
2180− ++ new-lobes :: object hash set
2181− |= [b=(set lobe) a=(set tako)] :: that aren't in b
2182− ^- (set lobe)
2183− %+ roll (~(tap in a) ~)
2184− |= [tak=tako bar=(set lobe)]
2185− ^- (set lobe)
2186− =+ yak=(tako-to-yaki tak)
2187− %+ roll (~(tap by q.yak) ~)
2188− |= [[path lob=lobe] far=_bar]
2189− ^- (set lobe)
2190− ?~ (~(has in b) lob) :: don't need
2191− far
2192− =+ gar=(lobe-to-blob lob)
2193− ?- -.gar
2194− %direct (~(put in far) lob)
2195− %delta (~(put in $(lob q.gar)) lob)
2196− %indirect (~(put in $(lob s.gar)) lob)
2197− ==
2198−```
2199−
2200−Here, we're creating a set of lobes referenced in a commit in `a`. We
2201−start out with `b` as the initial set of lobes, so we don't need to
2202−recompute any of the lobes referenced in there.
2203−
2204−The algorithm is pretty simple, so we won't bore you with the details.
2205−We simply traverse every commit in `a`, looking at every blob referenced
2206−there, and, if it's not already in `b`, we add it to `b`. In the case of
2207−a direct blob, we're done. For a delta or an indirect blob, we
2208−recursively add every blob referenced within the blob.
2209−
2210−```hoon
2211− ++ new-lobes-takos :: garg & repack
2212− |= [b=(set lobe) a=(set tako)]
2213− ^- [(set tako) (set lobe)]
2214− [a (new-lobes b a)]
2215−```
2216−
2217−Here, we just update the set of lobes we're given with the commits we're
2218−given and produce both sets.
2219−
2220−This concludes our discussion of a local subscription.
2221−
2222−## Lifecycle of a Foreign Read or Subscription
2223−
2224−Foreign reads and subscriptions are handled in much the same way as
2225−local ones. The interface is the same -- a vane or app sends a `%warp`
2226−kiss with the request. The difference is simply that the `sock` refers
2227−to the foreign ship.
2228−
2229−Thus, we start in the same place -- in `++call`, handling `%warp`.
2230−However, since the two side of the `sock` are different, we follow a
2231−different path.
2232−
2233−```hoon
2234− =+ wex=(do now p.q.hic p.q.q.hic ruf)
2235− =+ ^= woo
2236− ?~ q.q.q.hic
2237− abet:(ease:wex hen)
2238− abet:(eave:wex hen u.q.q.q.hic)
2239− [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
2240−```
2241−
2242−If we compare this to how the local case was handled, we see that it's
2243−not all that different. We use `++do` rather than `++un` and `++de` to
2244−set up the core for the foreign ship. This gives us a `++de` core, so we
2245−either cancel or begin the request by calling `++ease` or `++eave`,
2246−exactly as in the local case. In either case, we call `++abet:de` to
2247−resolve our various types of output into actual moves, as described in
2248−the local case. Finally, we call `++posh` to update our raft, putting
2249−the modified rung into the raft.
2250−
2251−We'll first trace through `++do`.
2252−
2253−```hoon
2254− ++ do
2255− |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
2256− =+ ^= rug ^- rung
2257− =+ rug=(~(get by hoy.ruf) him)
2258− ?^(rug u.rug *rung)
2259− =+ ^= red ^- rede
2260− =+ yit=(~(get by rus.rug) syd)
2261− ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
2262− ((de now ~ ~) [who him] syd red ran.ruf)
2263−```
2264−
2265−If we already have a rung for this foreign ship, then we use that.
2266−Otherwise, we create a new blank one. If we already have a rede in this
2267−rung, then we use that, otherwise we create a blank one. An important
2268−point to note here is that we let `ref` in the rede be `[~ *rind]`.
2269−Recall, for domestic desks `ref` is null. We use this to distinguish
2270−between foreign and domestic desks in `++de`.
2271−
2272−With this information, we create a `++de` core as usual.
2273−
2274−Although we've already covered `++ease` and `++eave`, we'll go through
2275−them quickly again, highlighting the case of foreign request.
2276−
2277−```hoon
2278− ++ ease :: release request
2279− |= hen=duct
2280− ^+ +>
2281− ?~ ref +>
2282− =+ rov=(~(got by qyx) hen)
2283− =. qyx (~(del by qyx) hen)
2284− (mabe rov (cury best hen))
2285− =. qyx (~(del by qyx) hen)
2286− |- ^+ +>+.$
2287− =+ nux=(~(get by fod.u.ref) hen)
2288− ?~ nux +>+.$
2289− %= +>+.$
2290− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
2291− fod.u.ref (~(del by fod.u.ref) hen)
2292− bom.u.ref (~(del by bom.u.ref) u.nux)
2293− ==
2294−```
2295−
2296−Here, we still remove the duct from our cult (we maintain a cult even
2297−for foreign desks), but we also need to tell the foreign desk to cancel
2298−our subscription. We do this by sending a request (by appending to
2299−`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
2300−the foreign ship to cancel the subscription. Since we don't anymore
2301−expect a response on this duct, we remove it from `fod` and `bom`, which
2302−are the maps between ducts, raves, and request sequence numbers.
2303−Basically, we remove every trace of the subscription from our request
2304−manager.
2305−
2306−In the case of `++eave`, where we're creating a new request, everything
2307−is exactly identical to the case of the local request except `++duce`.
2308−We said that `++duce` simply puts the request into our cult. This is
2309−true for a domestic request, but distinctly untrue for foreign requests.
2310−
2311−```hoon
2312− ++ duce :: produce request
2313− |= [hen=duct rov=rove]
2314− ^+ +>
2315− =. qyx (~(put by qyx) hen rov)
2316− ?~ ref +>.$
2317− |- ^+ +>+.$ :: XX why?
2318− =+ rav=(reve rov)
2319− =+ ^= vaw ^- rave
2320− ?. ?=([%& %v *] rav) rav
2321− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
2322− =+ inx=nix.u.ref
2323− %= +>+.$
2324− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
2325− nix.u.ref +(nix.u.ref)
2326− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
2327− fod.u.ref (~(put by fod.u.ref) hen inx)
2328− ==
2329−```
2330−
2331−If we have a request manager (i.e. this is a foreign desk), then we do
2332−the approximate inverse of `++ease`. We create a rave out of the given
2333−request and send it off to the foreign desk by putting it in `say`. Note
2334−that the rave is created to request the information starting at the next
2335−revision number. Since this is a new request, we put it into `fod` and
2336−`bom` to associate the request with its duct and its sequence number.
2337−Since we're using another sequence number, we must increment `nix`,
2338−which represents the next available sequence number.
2339−
2340−And that's really it for this side of the request. Requesting foreign
2341−information isn't that hard. Let's see what it looks like on the other
2342−side. When we get a request from another ship for information on our
2343−ship, that comes to us in the form of a `%wart` from ames.
2344−
2345−We handle a `%wart` in `++call`, right next to where we handle the
2346−`%warp` case.
2347−
2348−```hoon
2349− %wart
2350− ?> ?=(%re q.q.hic)
2351− =+ ryf=((hard riff) s.q.hic)
2352− :_ ..^$
2353− :~ :- hen
2354− :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
2355− %c
2356− [%warp [p.p.q.hic p.p.q.hic] ryf]
2357− ==
2358−```
2359−
2360−Every request we receive should be of type `riff`, so we coerce it into
2361−that type. We just convert this into a new `%warp` kiss that we pass to
2362−ourself. This gets handled like normal, as a local request. When the
2363−request produces a value, it does so like normal as a `%writ`, which is
2364−returned to `++take` along the path we just sent it on.
2365−
2366−```hoon
2367− %writ
2368− ?> ?=([@ @ *] tea)
2369− =+ our=(need (slaw %p i.tea))
2370− =+ him=(need (slaw %p i.t.tea))
2371− :_ ..^$
2372− :~ :- hen
2373− [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
2374− ==
2375−```
2376−
2377−Since we encoded the ship we need to respond to in the path, we can just
2378−pass our `%want` back to ames, so that we tell the requesting ship about
2379−the new data.
2380−
2381−This comes back to the original ship as a `%waft` from ames, which comes
2382−into `++take`, right next to where we handled `%writ`.
2383−
2384−```hoon
2385− %waft
2386− ?> ?=([@ @ ~] tea)
2387− =+ syd=(need (slaw %tas i.tea))
2388− =+ inx=(need (slaw %ud i.t.tea))
2389− =+ ^= zat
2390− =< wake
2391− (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
2392− =^ mos ruf
2393− =+ zot=abet.zat
2394− [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
2395− [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
2396−```
2397−
2398−This gets the desk and sequence number from the path the request was
2399−sent over. This determines exactly which request is being responded to.
2400−We call `++knit:de` to apply the changes to our local desk, and we call
2401−`++wake` to update our subscribers. Then we call `++abet:de` and
2402−`++posh` as normal (like in `++eave`).
2403−
2404−We'll examine `++knit` and `++wake`, in that order.
2405−
2406−```hoon
2407− ++ knit :: external change
2408− |= [inx=@ud rot=riot]
2409− ^+ +>
2410− ?> ?=(^ ref)
2411− |- ^+ +>+.$
2412− =+ ruv=(~(get by bom.u.ref) inx)
2413− ?~ ruv +>+.$
2414− => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
2415− %_ .
2416− bom.u.ref (~(del by bom.u.ref) inx)
2417− fod.u.ref (~(del by fod.u.ref) p.u.ruv)
2418− ==
2419− ?~ rot
2420− =+ rav=`rave`q.u.ruv
2421− %= +>+.$
2422− lim
2423− ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
2424− ::
2425− haw.u.ref
2426− ?. ?=(& -.rav) haw.u.ref
2427− (~(put by haw.u.ref) p.rav ~)
2428− ==
2429− ?< ?=(%v p.p.u.rot)
2430− =. haw.u.ref
2431− (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
2432− ?. ?=(%w p.p.u.rot) +>+.$
2433− |- ^+ +>+.^$
2434− =+ nez=[%w [%ud let.dom] ~]
2435− =+ nex=(~(get by haw.u.ref) nez)
2436− ?~ nex +>+.^$
2437− ?~ u.nex +>+.^$ :: should never happen
2438− =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
2439− ?>(?=(^ ref.roo) roo)
2440− %= $
2441− haw.u.ref (~(del by haw.u.ref) nez)
2442− ==
2443−```
2444−
2445−This is kind of a long gate, but don't worry, it's not bad at all.
2446−
2447−First, we assert that we're not a domestic desk. That wouldn't make any
2448−sense at all.
2449−
2450−Since we have the sequence number of the request, we can get the duct
2451−and rave from `bom` in our request manager. If we didn't actually
2452−request this data (or the request was canceled before we got it), then
2453−we do nothing.
2454−
2455−Else, we remove the request from `bom` and `fod` unless this was a
2456−subscription request and we didn't receive a null riot (which would
2457−indicate the last message on the subscription).
2458−
2459−Now, if we received a null riot, then if this was a subscription request
2460−by date, then we update `lim` in our request manager (representing the
2461−latest time at which we have complete information for this desk) to the
2462−date that was requested. If this was a single read request, then we put
2463−the result in our simple cache `haw` to make future requests faster.
2464−Then we're done.
2465−
2466−If we received actual data, then we put it into our cache `haw`. Unless
2467−it's a `%w` request, we're done.
2468−
2469−If it is a `%w` request, then we try to get the `%w` at our current head
2470−from the cache. In general, that should be the thing we just put in a
2471−moment ago, but that is not guaranteed. The most common case where this
2472−is different is when we receive desk updates out of order. At any rate,
2473−since we now have new information, we need to apply it to our local copy
2474−of the desk. We do so in `++edis`, and then we remove the stuff we just
2475−applied from the cache, since it's not really a true "single read", like
2476−what should really be in the cache.
2477−
2478−```hoon
2479− ++ edis :: apply subscription
2480− |= nak=nako
2481− ^+ +>
2482− %= +>
2483− hit.dom (~(uni by hit.dom) gar.nak)
2484− let.dom let.nak
2485− lat.ran %+ roll (~(tap in bar.nak) ~)
2486− =< .(yeb lat.ran)
2487− |= [sar=blob yeb=(map lobe blob)]
2488− =+ zax=(blob-to-lobe sar)
2489− %+ ~(put by yeb) zax sar
2490− hut.ran %+ roll (~(tap in lar.nak) ~)
2491− =< .(yeb hut.ran)
2492− |= [sar=yaki yeb=(map tako yaki)]
2493− %+ ~(put by yeb) r.sar sar
2494− ==
2495−```
2496−
2497−This shows, of course, exactly why nako is defined the way it is. To
2498−become completely up to date with the foreign desk, we need to merge
2499−`hit` with the foreign one so that we have all the revision numbers. We
2500−update `let` so that we know which revision is the head.
2501−
2502−We merge the new blobs in `lat`, keying them by their hash, which we get
2503−from a call to `++blob-to-lobe`. Recall that the hash is stored in the
2504−actual blob itself. We do the same thing to the new yakis, putting them
2505−in `hut`, keyed by their hash.
2506−
2507−Now, our local dome should be exactly the same as the foreign one.
2508−
2509−This concludes our discussion of `++knit`. Now the changes have been
2510−applied to our local copy of the desk, and we just need to update our
2511−subscribers. We do so in `++wake:de`.
2512−
2513−```hoon
2514− ++ wake :: update subscribers
2515− ^+ .
2516− =+ xiq=(~(tap by qyx) ~)
2517− =| xaq=(list ,[p=duct q=rove])
2518− |- ^+ ..wake
2519− ?~ xiq
2520− ..wake(qyx (~(gas by *cult) xaq))
2521− ?- -.q.i.xiq
2522− &
2523− =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
2524− ?^ cas
2525− %= $
2526− xiq t.xiq
2527− ..wake ?~ u.cas (blub p.i.xiq)
2528− (blab p.i.xiq p.q.i.xiq u.u.cas)
2529− ==
2530− =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
2531− ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
2532− $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
2533− ::
2534− |
2535− =+ mot=`moot`p.q.i.xiq
2536− =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
2537− ?~ nab
2538− $(xiq t.xiq, xaq [i.xiq xaq])
2539− =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
2540− ?~ huy
2541− =+ ptr=[%ud +(let.dom)]
2542− %= $
2543− xiq t.xiq
2544− xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
2545− ..wake =+ ^= ear
2546− (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
2547− ?: =(s.p.q.i.xiq ear) ..wake
2548− =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
2549− (bleb p.i.xiq let.dom fud)
2550− ==
2551− %= $
2552− xiq t.xiq
2553− ..wake =- (blub:- p.i.xiq)
2554− =+ ^= ear
2555− (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
2556− ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
2557− =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
2558− (bleb p.i.xiq +(u.nab) fud)
2559− ==
2560− ==
2561− --
2562−```
2563−
2564−This is even longer than `++knit`, but it's pretty similar to `++eave`.
2565−We loop through each of our subscribers `xiq`, processing each in turn.
2566−When we're done, we just put the remaining subscribers back in our
2567−subscriber list.
2568−
2569−If the subscriber is a single read, then, if this is a foreign desk
2570−(note that `++wake` is called from other arms, and not only on foreign
2571−desks). Obviously, if we find an identical request there, then we can
2572−produce the result immediately. Referential transparency for the win. We
2573−produce the result with a call to `++blab`. If this is a foreign desk
2574−but the result is not in the cache, then we produce `++blub` (canceled
2575−subscription with no data) for reasons entirely opaque to me. Seriously,
2576−it seems like we should wait until we get an actual response to the
2577−request. If someone figures out why this is, let me know. At any rate,
2578−it seems to work.
2579−
2580−If this is a domestic desk, then we check to see if the case exists yet.
2581−If it doesn't, then we simply move on to the next subscriber, consing
2582−this one onto `xaq` so that we can check again the next time around. If
2583−it does exist, then we call `++balk` to fulfill the request and produce
2584−it.
2585−
2586−`++balk` is very simple, so we'll describe it here before we get to the
2587−subscription case.
2588−
2589−```hoon
2590− ++ balk :: read and send
2591− |= [hen=duct oan=@ud mun=mood]
2592− ^+ +>
2593− =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
2594− ?~ vid (blub hen) (blab hen mun u.vid)
2595−```
2596−
2597−We call `++read-at-aeon` on the given request and aeon. If you recall,
2598−this processes a `mood` at a particular aeon and produces the result, if
2599−there is one. If there is data at the requested location, then we
2600−produce it with `++blab`. Else, we call `++blub` to notify the
2601−subscriber that no data can ever come over this subscriptioin since it
2602−is now impossible for there to ever be data for the given request.
2603−Because referential transparency.
2604−
2605−At any rate, back to `++wake`. If the given rave is a subscription
2606−request, then we proceed similarly to how we do in `++eave`. We first
2607−try to get the aeon referred to by the starting case. If it doesn't
2608−exist yet, then we can't do anything interesting with this subscription,
2609−so we move on to the next one.
2610−
2611−Otherwise, we try to get the aeon referred to by the ending case. If it
2612−doesn't exist yet, then we produce all the information we can. We call
2613−`++lobes-at-path` at the given aeon and path to see if the requested
2614−path has actually changed. If it hasn't, then we don't produce anything;
2615−else, we produce the correct nako by calling `++bleb` on the result of
2616−`++make-nako`, as in `++eave`. At any rate, we move on to the next
2617−subscription, putting back into our cult the current subscription with a
2618−new start case of the next aeon after the present.
2619−
2620−If the aeon referred to by the ending case does exist, then we drop this
2621−subscriber from our cult and satisfy its request immediately. This is
2622−the same as before -- we check to see if the data at the path has
2623−actually changed, producing it if it has; else, we call `++blub` since
2624−no more data can be produced over this subscription.
2625−
2626−This concludes our discussion of foreign requests.
arvo/dill.mddeleted−24
@@ -1,24 +0,0 @@
1−+++
2−title = "Dill"
3−weight = 4
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/dill/"]
6−+++
7−Our terminal driver.
8−
9−Unix sends keyboard events to `%dill` from either the console or telnet,
10−and `%dill` produces terminal output. The only app that should directly
11−talk to `%dill` is the terminal app. Command-line apps are run by,
12−receive input from, and produce output to, the `%shell` app, which is
13−controlled by `%terminal`, which talks to `%dill`, which talks to unix.
14−Clay also uses `%dill` directly to print out the filesystem change
15−events, but this is questionable behavior.
16−
17−`%dill` has two main components. First, it controls the terminal on a
18−very basic, event-by-event level. This includes keeping track of things
19−like the dimensions of the terminal, the prompt type (plain text or
20−password), which duct to produce effects on, and so forth. Second, it
21−handles terminal events, keystroke by keystroke. Most characters are
22−simply pushed onto the buffer and blitted to the screen, but some
23−characters, including control-modified keys, arrow keys, etc. require
24−special handling. Most of the readline functionality is in `%dill`.
arvo/eyre.mddeleted−717
@@ -1,717 +0,0 @@
1−+++
2−title = "Eyre"
3−weight = 5
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/eyre/"]
6−+++
7−Our HTTP server.
8−
9−Unix sends http messages to `%eyre`, and `%eyre` produces http messages
10−in response. In general, apps and vanes do not call `%eyre`; rather,
11−`%eyre` calls apps and vanes. `%eyre` uses `%ford` and `%gall` to
12−functionally publish pages and facilitate communication with apps.
13−
14−`%eyre` primarily parses web requests and handles them in a variety of
15−ways, depending on the control string. Nearly all of these are
16−essentially stateless, like functional publishing with `%ford`.
17−Additionally, there's a fairly significant component that handles
18−`%gall` messaging and subscriptions, which must be stateful.
19−
20−## Reference
21−
22−### State
23−
24−Stored
25−
26−- `++bolo`
27−- `++cyst`
28−- `++stem`
29−
30−Runtime
31−
32−- `perk`
33− + `perk-auth`
34−- `pest`
35−- `even`
36−
37−### Cores
38−
39−- `++handle`
40− + `++parse`
41− - `++as...`
42−- `++ya`
43−- `++ix`
44−
45−## Commentary
46−
47−
48−Let us follow the loading of a simple cli app, as it bounces from
49−browser to server to browser and back.
50−
51−### Initial request
52−
53−An http request for `http://sampel-sipnym.urbit.org/cli` will be [redirected](dns)
54−to the `%eyre` on ~sampel-sipnym, and come in as a `%this` task.
55−
56−From arvo, requests enter `++call`, which after some type reification are passed
57−along to `++apex:ye`. In the case of a `%this` task, its components are
58−parsed(see `++zest:epur`, `++eat-headers`) and handed off to `++handle`, wrapped
59−in `++emule` to produce a `++fail` page in case of error. `++apex:handle` will
60−`++process` the request to a `pest` or a `++done` core, and in the former case
61−`++resolve` the pest into an outgoing card.
62−
63−XX it also seems to affect the current ship, test that serving ship name is consistently correct
64−
65−The pest is produced by `++process`, which will first further `++parse` the
66−request, and if this does not make the response immediately obvious,
67−`++process-parsed` the resulting `perk`.
68−
69−`++parse` produces the `perk`, by attempting to interpret the `pork`(url path)
70−[`++as-magic-filename`](#mage), `++as-beam`, and `++as-aux-request`. In this
71−case, `/cli` is parsed by the second case as a `%beam` query to `/=cli=`: a path
72−which starts with a valid ship name is expected to be a full clay(well, ford)
73−path, and one starting with a term implies the current serving ship and a case
74−of `0`, the current revision.
75−
76−XX spur: when the desks are merged, `/cli` shall point to `/=main=/pub/cli`
77−
78−The parsed `perk` generates a `%f %boil` note, `mark`ed as its extension(here
79−defaulting to `%urb`) and `wire`d with `~` to return unaltered to the client. It
80−goes on to `++resolve` by being passed to `++ford-get-beam`, which translates
81−the perk it into a `%boil` `++ford-req`, adding an `++fcgi` path-segment
82−containing query string and `++fcgi-cred:for-client` auth information.
83−
84−`%ford`s translation of `/=cli=/hymn/hook` to a self-refreshing `%urb` html page
85−[deserves its own commentary](/docs/arvo/ford#commentary), but
86−we resume in `%eyre` when the `%made` sign arrives in `++take`, and soon after
87−`++axon:ye`. There the `wire`, or rather the `whir` it has been verified to be,
88−determines that the response should be served immediately. However, as the mark
89−is not `%mime`, another trip to `%ford` is required to encode it, on the same
90−wire; afterwards, the value of the `%mime` cage is verified to be of the correct type, and finally
91−delivered back up the requesting duct as a successful `%thou` HTTP response.
92−
93−XX `%cast %mime` used to be in ford-get-beam, is there a reason it was removed?
94−
95−## Back into the breach, or: auxilary requests
96−
97−Now, it was mentioned that this result is self-refreshing: the `%urb`
98−translation door injects a `;script@"/~/on/{deps}.js"` into every page, `deps`
99−is a ford-readable hash of the set of resources that page construction depended
100−on.
101−
102−This triggers another `%this` request. Its handling is identical to that of
103−`/cli` up until `++parse`, where it is seen not `++as-beam` but
104−`++as-aux-request`(auxillary requests starting with `/~/` or `/~~/`).
105−`/on/[hash]` is a long-`%poll`, which `++process-parsed`, for a `.js` mark,
106−answers with a direct `%js`. Its contents are the static `++poll:js`, which
107−initiates the long-polling loop, run against an injected `urb.js` of
108−`{poll:[hash]}`.
109−
110−A `%js` `pest` is `resolve`d as a `text/javascript` success `%this`.
111−
112−When `poll.js` is received by the client, it opens an `XMLHttpRequest` for
113−`/~/on/{window.urb.poll}.json`, bringing us back to `%poll:process`.
114−
115−In the case of a non-`%js` `/~/on/`, `%poll:process-parsed` turns into a
116−`++new-dependency`, which stores the listening duct, and `pass-note`s a `%wasp`
117−with the deps-hash back to `%ford` whence it came. While this occured, the page
118−has loaded.
119−
120−Some indeterminate amount of time afterwards, with dropped `/~/on/{...}.json`s
121−being retried upon expiring and also being stored, a `%news` sign arrives in
122−`++axon`, and the hash in question is retrieved from the wire, and the listening
123−long-polls retrieved by the hash. Each receives a 205 "Reload parent view" HTTP
124−response, which `poll.js` dutifully executes, and a fixed typo of markdown is
125−rendered.
126−
127−## Authentication
128−
129−Now, while this accurately reflects the presentation of e.g. a markdown file,
130−`/cli` is an application front-end, and one that permits only owner access. Its
131−second script is `@"/~~/~/at/main/lib/urb.js"`, semantically equivalent to
132−`/~/as/own/~/at/main/lib/urb.js`, and handled as follows.
133−
134−In `++as-aux-request`, `%as %own` becomes `%auth %get our` perk, which
135−`++process` passes to `++process-parsed` passes to `++process-auth`. There, a
136−`yac` "ya" core is built `++for-client`: a `++cookie-prefix`, which is just the
137−serving ship name, is used to get a `++session-from-cookies`, here nil as the
138−client has no cookie set. In lieu of a cookie, a `++new-ya` is constructed, with
139−a random token `hole` and a `++new-cyst` which fills out `cyst` session state
140−from request data.
141−
142−Returning to `++process-auth`, `%get` checks if the yac is authenticated with
143−the requested credentials(`anon` requests are always granted), which for the
144−fresh new `cyst` is not the case (more on success [later](#auth-ok)). Unless
145−authenticating as a [foreign ship](#xeno), the only thing left is to
146−`++show-login-page`, which detects that the requested resource is not `%html`,
147−and produces a `%red` pest. For `%js`, `%red`irections `++resolve` to
148−`++auth-redir:js`, a line of javascript which prepends `/~~` to the url path.
149−
150−The owner-authenticated main page request similarly ends in `++show-login-page`,
151−which for the empty session is an `[%htme ++login-page:xml]`, `resolve`d to
152−`++give-html` with a 401 "unathorized".
153−
154−The login page shows a simple prompt, and requests `/~/at/auth.js` to handle the
155−submission. And so we are, once again, attempting to divine if what we're doing
156−makes sense `++as-aux-request`.
157−
158−To understand `/~/at`, there will first be a brief diversion to `~/auth.json`.
159−`auth.json`, perk `[%auth %json]`, in `++process-auth` serves `++stat-json:ya`,
160−containing such information as the serving ship, which identities are associated
161−with this session, and `oryx`, a CSRF token. An oryx must be present on all
162−stateful requests, in this case executing a log in. It also saves the new/old
163−session using `abet`.
164−
165−XX explain `ixor` here and not [later](#ixor)?
166−
167−`/~/at` is an alternate interface, which injects `auth.json` data into the
168−requested file. `/~/at/auth.js`, then, is a request for the built-in `auth:js`
169−(parsed to and processed from an `[%auth %js ~]` perk), with session data added
170−as `window.urb`. And indeed, ``[`%js /~/at/auth]`` is parsed to
171−``[%auth at [`%js /auth]``, which in `++process-auth` is re-`process`ed to
172−`[%js ++auth:js]`, which is `++resolve`d after an `++add-json` of
173−the relevant data. The yac cookies are also passed to `resolve`, which
174−`++add-cookies` injects into the `httr`.
175−
176−It is at this point that there is first occasion for user input, namely the password.
177−
178−The `auth:js` script sends a `PUT` request, also to `/~/auth.json`. In `parse`,
179−the first nontrivial `++check-oryx` occurs, `++grab-body` the request oryx and
180−ensuring it is recorded for the session. The request parsed with `++need-body`
181−to a `[%auth %try {password}]` perk. `%get:process-auth` checks it against
182−`++load-secret`, upon success updates the session with `++logon:ya`, and
183−serves a fresh `auth.json` which reflects the changed `user`. Upon receiving
184−this, the page is refreshed to retry the original request.
185−
186−### Post-authentication: app communication.
187−
188−Upon refresh, `/~~/cli` brings us for the third time to `%get:process-auth`, but
189−this time the cookie is set, and the `yac` fetched contains the serving ship as
190−authenticated. The `++handle` sample is updated to reflect the requesting ship,
191−and the `process` continues for the rest of the pork, once again serving the
192−ford page.
193−
194−The `/~/on/[deps].json` poll starts anew, and `/~~/~/at/main/lib/urb.js` we now
195−know to serve the window.urb necessary to make requests, and the `urb.js`
196−standard library which extends it with a number of wrappers to them and other
197−useful functions.
198−
199−One of those functions is `urb.bind`, which is used to subscribe to application
200−data. Userspace javascript sets `urb.appl` to `/tic`, and binds `lines` to a
201−`;pre;` text display, using a callback.
202−
203−This triggers a `PUT` to `/~/is/{ixor}/cli/lines.json`, where `ixor` is a hash
204−of `oryx` that identifies the connection. `++as-aux-request`, an `%is` is a
205−`%subs` subscription update update, which for `%put` forwards to
206−`++add-subs:ix`, the ix core fetched `++for-view` by hashing the request
207−`++oryx-to-ixor`.
208−
209−A view has all the state associated with a client that must be
210−remembered between events. In this case, this is what app/path the request duct
211−is associated with; but mainly, `++add-subs:ix` will `pass-note` to `%gall` so
212−it `%show`s the data on the path, current and future.
213−
214−This will immediately(assuming the ship is local) result in a `%nice` by the
215−`/cli` app, returning `{ok:true}` `++nice-json` to `urb.bind`'s second callback
216−as `{ok:true}`. The initial `%rush` results also arrive, and in `++axon` are
217−converted to json using `++back`(ford `%cast` wrapper), and when `%made` get
218−passed to `++get-rush:ix`. There the source application/path are decoded by
219−duct, and then the full event goes to `++get-even`; `++add-even` inserts it to
220−the queue, and as there is no long poll it simply stays there.
221−
222−Upon receipt, the client realizes the long-poll isn't actually running, so that
223−is started using `urb.poll`. At `/~/of/{ixor}`, perk
224−`[%view ixor ~ {sequence-number}]`, it is `process`ed by `++poll:ix` (the cyst
225−is retrieved by `++ire-ix` form global state, using the perk `ixor`): the
226−sequence number is in the past, so the previously received `%rush` is
227−`++give-even`. After deleting the previous message in the queue and invoking
228−`++pass-took` to signal `%gall` of this occurrence, the data is annotated with
229−the source app+path `++subs-to-json`, and returned to the polling duct.
230−
231−On the client, the user callback receives the `/cli` history, and displays it on
232−the page. The `/~/of` long poll is continued, this time reaching `++poll:ix`
233−with the "pending" sequence number, and being stored in the `cyst` for its troubles.
234−
235−Its next update proceeds idenitcally, but first it must be triggered, which
236−happens when the user enters "(add 2 2)\n", firing an `urb.send` from the event
237−handler. This sends a `POST` request to `/~/to/cli/json.json`, perk `%mess`,
238−`++process`ed to a `%g %mess`. Were the mark not `%json`, a `%ford` conversion
239−would occur first, and `%made:axon` would send the gall message proper. In
240−either case, eventually a `%mean` or `%nice` arrives, is encoded as json, and
241−sent to the client callback.
242−
243−## A path not taken: magic filenames
244−
245−The `/robots.txt` and `/favicon.(ico|png)` files are static, and served
246−immediately when caught by a `++parse`.
247−
248−XX index.html?
249−
250−## A path not taken: foreign auth
251−
252−While this example details a login `/~/as/own`, it is possible to be
253−authenticated as any ship on the network. A request for such seen in
254−`%get:process-auth` is passed to `++foreign-auth:ya`, which sends an
255−`%ames /lon` message to the ship in question. The foreign ship stores the
256−inquiry, calculates(the local) `++our-host` and responds with a `/hat`,
257−containing the redirection host, which is stored by `++foreign-hat`; it is later
258−used to send the client to a `/~/am` url on the foreign client, which acts as a
259−normal login page but later sends the client back. XX expand, basically the
260−status quo is you're logged in and `/~/as/foo` is ignored, just setting your
261−`urb.user` XX
262−
263−
264−### A path not taken: deauthentication
265−
266−`/~/away`, perk `[%away ~]`, produces a static `++logout-page:xml`, which also
267−uses `/~/at/auth.js`, to send a `DELETE /~/auth.json`, perk `[%auth %del]`. This
268−executes `++logoff:ya` for the cookie session, resolving to `++abut` to wipe it
269−from memory.
270−
271−### A path not taken: unsubscription
272−
273−`DELETE /~/is/app/path/within` works much like `PUT /~/is/app/path/within`,
274−`++del-subs:ix` acting as reverse of `++add-subs` by deleting the duct binding
275−and sending `%g %nuke`.
276−
277−
278−XX unmentioned arms: abet, add-poll, adit, ames-gram, anon, ares-to-json, bolo, cyst, doze, even, ford-kill, get-mean, gift, give-json, give-thou, gram, hapt, hasp, host-to-ship, ix, ixor, js, kiss, load, mean-json, move, note, pass-note, perk, perk-auth, pest, poke-test, print-subs, render-tang, resp, root-beak, scry, ses-authed, ses-ya, sign, silk, sine, stay, stem, teba, titl, to-oryx, urb, wait-era, wake, whir, wush, xml, ya, ye
279−
280−### Appendix A: DNS
281−
282−The `*.urbit.org` domain can be used to access destroyers and cruisers. In the
283−common case oh hosted ships, this is done by dynamic DNS directly to the hosting
284−instance. We do not speak of the uncommon case. When ports are blocked and
285−infrastructure crumbles around you, only imported martian networking can be
286−trusted: the `%get` and `%got` [gram]()s are used to proxy [`%this` requests]() and
287−[`%thou` responses]() respectively.
288−
289−## Specification
290−
291−The `%eyre` vane serves one purpose: receiving inbound HTTP requests from browsers and clients pretending to be browsers. To facilitate this communication, `%eyre` does two things: 1. provide an API for traditional clients to talk to; and 2. provide a mechanism for saving state that allows the server to keep track of identities/sessions, subscription data, and active connections.
292−
293−This document outlines the following:
294−
295−1. [`perk`](#perk), a `pork` subset that defines what URLs the client can send to `%eyre`.
296−
297−2. [the values stored on the client](#client), both statically in cookies and dynamically as the `window.urb` object, which facilitate this transaction.
298−
299−3. [`task`](#task), the requests `%eyre` will accept.
300−
301−4. [`gift`](#gift), the responses it will give to those requests.
302−
303−5. [`note`](#note), the set of arvo requests that %eyre makes to the other vanes.
304−
305−6. [`whir`](#whir), a `wire` subset, the associated dynamic state
306−
307−7. [`sign`](#sign), the responses `%eyre` accepts
308−
309−8. [`bolo`](#bolo), the state stored between separate events.
310−
311−## 1. URL structure
312−
313−There exist several URL forms accepted by `%eyre`.
314−
315−### 1.1 Functional request
316−
317−The simplest of them is a static `%f` functional publish request:
318−
319−```
320− GET /[ship]/[desk]/[case]/path/to/file.[mark]
321−```
322−e.g.
323−
324−```
325− /~pittyp-pittyp/main/5/lib/urb.js
326−```
327−A `case` of 0 signifies the most recent version.
328−
329−If no file extension is provided, the default `mark` is `%urb`, which consists of `%html` injected with an auto-refresh script.
330−
331−A shorter form:
332−
333−```
334− /path/to.[mark]
335−```
336−is prepended with the [default request path](#prefix). For example, if `%eyre`
337−is configured with a root of `/<our>/main/0/pub`, then `/doc/arvo` is
338−interpreted as a request for `/=main=/pub/doc/arvo.urb`.
339−
340−Auxiliary paths start with `/~/`, and provide other functionality, such as:
341−
342−### 1.2 Auto-reload
343−
344−When a new version of a page becomes available, it is useful to propagate it to the client. The `%f` vane manages the particulars, and provides an update token along with all published pages. The `/~/on` long-polling endpoint makes use of that token, which is a hash of the server-stored dependency set.
345−- `/~/on/[hash].json` retuns `true` when a page may require updating.
346−- `/~/on/[hash].js` is a lightweight script that polls for the above. It is primarily used in error messages.
347−
348−### 1.3 Authentication
349−
350−Authenticated requests are accomplished through sessions, tracked with cookies which are set on the first such request.
351−- `/~/as/[user]/...` is an authenticated request to `...`, where `user` can be a `@p` ship, `'own'`, `'any'`, or `'anon'`.
352− + `'anon'` is a randomly-generated per-session submarine, and requires no further authentication.
353− + `'own'` represents the serving ship. The short form of `/~/as/own/` is `/~~/`
354− + `'any'` requires a network ship, chosen with a prompt if unknown. The short form of `/~/as/any/` is `/_/`
355− + Auth requests are handled in three ways:
356− + I. If the session is associated with the `ship`, serve `...`, storing the ship as the session's default ship. For example, `/~/as/sivtyv-barnel/main/pub/test.html` is an authenticated request of `/main/pub/test.html` with the identity of `~sivtyv-barnel`.
357− + II. If the session is not associated with the `ship` in the path, the client is redirected to a login page, where a password can be entered. Successful authentication results in a page refresh to the requested path.
358− + III. otherwise, [send a message](#foreign) to the claimed ship, and redirect the user to `https://[foreign-host]/~/am/[ses]/...#[current-host]&?code=[code]`
359−- `/~/am/[ses]/...#original-host` similarly serves a login page. Upon success, inform the `ship` of the success and redirect it back to `http://[original-host]/~/as/<this-ship>/...`
360−- `/~/away.html` is a log-out page.
361−- `/~/auth.json` returns `{ship,oryx,user,auth}`: the serving ship, a CSRF token, active user, and all allowed users respectively.
362−- `/~/at/{...}.js` is an alternate form of `/~/auth.json`, which injects a line into the served js file that sets `{ship, oryx, user, auth}` on the `window.urb` object.
363−
364−So far, all the paths specified have been GET requests. Authentication, however, requires sending data. This is also done at the `/~/auth.json` endpoint.
365−- `POST {oryx,ship,code} /~/auth.json?PUT` is used by the login script to authorize a user, and returns the same result as `GET`, additionally containing either`{ok:true}` or `{fail:'type',mess:"Error message"}`
366−- `POST {oryx,ship?} /~/auth.json?DELETE` revokes authorization. Response as above.
367−
368−### 1.4 Messaging
369−
370−- `POST {oryx, wire, xyro} /~/to/[app]/[mark].json`, where `xyro` is data that will be converted to the `mark`. In the simplest case, `/~/to/hello/json.json` will pass `xyro` through verbatim, sending `[%json xyro]` to the `++poke` arm of app `%hello`.
371−- `POST {oryx, wire, xyro} /~/to/<ship>/[app]/[mark].json` is a foreign message send, as above.
372−
373−### 1.5 Subscriptions
374−
375−- `/~/of/[ixor]` is an `EventSource`: a conceptually infinite file containing a stream of events. By default, it sends a newline every 30 seconds serving to signal that the connection is alive to both the server and IP middleware.
376− + `/~/of/[ixor]?poll={n}` is a long-polling fallback interface. Produces event number `{n}`, blocking until it occurs. Its contexts can be affected by `POST` requests with a body of `{oryx, wire}`, and a query string of `PUT` or `DELETE`. They return either `{mark}`(which may be `null`), or [`{fail, mess}`](#mean-json)
377−- `/~/in/[hash].json` is a dual to [`/~/on`](#on-change). It binds `mod` events, which echo the requesting token.
378−- `/~/is/[app]/path/to.[mark]` binds `rush` events, formatted with a first line of `[app] /path/to`, and the rest containing subscription data. Additionally, `mean` events formatted similarly may arrive, also converted to the relevant mark.
379−
380−
381−
382−### 1.6 Ablative
383−
384−These interfaces will temporarily exist to aid development, and are to be considered unstable.
385−- `/~/debug/...` access normally inaccessible pages. For example, `/~/debug/as.html` will present the login page, regardless of current session status.
386−
387−
388−## 2. Client state
389−
390−Some information is stored on, and provided to, browser clients
391−
392−### 2.1 Cookies
393−
394−Authenticated users receive a cookie on the domain of `*.urbit.org`. The cookie contains a client session token, keyed by the serving ship.
395−
396−### 2.2 Authentication
397−
398−It is common(e.g. by the `%urb` mark) to set window.urb to the contents of `/~/auth.json`:
399−- `ship` is the serving ship
400−- `oryx` is a unique CSRF token that identifies this view, bound to the session cookie
401−- `ixor` is a hash of `oryx`, used as an insecure view identifier
402−- `user` is the authenticated/generated ship name
403−- `auth` is a list of identities usable by this session
404−
405−### 2.3 Client library
406−
407−To this object, `/main/lib/urb.js` adds helpers:
408−- `app` is an optional app name to send messages to by default
409−- `send({data,mark?='json',app?=urb.app,ship?}, cb?)` delivers messages
410−- `bind({path,app?=urb.app}, cb)` subscribes by path
411−- `drop({path,app?=urb.app}, cb?)` pulls the subscription
412−- `util` is an object containing methods for converting between JavaScript types and Hoon atom odors.
413−
414−## 3. Requests
415−
416−## `[%born port=@ud]`, unix init
417−
418−When the `vere` process is re/started, a TCP port is bound, HTTP requests on which are the scope of this document. The `%born` gift informs eyre of this occurrence, which in turn updates [its state.](#bolo)
419−
420−**Gifts given in response:** none.
421−
422−## `[%hiss p=mark q=cage]`, outbound http
423−
424−Userspace http request, converted by `%ford` into an actual `hiss`.
425−
426−**Gifts given in response:** a [`%sigh`]()
427−
428−### 3.1 `[%this httq]`, inbound http
429−
430−The primary `%eyre` request type comes from the host system, and constitutes an inbound http request. It consists of five parts:
431−
432−I. `p=[? @if]`: a loobean determining whether the request is being made over https, and the client source, an IPv6 address possibly encoding an IPv4 one as `.0.0.0.0.0.ffff.wwxx.yyzz`
433−
434−II. `q=meth`, an http method
435−
436−III. `r=@t`, the unparsed URL
437−
438−IV. `s=mess`, an associative list of header keys/values
439−
440−V. `t=(unit octs)`, the request body, if any.
441−
442−After `r` is parsed to a `purl`, the `pork`(relative path) determines the resource being served. The first step in handling an http request is [classifying its intent](#perk).
443−
444−- A ford request results in a [`%boil` note](#boil).
445−- `/~/[name].js` is generated from [session](#sink) or [view](#stem) state, and [served](#mime) as `%js`.
446−- `/~/am` generates a login page.
447−- `/~/as` is resolved further if authenticated, generates a similar login page if the claimed ship is local, and otherwise is saved to [session state](#sink) and sends a ["login" `%a` message](#lon) to the foreign ship.
448−- `/~/at` and `/~/auth.json` generate a new `oryx` and store it in the [session state](#sink).
449−- `/~/in` and `/~/is` affect [view state](#stem), possibly sending subscriptions or unsubscriptions to `%f` and `%g` respectively, and are generated from view state.
450−- `/~/on` is saved to the `bolo` by `hash`, and translated to a [`%wasp` note](#wasp).
451−- `/~/of` fails if the `ixor` is unknown, and otherwise is stored in the `ixor`, receiving a partial response and all events after its [last-seen header](#). If it has a `poll` parameter, the response is full, and only occurs if the body is non-empty. Otherwise the oryx is saved as a [live](#live) request in case of cancellation.
452−- `/~/to` transforms into a [`%g` message](#mess).
453−
454−**Gifts given in response:** a [`%thou`](), or a [`%that`](#that) followed by multiple [`%thar`]()s.
455−
456−### 3.2 `[%thud ~]`, inbound close
457−
458−Sent when an unresponded-to request is cancelled. The [live](#live) effect of the request is looked up, and
459−- `%exec` ford boil requests are cancelled with `[%exec ~]`
460−- `%wasp` ford deps requests are cancelled with `[%wasp |]`
461−- `%poll` session polls `%rest` the session heartbeat timeout
462−
463−### 3.3 `[%thin p=@ud]`, delivery failure
464−
465−Sent when a partial [response](#that) or [body](#thar) fails to arrive. Its `duct` is the same as that of the original request. This is handled by [waiting](#wait) for the client to reconnect, and if this not occur, unwinding all subscription state.
466−
467−
468−**Gifts given in response:** None.
469−
470−### 3.4 ``[%wart sock [path *]]``, inbound message
471−
472−Sometimes, messages are received from other ships. They are expected to take the from of a [`gram`]().
473−
474−**Gifts given in response:** [`%nice` or `%mean`](#ack).
475−
476−#### 3.4.1 `gram`
477−
478−There are three messages of note, all concerning authentication
479−- `[/lon ses]` is a login request, which contains the session wishing to authenticate.
480−- if the session is already authorized, a reply of `[/aut ses]` from (%eyre on) a foreign ship prescribes that the session is henceforth allowed to act on its behalf. All waiting `/~/as` are resolved as successful.
481−- otherwise, `[/hat ses hart]` contains the ship's preferred hostname. This can then be used to redirect the client. All waiting `/~/as` are given `307 Redirect`s to `/~/am` on the provided host.
482−
483−**Gifts given in response:** nice?
484−
485−## 4. Responses
486−
487−### 4.1 `[%nice ~]`, `[%mean ares]`, network acknowledgement
488−
489−A `%nice` is given upon receiving an [ames message](#gram), indicating succesful receipt. `%mean` is currently unused directly, but reserved for error conditions.
490−
491−## `[%sigh p=cage]`, inbound http response
492−
493−An HTTP response gets converted to the requested mark, or `%tang` in case of error.
494−
495−### 4.2 `[%thou httr]`, full HTTP response
496−
497−Most requests are served with one coherent response, consisting of
498−- `p=@ud`, an HTTP status code
499−- `q=mess`, response headers
500−- `r=(unit octs)`, an optional body
501−
502−### 4.3 `[%that httr]`, partial HTTP response
503−
504−[EventStream responses](#of-ixor) consist of multiple sequential chunks. Treated as `%thou`, except the request is kept open.
505−
506−### 4.4 `[%thar (unit octs)]`, partial HTTP body
507−
508−Complementing `%that`, `%thar` is a body chunk, containing an event. An empty `%thar` signals for the connection to be closed.
509−
510−Body chunks, besides `[1 '\0a']`(a heartbeat newline), are encoded from `even` events. The stem becomes the [`event` field](#eventsource), and the content, `data` lines.
511−
512−#### 4.4.1 `even`, event types
513−
514−There are three events that a [client subscription](#subs) will be given.
515−
516−- `[%news hash]` is a `%f` update, and contains the relevant dependency token.
517−- `[%mean [term path] ares]` is a sourced subscription error.
518−
519−## 5. Vane requests
520−
521−### 5.1 ``[%a %wont sock `[path *]`gram]``, outbound message
522−
523−The `%a` interface provides conveyance of [messages](#gram) over UDP.
524−
525−Signs a `%woot` upon message arrival.
526−
527−
528−All open [subscriptions](#of-ixor) require a "heartbeat" newline every `~s30`. When this fails to arrive, a complementary timer is set for `~m1`, after which the client is considered to have departed.
529−The `%b` timer interface is used to schedule the next such event, or cancel past scheduled ones when a connection closes.
530−
531−Signs a `%wake` upon timer activation.
532−
533−### 5.3 `[%f %wasp @uvI]`, dependency listen
534−
535−Knowledge of filesystem changes, requested by `/~/on` and `/~/in`, is requested the `%wasp` note. It contains the hash token which identifies a set of dependencies to query. Saved as a (live[live](#live)#live] request in case of cancellation when caused by `/~/on`.
536−
537−Signs a `%writ` upon change.
538−
539−### 5.4 `[%f %exec (unit silk)]`, functional transformations
540−
541−The `%f` interface converts nouns from one form to another. An empty unit represents cancellation.
542−
543−Signs a `%made` containing the computation result.
544−
545−The `silk`s used are as follows:
546−
547−### `[%cast %mime %boil mark beam [%web span ~]]`, file load
548−
549−The simplest functional request is the construction of a page. Saved as a [live](#live) request in case of cancellation.
550−- The `mark` is the request extension, defaulting to `%html`.
551−- A `beam`(path in `%clay`) is decoded from the request path.
552−- A `/web/<nyp ced quy>` virtual path is appended, span-encoding method, auth, and query string.
553−
554−### `[%cast mark %done ~ cage]`, convert
555−
556−This is used when communicating with apps, in both directions.
557−- Client messages are encoded as JSON objects, but can contain many different marks. Ones sent to non-`json.json` endpoints are `%cast` to he relevant mark, with a `cage` of `[%json p:!>(*json) jon]`, prior to being sent onwards to applications with `[%g %mess]`.
558−- Subscription responses also come in arbitrary marks, but are required to be sent as whichever mark an endpoint is subscribed to. They get `%cast` prior to being sent back as a `%that` EventSource segment.
559−
560−### 5.5 `%g`, app actions
561−
562−The end goal of many a userspace `hymn.hook` is to provide UI for a `%gall` app. To accommodate this, various functionality needs to be interfaced with.
563−
564−### `[%mess hapt ship cage]`, app message
565−
566−After a `/~/to` POST has been received, and possibly converted to the correct mark, it is sent to `%g` for processing. The `hapt` is the destination, the `ship` is the source, the `cage` is the marked message data.
567−
568−Signs a `%nice` or `%mean`, in userspace or upon crashing.
569−
570−### `[%show hapt ship path]`, app subscription
571−
572−An `/~/is` PUT, if not already registered, results in a new subscription. A request for such contains the destination `hapt`, requesting `ship`, and app-internal `path`.
573−
574−Signs a `%nice` on init, `%rush` on data, and a `%mean` in subscription termination.
575−
576−### `[%took hapt ship]`, %rush confirmation
577−
578−A `%took` must be sent to acknowledge the receipt of subscription data, which in this case occurs automatically.
579−
580−Causes no signs.
581−
582−### `[%nuke hapt $|(ship [ship path])]`, subscription cancel
583−
584−An `/~/is` DELETE is used to remove a subscription, and is converted straightforwardly to a `%nuke`. Additionally, when a client disconnects, all of its subscriptions are `%nuke`d to reflect their expiration.
585−
586−Signs an empty `%mean` for each open subscription that is closed.
587−
588−## 6. In-flight metadata
589−
590−Various state can be associated with requests, but not necessarily be returned in responses to them.
591−
592−### 6.1 `~`, dropthrough
593−
594−If the response should be sent statelessly further up the duct, the `wire` is empty. This is used in `%f` pure functional page generation.
595−
596−### 6.2 `[?(%y %n) ...]`, stability
597−
598−The first element of a [`%b` timer](#wait) path distinguishes between live(%y) and dying(%n) channels.
599−
600−### 6.3 `/of/[ixor]`, view
601−
602−Designates which stream to act upon. Present on `%b` timer cards.
603−
604−### 6.4 `/on/<deps>`
605−
606−Present on `%f` dependency news. Looked up in [the state](#bolo) to see if any response is necessary.
607−
608−### 6.5 `/to/<hasp>/<ship>`, app
609−
610−Present on `%f` translations of message marks
611−
612−### 6.6 `/is/[ixor]/{hasp path}`, subscription
613−
614−Subscription requests. Present on `%g` subscription requests, and `%f` translations of [`%rush` subscription data](#show).
615−
616−## 7. Vane responses
617−
618−The goal of requests is to cause some manner of result. Specifically,
619−
620−### 7.1 `[%a %woot ship coop]`, acknowledgement
621−
622−A [message](#mess) which has been acknowledged remotely.
623−
624−### 7.2 `[%b %wake ~]`, timer
625−
626−Timer activate. If this is a `%y` [timer](#wire-live), send a newline to each `/~/of/[oryx]`; if `%n` and the `oryx` still has no listeners, wipe its state/subscriptions.
627−
628−### 7.3 `[%f %news ~]`, dependency update
629−
630−This message signifies a `hash` has changed, and listeners to it should be updated. Results in [`%news` events](#even-news) to concerned streams, and [full responses](#thou) to relevant long-polls.
631−
632−### 7.4 `[%f %made (each bead (list tank))]`, compute result
633−
634−Further action depends on the [`wire`](#whir). It can:
635−- Be empty, designating direct request data, which is [served](#mime) back up the `duct`.
636−- Contain [app and requester identities](#wire-to), which designates an app message has been converted to the correct `mark`, and can now be [sent to the app](#mess) with an empty `wire`.
637−- Contain an `oryx`, app, and `path`, designating subscription data. If the subscription is active in the relevant `stem`, it is acknowledged with a `%took` and given as a [`%rush` event](#even-rush) to all listeners. Otherwise, the subscription is `%nuke`d.
638−
639−### 7.5 `%g`, applications
640−
641−The `%g` interface sends several responses.
642−
643−### `[%nice ~]` and `[%mean ares]`, acknowledgment
644−
645−These are given as a response to `%mess`, with an empty wire, and `%show`s, with a [subscription wire](#wire-is).
646−The former is [served](#mime) back to the requester(i.e. the remaining duct), and the latter returned to the client.
647−
648−#### 7.5 `[%rush cage]`, subscription data
649−
650−A `%rush` arrives on a [subscription wire](#wire-is), and is then sent [for conversion](#done) to the correct mark. An unexpected `%rush` is `%nuke`d.
651−
652−## 8. Server state
653−
654−There is a quantity of data that persists between events.
655−
656−### 8.1 Global
657−
658−- `path` the default path which is prepended to relative plain requests. Initialized to `/<our>`, the serving ship; this interprets the first element of requests as a desk, and injects a `case` of `0`.
659−- `(jar ship hart)` remembered hostnames in order of preference, made accessible through `.^`
660− + The default values(for self) are `http://<ship>.urbit.org:80` if not on a fake network, followed by `https://0.0.0.0:[port]`.
661−- `(jug deps (each duct oryx))`, `/~/on` and `/~/in` endpoints listening to `%c` updates.
662−- `(map duct live)`, inbound request state
663−- `(map ixor oryx)`, open `/~/of` streams.
664−- `(map oryx stem)`, open view state.
665−- `(map hole sink)`, session state.
666−- `(map hole ,[ship ?])`, foreign session names, along with their origin ships and whether they are authorized to act on our behalf.
667−
668−### 8.2 `live`, per-request state
669−
670−To honor request cancellations, each unserved request must track which effect it is causing.
671−+ `[%exec whir]` if it is a ford data request
672−+ `[%wasp (list @uvH)]` if it is a ford dependency poll
673−+ `[%xeno ship]` if this is a proxied request
674−+ `[%poll ixor]` if this is a session long-poll
675−
676−### 8.3 `sink`, per-session state
677−
678−Each `hole` has associated authentication state.
679−- `priv`, a random secret that verifies the session, stored in cookie.
680−- `[ship (set ship)]`, the `ship` a session is acting as and any others it has been authorized with.
681−- `(jug ship ,[path duct])`, authentication `/~/as` requests waiting on foreign ships.
682−- `(set oryx)`, views associated with this session. Dual of `hole` in `stem`.
683−
684−### 8.4 `stem`, per-view state
685−
686−Each `oryx` has active subscription state.
687−- `hole`, session in which this view resides. Dual of `(set oryx)` in `sink`.
688−- `ixor`, a cached hash of the `oryx` that is used as a subscription id, by the `/~/of` EventStream.
689−- `[,@u (map ,@u even)]`, queued [events](#even). Has a maximum size.
690−- `(unit ,[duct @u ?])`, http connection, its last received event, and whether it is a long-poll request.
691−- `(set deps)`, subscribed `/~/in` points. Mirrored in `bolo`.
692−- `(map ,[hasp path] mark)`, subscribed `/~/is` points
693−- `(que duct)`, where any `%nice`/`%mean
694−
695−## Appendix A: Glossary
696−
697−- An `oryx` is a CSRF token used for [authenticated requests](#auth)
698−- `mean.json` is a rendering of hoon `ares`: an error message formatted as `{fail:'type',mess:"Error message"}`
699−- `urb.js` is the standard client-side implementation of the `%eyre` protocols, normally found in `/=main=/lib`
700−- The act of "serving", refers to the wrapping of a `%mime` cage in an HTTP `200 Success` response, and errors or other marks being [sent to ford](#done) for conversion. Inside a `sign`, this conversion occurs along the same [`wire`](#wire); otherwise, the `wire` is [empty](#wire-drop).
701−
702−## Appendix B: EventSource
703−
704−UNIMPLEMENTED
705−
706−For more information, see <http://dev.w3.org/html5/eventsource/>
707−
708−An EventSource is a stream of events, encoded in a conceptually infinite `GET` request. Each event is formatted as
709−```
710− http
711− id: {number}
712− event: {type}
713− data: {contents}
714− data: {more-contents}
715−```
716−
717−Data lines are joined by ASCII `10` newline characters; multiple newlines signify separate events. The `id` is used in a `Last-Event-ID` HTTP request header upon reconnection.
arvo/ford.mddeleted−571
@@ -1,571 +0,0 @@
1−+++
2−title = "Ford"
3−weight = 6
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/ford/"]
6−+++
7−Our typed and marked computation engine.
8−
9−A variety of different services are provided by `%ford`, but they mostly
10−involve compiling hook files, slapping/slamming code with marked data,
11−and converting data between marks, including validating data to a mark.
12−Throughout every computation, `%ford` keeps track of which resources are
13−dependencies so that the client may be aware when one or more
14−dependencies are updated.
15−
16−`%ford` neither accepts unix events nor produces effects. It exists
17−entirely for the benefit of applications and other vanes, in particular
18−`%gall`. `%eyre` exposes the functional publishing aspects of `%ford`
19−while `%gall` uses `%ford` to control the execution of applications.
20−`%clay` is intended to use `%ford` to managed marked data, but this is
21−not yet reality.
22−
23−## Cards
24−
25−`%ford` accepts just one card, `%exec`. This is misleading, however,
26−since there are fourteen different `silk`s that may be used with it. In
27−every case, the expected response to a `%exec` card is a `%made` gift
28−with either an error or the produced result along with its set of
29−dependencies.
30−
31−Silks may autocons, so that the product of a cell of silks is a cell of
32−the product of the two silks.
33−
34−### `%bake`
35−
36−Tries to functionally produce the file at a given beam with the given
37−mark and heel. It fails if there is no way to translate at this level.
38−
39−### `%boil`
40−
41−Functionally produces the file at a given beam with the given mark and
42−heel. If there is no way to translate at this beam, we pop levels off
43−the stack and attempt to bake there until we find a level we can bake.
44−This should almost always be called instead of `%bake`.
45−
46−### `%call`
47−
48−Slams the result of one silk against the result of another.
49−
50−### `%cast`
51−
52−Translates the given silk to the given mark, if possible. This is one of
53−the critical and fundamental operations of ford.
54−
55−### `%diff`
56−
57−Diffs the two given silks (which must be of the same mark), producing a
58−cage of the mark specified in `++mark` in `++grad` for the mark of the
59−two silks.
60−
61−### `%done`
62−
63−Produces exactly its input. This is rarely used on its own, but many
64−silks are recursively defined in terms of other silks, so we often need
65−a silk that simply produces its input. A monadic return, if you will.
66−
67−### `%dude`
68−
69−Computes the given silk with the given tank as part of the stack trace
70−if there is an error.
71−
72−### `%dune`
73−
74−Produces an error if the cage is empty. Otherwise, it produces the value
75−in the unit.
76−
77−### `%mute`
78−
79−Takes a silk and a list of changes to make to the silk. At each wing in
80−the list we put the value of the associated silk.
81−
82−### `%pact`
83−
84−Applies the second silk as a patch to the first silk. The second silk
85−must be of the mark specified in `++mark` in `++grad` for the mark of
86−the first silk.
87−
88−### `%plan`
89−
90−Performs a structured assembly directly. This is not generally directly
91−useful because several other silks perform supersets of this
92−functionality. We don't usually have naked hoods outside ford.
93−
94−### `%reef`
95−
96−Produces a core containing the entirety of Zuse and Hoon, suitable for
97−running arbitrary code against. The mark is `%noun`.
98−
99−### `%ride`
100−
101−Slaps a hoon against a subject silk. The mark of the result is `%noun`.
102−
103−### `%vale`
104−
105−Validates untyped data from a ship against a given mark. This is an
106−extremely useful function.
107−
108−## Ford runes
109−
110−One of the most common ways to use ford is through ford's runes, all of which begin with `/` ("fas"). A ford rune runs a step of a ford build and places the result in the subject. There are various kinds of build steps, some of which take other build steps as parameters. The most common pattern is to have a sequence of ford runes at the top of a hoon source file that import the results of evaluating other hoon files. This is how we "import a library" in urbit: we add the result of compiling another hoon file into the current subject, possibly renaming it by wrapping a face around it.
111−
112−Another common use case is assembling and rendering markdown templates into a single HTML file, to be sent as an HTTP response in urbit's web server `%eyre`. It's important to keep in mind that %ford is quite flexible and generic, and is used in other parts of urbit -- such as the dojo -- that would not traditionally fall under the purview of a build system.
113−
114−### `/+` import from lib/
115−
116−The `/+` rune accepts a filename as an argument. It interprets that filename
117−as a hoon source file within the `lib` directory. This is how we import a shared
118−library in urbit.
119−
120−To run this example, put this code in your desk at `gen/faslus.hoon` and run
121−`+faslus` in your dojo. This example is a generator. For more information on
122−generators, see the [generator docs](@/docs/hoon/hoon-tutorial/generators.md).
123−
124−```hoon
125−/+ time-to-id
126−::
127−:- %say
128−|= {{now/@da * *} $~ $~}
129−:- %noun
130−(time-to-id now)
131−```
132−
133−produces: `"c.314d"` (or something similar depending on when you run it)
134−
135−You can import multiple libraries with a single `/+` rune by separating them
136−with commas.
137−
138−Replace the code in `gen/faslus.hoon` with the following:
139−
140−```hoon
141−/+ time-to-id, hep-to-cab
142−::
143−:- %say
144−|= {{now/@da * *} $~ $~}
145−:- %noun
146−=/ id (time-to-id now)
147−=/ str "my-id-is-{id}"
148−(hep-to-cab (crip str))
149−```
150−
151−This should print something like `my_id_is_c.3588`.
152−
153−Another feature of the
154−`/+` and `/-` runes is the ability to specify the ship and case from which to
155−load the library.
156−
157−Example:
158−
159−```
160−/+ time-to-id, hep-to-cab/4/~zod
161−```
162−
163−will load the `hep-to-cab` library from `~zod` at `%clay` revision `4`.
164−
165−### `/-` import from sur/
166−
167−The `/-` rune accepts a filename as an argument. It interprets that filename as
168−a hoon source file within the `sur` directory. The `sur` directory contains
169−shared structures that can be used by other parts of urbit. This is somewhat
170−similar to including a header file in C.
171−
172−Example:
173−
174−```hoon
175−/- talk
176−::
177−*serial:talk
178−```
179−
180−produces: `0v0`
181−
182−`/-` can also take multiple files as arguments, and the ship and case of those
183−arguments can be specified. See the `/+` docs for more details about the syntax
184−for those features.
185−
186−### `/~` twig by hand
187−
188−`/~ <twig>` produces a "horn" that evaluates a twig and places the product in
189−the subject. Arbitrary hoon can be in the twig. A
190−horn is a data
191−structure representing a `%ford` static resource.
192−
193−Example:
194−
195−```hoon
196−/~ [a=0 b=1]
197−[a b]
198−```
199−
200−produces: `[0 1]`
201−
202−In wide-form, `/~` always takes a tuple (which may be a degenerate tuple of one element), and produces it.
203−
204−Example:
205−```hoon
206−/~[%something]
207−```
208−produces: `%something`
209−
210−```hoon
211−/~[%a %b]
212−```
213−produces: `[%a %b]`
214−
215−### `//` include a file by relative path
216−
217−`// <rel-path>` parses `rel-path` as a hoon twig, and then adds the resulting
218−twig to the subject. Note that the result type of this rune is not a horn, but
219−just a hoon twig, so its result can't be used as an argument to other runes
220−that expect a horn. There is no wide-form for this rune.
221−
222−Example:
223−```hoon
224−// %/file-to-include
225−::
226−(frobnicate:file-to-include %.n)
227−
228−:: contents of file-to-include.hoon
229−|%
230−++ frobnicate
231− |= a/? ^+ a
232− !a
233−--
234−```
235−produces: `%.y`
236−
237−_Note: `%` means current directory, which in a hoon file will resolve to the
238−"directory" containing that file. Also, %clay doesn't have first-class
239−directories the way unix filesystems do. Whereas in unix, a directory is a
240−special kind of file, in %clay it's just a path prefix, and there is no file
241−stored at that path._
242−
243−### `/=` wrap a face around an included horn
244−
245−`/=` runs a horn (usually produced by another ford rune), takes the result of
246−that horn, and wraps a face around it.
247−
248−Example:
249−```hoon
250−/= foo /~ [a=0 b=1]
251−::
252−[a.foo b.foo]
253−```
254−produces: `[0 1]`
255−
256−In wide-form, `/=` uses `=` as a delimiter: `/=foo=/~[a=0 b=1]`
257−
258−### `/:` evaluate at path, and `/<mark>/` render mark at current path
259−
260−`/:` takes a path and a horn, and evaluates the horn with the current path set to the supplied path.
261−`/mar/` renders the mark 'mar' at the current path.
262−
263−Example:
264−```hoon
265−/= hoo-source /: /path/to/hoon-file /hoon/
266−::
267−`@t`hoo-source
268−```
269−
270−produces the text of the hoon file at "/path/to/hoon-file/hoon".
271−
272−`/hoon/` renders the current path using the `%hoon` mark, which in this case
273−passes the contents through unchanged. In general, rendering a file with a
274−mark will potentially run the contents through a series of conversion
275−operations. For details on marks, see the
276−[Gall docs](gall).
277−
278−Here's an example that includes a mark conversion:
279−```hoon
280−/= page /: /path/to/html/file /mime/
281−::
282−page
283−
284−:: contents of /path/to/html/file:
285−<html><head><title>My Fascinating Blog</title></head></html>
286−```
287−produces:
288−`[[%text %html ~] 60 '<html><head><title>My Fascinating Blog</title></head></html>']`
289−
290−This result includes the MIME type ('text/html'), the content length in bytes,
291−and the HTML itself.
292−
293−In wide-form, `/:` uses `:` as a delimiter: `/=page=/:/path/to/html/file:/mime/`
294−
295−### `/!mark/` evaluate as hoon, then pass through mark
296−
297−Example:
298−```hoon
299−/= mime /: /%/some-hoon-file /!mime/
300−::
301−mime
302−
303−:: contents of /%/some-hoon-file:
304−%produces-a-cord
305−```
306−produces: `[[%text %plain ~] 15 'produces-a-cord']`
307−
308−### `/&` pass through a series of marks
309−
310−`/&` passes a horn through multiple marks, right-to-left. It has both a
311−wide-form and a tall-form syntax. In wide-form, it takes a series of mark
312−arguments followed by a horn. In tall-form, it takes a single mark followed by
313−a horn.
314−
315−```hoon
316−/= some-text /: /%/text-file /&mime&/txt/
317−::
318−some-text
319−```
320−produces: `[[%text %plain ~] p=17 q='Hi I\'m some text\0a']`
321−
322−This example shows two of the ways marks are used. The first way is what
323−happens with the `/txt/` mark: we use it to find a file in clay with that
324−extension, without performing any conversions. Since this file is stored with
325−the `%txt` mark in `%clay`, its type is a `wain`: a list of cords, where each
326−cord is a single line. Once we've read the file, the `%mime` mark converts the
327−`wain` to a triple that includes the MIME type ("text/plain"), the content
328−length in bytes, and the content itself as a cord.
329−
330−```hoon
331−/= page /&html&elem&/~[;div.foo;]
332−::
333−page
334−```
335−produces: `'<html><head></head><body><div class="foo"></div></body></html>'`
336−
337−This runs the sail expression `;div.foo;` through the `%elem` mark, then
338−through the `%html` mark. The `/~` rune produces an item of mark `noun`. The
339−`%elem` mark converts the mark of the expression from `noun` to `elem` by
340−checking that the type fits in `manx` (a hoon/sail type indicating an XML
341−element). The `%html` mark recognizes the `%elem` and converts it to an HTML
342−string with enclosing `<html>`, `<head>`, and `<body>` tags.
343−
344−It's possible to use wide-form `/&` with more than two marks, by using `&` as a
345−delimiter between marks and adding a `/` before the last mark, like:
346−`/&d&c&b&/a/`. The last argument here can actually be any arbitrary horn, not
347−just a mark: `/&c&b&/:path:/mark/`
348−
349−Tall-form `/&` takes only two arguments: a mark and a horn. The mark does not
350−need to be enclosed in `/`'s: `/& html /elem/`
351−
352−### `/|` short-circuiting 'or'
353−
354−`/|` takes a series of horns and produces the first one (left-to-right) that
355−succeeds. If none succeed, it produces stack traces from all of its arguments.
356−
357−Example:
358−```hoon
359−/= res /: /%/path/to/file
360−/|
361− /!elem/
362− /elem/
363−==
364−::
365−res
366−```
367−tries to parse the file at `/%/path/to/file` as a hoon expression and evaluate
368−it (`/!elem/`), and then if that fails, tries to convert the file to an HTML
369−element directly (`/elem/`). This is used in urbit's `tree` publishing system
370−to enable a user to place either a hoon file or a static file in a directory,
371−and have them both result in webpages, with preference given to treating the
372−file as hoon to be evaluated.
373−
374−Wide-form `/|` encloses its arguments in parentheses, with a single space as a delimiter:
375−`/|(/!elem/ /elem/)`
376−
377−### `/_` unfiltered: run a horn on each file in the current directory
378−
379−`/_` can be used in two ways: filtered and unfiltered.
380−
381−Unfiltered `/_` takes a horn as an argument. It produces a new horn representing the
382−result of mapping the supplied horn over the list of files in the current
383−directory. The keys in the resulting map are the basenames of the files in the
384−directory, and each value is the result of running that horn on the contents of
385−the file.
386−
387−Example:
388−```hoon
389−/= kids /_ /hoon/
390−::
391−`(map term cord)`kids
392−```
393−
394−produces a value of type `(map term cord)`, where each key is the basename (the
395−filename without the prefix), and each value is the result of running the
396−contents of the file through the `%hoon` mark, which validates that it's valid
397−hoon code and returns it unmodified. So, the resulting map associates basenames
398−with file contents.
399−
400−Wide-form unfiltered `/_` doesn't need a delimiter: `/= kids /_/hoon/`
401−
402−### `/_` filtered: run a horn on each file in the directory matching an aura
403−
404−Filtered `/_` takes an aura and a horn, and filters the list of files in the
405−current directory by whether their filenames can be parsed to an atom of that
406−aura. It then produces a map where each key is the filename after parsing into
407−that atom type, and each value is the result of running the horn on the
408−contents of that file.
409−
410−Example:
411−```hoon
412−/= timed-posts /_ @da /md/
413−`(map @da @t)`timed-posts
414−```
415−produces a map from dates to cords. This product will only contain files whose
416−names are parsable into `@da` dates. The values are the file contents converted
417−to a cord of markdown-formatted text.
418−
419−Wide-form filtered `/_` uses `_` as a delimiter: `/= timed-posts /_@da_/md/`
420−
421−### `/;` operate on
422−
423−`/;` takes a twig and a horn. The twig should evaluate to a gate, which is then slammed
424−with the result of the horn as its sample.
425−
426−Example:
427−```hoon
428−/= goo
429− /; |=({a/@ b/@} +(b))
430− /~ [a=0 b=1]
431−::
432−goo
433−```
434−
435−produces: `2`
436−
437−Here's a slightly more complex example with runes that use the filesystem:
438−```hoon
439−/= file-length
440− /; |=(a/@t (lent (crip a)))
441− /: /%/path/to/hoon/file /hoon/
442−::
443−file-length
444−```
445−produces the number of bytes in the file "/%/path/to/hoon/file."
446−
447−### `/,` switch by path
448−
449−`/,` is a switch statement, which picks a branch to evaluate based on
450−whether the current path matches the path in the switch statement.
451−Takes a sequence of pairs of (path, horn) terminated by a `==`. No wide-form.
452−
453−Example:
454−```hoon
455−/= just-right
456− /: /===/right-path :: set path to /%/right-path
457− /,
458− /wrong-path /~ ~
459− /another-wrong-path /~ ~
460− /right-path /~ %evaluate-me :: only evaluate this horn
461− ==
462−::
463−`@t`just-right
464−```
465−
466−produces: `'evaluate-me'`
467−
468−### `/.` list
469−
470−Produce a null-terminated list from a sequence of horns, terminated by a `==`. No wide-form.
471−
472−Example:
473−```hoon
474−/= vanes
475− /.
476− /~ %ames
477− /~ %behn
478− /~ %clay
479− /~ %dill
480− /~ %eyre
481− /~ %ford
482− /~ %gall
483− ==
484−::
485−vanes
486−```
487−produces: `[%ames %behn %clay %dill %eyre %ford %gall ~]`.
488−
489−### `/*` heterogeneous map
490−
491−_DEPRECATED_
492−TODO: remove
493−
494−### `/^` cast
495−
496−`/^` takes a mold and a horn, and casts the result of the horn to the mold.
497−
498−Example:
499−```hoon
500−/= liz /^ (list @) :: cast to real list
501− /~ ~[1 2 3] :: no 'i' or 't' faces
502−::
503−?< ?=($~ liz) :: prevent find-fork
504−i.liz
505−```
506−
507−produces: `1`
508−
509−Without the cast, we wouldn't be able to access the 'i' face of the list.
510−
511−Wide-form `/^` uses `^` as a delimiter: `/^(list @)^/~[1 2 3 ~]`
512−
513−### `/#` insert dephash
514−
515−`/#` takes a horn and produces a cell of the dependency
516−hash of the result of the horn, and the result itself.
517−
518−Example:
519−```hoon
520−/= inline /^ {dep/@uvH txt/@t} /# /: /%/my-script /js/
521−::
522−;= ;script: (trip txt.inline) :: set script contents
523− ;script@"/~/on/{<dep.inline>}.js"; :: set script src
524−==
525−```
526−produces two `<script>` tags. The first has its contents set to the contents
527−of the JavaScript file we loaded from clay. The second is an auto-update
528−script that polls the server to check whether the dependency hash has changed.
529−This pattern is used in urbit's `tree` web publishing system.
530−
531−Wide-form `/#` does not need a delimiter:
532−`/= inline /^ {dep/@uvH txt/@t} /#/:/%/my-script:/js/`
533−
534−### `/$` process extra arguments
535−
536−`/$` will slam a gate on whatever extra arguments have been supplied to this build.
537−At the moment, only HTTP requests forwarded by `%eyre` contain any extra arguments,
538−and using this rune outside of that context will cause an error. Requests from `%eyre`
539−contain an argument representing the query string, which can be parsed using the
540−standard library gate `++fuel:html`.
541−
542−Example:
543−```hoon
544−/= gas /$ fuel:html
545−::
546−:*
547− %who {<(~(get ju aut.ced.gas) 0)>}
548− %where {(spud s.bem.gas)}
549− %case {(scow %ud p.r.bem.gas)}
550−==
551−```
552−produces: [%who '~zod' %where /ford/pages/web %case 60]
553−
554−Wide-form `/$` takes its arguments inside brackets, like `/~`:
555−`/=gas=/$[fuel:html]`
556−
557−### `/%` propagate extra arguments into renderers
558−
559−`/%` will forward extra arguments (usually from `%eyre`) on to any enclosed `/renderer/`'s. Without this,
560−renderers that use `/$` to read the extra arguments will crash.
561−
562−Example:
563−```hoon
564−/= dat /% /tree-json/
565−::
566−dat
567−```
568−produces the results of running `ren/tree-json` on the current path. This renderer needs the query string,
569−which is one of the extra arguments passed in from `%eyre`.
570−
571−Wide-form `/%` has no delimiter: `/%/tree-json/`
arvo/gall.mddeleted−2318
@@ -1,2318 +0,0 @@
1−+++
2−title = "Gall Apps"
3−weight = 6
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/gall/"]
6−+++
7−This is documentation about how to write Gall apps. Some knowledge of Hoon is assumed.
8−
9−> Note: the last major revision of these lessons was in 2016. They need to be
10− rewritten; in some ways they are outdated, and in other ways they were not
11− always accessible enough to beginners. We are planning to rewrite these in the
12− near future. There is still useful information to be found in the meantime.
13−
14−## API Connectors
15−
16−> Note: This lesson depends on some code that needs to be updated before the examples will work correctly. This will be addressed in the near future. We apologize!
17−
18−Most people have lots of data stored in online services, many of
19−which have APIs. API connectors allow the user to access this
20−data from within their Urbit.
21−
22−A security driver allows the user to make authenticated requests
23−to the service's API, but the user still needs to know the API
24−and send and receive JSON. An API connector puts a layer of
25−porcelain over this to allow the user easier control over their
26−data.
27−
28−Each connector should perform two basic functions. First, it
29−should expose a tree of the data in the service that's accessible
30−through `.^` and FUSE. Second, it should expose event streams as
31−actions occur in the service. Let's take a look at how the `%gh`
32−app accomplishes both for Github.
33−
34−After starting `%gh` (`|start %gh`), let's look at the root of
35−the tree that `%gh` exposes:
36−
37−```
38−~your-urbit:dojo> .^(arch %gy /=gh=)
39−[fil=~ dir={[p=~.issues q=~]}]
40−```
41−
42−`%gh` is currently a skeleton -- it contains examples of all the
43−functionality necessary for a connector, but many endpoints
44−aren't implemented. As we can see here, only issues are
45−implemented. We can explore this tree:
46−
47−```
48−~your-urbit:dojo> .^(arch %gy /=gh=/issues)
49−[fil=~ dir={[p=~.by-repo q=~] [p=~.mine q=~]}]
50−```
51−
52−And eventually:
53−
54−```
55−/- gh
56−.^(issue:gh %gx /=gh=/issues/by-repo/philipcmonktest/testing/7)
57−<issue...>
58−login.user:.^(issue:gh %gx /=gh=/issues/by-repo/philipcmonktest/testing/7)
59−'philipcmonktest'
60−```
61−
62−The other thing an API connector needs to do is expose event
63−streams. One straightforward way to use this capacity is with
64−the `:pipe` app:
65−
66−```
67−:pipe|connect %gh /listen/philipcmonktest/testing/issues/'issue_comment' %public
68−```
69−
70−Now creating an issue results in the following message in your
71−`%public` `:talk` channel:
72−
73−```
74−~your-urbit[philipcmonktest@github]: opened issue ##11: i found a bug!
75−```
76−
77−You'll also get notifications of issue status changes and
78−comments.
79−
80−As is often the case, the best way to write an API connector is
81−to copy an existing one and modify it. We'll dissect the Github
82−connector here. This code is in `/=home=/app/gh/hoon`, and it's
83−also reproduced at the bottom of this page (in case the code
84−drifts out of sync with this doc).
85−
86−We'll go over the two parts to an API connector (one-time reading vs listening
87−for events) separately.
88−
89−#### Reading
90−
91−A connector exposes a tree of data. Every read request has a
92−`care`, which is generally either `%x` or `%y. `%x` is a request
93−for a particular piece of data, while `%y` is a request for a
94−directory listing. Roughly, `%x` means Unix `cat` and `%y` means
95−Unix `ls`.
96−
97−> Sometimes you wish to expose a tree where a part of the path can't be enumerated. For example, a `%y` of `/issues/by-repo` "should" produce a list of all Github users, but we don't do that because it's too long. Instead, we just produce our own username (from the `web.plan` file). You can still access repos from other users, you just don't see them in the directory listing.
98−
99−The usual flow for implementing this tree of data makes heavy use
100−of the `connector` library. This library is well documented in
101−the source, so check out `/=home=/lib/connector/hoon`.
102−
103−The `connector` library needs to be initialized with definitions
104−of `move` and `sub-result` (all the types of data that can be
105−returned by a place). This can just be a line at the top of the
106−main core:
107−
108−```hoon
109−=+ connector=(connector move sub-result) :: Set up connector library
110−```
111−
112−Most of the Github-specific logic is in `++places`, which is a
113−list of all the places we can request. A place consists of:
114−
115−```hoon
116−++ place
117− $: guard/mold
118− read-x/$-(path move)
119− read-y/$-(path move)
120− sigh-x/$-(jon/json (unit sub-result))
121− sigh-y/$-(jon/json (unit arch))
122− ==
123−```
124−
125−- `guard`, the type of the paths we should match. For example, to match `/issues/<user>/<repo>` use `{$issues @t @t $~}`.
126−
127−- `read-x`, called when someone tries to read the place with `care` `%x`. Should produce a single move, usually either a `%diff` response if we can immediately answer or a `%hiss` http request if we need to make a request to the api. See the `++read-*` functions in `++helpers` for some common handlers.
128−
129−- `read-y`, same as `read-x` except with care `%y`.
130−
131−- `sigh-x`, called when an http response comes back on this place. You're given the json of the result, and you should produce either a result or null. Null represents an error. If you didn't create an http request in `read-x`, then this should never be called. Use `++sigh-strange` from `++helpers` to unconditionally signal an error.
132−
133−- `sigh-y`, same as `sigh-x` except with care `%y`. Note that a `%y` request must produce an arch, unlike a `%x` request, which may produce data of any mark.
134−
135−Filling out the list of places is a lot of grunt work, but most
136−places are fairly straightforward, and the `++read-*` helper
137−functions are useful. Check out the library source for more
138−information on those.
139−
140−Besides the list of places, we just need to handle the flow of
141−control. `++peek` and `++peer-scry` are the interface we expose
142−to the rest of the system while `++sigh-httr` and `++sigh-tang`
143−are used to handle responses when we make HTTP requests.
144−
145−- `++peek` should usually just produce `~`. If there are cases where we can respond directly to a `.^` request without blocking on anything, we could do it here, but it's generally not worth the hassle since the same logic should be duplicated in `++peer-scry`.
146−
147−- `++peer-scry` is where the actual handling for a read request goes. In general, we just need to call `++read` from the `connector` library with the bone, list of places, care, and path. This will match the path to the appropriate place and run either `++read-x` or `++read-y`, depending on the care.
148−
149−- If `++read-x` or `++read-y` made a successful API request, then the response will come back on `++sigh-httr`. Here, we just need to parse out the wire and call `++sigh` from the `connector` library with the list of places, care, path, and HTTP result. This will match the path to the appropriate place and run either `++sigh-x` or `++sigh-y`, depending on the care.
150−
151−- If `++read-x` or `++read-y` made an API request that failed, then we'll get a stack trace in `++sigh-tang`. Here, we just print it out and move on.
152−
153−That's really all there is to the reading portion of API
154−connectors.
155−
156−One of the most accessible ways to jump into Arvo programming is
157−to just add more places to an existing API connector. It's
158−useful, small in scope, and comes in bite-sized chunks since most
159−places are less than ten lines of code.
160−
161−#### Listening
162−
163−Listening for events is fairly service-specific. In some
164−services, we poll for changes. The Twitter connector has an
165−example of this, but note that it predates the `connector`
166−library and is thus more complicated than it needs to be, and the
167−interface it exposes isn't standard. In Github, we power our
168−event streams with webhooks.
169−
170−For Github, when someone subscribes to
171−`/listen/<user>/<repo>/<events...>`, we want to produce
172−well-typed results when they occur.
173−
174−We only want to create one webhook per event, so in our state we
175−have `hook`, which is a map of event names to the set of bones
176−which are subscribed to that event. We must always keep this
177−up-to-date.
178−
179−Flow of control starts in `++peer-listen`, where we just call
180−`++listen`. In `++listen`, for each event in the list of events,
181−we check to see if we have that hook set up (by checking whether
182−it exists in `hook`). If so, we call `++update-hook` to add the
183−current bone to the set of listeners. Otherwise, we call
184−`++create-hook`, which sends a request to Github to set up the
185−new webhook. We also create an entry in `hook` with the current
186−bone.
187−
188−When we created the webhook, we told Github to send the event to
189−`/~/to/gh/gh-<event>.json?anon&wire=/`. This turns into a poke.
190−Let's parse out this url. The first `gh` is the app name to
191−poke. The next portion, `gh-<event>` is the mark to convert the
192−JSON to. For example, when the "issues" event fires, it'll get
193−converted to mark `gh-issues`. This mark has a conversion
194−routine from `json` to the `issues` type, which is defined in the
195−`gh` structure (`/=home=/sur/gh/hoon`). Once this conversion
196−happens, the `gh` app will get poked with the correctly marked
197−data in `++poke`.
198−
199−In `++poke`, we check `hook` to find the subscribers to the event
200−that was fired, and we update them.
201−
202−That's really all there is to it. Webhook flow isn't well
203−standardized, so even if your chosen service is powered by
204−webhooks, your listening code might look rather different. The
205−point is to expose the correct interface.
206−
207−
208−#### Github API Connector Code
209−
210−In case the code in `/=home=/app/gh/hoon` drifts out of sync with
211−this doc:
212−
213−```
214−:: This is a connector for the Github API v3.
215−::
216−:: You can interact with this in a few different ways:
217−::
218−:: - .^({type} %gx /=gh={/endpoint}) to read data or
219−:: .^(arch %gy /=gh={/endpoint}) to explore the possible
220−:: endpoints.
221−::
222−:: - subscribe to /listen/{owner}/{repo}/{events...} for
223−:: webhook-powered event notifications. For event list, see
224−:: https://developer.github.com/webhooks/.
225−::
226−:: This is written with the standard structure for api
227−:: connectors, as described in lib/connector.hoon.
228−::
229−/? 314
230−/- gh, plan-acct
231−/+ gh-parse, connector
232−::
233−!:
234−=> |%
235− +$ move (pair bone card)
236− +$ card
237− $% [%diff sub-result]
238− [%them wire (unit hiss:eyre)]
239− [%hiss wire [%~ %~] %httr [%hiss hiss:eyre]]
240− ==
241− ::
242− :: Types of results we produce to subscribers.
243− ::
244− +$ sub-result
245− $% [%arch arch]
246− [%gh-issue issue:gh]
247− [%gh-list-issues (list issue:gh)]
248− [%gh-issues issues:gh]
249− [%gh-issue-comment issue-comment:gh]
250− [%json json]
251− [%null %~]
252− ==
253− ::
254− :: Types of webhooks we expect.
255− ::
256− +$ hook-response
257− $% [%gh-issues issues:gh]
258− [%gh-issue-comment issue-comment:gh]
259− ==
260− --
261−=+ connector=(connector move sub-result) :: Set up connector library
262−::
263−|_ $: hid=bowl:gall
264− hook=(map @t [id=@t listeners=(set bone)]) :: map events to listeners
265− ==
266−:: ++ prep _`. :: Clear state when code changes
267−::
268−:: List of endpoints
269−::
270−++ places
271− |= wir=wire
272− ^- (list place:connector)
273− =+ (helpers:connector ost.hid wir "https://api.github.com")
274− => |% :: gh-specific helpers
275− ++ sigh-list-issues-x
276− |= jon=json
277− %+ bind ((ar:jo issue:gh-parse) jon)
278− |= issues=(list issue:gh)
279− gh-list-issues+issues
280− ::
281− ++ sigh-list-issues-y
282− |= jon=json
283− %+ bind ((ar:jo issue:gh-parse) jon)
284− |= issues=(list issue:gh)
285− :- `(shax (jam issues))
286− (malt (turn issues |=(issue:gh [(rsh 3 2 (scot %ui number)) ~])))
287− --
288− :~ ^- place :: /
289− :* guard=,%~
290− read-x=read-null
291− read-y=(read-static %issues ~)
292− sigh-x=sigh-strange
293− sigh-y=sigh-strange
294− ==
295− ^- place :: /issues
296− :* guard=,[%issues %~]
297− read-x=read-null
298− read-y=(read-static %mine %by-repo ~)
299− sigh-x=sigh-strange
300− sigh-y=sigh-strange
301− ==
302− ^- place :: /issues/mine
303− :* guard=,[%issues %mine %~]
304− read-x=(read-get /issues)
305− read-y=(read-get /issues)
306− sigh-x=sigh-list-issues-x
307− sigh-y=sigh-list-issues-y
308− ==
309− ^- place :: /issues/by-repo
310− :* guard=,[%issues %by-repo %~]
311− read-x=read-null
312− ^= read-y
313− |= pax=path
314− =+ /(scot %p our.hid)/home/(scot %da now.hid)/web/plan
315− =+ .^([* acc=(map knot plan-acct)] %cx -)
316− ::
317− ((read-static usr:(~(got by acc) %github) ~) pax)
318− sigh-x=sigh-strange
319− sigh-y=sigh-strange
320− ==
321− ^- place :: /issues/by-repo/<user>
322− :* guard=,[%issues %by-repo @t %~]
323− read-x=read-null
324− read-y=|=(pax=path (get /users/[-.+>.pax]/repos))
325− sigh-x=sigh-strange
326− ^= sigh-y
327− |= jon=json
328− %+ bind ((ar:jo repository:gh-parse) jon)
329− |= repos=(list repository:gh)
330− [~ (malt (turn repos |=(repository:gh [name ~])))]
331− ==
332− ^- place :: /issues/by-repo/<user>/<repo>
333− :* guard=,[%issues %by-repo @t @t %~]
334− read-x=|=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues))
335− read-y=|=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues))
336− sigh-x=sigh-list-issues-x
337− sigh-y=sigh-list-issues-y
338− ==
339− ^- place :: /issues/by-repo/<user>/<repo>
340− :* guard=,[%issues %by-repo @t @t @t %~]
341− ^= read-x
342− |=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues/[-.+>+>.pax]))
343− ::
344− read-y=(read-static ~)
345− ^= sigh-x
346− |= jon=json
347− %+ bind (issue:gh-parse jon)
348− |= issue=issue:gh
349− gh-issue+issue
350− ::
351− sigh-y=sigh-strange
352− ==
353− ==
354−::
355−:: When a peek on a path blocks, ford turns it into a peer on
356−:: /scry/{care}/{path}. You can also just peer to this
357−:: directly.
358−::
359−:: We hand control to ++scry.
360−::
361−++ peer-scry
362− |= pax=path
363− ^- [(list move) _+>.$]
364− ?> ?=([care:clay *] pax)
365− :_ +>.$ :_ ~
366− (read:connector ost.hid (places %read pax) i.pax t.pax)
367−::
368−:: HTTP response. We make sure the response is good, then
369−:: produce the result (as JSON) to whoever sent the request.
370−::
371−++ sigh-httr
372− |= [way=wire res=httr:eyre]
373− ^- [(list move) _+>.$]
374− ?. ?=([%read care:clay @ *] way)
375− ~& res=res
376− [~ +>.$]
377− =* style i.way
378− =* ren i.t.way
379− =* pax t.t.way
380− :_ +>.$ :_ ~
381− :+ ost.hid %diff
382− (sigh:connector (places ren style pax) ren pax res)
383−::
384−:: HTTP error. We just print it out, though maybe we should
385−:: also produce a result so that the request doesn't hang?
386−::
387−++ sigh-tang
388− |= [way=wire tan=tang]
389− ^- [(list move) _+>.$]
390− %- (slog >%gh-sigh-tang< tan)
391− [[ost.hid %diff null+~]~ +>.$]
392−::
393−:: We can't actually give the response to pretty much anything
394−:: without blocking, so we just block unconditionally.
395−::
396−++ peek
397− |= [ren=@tas tyl=path]
398− ^- (unit (unit (pair mark *)))
399− ~ ::``noun=[ren tyl]
400−::
401−::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
402−:: Webhook-powered event streams (/listen) ::
403−::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
404−::
405−:: To listen to a webhook-powered stream of events, subscribe
406−:: to /listen/<user>/<repo>/<events...>
407−::
408−:: We hand control to ++listen.
409−::
410−++ peer-listen
411− |= pax=path
412− ^- [(list move) _+>.$]
413− ?. ?=([@ @ *] pax)
414− ~& [%bad-listen-path pax]
415− [~ +>.$]
416− (listen pax)
417−::
418−:: This core handles event subscription requests by starting or
419−:: updating the webhook flow for each event.
420−::
421−++ listen
422− |= pax=path
423− =| mow=(list move)
424− =< abet:listen
425− |%
426− ++ abet :: Resolve core.
427− ^- [(list move) _+>.$]
428− [(flop mow) +>.$]
429− ::
430− ++ send-hiss :: Send a hiss
431− |= hiz=hiss:eyre
432− ^+ +>
433− =+ wir=`wire`[%x %listen pax]
434− +>.$(mow [[ost.hid %hiss wir `~ %httr [%hiss hiz]] mow])
435− ::
436− :: Create or update a webhook to listen for a set of events.
437− ::
438− ++ listen
439− ^+ .
440− =+ pax=pax :: TMI-proofing
441− ?> ?=([@ @ *] pax)
442− =+ events=t.t.pax
443− |- ^+ +>+.$
444− ?~ events
445− +>+.$
446− ?: (~(has by hook) i.events)
447− $(+>+ (update-hook i.events), events t.events)
448− $(+>+ (create-hook i.events), events t.events)
449− ::
450− :: Set up a webhook.
451− ::
452− ++ create-hook
453− |= event=@t
454− ^+ +>
455− ?> ?=([@ @ *] pax)
456− =+ clean-event=`tape`(turn (trip event) |=(a=@tD ?:(=('_' a) '-' a)))
457− =. hook
458− %+ ~(put by hook) (crip clean-event)
459− =+ %+ fall
460− (~(get by hook) (crip clean-event))
461− *[id=@t listeners=(set bone)]
462− [id (~(put in listeners) ost.hid)]
463− %- send-hiss
464− :* %+ scan
465− =+ [(trip i.pax) (trip i.t.pax)]
466− "https://api.github.com/repos/{-<}/{->}/hooks"
467− auri:de-purl:html
468− %post ~ ~
469− %- as-octs:mimes:html %- crip %- en-json:html %- pairs:enjs:format :~
470− name+s+%web
471− active+b+&
472− events+a+~[s+event] ::(turn `(list ,@t)`t.t.pax |=(a=@t s=a))
473− :- %config
474− %- pairs:enjs:format :~
475− =+ =+ clean-event
476− "http://107.170.195.5:8443/~/to/gh/gh-{-}.json?anon&wire=/"
477− [%url s+(crip -)]
478− [%'content_type' s+%json]
479− ==
480− ==
481− ==
482− ::
483− :: Add current bone to the list of subscribers for this event.
484− ::
485− ++ update-hook
486− |= event=@t
487− ^+ +>
488− =+ hok=(~(got by hook) event)
489− %_ +>.$
490− hook
491− %+ ~(put by hook) event
492− hok(listeners (~(put in listeners.hok) ost.hid))
493− ==
494− --
495−::
496−:: Pokes that aren't caught in more specific arms are handled
497−:: here. These should be only from webhooks firing, so if we
498−:: get any mark that we shouldn't get from a webhook, we reject
499−:: it. Otherwise, we spam out the event to everyone who's
500−:: listening for that event.
501−::
502−++ poke
503− |= response=hook-response
504− ^- [(list move) _+>.$]
505− =+ hook-data=(~(get by hook) (rsh 3 3 -.response))
506− ?~ hook-data
507− ~& [%strange-hook hook response]
508− [~ +>.$]
509− :: ~& response=response
510− :_ +>.$
511− %+ turn ~(tap in listeners.u.hook-data)
512− |= ost=bone
513− [ost %diff response]
514−--
515−```
516−
517−## Generators
518−
519−Up until now we've poked apps directly. This requires the user to
520−specify the mark, and it requires the app to accept the arguments in a
521−way that's convenient for users to input. This is the "plumbing" way to
522−interact with apps. Generators are the "porcelain" layer. This is why
523−when you run a command like `+ls` or `|merge`, there are no marks in
524−sight.
525−
526−At that point, we just used the
527−generators to produce values -- we didn't pipe their results into apps.
528−In the dojo cast, the role of a generator is to take a list of arguments
529−and produce a value, which is often, though not always, piped into an
530−app. Generators are pure, stateless functions, and they cannot send
531−moves.
532−
533−`+ls` and `+cat` are commonly-used generators that produce a directory
534−listing and print out a file, respectively. These are useful in
535−themselves, so we generally don't pipe the results into an app.
536−
537−Another generator is `+hood/merge`. Try running `+hood/merge` with the
538−normal arguments for `|merge`:
539−
540−```
541−> +hood/merge %home our %they
542−[syd=%home her=~zod sud=%they cas=[%da p=~2018.10.4..21.11.49..901c] gem=%auto]
543−
544−> +hood/merge %home our %they, =gem %this
545−[syd=%home her=~zod sud=%they cas=[%da p=~2018.10.4..21.12.11..ee32] gem=%this]
546−```
547−
548−This didn't run any merge, it just constructed the command that, if sent
549−to `:hood`, would run it. Note first that, even though it's not printed,
550−this value has mark `kiln-merge`. Also, the merge strategy `gem=%auto`
551−was added automatically. Optional arguments are straightforward with
552−generators.
553−
554−In general, generators are prepended by either `+` or `|`. The general
555−form is `+generator`, but often generators are created specifically to
556−work with a single app, they're usually placed in a subdirectory of gen
557−and run with `|`. Thus, if `my-generator` generator is made for use with
558−`:my-app`, then `my-generator` is put in
559−`/gen/my-app/my-generator.hoon`, and can be run directly with
560−`+my-app/my-generator <args>`. If you want to pipe the result into
561−`:my-app`, then run `:my-app +my-app/my-generator <args>`. Because this
562−pattern is so common, this can be abbreviated to
563−`:my-app|my-generator <args>`. Because most built-in commands are
564−generators for the `:hood` app, `:hood|generator <args>` can be
565−shortened to `|generator <args>`.
566−
567−Let's write a generator called `:pong` that takes an urbit address, which is of
568−mark `urbit`, and sends that urbit the message `'howdy'`. First--without a
569−generator--let's make `:ping` that does the same, except that
570−it lets the user optionally specify the message as well.
571−
572−We'll need a new mark for our arguments. Let's call it
573−`ping-message`.
574−
575−> For app-specific marks, it's good style to prefix the name of the mark with the name of the app. Since many apps have several such marks, subdirectories in `/mar` are rendered as `-`, so that `ping-message` is written in (/mar/ping/message.hoon).
576−
577−```hoon
578−::
579−:::: /mar/ping/message/hoon
580− ::
581−/? 314
582−|_ [to=@p message=@t]
583−++ grab
584− |%
585− +$ noun [@p @t]
586− --
587−--
588−```
589−
590−The app can easily be modified to use this (`/app/ping.hoon`):
591−
592−```hoon
593−:: Allows one ship to ping another with a string of text
594−::
595−:::: /app/ping/hoon
596− ::
597−/? 314
598−|%
599− +$ move [bone term wire *]
600−--
601−!:
602−|_ [bowl:gall state=%~]
603−::
604−++ poke-ping-message
605− |= [to=@p message=@t]
606− ~& 'sent'
607− ^- [(list move) _+>.$]
608− :- ^- (list move)
609− :~ `move`[ost %poke /sending [to dap] %atom message]
610− ==
611− +>.$
612−::
613−++ poke-atom
614− |= arg=@
615− ~& 'received'
616− ^- [(list move) _+>.$]
617− ::
618− ~& [%receiving (@t arg)]
619− [~ +>.$]
620−::
621−++ coup |=(* `+>)
622−--
623−```
624−
625−Now we can run this with:
626−
627−```
628−~fintud-macrep:dojo> |start %ping
629−>=
630−
631−~fintud-macrep:dojo> :ping &ping-message [~sampel-sipnym 'heyya']
632−>=
633−```
634−
635−And on `~sampel-sipnym`, assuming it's running `:ping` as well,
636−we see `[%receiving 'heyya']`.
637−
638−This is an annoying way to invoke the app, though. The `[]` are
639−mandatory, and optional arguments are hard. Let's make a generator,
640−`+send` to make everything nicer. Since it's specific to
641−`:ping`, let's put it in `/gen/ping/send.hoon`:
642−
643−```hoon
644−:- %say
645−|= [^ [to=@p message=?(%~ [text=@t %~])] %~]
646−[%ping-message to ?~(message 'howdy' text.message)]
647−```
648−
649−A couple of new things here. Firstly, `message=?(%~ [text=@t %~])] %~]`
650−should be read as "the message is either null or a pair of text and
651−null". Generator argument lists are always null-terminated, which makes
652−it convenient to accept lists in tail position (which are particularly
653−annoying without generators). `?(a b)` is the irregular form of
654−`$?(a b)`, which is a union type. Thus, `?(a b)` means the type of
655−anything that's in either `a` or `b`. Thus, in our case,
656−`?(~ [text=@t ~])` is either null or a pair of text and null.
657−
658−This is run as follows:
659−
660−```
661−~fintud-macrep:dojo> :ping|send ~sampel-sipnym
662−>=
663−
664−~fintud-macrep:dojo> :ping|send ~sampel-sipnym 'how do you do'
665−>=
666−```
667−
668−Which causes `~sampel-sipnym` to print `[%receiving 'howdy']` and
669−`[%receiving 'how do you do']`.
670−
671−(Note: `:ping|send ~sampel-sipnym` is short for `:ping +ping/send ~sampel-sipnym`.)
672−
673−**Exercises**:
674−
675−- Create a generator for `:sum` from [State](#state) so that you can run `:sum|add 5` to add numbers to it.
676−
677−- Create a generator for `:click` from [Web Apps](#backend) so that you can run `:click|poke` to poke it.
678−
679−
680−## Writing an HTTP Request
681−
682−There's a variety of arvo services we haven't touched on yet.
683−Let's figure out how to make HTTP requests and set timers.
684−
685−Let's build an uptime-monitoring system. It'll ping a web
686−service periodically and print out an error when the response
687−code isn't 2xx. Save the following as `app/up.hoon`:
688−
689−```hoon
690−:: Up-ness monitor. Accepts atom url, 'on', or 'off'
691−::
692−:::: /hoon/up/app
693− ::
694−/? 314
695−|%
696−+$ move [bone card]
697−+$ card
698− $% [%hiss wire unit-iden=$~ mark=%httr cage=[mark=%purl vase=purl:eyre]]
699− [%wait wire @da]
700− ==
701−+$ action
702− $% [%on $~] :: enable polling('on')
703− [%off $~] :: disable polling('off)
704− [%target p=cord] :: set poll target('http://...')
705− ==
706−--
707−|_ [hid=bowl:gall on=_| in-progress=_| target=@t]
708−++ poke-atom
709− |= url-or-command=@t ^- (quip move _+>)
710− =+ ^- act/action
711− ?: ?=($on url-or-command) [%on ~]
712− ?: ?=($off url-or-command) [%off ~]
713− [%target url-or-command]
714− ?- -.act
715− $target [~ +>.$(target p.act)]
716− $off [~ +>.$(on |)]
717− $on
718− :- ?: |(on in-progress) ~
719− [ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]~
720− +>.$(on &, in-progress &)
721− ==
722−++ sigh-httr
723− |= [wir=wire code=@ud headers=mess:eyre body=(unit octs)]
724− ~& 'arrive here'
725− ^- [(list move) _+>.$]
726− ?: &((gte code 200) (lth code 300))
727− ~& [%all-is-well code]
728− :_ +>.$
729− [ost.hid %wait /timer (add ~s10 now.hid)]~
730− ~& [%we-have-a-problem code]
731− ~& [%headers headers]
732− ~& [%body body]
733− :_ +>.$
734− [ost.hid %wait /timer (add ~s10 now.hid)]~
735−++ wake-timer
736− |= [wir=wire $~] ^- (quip move _+>)
737− ?: on
738− :_ +>.$
739− [ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]~
740− [~ +>.$(in-progress |)]
741−::
742−++ prep ~& target _`. :: computed when the source file changes;
743−-- :: here it prints target then resets our state
744−```
745−
746−There's some fancy stuff going on here. We'll go through it line by
747−line, though.
748−
749−There's two kinds of cards we're sending to arvo. A `%hiss` move tells
750−`%eyre` to make an HTTP request. It expects a `(unit iden)`, which will
751−be null here because we aren't doing any authentication; a mark, in this
752−case the http request mark `&httr`; and some data in the form of a
753−`cage`, which is a `[mark vase]`. This is confusing, so the mold in the
754−code quoted above includes a bunch of otherwise unnecessary faces for
755−the purpose of illustration. Compare: `[%hiss p=(unit user) q=mark
756−r=cage]` from `zuse`.
757−
758−> You can grep zuse.hoon and arvo.hoon for most of these definitions. However, beware the ambiguity surrounding "hiss": there's ++hiss in section 3bI of `zuse` ("Arvo structures"), and there's `%hiss` the move that is sent to %eyre to make our HTTP request happen. Here we're talking about the latter. See `++task:able:eyre` in `zuse`.
759−
760−> Recall that `++unit` means "maybe". Formally, "`(unit a)` is either null or a pair of null and a value in `a`". Also recall that to pull a value out of a unit (`u.unit`), you must first verify that the unit is not null (for example with `?~`). See `++need`.
761−
762−A `purl:eyre` is a parsed url structure, which can be created with `de-purl:html`,
763−which is a function that takes a url as text and parses it into a `(unit
764−purl:eyre)`. Thus, the result is null if and only if the url is malformed.
765−'Purl' is also the mark which will be applied to this result.
766−
767−When you send this request, you can expect a `%sigh` with the
768−response, which we handle later on in `++sigh-httr`.
769−
770−For `%wait`, you just pass a `@da` (absolute date), and arvo will
771−produce a `%wake` when the time comes.
772−
773−> A timer is guaranteed to not be triggered before the given time, but it's currently impossible to guarantee the timer will be triggered at exactly the requested time.
774−
775−Let's take a look at our state:
776−
777−```hoon
778−|_ [hid=bowl:gall on=_| in-progress=_| target=@t]
779−```
780−
781−We have three pieces of app-specific state. `target` is the url
782−we're monitoring. `on` and `in-progress` are booleans
783−representing, respectively, whether or not we're supposed to keep
784−monitoring and whether or not we're in the middle of a request.
785−
786−The type of booleans is usually written as `?`, which is a union
787−of `&` (true) and `|` false. This type defaults to `&` (true). In our
788−case, we want both of these to default to `|` (false). Because
789−of that, we use `_|` as the type. `_value` means "take the type
790−of `value`, but make the default value be `value`". Thus, our
791−type is still a boolean, just like `?`, but the default value is
792−`|` (false).
793−
794−> This is the same `_` used in `_+>.$`, which means "the same type as the value "+>.$". In other words, the same type as our current context and state.
795−
796−Let's take a look at `++poke-atom`. When we're poked with an atom, we
797−first check whether the atom is `'off'`. If so, we set our state
798−variable `on` to false.
799−
800−If not, we check whether the atom is `'on'`. If so, we set `on` and
801−`in-progress` to true. If it was already either on or in progress, then
802−we don't take any other immediate action. If it was both off and not in
803−progress, then we send an HTTP request.
804−
805−If the argument is neither 'off' nor 'on', then we assume it's an
806−actual url, so we save it in `target`.
807−
808−Here's the move that sends the HTTP request:
809−
810−```hoon
811−[ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]
812−```
813−
814−> Remember, we are expected to produce a **list** of moves. Note the `~` after the move in the full example. This is a convenient shortcut for creating a list of a single element. It's part of a small family of such shortcuts. `~[a b c]` is `[a b c ~]`, `[a b c]~` is `[[a b c] ~]` and `\`[a b c]` is `[~ a b c]`. These may be mixed and matched to create various convoluted structures and emojis.
815−
816−The correspondence between this move and `[bone card]` can be hard to
817−visualize on one line. Here it is more pedantically:
818−
819−```hoon
820−:* bone=ost.hid :: the move
821− term=%hiss
822− wire=/request
823− unit-iden=~
824− mark=%httr
825− cage=[%purl (need (de-purl:html target))]
826−==
827−```
828−
829−When the HTTP response comes back, we handle it with
830−`++sigh-httr`, which, along with the wire the request was sent
831−on, takes the status code, the response headers, and the response
832−body.
833−
834−We check whether the status code is between 200 and 300. If so,
835−all is well, and we print a message saying so. We start the
836−timer for ten seconds after the present time.
837−
838−If we got a bad status code, then we print out the entire
839−response and start the timer again.
840−
841−After ten seconds, arvo will give us a `%wake` event, which will
842−be handled in `++wake-timer`. If we're still supposed to keep
843−monitoring, we send the same HTTP request as before. Otherwise,
844−we set `in-progress` to false.
845−
846−Let's try it out:
847−
848−```
849−~fintud-macrep:dojo> |start %up
850−>=
851−~fintud-macrep:dojo> :up &atom 'http://www.google.com'
852−>=
853−[%all-is-well 200]
854−[%all-is-well 200]
855−~fintud-macrep:dojo> :up &atom 'http://example.com'
856−>=
857−[%all-is-well 200]
858−~fintud-macrep:dojo> :up &atom 'http://google.com'
859−>=
860−[%we-have-a-problem 301]
861−[ %headers
862− ~[
863− [p='X-Frame-Options' q='SAMEORIGIN']
864− [p='X-XSS-Protection' q='1; mode=block']
865− [p='Content-Length' q='219']
866− [p='Server' q='gws']
867− [p='Cache-Control' q='public, max-age=2592000']
868− [p='Expires' q='Sun, 10 Jan 2016 23:45:05 GMT']
869− [p='Date' q='Fri, 11 Dec 2015 23:45:05 GMT']
870− [p='Content-Type' q='text/html; charset=UTF-8']
871− [p='Location' q='http://www.google.com/']
872− ]
873−]
874−[ %body
875− [ ~
876− [ p=219
877− q
878− \/'<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">\0a<TITLE>301 Moved</TI\/
879− TLE></HEAD><BODY>\0a<H1>301 Moved</H1>\0aThe document has moved\0a<A HREF="http://www.google.com/">her
880− e</A>.\0d\0a</BODY></HTML>\0d\0a'
881− \/ \/
882− ]
883− ]
884−]
885−~fintud-macrep:dojo> :up &atom 'off'
886−```
887−
888−## Marks
889−
890−We've used predefined marks already, but we haven't yet created
891−our own marks. Let's write a sample mark of our own, then chain
892−it together with some preexisting ones to have fun with type
893−conversions.
894−
895−Let's make a small "cord" mark. "Cord" is a name we use for `@t`
896−text, but there's no predefined mark for it. Let's put the following code in:
897−`/mar/cord.hoon`:
898−
899−```hoon
900−/? 314
901−|_ cod=@t
902−++ grab
903− |%
904− ++ atom |=(arg=@ `@t`(scot %ud arg))
905− --
906−++ grow
907− |%
908− ++ md cod
909− --
910−--
911−```
912−
913−`/? 314` is the required
914−version number, just like in apps. After that everything's in a
915−`|_`, which is a `|%` core, but with input arguments. In our
916−case, the argument is the marked data.
917−
918−There are three possible top-level arms in the `|_` core,
919−`++grab`, `++grow`, and `++grad` (which is used for revision
920−control, covered elsewhere). `++grab` specifies
921−functions to convert from another mark to the current mark.
922−`++grow` specifies how to convert from the current mark to
923−another one.
924−
925−In our case, we only define one arm in `++grab`, namely `++atom`.
926−This allows us to convert any atom to a cord. `++scot` is a
927−standard library function in `hoon.hoon` which pretty-prints
928−atoms of various types. We want to treat the atom as an
929−unsigned decimal number, so we give `%ud` and the given argument
930−to `++scot`. Thus, the form of an arm in `++grab` is
931−`|=(other-mark-type this-mark-value)`.
932−
933−In `++grow`, we just convert to the `md` mark, which is just a
934−`@t` internally, but it has fancy conversion functions to things
935−like html. `++md` isn't a function because the "argument" is
936−already a `@t`, so we can just produce the new value directly.
937−
938−Let's play around a bit with this mark. First, let's take a
939−marked atom and convert it to our new mark.
940−
941−```
942−~fintud-macrep:dojo> &atom 9
943−9
944−
945−~fintud-macrep:dojo> &cord &atom 9
946−'9'
947−
948−~fintud-macrep:dojo> &cord &atom &cord &atom 9
949− '57'
950−```
951−
952−ASCII 9 is 57. There's no requirement, implicit or otherwise,
953−that conversions back and forth between marks be inverses of each
954−other. These are semantic conversions, in that they refer to the
955−same concept. They're not isomorphisms.
956−
957−Let's play around a little more:
958−
959−```
960−~fintud-macrep:dojo> &md &cord &atom 17
961−'17'
962−
963−~fintud-macrep:dojo> &hymn &md &cord &atom 17
964−[ [%html ~]
965− [[%head ~] ~]
966− [[%body ~] [g=[n=%pre a=~] c=~[[g=[n=%$ a=~[[n=%$ v="17"]]] c=~]]] ~]
967− ~
968−]
969−```
970−
971−That was exciting. If you squint at that, it looks an
972−awful lot like html. Our value `17` is still in there, in the
973−body. `urb` is the mark we render most web pages to. It makes
974−sure you have a complete skeleton of a web page. Of course, by
975−the time this gets to the web page, it's plain html. Let's do
976−the final step in the conversion.
977−
978−```
979−~fintud-macrep:dojo> &mime &hymn &md &cord &atom 17
980−[[%text %html ~] p=52 q='<html><head></head><body><pre>17</pre></body></html>']
981−```
982−
983−This is a mime-typed octet stream with type `/text/html`, length
984−121 bytes, and our lowly number `17` rendered to a web page.
985−`cord` was just one step in the chain.
986−
987−Of course, arvo can infer some parts of this chain:
988−
989−```
990−~fintud-macrep:dojo> &cord 17
991−'17'
992−```
993−
994−Likewise, `md` is the only way to get from `cord` to `hymn`, so
995−that can be omitted. If we omit the `hymn`, though, we get:
996−
997−```
998−~fintud-macrep:dojo> &mime &cord 17
999−[[%text %x-markdown ~] p=2 q='17']
1000−```
1001−
1002−Here, we converted straight from `cord` to `md` to `mime`. Arvo
1003−decided that was the most straightforward conversion, but it
1004−gives a different result than passing it through the `hymn`
1005−mark.
1006−
1007−The minimal correct input, then, is `&mime &hymn &cord &atom 17`.
1008−
1009−## Network Messages
1010−
1011−In the following we assume that you have some knowledge of Hoon. If you don't, check out chapters 1 and 2 of the Hoon tutorial and check back when you're ready.
1012−
1013−Let's get our planets to talk to each other. To listen for and receive messages from other planets, we'll need an app. Let's look at a very simple one, `echo.hoon`:
1014−
1015−```hoon
1016−:: Accepts any noun from dojo and prints it out
1017−::
1018−:::: /===/app/echo/hoon
1019− ::
1020−!: :: enables debug printfs
1021−|% :: forms a core with subject as payload
1022−+$ move [bone card] :: defines echo app's arvo move mold
1023−+$ card $% $~ :: defines card (data) mold as null tagged union
1024− == :: end of mold definition; see $%
1025−-- :: end of card arm definition
1026−:: ::
1027−|_ [bow=bowl:gall $~] :: forms a core with bowl (app state) as sample
1028−++ poke-noun :: begin definition of poke-noun arm
1029− |= non=* :: forms a gate which accepts any noun
1030− ^- [(list move) _+>.$] :: casts product to mold of moves and context
1031− ~& echo+noun+non :: debug printf, i.e. '[%echo %noun *]'
1032− [~ +>.$] :: produce a cell of empty list and our state
1033−-- :: end of poke-noun arm definition
1034−```
1035−
1036−Save this as `echo.hoon` in the `/app` directory of your urbit's pier.
1037−
1038−This is a very simple app that does only one thing. If you poke it with
1039−a value, it prints that value out. To try this out, you have to start
1040−the app, then you can poke it from the command line with the following
1041−commands:
1042−
1043−```
1044−~fintud-macrep:dojo> |start %echo
1045−>=
1046−
1047−~fintud-macrep:dojo> :echo 5
1048−[%echo %noun 5]
1049−>=
1050−
1051−~fintud-macrep:dojo> :echo [1 2]
1052−[%echo %noun [1 2]]
1053−>=
1054−```
1055−
1056−> There is currently a bug where the `[%echo %noun *]` lines are printed **above** the line you entered, so your output may not look exactly like this. `>=` means that a command was successfully received and executed.
1057−
1058−Most of the app code should be simple enough to guess its function. The
1059−important part of this code is the definition of `++poke-noun`.
1060−
1061−Once an app starts, it's always running in the background and you interact with
1062−it by sending it messages. The most straightforward way to do that is to poke it
1063−from the command line, which we we did with `:echo 5`
1064−(`:[app-name] [argument(s)]`).
1065−
1066−In this case, `++poke-noun` takes an argument (**sample**) `arg` and
1067−prints it to dojo with `~&` ([sigpam](/docs/hoon/hoon-expressions/rune/sig#sigpam/)).
1068−This is an unusual rune that formally "does nothing", but the interpreter
1069−detects it and printfs the first child, before executing the second as if the
1070−first didn't exist. This is a slightly hacky way of printing to the console,
1071−but we'll get to the correct way later on.
1072−
1073−But what does `++poke-noun` produce? Recall that `^-` casts to a type. In this
1074−case, it's declaring that the end result (**product**) of the function
1075−(`++poke-noun`'s **gate**) will be of type `[(list) _+>.$]`. But what does this
1076−mean?
1077−
1078−The phrase to remember is "a list of moves and our state". Urbit is a message
1079−passing system, so whenever we want to do something that interacts with the rest
1080−of the system, we send a message. Thus, a move is Arvo's equivalent of a
1081−syscall. The first thing that `++poke-noun` produces is a list of messages,
1082−called "moves". In this case, we don't actually want the system to do anything,
1083−so we produce the empty list, `~` (in the `[~ +>.$]` line).
1084−
1085−The second thing `++poke-noun` produces is our state. `+>.$` refers to a
1086−particular address in our subject where our formal app state is stored.
1087−It'll become clear why this is later on, but for now pretend that `+>.$`
1088−is a magic invocation that means "app state".
1089−
1090−Let's look at another example. Say we want to
1091−only accept a number, and then print out the square of that number.
1092−
1093−```hoon
1094−:: Accepts an atom from the dojo and squares it.
1095−::
1096−:::: /===/app/square/hoon
1097− ::
1098−!:
1099−|% :: no moves in :square
1100−+$ move [bone card] :: no cards in :square
1101−+$ card $% $~
1102− ==
1103−--
1104−:: :: stateless
1105−|_ [bow=bowl:gall $~]
1106−++ poke-atom
1107− |= tom=@
1108− ^- [(list move) _+>.$]
1109− ~& square+(mul tom tom)
1110− [~ +>.$]
1111−--
1112−```
1113−
1114−Save this as `square.hoon` in the `/app` directory of your urbit's pier.
1115−
1116−A few things have changed. Firstly, we no longer accept arbitrary nouns because
1117−we can only square atoms (integers, in this case an unsigned one). Thus, our
1118−argument is now `tom=@`. Secondly, it's `++poke-atom` rather than `++poke-noun`.
1119−
1120−### Intro to marks
1121−
1122−Are there other `++poke`s? Yes. In fact, `noun` and `atom` are just two
1123−of arbitrarily many "marks". A mark is fundamentally a type definition,
1124−but accessible at the Arvo level. Each mark is defined in the `/mar`
1125−directory. Some marks have conversion routines to other marks, and some
1126−have diff, patch, and merge algorithms. None of these are required for a
1127−mark to exist, however.
1128−
1129−`noun` and `atom` are two predefined marks. In your `/mar` directory,
1130−there are already many more, and you may add more at will. The type
1131−associated with `noun` is `*`, and the type associated with `atom` is
1132−`@`.
1133−
1134−When we poke an app from anywhere, we do so with a mark that searches
1135−for the corresponding (`++poke-[mark]`) arm. Data constructed on the
1136−command line is by default marked with `noun`. In this case, the app is
1137−expecting an atom, so we have to explicitly mark the data with `atom`
1138−using `&[mark]`. Try the following commands:
1139−
1140−```
1141−~fintud-macrep:dojo> |start %square
1142−>=
1143−
1144−~fintud-macrep:dojo> :square 6
1145−gall: %square: no poke arm for noun
1146−
1147−~fintud-macrep:dojo> :square &atom 6
1148−[%square 36]
1149−>=
1150−```
1151−
1152−> Recall the bug where `%square` may get printed above the input line.
1153−
1154−Marks are powerful, and they're the backbone of Urbit's data pipeline,
1155−so we'll be getting quite used to them.
1156−
1157−**Exercise**:
1158−
1159−- Write an app that computes fizzbuzz on its input.
1160−
1161−#### Sending a message to another urbit
1162−
1163−Let's write our first network message! Here's `examples/app/pong.hoon`:
1164−
1165−```hoon
1166−:: Allows one urbit to send the string 'Pong' to
1167−:: another urbit.
1168−::
1169−:::: /===/app/pong/hoon
1170− ::
1171−!:
1172−|%
1173−+$ move [bone card]
1174−+$ card $% [$poke wire dock poke-contents]
1175− ==
1176−+$ poke-contents $% [$atom @]
1177− ==
1178−--
1179−|_ [bow=bowl:gall $~] :: stateless
1180−::
1181−++ poke-urbit
1182− |= to=ship
1183− ^- [(list move) _+>.$]
1184− ~& pong+'Outgoing pong!'
1185− :_ +>.$
1186− ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong']]
1187−::
1188−++ poke-atom
1189− |= tom=@
1190− ^- [(list move) _+>.$]
1191− ~& pong+'Incoming pong!'
1192− ~& pong+received+`@t`tom
1193− [~ +>.$]
1194−::
1195−++ coup |=(* [~ +>.$])
1196−::
1197−--
1198−```
1199−
1200−
1201−Run it with these commands:
1202−
1203−```
1204−~fintud-macrep:dojo> |start %pong
1205−>=
1206−
1207−~fintud-macrep:dojo> :pong &urbit ~sampel-sipnym
1208−>=
1209−```
1210−
1211−Replace `~sampel-sipnym` with another urbit. The easiest thing to do is to start
1212−a comet, a free and disposable Urbit identity. If you don't know how to start a
1213−comet, see [the user setup section](@/operations.md). Don't forget to start
1214−the `%pong` app on that urbit, too. You should see, on the foreign
1215−urbit, this output:
1216−
1217−```hoon
1218−[%pong 'Incoming pong!']
1219−[%pong %received 'Pong']
1220−```
1221−
1222−Most of the code should be straightforward. In `++poke-atom`, the only new thing
1223−is the expression `` `@t`tom ``, which is **casting** the argument `tom` to type
1224−`@t`. As we already know, `@t` is the type of "cord" (text string).
1225−
1226−The more interesting part is in `++poke-urbit`. The `urbit` mark is an urbit
1227−identity, and the Hoon type associated with it is `ship` or `@p` (the "p"
1228−stands for "phonetic base").
1229−
1230−Recall that in a `++poke` arm we produce "a list of moves and our state". Until
1231−now, we've left the list of moves empty, since we haven't wanted to tell Arvo to
1232−do anything in particular. Now we want to send a message to another urbit. Thus,
1233−we produce a list with one element:
1234−
1235−```hoon
1236−~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong]]
1237−```
1238−
1239−#### Moves
1240−
1241−The general form of a move is `[bone term wire *]`.
1242−
1243−Or, in pseudo-code:
1244−
1245−`["cause" sys-call/action tack-new-layer-on-cause action-specific information]`
1246−
1247−Let's walk through each of these elements step by step.
1248−
1249−###### Bones ("cause")
1250−
1251−If you look up `++bone` in `hoon.hoon`, you'll see that it's a number (`@ud`),
1252−and that it's an opaque reference to a duct. `++duct` in `hoon.hoon` is a list
1253−of `wire`s, where `++wire` is an alias for `++path`. `++path` is a list of
1254−`++knot`s, which are ASCII text. Thus, a duct is a list of paths, and a bone is
1255−an opaque reference to it (in the same way that a Unix file descriptor is an
1256−opaque reference to a file structure). Thus, to truly understand bones, we must
1257−understand ducts.
1258−
1259−A duct is a stack of causes, again, represented as paths, which are called wires.
1260−At the bottom of every duct is a unix event, such as a keystroke, network
1261−packet, file change, or timer event. When Arvo is given this event, it routes
1262−the event to appropriate kernel module for handling.
1263−
1264−Sometimes, the module can immediately handle the event and produce any necessary
1265−results. For example, when we poked the `++poke-atom` arm above, we poked %gall,
1266−our application server, which was able to respond to our poke directly. When the
1267−module cannot service the request itself, it sends instructions to another
1268−kernel module or application (through the %gall module) to do a specified
1269−action, and produces the result from that.
1270−
1271−Furthermore, when one module sends a message to another kernel module or
1272−application, it also sends along the duct it was given with its new wire tacked
1273−onto the top. Now the duct has two entries, with the unix event on the bottom
1274−and the kernel module that handled it on top. This process can continue
1275−indefinitely, pushing more and more wires onto the top of the duct. When an
1276−entity finally produces a result, a wire is popped off the duct, and the result
1277−is passed all the way back down, repeating the process of wire popping
1278−sequentially until the bottom of the duct is reached.
1279−
1280−In effect, a duct is an Arvo-level call stack. It's worth noting that while in
1281−traditional call stacks a function call happens synchronously and returns
1282−exactly once. In Arvo, multiple moves can be sent at once, are evaluated
1283−asynchronously, and each one may be responded to zero or more times.
1284−
1285−The point to take home is that whatever caused `++poke-urbit` to be called is
1286−also the root cause for the network message we're trying to send. Thus, we say
1287−to send the network message along the given bone `ost`.
1288−
1289−##### Wire (path)
1290−
1291−Of course, we have to push a new wire onto our duct before passing it along (or
1292−responding to it directly) anywhere. This wire can have any data we want in it,
1293−but we don't need anything specific here, so we just use the wire `/sending`
1294−(`/elem1/elem2/elemN` is one syntax used to create `++path`s and `++wire`s of N
1295−elements). If we were expecting a response (which we're not), it would come back
1296−along the `/sending` wire, meaning that the path `/sending` will be passed back
1297−to the response handler as an argument. Although it's not required, it's
1298−generally a good idea to make the wire human-readable for bug-handling purposes.
1299−
1300−##### Term (sys-call)
1301−
1302−Each move also has a `term`, composed of lowercase ASCII and/or `-`. This `term`
1303−has the sign `@tas`. In this case, our `term` is `%poke`, which is the name of
1304−the particular kind of move we're sending. You can always use `%poke` to message
1305−an app. Other common names include `%warp`, to read from the filesystem;
1306−`%wait`, to set a timer; and `%them`, to send an http request.
1307−
1308−The move ends with `*` (that is, any noun) since each type of move takes
1309−different data. In our case, a `%poke` move takes a target (urbit and app) and
1310−marked data, then pokes the arm of the corresponding mark on that app on that
1311−urbit with that data. `[to-urbit-address %pong]` is the target urbit and app,
1312−`%atom` is the `mark`, and`'Pong'` is the data.
1313−
1314−When Arvo receives a `%poke` move, it calls the appropriate `++poke`.
1315−The same mechanism is used for sending messages between apps on the same
1316−urbit as for sending messages between apps on different urbits.
1317−
1318−> We said earlier that we're not expecting a response. This is not entirely true: the `++coup` is called when we receive acknowledgment that the `++poke` was called. We don't do anything with this information right now, but we could.
1319−
1320−**Exercises**:
1321−
1322−- Extend either of the apps in the first two exercises to accept input over the network in the same way as `pong`.
1323−
1324−- Modify `pong.hoon` to print out a message when it receives acknowledgement.
1325−
1326−- Write two apps, `even` and `odd`. When you pass an atom to `even`, check whether it's even. If so, divide it by two and recurse; otherwise, poke `odd` with it. When `odd` receives an atom, check whether it's equal to one. If so, terminate, printing "%success". Otherwise, check whether it's odd. If so, multiply it by three, add one, and recurse; otherwise, poke `even` with it. When either app receives a number, print it out along with the name of the app. In the end, you should be able to watch Collatz's conjecture play out between the two apps. Sample output:
1327−
1328−```
1329−~fintud-macrep:dojo> :even &atom 18
1330−[%even 18]
1331−[%odd 9]
1332−[%even 28]
1333−[%even 14]
1334−[%odd 7]
1335−[%even 22]
1336−[%odd 11]
1337−[%even 34]
1338−[%odd 17]
1339−[%even 52]
1340−[%even 26]
1341−[%odd 13]
1342−[%even 40]
1343−[%even 20]
1344−[%even 10]
1345−[%odd 5]
1346−[%even 16]
1347−[%even 8]
1348−[%even 4]
1349−[%even 2]
1350−%success
1351−```
1352−
1353−- Put `even` and `odd` on two separate urbits and pass the messages over the network. Post a link to a working solution in :talk to receive a cookie.
1354−
1355−
1356−## Security Drivers
1357−
1358−A security driver is a file in `/=home=/sec/<tld>/<domain>/hoon`
1359−that handles the authentication for all HTTP requests to
1360−`https://<domain>.<tld>`. When anything in Urbit makes an HTTP
1361−request through `%eyre` (our web server), it checks to see if we
1362−have a security driver for the requested domain, and if so
1363−filters the request through the driver. The security driver will
1364−usually either decorate the request with the needed credentials
1365−if it has them, or else it will guide the user through the
1366−process of authenticating Urbit with the service.
1367−
1368−Each web service needs its own security driver, but most of them
1369−are pretty standard. We recommend starting with an existing
1370−security driver based on your needed authentication method (e.g.
1371−basic auth, OAuth1, OAuth2), and changing whatever is specific to
1372−your service.
1373−
1374−The best strategy for building security drivers is to copy a
1375−similar one and tweak it until it works for you. The best
1376−representatives are Github for Basic Authentication, Twitter for
1377−OAuth1, Slack for OAuth2 when access tokens don't expire, and
1378−Google APIs for OAuth2 when access tokens do expire. In most
1379−cases you'll need to make very few changes to one of these
1380−models.
1381−
1382−Still, it's worth seeing one or two built from the ground up.
1383−Here, we'll build a connector for the Github API v3. (It's already in `/sec/com/github.hoon` if you want to see it.)
1384−
1385−The
1386−simplest way to interact with the Github API is to just fetch
1387−https://api.github.com from the dojo. First, run this:
1388−
1389−```
1390−> |init-auth-basic /com/github
1391−```
1392−
1393−Input your Github username and password as directed. Next:
1394−
1395−```
1396−~your-urbit:dojo> +https://api.github.com
1397−```
1398−
1399−> Note: the current version of this API is outdated, so you'll get a 403 message at this point. We need to update this so you can follow along with the examples. We're sorry!
1400−
1401−Github exposes a few endpoints to the general web, and the root
1402−endpoint is one of them. This gives you a textual representation
1403−of a JSON object that contains a bunch of urls to other parts of
1404−Github's API. This is exactly the same response you would get
1405−from just running `curl https://api.github.com` on UNIX.
1406−
1407−If we don't have a security driver for Github yet, many of the
1408−endpoints won't be accessible, or they will only have publicly
1409−accessible information. Most of what we care about requires us
1410−to be authenticated.
1411−
1412−#### Basic auth
1413−
1414−Here's a simple security driver:
1415−
1416−```hoon
1417−:: Test url +https://api.github.com/user
1418−::
1419−:::: /hoon/github/com/sec
1420− ::
1421−/+ basic-auth
1422−!:
1423−|_ [bal=(bale keys:basic-auth) $~]
1424−++ aut ~(standard basic-auth bal ~)
1425−++ filter-request out-adding-header:aut
1426−--
1427−```
1428−
1429−Github supports authentication through either Basic
1430−Authentication or OAuth2. We'll show the basic auth example
1431−first, but in general we'd prefer OAuth2.
1432−
1433−Since this driver is for Github, put it in
1434−`/=home=/sec/com/github/hoon`.
1435−
1436−To try this out, we first have to initialize our credentials with
1437−`|init-auth-basic`, which prompts for the url of the service
1438−(api.github.com), username, and password. It stores this
1439−information in a manner that `%eyre` knows how to decode and send
1440−put into your `bale`. Note that `|init-auth-basic` is standard for
1441−basic auth, but other auth schemes (like OAuth) are initialized
1442−in other ways.
1443−
1444−After you've run `|init-auth-basic`, you should be able to run
1445−`+https://api.github.com/user` and get a response indicating who
1446−you're logged in as.
1447−
1448−You can similarly POST:
1449−
1450−```
1451−~your-urbit:dojo> +https://api.github.com/gists &json _(cork de-json:html need) '{"files":{"file1.txt":{"content":"can\'t stop the signal"}}}'
1452−```
1453−
1454−This creates a gist, go to `https://gist.github.com/<username>` to
1455−see it.
1456−
1457−The `+url` syntax used in "source" position makes a GET request,
1458−but if you pass it data it will make a POST request with that
1459−data as the body. This request is authenticated seamlessly. You
1460−can send data of any mark as long as it has a conversion path to
1461−`%mime`.
1462−
1463−Let's take a look at the code and see if we can figure out what's
1464−happening here:
1465−
1466−```hoon
1467−/+ basic-auth
1468−```
1469−
1470−First, we load a library called `basic-auth`. This library
1471−exposes two items. `keys` is the type of the basic auth key,
1472−which is essentially a base64'd username and password.
1473−`standard` accepts a `bale` and produces a core with everything
1474−we'll need to implement basic auth.
1475−
1476−Every security driver needs some amount of state, which is stored
1477−in `bale`. `bale` contains:
1478−
1479−- `our`, our urbit name
1480−- `now`, the current time
1481−- `eny`, 256 bits of entropy
1482−- `byk`, the urbit, desk and case which the security driver is running from
1483−- `usr`, the particular identity we're logging in with
1484−- `dom`, the site we're accessing
1485−- `key`, the secrets required to authenticate requests. The type for this entry is supplied by the programmer as the argument to `++bale`. Thus, in our case, `key` in our bale is of type `keys:basic-auth`.
1486−
1487−Additionally, a security driver contains at least one out of the
1488−five "special" arms:
1489−
1490−- `++filter-request` is a function which takes a hiss (http request) and produces a `sec-move` (defined in zuse), which is one of:
1491− - `[%send hiss]`, which sends the new hiss. This is the case in, for example, basic auth, where all we need to do is add an extra header to the request.
1492− - `[%give httr]`, where httr is an http response. This immediately returns an http response to the sender.
1493− - `[%show purl]`, where a purl is a parsed url. This displays a message asking the user to visit the given url to continue the authentication process.
1494− - `[%redo ~]`, which redoes the request.
1495− - `%eyre` calls `++filter-request` just before sending an HTTP request to the specified domain. This allows the security driver to filter the requests, decorating them with authentication data.
1496−- `++filter-response` is a function which takes an httr and produces a `sec-move`. `%eyre` calls it after receiving an HTTP response from the specified domain. This allows the security driver to handle authentication errors, commonly caused by expired tokens, and retry the request.
1497−- `++receive-auth-query-string` is a function that takes a `quay` (list of query parameters) and produces a `sec-move`. `%eyre` calls it when it receives a request on the callback url. Generally, this happens in OAuth after the user has granted access to the urbit app, and the service makes a request to the callback url with the code. The security driver should then make a request to convert the code into an access token.
1498−- `++receive-auth-response` is a function that takes an httr and produces a `sec-move`. `%eyre` calls it when it gets a response to the request made in `++receive-auth-query-string`.
1499−- `++update` is a function which converts old state to a new format when the security driver gets updated. If you want to just get rid of the old state, define `++discard-state` as `~`.
1500−
1501−For basic auth, we only have to worry about `++filter-request`,
1502−since all we need to do is add the correct header to each
1503−request. Our `++aut` core contains a function
1504−`++out-addding-header`, which does exactly what we want.
1505−
1506−Where do the keys come from, though? Remember we ran
1507−`|init-auth-basic` to input them. This just prompts you for the
1508−service url, username, and password, and it stores them next to
1509−the driver. In our case, that's
1510−`/=home=/sec/com/gitub/api/atom`. These keys are stored
1511−encrypted, and you don't want to edit them directly. `%eyre`
1512−loads them directly into your `bale`.
1513−
1514−#### OAuth2
1515−
1516−Most services are better accessed through some form of OAuth.
1517−Github can be accessed with OAuth2, which is a little more
1518−complicated than basic auth, but not hugely so.
1519−
1520−The basic steps for OAuth2 are these:
1521−
1522−- create an app and get its client id and client secret (on Github)
1523−- store these in Urbit (with `|init-oauth2`)
1524−- try to make a request that requires authentication. The security driver should prompt you to visit a particular url.
1525−- visit the url and click "authorize", which gives the app access to your account
1526−- the security driver will turn the code it receives into an access token
1527−- on every request, include that access token
1528−
1529−Creating an app is easy and
1530−[well-documented](https://github.com/settings/applications/new).
1531−If necessary, set the callback url to
1532−`/~/ac/github.com/_state/in`, and note its client id and client
1533−secret.
1534−
1535−Run `|init-oauth2`, which will prompt for the hostname
1536−(api.github.com), client id, and client secret. This will store
1537−the information, encrypted, in `/=home=/sec/com/github.atom`,
1538−just as with Basic Authentication.
1539−
1540−Now we need a security driver. Use this:
1541−
1542−```hoon
1543−:: Test url +https://api.github.com/user
1544−::
1545−:::: /hoon/github/com/sec
1546− ::
1547−/+ oauth2
1548−!:
1549−::::
1550− ::
1551−|_ [bal=(bale keys:oauth2) tok=token:oauth2]
1552−++ scopes :: comment out scopes to taste
1553− :~ 'user' 'user:email' 'user:follow' 'public_repo' 'repo'
1554− 'repo_deployment' 'repo:status' 'delete_repo' 'notifications'
1555− 'gist' 'read:repo_hook' 'write:repo_hook' 'admin:repo_hook'
1556− 'admin:org_hook' 'read:org' 'write:org' 'admin:org'
1557− 'read:public_key' 'write:public_key' 'admin:public_key'
1558− ==
1559−:: ++aut is a "standard oauth2" core, which implements the
1560−:: most common handling of oauth2 semantics. see lib/oauth2 for more details,
1561−:: and examples at the bottom of the file.
1562−++ aut (~(standard oauth2 bal tok) . |=(tok/token:oauth2 +>(tok tok)))
1563−++ filter-request
1564− %^ out-add-query-param:aut 'access_token'
1565− scope=~[%client %admin]
1566− oauth-dialog='https://github.com/login/oauth/authorize'
1567−::
1568−++ receive-auth-query-string
1569− %- in-code-to-token:aut
1570− url='https://github.com/login/oauth/api/access_token'
1571−++ receive-auth-response bak-save-token:aut
1572−--
1573−```
1574−
1575−The oauth2 library provides the main "engine" in `standard`, just
1576−like in basic auth, except that we also have to specify a
1577−function to save the access token when we get it. It's worth
1578−noting that this library is well documented in the source,
1579−including examples: `/=home=/lib/oauth2/hoon`.
1580−
1581−Running `+http://api.github.com/user` tries to make a request to
1582−Github with authentication. This loads into the bale the keys,
1583−which are of type `keys:oauth2`, defined in the oauth2 library.
1584−We don't have to worry about the specifics of these keys -- the
1585−library handles them -- but they include the client id and the
1586−client secret.
1587−
1588−Before the request is sent, `%eyre` calls `++filter-request` to
1589−decorate it with authentication headers. Since we don't yet have
1590−an access token, we need to prompt the user to visit the "dialog"
1591−url. `++out-add-query-param` checks whether we have a token, and
1592−if we don't it produces `%show` and a message telling the user to
1593−visit the `oauth-dialog` url we provide, with the extra query
1594−parameters added (client id, scopes, and state).
1595−
1596−When the user visits that url, Github will ask them to log in and
1597−authorize the application. When they do so, Github will post a
1598−request to `/~/ac/github.com/_state/in` with a code in the query
1599−string. `%eyre` sends the query string to
1600−`++receive-auth-query-string`, which is a function that takes a
1601−quay and produces a `sec-move`. `++in-code-to-token` from our
1602−`aut` takes the `code` parameter from the quay and uses it to
1603−create a request to the given url. This request includes the
1604−client id, the client secret, and the code we just got.
1605−
1606−Github's response to that request includes an access token in its
1607−body. This is handled in `++receive-auth-response`.
1608−`++bak-save-token` extracts that token and gives it to the
1609−function that we passed in the definition of `++aut`. In our
1610−case, we just save that token into our state for later usage.
1611−
1612−Now we have the credentials we need, so `++filter-request` is
1613−called with the original request, and `++out-add-query-param`
1614−passes the request through with the addition of the query
1615−parameter `access_token`.
1616−
1617−Just like with Basic Authentication, you should be able to run
1618−`+https://api.github.com/user` and get a response indicating who
1619−you're logged in as.
1620−
1621−Some drivers a slightly more complicated. For example, Github's
1622−access token's don't expire, but that's not the case for all
1623−service. The googleapis driver shows the flow when the access
1624−token can expire. Twitter uses OAuth1, for which we have another
1625−library.
1626−
1627−Remember, of course, that the best strategy for building security
1628−drivers is to copy a similar one and tweak it to taste.
1629−
1630−## State
1631−
1632−In the last section we built a few small apps that sent moves. These apps were
1633−entirely stateless, however. Most useful apps require some amount of state.
1634−Let's build a trivial stateful app. It'll keep a running the sum of all the
1635−atoms we poke it with. Here's `examples/app/sum.hoon`:
1636−
1637−```hoon
1638−:: Keeps track of the sum of all the atoms it has been
1639−:: poked with and prints the sum out
1640−::
1641−:::: /===/app/sum/hoon
1642− ::
1643−!:
1644−|%
1645−+$ move [bone card]
1646−+$ card $% $~
1647− ==
1648−--
1649−|_ [bow=bowl:gall sum=@]
1650−::
1651−++ poke-atom
1652− |= tom=@
1653− ^- [(list move) _+>.$]
1654− ~& sum+(add sum tom)
1655− [~ +>.$(sum (add sum tom))]
1656−::
1657−++ coup
1658− |= [wir=wire err=(unit tang)]
1659− ^- [(list move) _+>.$]
1660− ?~ err
1661− ~& sum+success+'Poke succeeded!'
1662− [~ +>.$]
1663− ~& sum+error+'Poke failed. Error:'
1664− ~& sum+error+err
1665− [~ +>.$]
1666−::
1667−--
1668−```
1669−
1670−We can start it with `|start %sum`, and then run it:
1671−
1672−```
1673−~fintud-macrep:dojo> :sum &atom 5
1674−[%sum 5]
1675−>=
1676−
1677−~fintud-macrep:dojo> :sum &atom 2
1678−[%sum 7]
1679−>=
1680−
1681−~fintud-macrep:dojo> :sum &atom 15
1682−[%sum 22]
1683−>=
1684−```
1685−
1686−We can see that app state is being saved, but when, where, and how?
1687−
1688−The state is stored as the second thing in the `|_` line. In our case, it's
1689−simply an atom named `sum`. We change it by producing our state not with
1690−`+>.$` (as before), but with `+>.$(sum (add sum tom))`. We've seen all these
1691−parts before, but you might not recognize them.
1692−
1693−Recall in the first chapter that we recursed with the expression
1694−`$(b (add 3 b))`. This meant "produce `$` with `b` changed to `(add 3 b)`.
1695−Similarly, `+>.$(sum (add sum tom))` means "produce `+>.$` (i.e. our
1696−context, which contains our state) with `sum` changed to `(add sum tom)`.
1697−
1698−At a high level, then, when we handle state, we do it explicitly. It's passed in
1699−and produced explicitly. In Unix systems, application state is just a block of
1700−memory, which you need to serialize to disk if you want to keep it around for
1701−very long.
1702−
1703−In Urbit, app state is a single (usually complex) value. In our example, we have
1704−very simple state, so we defined `sum=@`, meaning that our state is an atom.
1705−Of course, `sum` is just a name, and you're free to name your state whatever
1706−you like. But let's clarify a couple other things before we continue.
1707−
1708−First, `bowl` is a set of general global states. This set is managed by the
1709−system. It includes things like `now` (the current time), `our` (our urbit
1710−identity), and `eny` (512 bits of guaranteed-fresh entropy). For the full list
1711−of things in `++bowl`, search for `++ bowl` (note: two spaces) in
1712−`/arvo/zuse.hoon`.
1713−
1714−> This is, perhaps, the most common way to learn Hoon. The easiest way to learn about an identifier you see in code is to search in `/arvo/sys/zuse.hoon` and `/arvo/sys/hoon.hoon` for it.\\ Urbit's codebase is less than 30000 lines of code combined, including the hoon parser, the compiler, and the `/arvo` microkernel, so you can usually use the code and its comments as a reference doc. You can also read [zuse.hoon](https://github.com/urbit/urbit/blob/master/pkg/arvo/sys/zuse.hoon) and [hoon.hoon](https://github.com/urbit/urbit/blob/master/pkg/arvo/sys/hoon.hoon) in your browser.
1715−
1716−The second thing we should clear up is this: Urbit needs no "serialize to disk"
1717−step. Everything you produce in the app state is persistent across calls to the
1718−app, restarts of the urbit, and even power failure. If you want to write to the
1719−Unix filesystem, you can, but it's not needed for persistence. Urbit has
1720−transactional events, which makes it an [ACID operating
1721−system](https://en.wikipedia.org/wiki/ACID). Thus, you don't have to worry about
1722−persistence when programming in Urbit, or ever go through the hassle of having
1723−to set up and write to a database.
1724−
1725−**Exercises**:
1726−
1727−- Modify `:sum` to reset the counter when you poke it with 0.
1728−
1729−- Write an app called `last` that prints out the previous value you poked it with.
1730−
1731−Sample output:
1732−
1733−```
1734−~fintud-macrep:dojo> :last 7
1735−[%last 0]
1736−>=
1737−
1738−~fintud-macrep:dojo> :last [1 2 3]
1739−[%last 7]
1740−>=
1741−
1742−~fintud-macrep:dojo> :last 'howdy'
1743−[%last [1 2 3]]
1744−```
1745−
1746−
1747−## Subscriptions
1748−
1749−We've dealt fairly extensively with "poke" messages to an app, but these
1750−are somewhat limited. A poke is a one-way message, but more often we
1751−want to subscribe to updates from another app. You could build a
1752−subscription model out of one-way pokes, but it's such a common pattern
1753−that it's built into Arvo.
1754−
1755−Let's take a look at two apps, `:source` and `:sink`. First,
1756−`:source`:
1757−
1758−```hoon
1759−:: Sends subscription updates to sink.hoon
1760−::
1761−:::: /===/app/source/hoon
1762− ::
1763−!:
1764−::
1765−|%
1766− +$ move [bone card]
1767− +$ card $% [%diff diff-contents]
1768− ==
1769−+$ diff-contents $% [%noun *]
1770− ==
1771−--
1772−::
1773−|_ [bow=bowl:gall $~]
1774−::
1775−++ poke-noun
1776− |= non=*
1777− ^- [(list move) _+>.$]
1778− :_ +>.$
1779− %+ turn (prey:pubsub:userlib /example-path bow)
1780− |=([o=bone *] [o %diff %noun non])
1781−::
1782−++ peer-example-path
1783− |= pax=path
1784− ^- [(list move) _+>.$]
1785− ~& source+peer-notify+'Someone subscribed to you!'
1786− ~& source+[ship+src.bow path+pax]
1787− [~ +>.$]
1788−::
1789−++ coup
1790− |= [wir=wire err=(unit tang)]
1791− ^- [(list move) _+>.$]
1792− ?~ err
1793− ~& source+success+'Poke succeeded!'
1794− [~ +>.$]
1795− ~& source+error+'Poke failed. Error:'
1796− ~& source+error+err
1797− [~ +>.$]
1798−::
1799−++ reap
1800− |= [wir=wire err=(unit tang)]
1801− ^- [(list move) _+>.$]
1802− ?~ err
1803− ~& source+success+'Peer succeeded!'
1804− [~ +>.$]
1805− ~& source+error+'Peer failed. Error:'
1806− ~& source+error+err
1807− [~ +>.$]
1808−::
1809−--
1810−```
1811−
1812−Save this as `source.hoon` in the `/app` directory of your urbit's pier.
1813−
1814−And secondly, `:sink`:
1815−
1816−```hoon
1817−:: Sets up a simple subscription to source.hoon
1818−::
1819−:::: /===/app/sink/hoon
1820− ::
1821−!:
1822−|%
1823−+$ move [bone card]
1824−+$ card $% [%peer wire dock path]
1825− [%pull wire dock $~]
1826− ==
1827−--
1828−::
1829−|_ [bow=bowl:gall val=?]
1830−::
1831−++ poke-noun
1832− |= non=*
1833− ^- [(list move) _+>.$]
1834− ?: &(=(%on non) val)
1835− :_ +>.$(val |)
1836− :~ :* ost.bow
1837− %peer
1838− /subscribe
1839− [our.bow %source]
1840− /example-path
1841− ==
1842− ==
1843− ?: &(=(%off non) !val)
1844− :_ +>.$(val &)
1845− ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
1846− ~& ?: val
1847− sink+unsubscribed+'You are now unsubscribed!'
1848− sink+subscribed+'You are now subscribed!'
1849− [~ +>.$]
1850−::
1851−++ diff-noun
1852− |= [wir=wire non=*]
1853− ^- [(list move) _+>.$]
1854− ~& sink+received-data+'You got something!'
1855− ~& sink+data+non
1856− [~ +>.$]
1857−::
1858−++ coup
1859− |= [wir=wire err=(unit tang)]
1860− ^- [(list move) _+>.$]
1861− ?~ err
1862− ~& sink+success+'Poke succeeded!'
1863− [~ +>.$]
1864− ~& sink+error+'Poke failed. Error:'
1865− ~& sink+error+err
1866− [~ +>.$]
1867−::
1868−++ reap
1869− |= [wir=wire err=(unit tang)]
1870− ^- [(list move) _+>.$]
1871− ?~ err
1872− ~& sink+success+'Peer succeeded!'
1873− [~ +>.$]
1874− ~& sink+error+'Peer failed. Error:'
1875− ~& sink+error+err
1876− [~ +>.$]
1877−::
1878−--
1879−```
1880−
1881−Save this as `sink.hoon` in the `/app` directory of your urbit's pier (make sure both `source` and `sink` are on the same ship).
1882−
1883−Two notes:
1884−
1885−- `bowl` is the type of the system state within our app. For example, it includes things like `our`, the name of the host urbit, and `now`, the current time.
1886−
1887−- You may have noticed the separate `|%` above the application core `|_`. We usually put our types in another core on top of the application core. We can access these type from our `|_` because in `hoon.hoon` files, all cores are called against each other. (The shorthand for 'called' is `=>`.) Thus, the `|%` with the types is in the context of the `|_`, as it lies above it: `hoon.hoon` `=> |% w types => |_`
1888−
1889−Here's some sample output of the two working together:
1890−
1891−```
1892−~fintud-macrep:dojo> |start %source
1893−>=
1894−
1895−~fintud-macrep:dojo> |start %sink
1896−>=
1897−
1898−~fintud-macrep:dojo> :sink %on
1899−[%source %peer-notify 'Someone subscribed to you!']
1900−[%source [%ship ~fintud-macrep] %path /]
1901−[%sink %success 'Peer succeeded!']
1902−>=
1903−
1904−~fintud-macrep:dojo> :source 5
1905−[%sink %received-data 'You got something!']
1906−[%sink %data 5]
1907−>=
1908−
1909−~fintud-macrep:dojo> :sink %off
1910−>=
1911−
1912−~fintud-macrep:dojo> :source 6
1913−>=
1914−
1915−~fintud-macrep:dojo> :sink %on
1916−[%source %peer-notify 'Someone subscribed to you!']
1917−[%source [%ship ~fintud-macrep] %path /]
1918−[%sink %success 'Peer succeeded!']
1919−>=
1920−
1921−~fintud-macrep:dojo> :source 7
1922−[%sink %received-data 'You got something!']
1923−[%sink %data 7]
1924−>=
1925−```
1926−
1927−###### :source
1928−
1929−Hopefully you can get a sense for what's happening here. When we poke
1930−`:sink` with `%on`, `:sink` subscribes to `:source`,
1931−and so whenever we poke `:source`, `:sink` gets the update and
1932−prints it out. Then we unsubscribe by poking `:sink` with `%off`, and
1933−`:sink` stops getting updates. We then resubscribe.
1934−
1935−There's a fair bit going on in this code. Let's look at `:source`
1936−first.
1937−
1938−Our definition of `move` is fairly specific, since we're only going to
1939−sending one kind of move. The `%diff` move is a subscription update, and
1940−its content is marked data which gall routes to our subscribers.
1941−
1942−This is a slightly different kind of move than we've dealt with so
1943−far. It's producing a result rather than calling other
1944−code (i.e. it's a return rather than a function call), so if you recall
1945−the discussion of ducts, a layer gets popped off the duct rather than
1946−added to it. This is why no wire is needed for the move -- we won't
1947−receive anything in response to it.
1948−
1949−Anyways, there are four functions (arms) inside the `|_`. We already know when
1950−`++poke-noun` is called. `++peer-example-path` is called when someone tries to
1951−subscribe to our app. Of course, you don't just subscribe to an app; you
1952−subscribe to a path on that app. This path comes in as the argument to `++peer`.
1953−
1954−In our case, we don't care what path you subscribed on, and all we do is print
1955−out that you subscribed. Arvo keeps track of your subscriptions, so you don't
1956−have to. You can access your subscribers by looking at `sup` in the bowl that's
1957−passed in. `sup` is of type `(map bone {@p path})`, which associates bones with
1958−the urbit who subscribed, and which path they subscribed on. If you want to
1959−communicate with your subscribers, send them messages along their bone.
1960−
1961−`++poke-noun` "spams" the given argument to all our subscribers.
1962−There's a few things we haven't seen before. Firstly, `:_(a b)` is the
1963−same as `[b a]`. It's just a convenient way of formatting things when
1964−the first thing in a cell is much more complicated than the second.
1965−Thus, we're producing our state unchanged.
1966−
1967−Our list of moves is the result of a call to `++turn`. `++turn` is what many
1968−languages call "map" -- it runs a function on every item in a list and collects
1969−the results in a list. The list is `(prey:pubsub:userlib /example-path bow)` and the function
1970−is the `|=` line right after it.
1971−
1972−`prey:pubsub:userlib` is a standard library function defined in `zuse.hoon`. It takes a path
1973−and a bowl and gives you a list of the subscribers who are subscribed on a path
1974−that begins with the given path. "Prey" is short for "prefix".
1975−
1976−Now we have the list of relevant subscribers. This a list of triples,
1977−`[bone @p path]`, where the only thing we really need is the bone, because we
1978−don't need to know their urbit or what exact path they subscribed on. Thus, our
1979−transformer function takes `[o=bone *]` and produces `[o %diff %noun non]`,
1980−which is a move that provides bone `o` with this subscription update:
1981−`[%noun non]`". This is fairly dense code, but what it's doing is
1982−straightforward!
1983−
1984−###### :sink
1985−
1986−`:source` should now make sense. `:sink` is a little longer, but not much more
1987−complicated.
1988−
1989−In `:sink`, our definition of of `++move` is different. All moves start
1990−with a `bone`, and we conventionally refer to the second half as the "card", so
1991−that we can say a move is an action that sends a card along a bone.
1992−
1993−We have two kinds of cards here: we `%peer` to start a subscription, and we
1994−`%pull` to stop it. Both of these are "forward" moves that may receive a
1995−response, so they need a wire to tack onto the duct before they pass it on. They
1996−also need a target, which is a pair of an urbit and an app name. Additionally,
1997−`%peer` needs a path on that app to subscribe too. `%pull` doesn't need this,
1998−because its semantics are to cancel any subscriptions coming over this duct. If
1999−your bone and wire are the same as when you subscribed, then the cancellation
2000−will happen correctly.
2001−
2002−The only state we need for `:sink` is a boolean to indicate whether
2003−we're already subscribed to `:source`. We use `val=?`, where `?`
2004−is the sign of type boolean (similar to `*`, `@`), which defaults to true (that
2005−is, `0`).
2006−
2007−In `++poke-noun` we check our input to see both if it's `%on` and we're
2008−available (`val` is true). If so, we produce the move to subscribe to
2009−`:source`:
2010−
2011−```hoon
2012−:~ :* ost.bow
2013− %peer
2014− /subscribe
2015− [our.bow %source]
2016− /example-path
2017− ==
2018−==
2019−```
2020−
2021−Also, in the preceding lines, we set `val` to false (`|`) with `+>.$(val |)`.
2022−Remember that the `:_` constructs an inverted cell, with the first child
2023−(`+>.$(val |` in our case) as the tail and the second child as the head. Here,
2024−the cell we produce when our subscription is `%on` and `val` is true has a
2025−head with our new state where `val` is set to false and a tail of our list of
2026−moves, which is shown in the code block above.
2027−
2028−Otherwise, if our input is `%off` and we're already subscribed (i.e. `val`
2029−is false), then we unsubscribe from `:source` and set `val` back to true (`&`),
2030−again using our handy inverted cell constructor mold `:_`:
2031−
2032−```hoon
2033−:_ +>.$(val &)
2034−~[[ost.bow %pull /subscribe [our.bow %source] ~]]
2035−```
2036−
2037−It's important to send over the same bone and wire (`/subscribe`) as the
2038−one we originally subscribed on.
2039−
2040−If neither of these cases are true, then we print our current subscription
2041−state, based on whether `val` is true or false, and return a cell containing
2042−a null list of moves and our unchanged app state:
2043−
2044−```hoon
2045−~& ?: val
2046− sink+unsubscribed+'You are now unsubscribed!'
2047− sink+subscribed+'You are now subscribed!'
2048−[~ +>.$]
2049−```
2050−
2051−`++diff-noun` is called when we get a `%diff` update along a subscription with a
2052−mark of `noun`. `++diff-noun` is given the wire that we originally passed with
2053−the `%peer` subscription request along and the data we got back. In our case we
2054−just print out the data:
2055−
2056−```hoon
2057−~& sink+received-data+'You got something!'
2058−~& sink+data+non
2059−```
2060−
2061−`++reap` is called when we receive an acknowledgment as to whether the
2062−subscription was handled successfully. You can remember that `++reap` is the
2063−counterpart to `++peer` as it's pronounced like 'peer' backwards. Similarly,
2064−`coup` is similar to 'poke' backwards.
2065−
2066−Moving forward, `++reap` is given the wire we attempted to subscribe over,
2067−possibly along with an error message in cases of failure. `(unit type)` means
2068−"either `~` or `[~ type]`, which means it's used like Haskell's "maybe" or C's
2069−nullability. If `err` is `~`, then the subscription was successful and we tell
2070−that to the user. Otherwise, we print out the error message.
2071−
2072−
2073−## Backend
2074−
2075−We've done purely functional web pages as hook files, and we've
2076−done command line apps, so now let's interact with an app over
2077−the web. The fundamental concepts are no different than from the
2078−command line -- you send "poke" messages to apps and subscribe to
2079−data streams. The only difference is that you do it with
2080−javascript.
2081−
2082−Let's create a small web app that counts the number of times you
2083−poke it. There'll be a button to poke the app, and line of text
2084−below it saying how many times the app has been poked. We can
2085−update this by subscribing our page to the relevant path on its app.
2086−
2087−Save the following as `click.hoon` in the `/app` directory of your urbit's pier.
2088−
2089−```hoon
2090−/? 314
2091−!:
2092−|%
2093−++ move [bone %diff %mark *]
2094−--
2095−!:
2096−|_ [hid=bowl:gall clicks=@]
2097−++ poke-click
2098− |= click=%click
2099− ~& [%poked +(clicks)]
2100− :_ +>.$(clicks +(clicks))
2101− %+ turn (prey:pubsub:userlib /the-path hid)
2102− |=([o=bone *] [o %diff %clicks +(clicks)])
2103−++ peer-the-path
2104− |= pax=path
2105− [[[ost.hid %diff %clicks clicks] ~] +>.$]
2106−--
2107−```
2108−
2109−There's nothing really new here, except that we use a couple of
2110−new marks, `click` and `clicks`. When we get poked with a
2111−`click`, we increment the variable `clicks` in our state and tell
2112−all our subscribers the new value. When someone subscribes to us
2113−on the path `/the-path`, we immediately give them the current
2114−number of clicks.
2115−
2116−Let's take a look at the new marks. Save this as `/mar/click.hoon`:
2117−
2118−```hoon
2119−|_ click=%click
2120−++ grab
2121− |%
2122− ++ noun |=(* %click)
2123− ++ json
2124− |= jon=^json
2125− ?> =('click' (need (so:dejs-soft:format jon)))
2126− %click
2127− --
2128−--
2129−```
2130−
2131−The mark `click` has type `%click`, which means the only
2132−valid value is `%click`. We can convert from `noun` by just
2133−producing `%click`.
2134−
2135−We also convert from json by parsing a json string with `so:dejs-soft:format`,
2136−asserting the parsing succeeded with `need`, and asserting the
2137−result was 'click' with `?>`, which asserts that its first child
2138−is true.
2139−
2140−> Note the argument to `++json`is `jon=^json`. Why `^json`? `++json` shadows the type definition, so if we want to refer to the type, we have to prepend a `^`. This extends to multiple levels: `^^^foo` means the fourth most innermost instance of `foo`.
2141−
2142−> `dejs-soft:format` in `zuse` is a useful library for parsing complex json into hoon structures. In this case, the `:` between `dejs-soft` and `format` means 'inside of', because `dejs-soft` is an arm contained within the core `format`. Our case is actually simple enough that the `?>` line could have been `?> =([%s 'click'] jon)`.
2143−
2144−We can test this mark from the command line (don't forget to start your app with `|start %click`)
2145−
2146−```
2147−~fintud-macrep:dojo> &click %click
2148−%click
2149−
2150−~fintud-macrep:dojo> &click &json [%s 'click']
2151−%click
2152−
2153−~fintud-macrep:dojo> &click &json &mime [/text/json (as-octs:mimes:html '"click"')]
2154−%click
2155−
2156−~fintud-macrep:dojo> &click &json &mime [/text/json (as-octs:mimes:html '"clickety"')]
2157−/~fintud-macrep/home/0/mar/click:<[7 5].[8 11]>
2158−ford: casting %json to %click
2159−ford: cast %click
2160−```
2161−
2162−And save the following as `/mar/clicks.hoon`:
2163−
2164−```hoon
2165−|_ clicks=@
2166−++ grab
2167− |%
2168− ++ noun @
2169− --
2170−++ grow
2171− |%
2172− ++ json
2173− (frond:enjs:format %clicks (numb:enjs:format clicks))
2174− --
2175−--
2176−```
2177−
2178−`clicks` is just an atom. We convert to json by creating an
2179−object with a single field "clicks" with our value.
2180−
2181−> Be sure to check out section 3bD, JSON and XML, in zuse.hoon `frond:enjs:format` is just a function that takes a key-value pair and produces a JSON object with one element.
2182−
2183−```
2184−~fintud-macrep:dojo> &json &clicks 6
2185−[%o p={[p='clicks' q=[%n p=~.6]]}]
2186−```
2187−
2188−Now that we know the marks involved, take another look at the app
2189−above. Everything should be pretty straightforward. Let's poke
2190−the app from the command line.
2191−
2192−```
2193−~fintud-macrep:dojo> |start %click
2194−>=
2195−~fintud-macrep:dojo> :click &click %click
2196−[%poked 1]
2197−>=
2198−~fintud-macrep:dojo> :click &click %click
2199−[%poked 2]
2200−>=
2201−```
2202−
2203−**Exercise**:
2204−
2205−- Modify `:sink` from the subscriptions chapter to listen to `:click` and print out the subscription updates on the command line.
2206−
2207−## Frontend
2208−
2209−> Note: the instructions below are outdated and do not work in the current version of Urbit. Feel free to experiment though.
2210−
2211−That's all that's needed for the back end. The front end is just
2212−some "sail" html (Hoon markup for XML) and javascript. Here's `/web/pages/click.hoon`:
2213−
2214−```
2215−;html
2216− ;head
2217− ;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js");
2218− ;script(type "text/javascript", src "/~/at/lib/js/urb.js");
2219− ;title: Clickety!
2220− ==
2221− ;body
2222− ;div##cont
2223− ;input##go(type "button", value "Poke!");
2224− ;div##err(class "disabled");
2225− ;div##clicks;
2226− ==
2227− ;script(type "text/javascript", src "/pages/click/click.js");
2228− ==
2229−==
2230−```
2231−
2232−You should recognize the sail syntax from an earlier chapter.
2233−Aside from jquery, we also include `urb.js`, which is a framework
2234−for interacting with urbit.
2235−
2236−To view the frontend, point your browser at `ship-name.urbit.org/~~/pages/click` if you're on the live network. If you're running a fake galaxy, navigate to whatever port it's running on, which is usually: `https://localhost:80/~~/pages/click`.
2237−
2238−We have a button labeled "Poke!" and a div with id `clicks` where
2239−we'll put the number of clicks. We also include a small
2240−javascript file where the client-side application logic can be
2241−found. It's in `/web/pages/click.js`:
2242−
2243−```js
2244−$(function() {
2245− var clicks, $go, $clicks, $err
2246−
2247− $go = $('##go')
2248− $clicks = $('##clicks')
2249− $err = $('##err')
2250−
2251− $go.on("click",
2252− function() {
2253− window.urb.send(
2254− "click", {mark: "click-click"}
2255− ,function(err,res) {
2256− if(err)
2257− return $err.text("There was an error. Sorry!")
2258− if(res.data !== undefined &&
2259− res.data.ok !== undefined &&
2260− res.data.ok !== true)
2261− $err.text(res.data.res)
2262− else
2263− console.log("poke succeeded");
2264− })
2265− })
2266−
2267− window.urb.appl = "click"
2268− window.urb.bind('/the-path',
2269− function(err,dat) {
2270− clicks = dat.data.clicks
2271− $clicks.text(clicks)
2272− }
2273− )
2274−})
2275−```
2276−
2277−We set up two event handlers. When we click the button, we run
2278−`window.urb.send`, which sends a poke to the app specified as the first argument, in this case our :click app. The arguments
2279−are data, parameters, and the callback. The data is the specific
2280−data we want to send. The parameters are all optional, but here's a list
2281−of the available ones:
2282−
2283−- `ship`: target urbit. Defaults to `window.urb.ship`, which
2284− defaults to the urbit which served the page.
2285−- `appl`: target app. Defaults to `window.urb.appl`, which
2286− defaults to null.
2287−- `mark`: mark of the data. Defaults to `window.urb.send.mark`,
2288− which defaults to "json".
2289−- `wire`: wire of the poke. Defaults to `/`.
2290−
2291−In our case, we specify only that the mark is "click".
2292−
2293−The callback function is called when we receive an
2294−acknowledgment. If there was an error, we put it in the `err`
2295−div that we defined above. Otherwise, we printf to the console a
2296−message saying the poke succeeded. As is common, we gray
2297−out the button when it is clicked. It is only reenabled when positive acknowledgement is received.
2298−
2299−Our second event handler is `window.urb.bind`, which is called immediately when the page is loaded, subscribing the page to the specified data stream on the app set with `urb.appl` (which is, in this case, :click). It also takes three arguments: path, parameters, and callback. The path is the path on the app to subscribe to. The parameters are all optional (indeed, we omit them entirely here), but are similar to those for `send`:
2300−
2301−- `ship`: target urbit. Defaults to `window.urb.ship`, which defaults to the urbit which served the page.
2302−- `appl`: target app. Defaults to `window.urb.appl`, which defaults to null.
2303−- `mark`: mark of expected data. Data of other marks is converted to this mark on the server before coming to the web front end. Defaults to `window.urb.bind.mark`, which defaults to "json".
2304−- `wire`: wire of the subscription. Defaults to the given path.
2305−
2306−The callback function here just updates the data in the `clicks`
2307−div. A truly robust app would intelligently handle errors, of
2308−course.
2309−
2310−Note that the app doesn't have anything web-specific in itself.
2311−As far as it knows, it's just receiving pokes and subscriptions.
2312−The javascript is fairly pure as well, sending and receiving json
2313−everywhere. The marks are the translation layer, and they're the
2314−only things that need to know how the hoon types map to json.
2315−
2316−**Exercise**:
2317−
2318−- Open the app in multiple tabs, click the button, and verify that all the tabs stay in sink. Poke it manually from the command line and verify the tabs are updated as well.
arvo/glossary.mddeleted−850
@@ -1,850 +0,0 @@
1−+++
2−title = "Glossary"
3−weight = 3
4−template = "doc.html"
5−aliases = ["docs/reference/arvo-glossary/"]
6−+++
7−
8−Urbit is renowned for its exotic terminology. Here's a simple overview
9−from the strange words within.
10−
11−As Dijkstra put it: "The purpose of abstraction is not to be vague, but
12−to create a new semantic level in which one can be absolutely precise."
13−
14−This glossary only covers terms the Arvo side of the project. You can find the
15−Azimuth glossary [here](../azimuth/glossary)
16−
17−### application
18−
19−Also known as an “app,” an _application_ is a Hoon program that can hold state.
20−
21−### arm
22−
23−An _arm_ is a named, functionally-computed attribute of a [core](#core).
24−
25−The [hoon](#a-hoon) of each arm is compiled to a Nock formula, with the
26−enclosing [core](#core) itself as the subject.
27−
28−There are two kinds of arms: _dry_ and _wet_. Most arms are
29−dry.
30−
31−#### dry
32−
33− normal, `++`, polymorphic by means of _variance_
34−
35− For a dry arm, we ask: is the new payload compatible with the old
36− payload (against which the core was compiled)?
37−
38−#### wet
39−
40− unusual, `+-`, polymorphic by means of _genericity_
41−
42− A wet arm uses the hoon as a macro. We create a new type analysis
43− path, which works as if we expanded the callee with the caller's
44− context.
45−
46−_See [advanced types](/docs/hoon/hoon-expressions/advanced/)_.
47−
48−
49−
50−### Arvo
51−
52−The Urbit operating system and kernel. Arvo's state is a pure function of its
53−event log, and it serves as the Urbit event manager. It contains vanes, which are
54−kernel modules that perform essential system operations. Arvo itself can only
55−deal with one file at a time. For more, it relies on Ford, the build-system
56−vane.
57−
58−Arvo being purely functional means that the it is a function that is:
59−
60−`(state, event) → (state, effects)`
61−
62−Arvo coordinates and reloads vanes. It can be thought of as a traffic-director.
63−Any vane needs to go through Arvo before reaching another vane. Events and
64−their effects happen like so:
65−
66−`Unix event → vere (the virtual machine that runs Urbit) → Arvo → vane → Arvo`
67−
68−Arvo is located in `/home/sys/arvo.hoon` within your urbit.
69−
70−More in-depth information on Arvo can be found
71−[`here`](@/docs/arvo/_index.md).
72−
73−Below are Arvo modules, which are called "vanes".
74−
75−#### Ames
76−
77− The networking vane. Ames handles all things UDP. Here live the protocols for
78− discovering and interacting with other urbits. It’s also the name for the Urbit
79− network itself. All communication is signed and encrypted.
80−
81− Ames is located in `/home/sys/vane/ames.hoon` within your urbit.
82−
83− More in-depth information on Ames can be found
84− [`here`](@/docs/arvo/ames.md).
85−
86−#### Behn
87−
88− The timing vane. Behn allows for applications to schedule events, which are
89− managed in a simple priority queue. For example, Clay, the Urbit filesystem,
90− uses Behn to keep track of time-specific file requests. Eyre, the Urbit web
91− vane, uses Behn for timing-out HTTP sessions.
92−
93− Behn is located in `/home/sys/vane/behn.hoon` within your urbit.
94−
95−#### Clay
96−
97− The filesystem and typed revision-control vane. Think of Clay as a
98− continuously synced git. It handles file-change events and maps them from Urbit
99− to Unix and vice versa.
100−
101− A common way to use it is to create a pier, a directory that exists in and is
102− visible in Unix.
103−
104− Clay is located at `/home/sys/vane/clay.hoon` within your urbit.
105−
106− Basic information on using Clay can be found
107− [`here`](@/operations.md). An in-depth explanation
108− of the architecture can be found
109− [`here`](@/docs/arvo/clay.md).
110−
111−#### Dill
112−
113− The terminal-driver vane. You run your urbit in your Unix terminal, and
114− Unix sends every event -- such as a keystroke or a change in the dimensions of
115− the terminal window -- to be handled by Dill. Dill acts as an intermediary for
116− anything that uses keyboard events. This is why there’s some input lag in
117− Urbit’s command-line interface. (Optimization will come later!)
118−
119− A keyboard event's journey from Unix to Dojo, the Urbit shell, can be imagined
120− as diagrammed below:
121− ```
122− Keystroke in Unix -> Vere (virtual machine) -> Arvo -> Dill -> the Dojo
123− ```
124−
125− Dill is located at `/home/sys/vane/dill.hoon` within your urbit.
126−
127− More in-depth information on Dill can be found
128− [`here`](@/docs/arvo/dill.md).
129−
130−#### Eyre
131−
132− The web-server vane. Anything HTTP-related lives here. Unix sends HTTP messages
133− though to Eyre, and Eyre produces HTTP messages in response.
134−
135− In general, apps and vanes do not call Eyre; rather, Eyre calls apps and vanes.
136− Eyre uses Ford and Gall to functionally publish pages and facilitate
137− communication with apps.
138−
139− Eyre is located at `/home/sys/vane/eyre.hoon` within your urbit.
140−
141− More in-depth information on Eyre can be found
142− [`here`](@/docs/arvo/eyre.md).
143−
144−#### Ford
145−
146− The build-system vane. Ford is capable of sequencing generic asynchronous
147− computations. Its uses include linking source files into programs, assembling
148− live-updating websites, and performing file-type conversions.
149−
150− Ford neither accepts Unix events nor produces Unix effects. It exists
151− entirely for the benefit of Urbit applications and other vanes, in particular
152− Gall.
153−
154− Ford is located at `/home/sys/vane/ford.hoon` within your urbit.
155−
156− More in-depth information on Ford can be found
157− [`here`](@/docs/arvo/ford.md).
158−
159−#### Gall
160−
161− The application-management vane. Userspace apps -- daemons, really -- are
162− started, stopped, and sandboxed by Gall. Gall provides developers with a
163− consistent interface for hooking their app up to the operating system. It allows
164− applications and other vanes to send messages to applications and subscribe to
165− data streams. Messages coming into Gall are routed to the intended application,
166− and the response comes back along the same route. If the intended target is on
167− another ship, Gall will route it, behind the scenes, through Ames to the other
168− ship.
169−
170− Gall is located at `/home/sys/vane/gall.hoon` within your urbit.
171−
172− More in-depth information on Gall can be found
173− [`here`](@/docs/arvo/gall.md).
174−
175−### atom
176−
177−An atom is any natural number, including zero. The atom is the most basic data
178−type in [Nock](#nock) and [Hoon](#hoon). A Hoon atom type describes a Nock
179−atom with two additional pieces of metadata: an [_aura_](#aura), and an
180−optional constant.
181−
182−An atom type is _warm_ or _cold_ based on whether the constant exists.
183−
184−
185−#### warm
186−
187− If the constant is `~` (null), any atom is in the type.
188−
189−#### cold
190−
191− If the constant is `[~ atom]`, its only legal value is `atom`.
192−
193−_See [basic types](@/docs/hoon/hoon-expressions/basic.md)_
194−
195−### aura
196−
197−An aura is a soft atom type. They appear as strings beginning with `@`. Auras
198−represent the structure of an atom, print format, or other semantics. Its
199−constraints on the value of an atom aren't enforced in any way.
200−
201−You can cast something to an aura, like a decimal, and get back its hexademical.
202−For example:
203−
204−```
205− > =a `@`29
206− > ^- @ux a
207− 0x1d
208−```
209−
210−Auras are an advisory type system. You can go up or down, but not sideways in
211−the hierarchy. `@t` and `@` can each be cast to the other, but @t can’t be cast
212−to `@u`, for example, without first being cast to the empty aura `@`.
213−
214−For example
215−
216−```
217− > ^- @ 'c' :: 'c' is of the aura @t
218− 99
219−
220− > ^- @u 'c'
221− ! exit
222−```
223−
224−Here is a non-exhaustive list of auras:
225−
226−```
227−Aura Meaning Example Literal Syntax
228−-------------------------------------------------------------------------
229−@d date
230− @da absolute date ~2018.5.14..22.31.46..1435
231−@n nil ~
232−@p phonemic string (ship name) ~sorreg-namtyv
233−@r IEEE floating-point
234− @rd double precision (64 bits) .~6.02214085774e23
235− @rh half precision (16 bits) .~~3.14
236−@s signed integer, sign-bit low
237− @sb signed binary --0b11.1000
238− @sd signed decimal --1.000.056
239− @sx signed hexadecimal -0x5f5.e138
240−@t UTF-8 text (cord) 'howdy'
241− @ta ASCII text (knot) ~.howdy
242− @tas ASCII text symbol (term) %howdy
243−@u unsigned integer
244− @ub unsigned binary 0b11.1000
245− @ud unsigned decimal 1.000.056
246− @ux unsigned hexadecimal 0x5f5.e138
247−```
248−
249−You can find the list of all auras [here](@/docs/hoon/hoon-expressions/rune/constants.md).
250−
251−### blocksize
252−
253−Blocksize is the power-of-two bitwidth of an atom. So, an atom with a blocksize
254−of `3` has a bitwidth of `2^3`, which is 8. A bitwidth of 8, in turn, can
255−represent `2^8` values, or 256.
256−
257−### cast
258−
259−To cast is to put a Hoon expression through the compiler’s type-checker to test
260−whether the expression is guaranteed to evaluate to a product that falls within
261−the desired type. If the expression is not guaranteed to behave in this way,
262−then the compiler will halt with a nest-fail crash. Proper Hoon code will
263−include a cast for the product type of each gate.
264−
265−The cast rune is `^-` (pronounced "ket-hep"). So, to cast to a list of atoms,
266−we write `^- (list @)`. The irregular form of that expression is ``(list @)``.
267−
268−### cell
269−
270−In Nock and Hoon, a _cell_ is an ordered pair of [nouns](#noun).
271−
272−Syntax: `[a b]`.
273−
274−Cells orient to the right; for example, the noun [2 6 14 15] is short for
275−[2 [6 [14 15]]].
276−
277−
278−### clam
279−
280−A clam is the use of a structure as a gate. Usually used to verify marks from
281−other urbits.
282−
283−```
284− > ((list @t) [97 98 ~])
285− <|a b|>
286−```
287−
288−### cord
289−
290−In Hoon, `cord` is an aura for representing atoms as strings. UTF-8,
291−least-significant bit first. Represented as the aura `@t`.
292−
293−```
294− > `@t`478.560.413.032
295− 'hello'
296−```
297−
298−### core
299−
300−A _core_ is a [cell](#nock-cell) of `[code data]`, where we call the
301−code head the _battery_ and the data tail the _payload_. All code-data
302−structures in normal languages (functions, objects, modules, etc.)
303−translate to cores in Hoon.
304−
305−#### battery
306−
307− The code-containing head of a core.
308−
309−#### payload
310−
311− The data-containing tail of a core.
312−
313−_See [basic types](@/docs/hoon/hoon-expressions/basic.md)._
314−
315−### Dojo
316−
317−The Dojo is the Urbit shell; the command line where you run programs,
318−expressions, and system commands. It’s a CLI that is encountered right when
319−an urbit is started for the first time. It is somewhat analogous to Bash, the
320−Unix terminal, and more analogous to a Hoon REPL.
321−
322−You’ll notice that many things can’t be written here; this is normal. The Dojo
323−enforces syntactical correctness right at the command line. Strings that can’t
324−be continued into a valid expression are automatically trimmed back to something
325−that can be. Some syntactically invalid expressions can be completed, but the
326−Dojo will prevent them from being entered as a command. You can play around
327−with this functionality learn what syntax is kosher.
328−
329−### desk
330−
331−A desk is independently revision-controlled branch of urbit filesystem.
332−
333−_See [filesystem](@/operations.md#filesystem) and [Clay](@/docs/arvo/clay.md)._
334−
335−### duct
336−
337−A duct is an Arvo-level call stack. At the beginning of every duct is a Unix
338−event, such as a keystroke, network packet, timer event, or file change.
339−
340−A duct is a `list` of `wire`s. A wire is itself a `list` of `knot`s. A `knot`
341−is, in turn, a knot.
342−
343−### face
344−
345−A _face_ is the Hoon analog to what is a variable name in most other
346−programming languages. Faces are metadata labels for legs, allowing us to
347−address parts. Because there is no metadata in Nock, faces cannot exist in Nock.
348−
349−```
350− > a=2
351− a=2
352−```
353−
354−In the above example, `a` is the face and `2` is the value.
355−
356−Hoon has no scope or symbol-table; there is only the subject. To "declare" a
357−"variable" is to construct a new subject: `[name=value old-subject]`.
358−
359−_See [advanced types](@/docs/hoon/hoon-expressions/advanced.md)_.
360−
361−
362−### flag
363−
364−A `flag` is Hoon's version of a boolean. `0` (`%.y`) is _yes_, `1` (`%.n`) is
365−_no_.
366−
367−### gate
368−
369−A _gate_ is a [core](#core) with one [arm](#arm) -- Hoon's closest
370−analog to a function. To call a gate on an argument, replace the sample
371−(at [tree address](@/docs/hoon/hoon-expressions/limb/limb.md) `+6`
372−in the core) with the argument, and then compute the arm.
373−
374−The payload of a gate has a shape of `[sample context]`.
375−
376−#### sample
377−
378− The argument tuple.
379−
380−#### context
381−
382− The subject in which the gate was defined.
383−
384−_See [basic types](@/docs/hoon/hoon-expressions/basic.md),
385−[`%-` ("cenhep")](@/docs/hoon/hoon-expressions/rune/cen.md#cenhep) (the
386−[rune](#rune) for calling a `gate`)._
387−
388−### generator
389−
390−A _generator_ is like a limited Hoon script: it’s a shell command that produces
391−a value before disappearing. Generators take an input [noun](#noun) (a value)
392−and produce an output `noun` by performing calculations on its arguments,
393−prompting for input, or making HTTP requests.
394−
395−You need a `bar` rune like `|=` in your generator, because a generator is
396−essentially a function that you’re calling.
397−
398−Generators, unlike [apps](#application), hold no state. They are pure,
399−stateless functions, and they cannot send [moves](#move). Because of this,
400−generators are have a more narrow use than apps. Among the non-trivial uses of
401−a a generator is moving data into apps -- they’re the backbone of Urbit’s
402−information pipeline.
403−
404−Generators are run from the `/gen` directory of your current desk. For example,
405−to run a generator named `whatever.hoon`, you would type `> +whatever` in the
406−[Dojo](@/operations.md#using-the-shell).
407−
408−### glyph
409−
410−A _glyph_ is a single, non-alphanumeric ASCII character. Each glyph has its own
411−monosyllabic name, which allows the efficient communication of Hoon-related
412−information in speech. [`Runes`](#rune) are composed of two glyphs.
413−Below is a complete list of glyphs with their associated pronunciations.
414−
415−```
416−ace [1 space] gal < pal (
417−bar | gap [>1 space, nl] par )
418−bas \ gar > sel [
419−buc $ hax # mic ;
420−cab _ hep - ser ]
421−cen % kel { sig ~
422−col : ker } soq '
423−com , ket ^ tar *
424−doq " lus + tic `
425−dot . pam & tis =
426−fas / pat @ wut ?
427−zap !
428−```
429−
430−### Hall
431−
432−_Hall_ is the Urbit communication back-end. It’s a messaging bus that can work
433−with clients of all sorts. [`:talk`](#talk), the built-in chat client, is one
434−such app that uses Hall.
435−
436−_More information on Hall can be found [here](@/docs/arvo/hall.md)._
437−
438−#### circle
439−
440− A circle is the “audience” of your messages -- who can receive them. It can be
441− thought of as a chat channel, but this is a little too narrow. More
442− specifically, it’s a named collection of messages created by and hosted on a
443− ship’s Hall, usually represented as `~ship-name/circle-name`. On Talk,
444− Urbit’s built-in chat front-end, the first circle that you will likely
445− encounter is `~dopzod/urbit-help`.
446−
447−### Hood
448−
449−_Hood_ orchestrates many of the Urbit initialization systems necessary
450−for boot.
451−
452−### Hoon
453−
454−Hoon is a strict, higher-order typed functional language that compiles itself
455−to Nock.
456−
457−The Hoon source file is located in `/home/sys/hoon.hoon` within your urbit.
458−
459−_More information can be found in the [hoon](@/docs/hoon/_index.md) section._
460−
461−#### Mint
462−
463− _Mint_ is the Hoon compiler function. Mint takes the subject type and the
464− expression source (a [hoon](#a-hoon), for example) and produces the product
465− type and nock formula. So [type hoon] is mapped to [type nock].
466−
467−### hoon
468−
469−A _hoon_ (lowercase) is the result of parsing a Hoon source expression into an
470−AST node. These AST nodes are nouns, like all other Hoon data. Because every
471−Hoon program is, in its entirety, a single expression of Hoon, the result of
472−parsing the whole thing into an AST is a single `hoon`.
473−
474−A hoon is a tagged union of the form `[%tag data]`, where the tag
475−is a constant such as `%brts` (from the source [rune](#rune) `|=`,
476−i.e. "bartis"), and is matched up with the appropriate type of data
477−(often more `hoon`s, from source subexpressions). For example, the
478−expression `:-(2 17)`, once parsed into an AST, becomes the following:
479−
480−```
481−[%clhp p=[%sand p=%ud q=2] q=[%sand p=%ud q=17]]
482−```
483−
484−The `%clhp` is produced from the rune `:-` (i.e. "colhep"). The 2 and
485−17 have each been parsed as `%sand`-tagged hoons, which represent
486−atoms (in this case each with an aura of `%ud`, i.e. unsigned
487−decimal).
488−
489−To parse Hoon source into a hoon AST, use `ream` on a `cord`
490−containing Hoon source. Try the following in [Dojo](@/operations.md#using-the-shell):
491−
492−```
493−(ream ':+(12 7 %a)')
494−```
495−
496−The result should be:
497−
498−```
499−[%clls p=[%sand p=%ud q=12] q=[%sand p=%ud q=7] r=[%rock p=%tas q=97]]
500−```
501−
502−See [expression reference](@/docs/hoon/hoon-expressions/rune/_index.md) for the full list of hoons.
503−
504−### irregular form
505−
506−Irregular forms are alternative ways of writing Hoon expressions, alternatives
507−to the digraphic runes such as `:~`. Irregular forms are usually more compact
508−than regular forms.=
509−
510−_See [irregular forms](@/docs/hoon/hoon-expressions/irregular.md)._
511−
512−### jet
513−
514−A _jet_ is a piece of C code that have equivalent products to a piece of Hoon or
515−Nock code. They are used for performance reasons; jets are meant to be faster
516−than the code that they are substituting for.
517−
518−Jets are necessary for mathematics, performance-wise, because Nock handles it
519−so inefficiently. Nock, for example, can’t decrement (reduce a number by one)
520−except by starting building a loop that starts from zero and increments to a
521−number just below.
522−
523−_See [API overview](@/docs/vere/api.md)._
524−
525−### lark
526−
527−A lark is an expression that returns a [limb](#limb) at the specified
528−address in a cell. Using `-` by itself returns the head of the subject, and
529−using `+` by itself returns the tail:
530−
531−```
532−> -:[[4 5] [6 [14 15]]]
533−[4 5]
534−
535−> +:[[4 5] [6 [14 15]]]
536−[6 14 15]
537−```
538−
539−You can combine `+` or `-` with either of `>` or `<` to get a more specific limb
540−of the subject. `-<` returns the head of the head; `->` returns the tail of the
541−head; `+<` returns the head of the tail; and `+>` returns the tail of the tail.
542−By alternating the `+`/`-` symbols with `<`/`>` symbols, you can go as deep as
543−you desire.
544−
545−```
546−> +>-:[[4 5] [6 [14 15]]]
547−14
548−
549−> +>+:[[4 5] [6 [14 15]]]
550−15
551−```
552−
553−### limb
554−
555−A _limb_ is an attribute or variable reference. A limb is an [arm](#arm) or a
556−[leg](#leg).
557−
558−To resolve a _limb_ named "foo", the subject is searched depth-first,
559−head-first for either a face named "foo" or a core with an arm of
560−"foo". If a face is found, the result is a leg, if a core is
561−found, the result is the product of the arm.
562−
563−#### leg
564−
565− a subexpression, or subtree of the
566− [subject](#nock-subject).
567−
568−#### wing
569−
570− a search path into the subject, composed of
571− limbs. Search occurs from right to left (`a.b` means `b` within `a`).
572−
573−_See [Limbs and wings](@/docs/hoon/hoon-expressions/limb/_index.md)_
574−
575−### move
576−
577−A move is the [Arvo](#arvo) equivalent of a syscall.
578−
579−### noun
580−
581−In [Nock](#nock) and [Hoon](#hoon), a _noun_ is an atom or a cell.
582−
583−### Nock
584−
585−Nock is a Turing-complete, non-lambda combinator interpreter. It's
586−Urbit's low-level programming language. Nock is functional and typeless.
587−
588−#### noun
589−
590− an _atom_ or a _cell_.
591−
592−#### atom
593−
594− any natural number, including zero.
595−
596−#### cell
597−
598− any ordered pair of nouns.
599−
600−
601−#### subject
602−
603− a noun - the data against which a _formula_ is evaluated.
604−
605−#### formula
606−
607− a noun - a function at the nock level.
608−
609−#### product
610−
611− a noun - the result of evaluating a formula against a subject.
612−
613−_See the [Nock definition](@/docs/nock/definition.md)._
614−
615−### mark
616−
617−A _mark_ is Urbit's version of a MIME type, if a MIME type was an
618−executable specification. The mark is just a label that's used as a path
619−to a local source file in the Arvo filesystem. This source file defines
620−a core that can mold untrusted data, diff and patch, convert to other
621−marks, etc.
622−
623−If this sounds like magic, it isn't quite magic. There's no way
624−for different urbits to make sure they mean the same thing by the
625−same mark. However, when incompatibility happens, marks ensure
626−that we at least handle the situation in a predictable way.
627−
628−#### metal
629−
630−Every core has a _metal_ which defines its variance model (ie, the
631−properties of the type of a compatible core). The default is `gold`
632−(invariant).
633−
634−- `gold`: _invariant_
635−- `lead`: _bivariant_
636−- `zinc`: _covariant_
637−- `iron`: _contravariant_
638−
639−_See [advanced types](@/docs/hoon/hoon-expressions/advanced.md)_.
640−
641−### ship
642−
643−An Urbit _ship_ is: a cryptographic title on a _will_ signed by private key; a
644−human-memorable name; and a packet-routing address. Ships are classed by the
645−number of bits in their address:
646−
647−```
648− Size Name Parent Object Example
649− ----- ------ ------ ------ -------
650− 2^8 galaxy ~ supernode ~zod
651− 2^16 star galaxy supernode ~dozbud
652− 2^32 planet star user ~tasfyn-partyv
653− 2^64 moon planet device ~sigsam-nimbot-tasfyn-partyv
654− 2^128 comet ~ bot ~racmus-mollen-fallyt-linpex--watres-sibbur-modlux-rinmex
655−```
656−
657−Any ship can be called an _urbit_. The lowercase "u" distinguishes it from Urbit
658−the software stack and Urbit the network.
659−
660−_You can find a longer-form summary [here.](https://urbit.org/posts/essays/the-urbit-address-space/)._
661−
662−An Urbit identity is a string like `~firbyr-napbes`. It means nothing,
663−but it's easy to remember and say out loud. `~firbyr-napbes` is actually
664−just a 32-bit number (`3.237.967.392`, to be exact), like an IP address,
665−that we turn into a human-memorable string. The full name of this string
666−can be viewed by typing `our` in the Dojo, Urbit's shell. This is useful
667−when running a ship with a longer name, such as a _moon_ or a _comet_.
668−
669−Technically, an urbit is a secure digital identity that you own and
670−control with a cryptographic key, like a Bitcoin wallet. As in Bitcoin,
671−the supply of urbits is mathematically limited. This keeps the network
672−friendly, by making spam and abuse expensive.
673−
674−An urbit name is just a number; smaller numbers make shorter names.
675−Shorter names are easier to remember, so they're more valuable. So
676−urbits are classified by the number of bits in their name. (A ship name
677−is just a scrambled base-256 representation of the number.)
678−
679−A 32-bit urbit (like `~firbyr-napbes`) is called a _planet._ A 16-bit
680−urbit (like `~pollev)` is a _star._ An 8-bit ship (like `~mun`) is a
681−_galaxy._ A planet is an identity for an independent, adult human. Stars
682−and galaxies are network infrastructure.
683−
684−Each planet or star is launched by its _parent,_ the star or galaxy
685−whose number is its bottom half. So the planet `~firbyr-napbes`,
686−`0xdead.beef` or `3.735.928.559`, is the child of `~pollev`, `0xbeef` or
687−`48.879`, whose parent is `~mun`, `0xef`, `239`. The galaxy at the address of
688−`0` is `~zod`.
689−
690−#### pier
691−
692− A ship's _pier_ is its Unix directory. For planets, the name of the pier is
693− usually the planet name.
694−
695−### structure
696−
697−A _structure_ is an idempotent [gate](#gate) (function) that constructs and
698−validates types in Hoon.
699−
700−An example: Arvo [marks](#mark) use Hoon's type system via structures to
701−validate untrusted network data.
702−
703−Here's some common structure terminology:
704−
705−#### bunt
706−
707− A bunt is the default value of a [structure](#structure). It's also a verb;
708− to _bunt_ a structure is to produce the bunt of that structure. For example,
709− bunting `@` results in `0`, and bunting `@t` results in `''`. Bunting is
710− performed with `*` followed by the structure in question:
711−
712− ```
713− > *@
714− 0
715− > *@t
716− ''
717− ```
718−
719−#### icon: The type of the mold's range
720−
721−_See [mold hoons](/docs/hoon/hoon-expressions/rune/buc/)._
722−
723−### rune
724−
725−A Hoon _rune_ is a pair of ASCII symbols used to begin a
726−[Hoon expression](#a-hoon).
727−
728−For example, the rune [`?:`](@/docs/hoon/hoon-expressions/rune/wut.md#wutcol) is
729−Hoon's most common conditional, a branch on a boolean test. The first
730−symbol in a rune represents a family of related runes. For example, the
731−[`?` family](@/docs/hoon/hoon-expressions/rune/wut.md) are all conditionals.
732−
733−The result of parsing a Hoon source expression&mdash;the rune, followed
734−by its respective children&mdash;into an AST node is simply called
735−a [`hoon`](#a-hoon).
736−
737−Runes have two syntactic forms, _tall_ and _flat_:
738−
739−#### tall
740−
741− multiple lines, no parentheses, two or more spaces between tokens
742−
743− Example:
744−
745− ```
746− > %+ add 2 2
747− 4
748− ```
749−
750−#### flat
751−
752− one line, parentheses, one space between tokens
753−
754− Example:
755− ```
756− > %+(add 2 2) :: regular flat form
757− 4
758−
759− > (add 2 2) :: irregular flat form
760− 4
761− ```
762−
763−Tall hoons can contain flat hoons, but not vice versa. All irregular
764−forms are flat.
765−
766−_See [hoon concept](#a-hoon),
767−[expressions](@/docs/hoon/hoon-expressions/rune/_index.md).
768−
769−### Sail
770−
771−_Sail_ is the Hoon markup language for XML.
772−
773−### scry
774−
775−To _scry_ means to request data from the Arvo namespace and bring it
776−to userspace.
777−
778−_See [.^ (dot-ket)](@/docs/hoon/hoon-expressions/rune/dot.md#dotket)._
779−
780−### slot
781−
782−`slot` is the name for Hoon's tree-addressing scheme.
783−
784−Every cell has a head and a tail, each of which may be either an atom or
785−a cell. Therefore every noun is a binary tree. `+1` or `.` resolves to
786−the whole cell (technically this would work against an atom as well).
787−The head of `+n` is `+2n`, the tail is `+(2n+1)`.
788−
789−`+7` is a special address for gates, because the position is defined
790−(by convention) as the context of a gate and of all cores.
791−
792−### talk
793−
794−_Talk_ is Urbit's built-in chat app. It’s one example of an app that can be
795−built on top of Hall, the Urbit back-end messaging system.
796−
797−_See [Messaging](@/operations.md#messaging). for more information._
798−
799−### type
800−
801−A Hoon _type_ defines a set (finite or infinite) of nouns and ascribes
802−some semantics to it. There is no direct syntax for defining
803−types; they are always defined by inference (i.e., by
804−[`mint`](#mint)), usually using a constructor ([structure](#structure)).
805−
806−All types are assembled out of base types defined in `++type`.
807−(Look up `++ type` in hoon.hoon for examples.) When the compiler
808−does type-inference on a program, it assembles complex types out
809−of the simpler built-in types.
810−
811−#### nest
812−
813− `nest` is an internal Hoon function on two types which performs a type
814− compatibility test. `nest` produces yes if the
815− set of nouns in the second type is provably a subset of the first.
816− If `nest` produces no, the Hoon programmer will receive a `nest-fail`
817− error. This is one of the most commons errors in Hoon programming.
818−
819− _See [advanced types](@/docs/hoon/hoon-expressions/advanced.md)_ and [troubleshooting](@/docs/arvo/ship-troubleshooting.md).
820−
821−
822−### Unit
823−
824−Hoon's equivalent of a nullable pointer or a Haskell Maybe. If `q` is `~`,
825−null, the type is _warm_; any atom is in the type. If `q` is `[~ x]`, where
826−`x` is any atom, the type is _cold_; its only legal value is the constant `x`.
827−
828−### Vane
829−
830−A _vane_ is an [Arvo](#arvo) module. Each Vane is a single file because Arvo
831−cannot, on its own, deal with programs that are split between multiple files.
832−Some vanes can do this, however.
833−
834−### Vere (pronounced “vair”)
835−
836−The runtime system, written in C, that implements [Nock](#nock). All
837−It’s written in C. Vere-level errors are prepended with as `bail:`.
838−
839−Vere is a virtual machine: it pretends to be hardware, and is the single point
840−of contact between your Urbit and the rest of your system. But more than that,
841−Vere handles the Urbit event log and handles jets. It’s also contains the i/o
842−drivers for Urbit’s vanes, responsible for generating events from Unix and
843−applying effects to Unix.
844−
845−### Zuse
846−
847−_Zuse_ is a defined interface for vanes. It contains the part of the Hoon
848−standard library that is specific to Arvo functionality.
849−
850−Arvo is located in `/home/sys/zuse.hoon` within your urbit.
arvo/hall.mddeleted−1335
@@ -1,1335 +0,0 @@
1−+++
2−title = "Hall"
3−weight = 7
4−template = "doc.html"
5−aliases = ["docs/learn/arvo/hall/"]
6−+++
7−> Last major revision of this tutorial: 2017. Some of the information and Hoon syntax here may
8− be outdated.
9−
10−
11−Hall is the Urbit messaging and notifications protocol. This document details Hall's architecture, its interfaces, and the new Gall model it's built to target.
12−
13−## Table of contents
14−
15−- [Hall Architecture](#hall-architecture)
16−
17−- [The Hall Interface](#the-hall-interface)
18−
19−- [The New Gall Model](#the-new-gall-model)
20−
21−# Hall Architecture
22−
23−This document is complemented by Hall's source code, but doesn't require it. Definitions of data structures, code snippets and diagrams will be provided where useful.
24−
25−Hall's implementation is structured according to the new Gall model. Familiarity with its concepts is assumed. See [the new Gall model](#the-new-gall-model).
26−
27−## Talk
28−
29−Talk was Urbit's first big user-facing application. It continues to enjoy a prominent role in the Urbit landscape, but now does so as two separate applications.
30−
31−The messaging parts of Talk have been separated from its user-interface parts. What we ended up with is a shiny new generic messaging bus, and the chat interface we all know and love. The messaging bus, which should now prove useful to many different applications, will be named `Hall`. Applications that use it are referred to as **clients**. One such application, as you might have guessed, is `:talk`.
32−
33−
34−## Structures & functionality
35−
36−### Circles
37−
38−```hoon
39−++ circle {hos/ship nom/term} :: native target
40−```
41−
42−A `circle` is essentially a named collection of messages created by and hosted on a ship's Hall, usually represented as `~ship-name/circle-name`. Most of Hall revolves around doing things with circles.
43−
44−### Messages
45−
46−When we subscribe to a circle, the primary thing we're interested in is its messages. Message data itself isn't that complicated, but a fair amount of metadata comes into play when actually sending a message. Let's work our way up, starting at the contents.
47−
48−```hoon
49−++ speech :> content body
50− $% {$lin pat/? msg/cord} :< no/@ text line
51− {$url url/purf:eyre} :< parsed url
52− {$exp exp/cord res/(list tank)} :< hoon line
53− {$ire top/serial sep/speech} :< in reply to
54− {$fat tac/attache sep/speech} :< attachment
55− {$app app/term sep/speech} :< app message
56− {$inv inv/? cir/circle} :< inv/ban for circle
57− == ::
58−```
59−
60−At the heart of every message lies a `speech` that describes the message body. There's a large number of different speech types, from simple text messages to parsed URLs, Hoon expressions and more.
61−
62−```hoon
63−++ audience (set circle) :< destinations
64−++ serial @uvH :< unique identifier
65−++ thought :> inner message
66− $: uid/serial :< unique identifier
67− aud/audience :< destinations
68− wen/@da :< timestamp
69− sep/speech :< content
70− == ::
71−```
72−
73−A `speech` is always accompanied by various bits of metadata. We include a unique identifier, a message timestamp and an `audience`, the set of all intended recipients of the message.
74−
75−```hoon
76−++ telegram {aut/ship thought} :< whose message
77−++ envelope {num/@ud gam/telegram} :< outward message
78−```
79−
80−Finally, before sending the message over the wire, we add on the message's original author. In most cases, we also include a sequence number, the index of the message in the originating circle's list of messages. This can be a useful point of reference for clients.
81−
82−### Participant metadata
83−
84−Messages aren't the only thing a subscription gets us. We're also kept up to date with relevant metadata.
85−
86−```hoon
87−++ crowd {loc/group rem/(map partner group)} :< our & srcs presences
88−++ group (map ship status) :< presence map
89−++ status {pec/presence man/human} :< participant
90−++ presence :> status type
91− $? $gone :< absent
92− $idle :< idle
93− $hear :< present
94− $talk :< typing
95− == ::
96−++ human :> human identifier
97− $: han/(unit cord) :< handle
98− tru/(unit truename) :< true name
99− == ::
100−++ truename {fir/cord mid/(unit cord) las/cord} :< real-life name
101−```
102−
103−`status` is user-set metadata that describes, well, the status of users in a circle. This encompasses their `presence`, which shows their activity, and their `human` identity, which includes their display handle.
104−
105−For reasons we'll discover shortly, circles keep track of both their own `group` and those of the circles they're subscribed to. `crowd` encapsulates this.
106−
107−### Configurations
108−
109−```hoon
110−++ lobby {loc/config rem/(map circle config)} :< our & srcs configs
111−++ config :> circle config
112− $: src/(set circle) :< active sources
113− cap/cord :< description
114− fit/filter :< message rules
115− con/control :< restrictions
116− == ::
117−++ filter :> content filters
118− $: cas/? :< dis/allow capitals
119− utf/? :< dis/allow non-ascii
120− == ::
121−++ control {sec/security ses/(set ship)} :< access control
122−```
123−
124−Another part of metadata we get from circle subscriptions is configurations. Again, circles want to remember their own configuration, as well as those of their subscriptions. But why, precisely?
125−
126−The `config` structure contains `src`, a set of partners. These indicate the different sources a circle is currently pulling content from. This allows circles to aggregate messages from multiple places. In doing so, it also receives metadata from those places, hence why we have structures for storing "remote" presences and configurations alongside local ones.
127−
128−Aside from that, `config` contains a description for the circle, which is exactly what it sounds like. It also specifies a `filter`, which are content formatting rules all messages passing through this circle are made to adhere to.
129−
130−Lastly, there's a `control` structure that contains both a security mode and a list of ships, which is either a white- or blacklist depending on the aforementioned mode. There are four such modes available.
131−
132−```hoon
133−++ security :> security mode
134− $? $channel :< blacklist
135− $village :< whitelist
136− $journal :< pub r, whitelist w
137− $mailbox :< our r, blacklist w
138− == ::
139−```
140−
141−A `channel` is publicly readable and writable, with a blacklist for blocking.
142−A `village` is privately readable and writable, with a whitelist for inviting.
143−A `journal` is publicly readable and privately writable, with a whitelist for authors.
144−A `mailbox` is readable by its owner and publicly writable, with a blacklist for blocking.
145−
146−### Stories
147−
148−To see how that all ties together, we're going to take a look at Hall's state.
149−
150−```hoon
151−++ state :> hall state
152− $: stories/(map term story) :< conversations
153− :: ... ::
154− == ::
155−++ story :> wire content
156− $: grams/(list telegram) :< all messages
157− locals/group :< local presence
158− remotes/(map circle group) :< remote presence
159− shape/config :< configuration
160− mirrors/(map circle config) :< remote config
161− :: ... ::
162− == ::
163−```
164−
165−Stories are the primary driver behind Hall. They are the structures that are used to power circles, which we can now say are named stories hosted on ships.
166−
167−With the configuration described above in mind, we can try and imagine the things we can do with stories. Knowing that we can subscribe them to any number of sources, they can function as central hubs for our messaging, aggregate specific kinds of data feeds, or simply accept whatever messages get sent to it like a regular old chatroom.
168−
169−### General use
170−
171−Upon initial startup, Hall creates a default story, a mailbox named `inbox`. This mailbox is the primary target for anyone and anything that wants to reach its owner. Applications can use it to send notifications and other information to the user (Hall itself does this as well), and users can use it to send direct messages to each other.
172−
173−Applications that use Hall, especially clients, are encouraged to use the default mailbox as the primary messaging hub. This way, users can easily switch between different applications without "losing" their subscriptions, message backlog, etc.
174−
175−As an example, Talk operates like this, serving as an interface for reading from and managing the user's mailbox. Local stories are subscribed to through the `inbox`, which ends up containing all messages the user receives.
176−
177−### Public membership
178−
179−To aid in discoverability of circles, it is possible for users to make their participation in any given circle public. This data can then be used by things like profile widgets, or read out directly by other users.
180−
181−
182−## Interfaces for applications
183−
184−Applications can interact with Hall in two complementary ways: they can tell it what actions to perform, and they can subscribe to its state and the changes made to it.
185−
186−### Interactions
187−
188−Hall can be commanded by poking it with `action`s.
189−
190−```hoon
191−++ action :> user action
192− $% :: circle configuration ::
193− {$create nom/term des/cord sec/security} :< create circle
194− {$delete nom/term why/(unit cord)} :< delete + announce
195− {$depict nom/term des/cord} :< change description
196− {$filter nom/term fit/filter} :< change message rules
197− {$permit nom/term inv/? sis/(set ship)} :< invite/banish
198− {$source nom/term sub/? srs/(set source)} :< un/sub to/from src
199− :: messaging ::
200− {$convey tos/(list thought)} :< post exact
201− {$phrase aud/audience ses/(list speech)} :< post easy
202− :: personal metadata ::
203− {$notify aud/audience pes/(unit presence)} :< our presence update
204− {$naming aud/audience man/human} :< our name update
205− :: changing shared ui ::
206− {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
207− {$nick who/ship nic/cord} :< new identity
208− :: misc changes ::
209− {$public add/? cir/circle} :< show/hide membership
210− == ::
211−```
212−
213−The largest part of these actions concern themselves with managing local circles. `nom` is always the name used to identify the relevant story. To disambiguate between "add" and "delete" type actions (for permissions and subscriptions), a loob `?` is used.
214−
215−To send messages, two interfaces are available. `%convey` lets you specify all details of the messages, including its timestamp, serial, and fully assembled audience. `%phrase`, on the other hand, takes care of that for you, allowing you to specify just the target partners and message contents.
216−
217−`%notify` and `%naming` are useful for setting your own presence and nickname in a circle respectively, so others can see if you're active and what to call you by.
218−
219−"Shared UI" encompasses UI data that should be consistent across applications. For example, if the user sets a local nickname for an identity, they expect to see that nickname regardless of the application they're currently using. The same goes for glyph bindings, for easy audience targeting.
220−
221−### Queries, prizes and rumors
222−
223−To receive data from Hall, applications will have to query it. There are two paths that are useful for clients to query. Let's look at them and their results.
224−
225−```hoon
226−++ query :> query paths
227− $% {$client $~} :< shared ui state
228− $: $circle :> story query
229− nom/naem :< circle name
230− wat/(set circle-data) :< data to get
231− ran/range :< query duration
232− == ::
233− :: ... ::
234− == ::
235−++ circle-data :> kinds of circle data
236− $? $grams :< messages
237− $group-l :< local presence
238− $group-r :< remote presences
239− $config-l :< local config
240− $config-r :< remote configs
241− == ::
242−++ range :> inclusive msg range
243− %- unit :< ~ means everything
244− $: hed/place :< start of range
245− tal/(unit place) :< opt end of range
246− == ::
247−++ place :> range indicators
248− $% {$da @da} :< date
249− {$ud @ud} :< message number
250− == ::
251−++ prize :> query result
252− $% $: $client :< /client
253− gys/(jug char (set partner)) :< glyph bindings
254− nis/(map ship cord) :< nicknames
255− == ::
256− {$circle burden} :< /circle
257− :: ... ::
258− == ::
259−++ burden :< full story state
260− $: gaz/(list telegram) :< all messages
261− cos/lobby :< loc & rem configs
262− pes/crowd :< loc & rem presences
263− == ::
264−```
265−
266−To be clear, the paths for those queries are `/client` and `/circle/[name]/[data]/[start]/[end]`, where data is at least one `circle-data`, and `start` and `end` are optional and can be either a date or a message number.
267−
268−`/client` queries produce shared UI state. That is, glyph bindings and nicknames.
269−`/circle` queries produce the entire public state of the requested story, including remotes.
270−
271−Any changes to the results of these queries are communicated via the following `rumor`s. It's a fairly long list of potential changes,
272−
273−```hoon
274−++ rumor :< query result change
275− $% {$client rum/rumor-client} :< /client
276− {$circle rum/rumor-story} :< /circle
277− :: ... ::
278− == ::
279−++ rumor-client :< changed ui state
280− $% {$glyph diff-glyph} :< un/bound glyph
281− {$nick diff-nick} :< changed nickname
282− == ::
283−++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
284−++ diff-nick {who/ship nic/cord} :< changed nickname
285−++ diff-story :> story change
286− $% {$new cof/config} :< new story
287− {$config cir/circle dif/diff-config} :< new/changed config
288− {$status cir/circle who/ship dif/diff-status} :< new/changed status
289− {$remove $~} :< removed story
290− :: ... ::
291− == ::
292−++ rumor-story ::> story rumor
293− $? diff-story ::< both in & outward
294− $% {$gram nev/envelope} ::< new/changed msgs
295− == == ::
296−++ diff-config :> config change
297− $% {$full cof/config} :< set w/o side-effects
298− {$source add/? src/source} :< add/rem sources
299− {$caption cap/cord} :< changed description
300− {$filter fit/filter} :< changed filter
301− {$secure sec/security} :< changed security
302− {$permit add/? sis/(set ship)} :< add/rem to b/w-list
303− {$remove $~} :< removed config
304− == ::
305−++ diff-status :> status change
306− $% {$full sat/status} :< fully changed status
307− {$presence pec/presence} :< changed presence
308− {$human dif/diff-human} :< changed name
309− {$remove $~} :< removed status
310− == ::
311−++ diff-human :> name change
312− $% {$full man/human} :< fully changed name
313− {$handle han/(unit cord)} :< changed handle
314− {$true tru/(unit truename)} :< changed true name
315− == ::
316−```
317−
318−These are, as enforced by Gall, the changes as they happen. This makes it possible for very minimal Hall clients to be implemented that only display a stream of changes, rather than keeping state themselves.
319−
320−
321−## Communication between Halls
322−
323−Halls can communicate with other Halls by sending commands and subscription updates.
324−
325−### Commands
326−
327−To request changes to a story, Halls can send `command`s.
328−
329−```hoon
330−++ command :> effect on story
331− $% {$publish tos/(list thought)} :< deliver
332− {$present nos/(set term) dif/diff-status} :< status update
333− :: ... ::
334− == ::
335−```
336−
337−A `%publish` command contains messages. These are sent to foreign Halls to be published to their stories.
338−
339−The `%present` command is used for sending status updates about our ship.
340−
341−### Querying
342−
343−Halls can query other halls. Here's the peer move we send when we open a query on a foreign circle:
344−
345−```hoon
346−:* ost.bol :< bone
347− %peer :< move type
348− /[our-circle]/[host]/[query-path] :< rumor path
349− [host %hall] :< query target
350− /circle/[their-circle]/[data]/[start]/[end] :< query path
351−== ::
352−```
353−
354−Again, the rumor path is what our Hall uses to identify what query a received message originates from. Our circle is specified so that we know what story is interested in the changes we get.
355−
356−The query path is slightly more interesting. Of course it specifies the name of their story we want to subscribe our story to, but also a "start" and "end". These can (optionally) be used to specify the range of messages we want to get from our query. Once that range has passed, we stop receiving updates.
357−
358−### Federation implementation
359−
360−Along the way so far, we've skipped some parts of structures. Most of those relate to federation. Let's see what we missed.
361−
362−```hoon
363−++ query :> query paths
364− $% {$burden who/ship} :< duties to share
365− {$report $~} :< duty reports
366− :: ... ::
367− == ::
368−++ prize :> query result
369− $% {$burden sos/(map term burden)} :< /burden
370− :: ... ::
371− == ::
372−++ rumor :< query result change
373− $% {$burden nom/term rum/rumor-story} :< /burden
374− :: ... ::
375− == ::
376−++ diff-story ::
377− $% {$bear bur/burden} :< new inherited story
378− :: ... ::
379− == ::
380−++ burden :> full story state
381− $: gaz/(list telegram) :< all messages
382− cos/lobby :< loc & rem configs
383− pes/crowd :< loc & rem presences
384− == ::
385−```
386−
387−We briefly touched upon how federation works on the higher level. On the lower, this is how things go down.
388−
389−1. When Hall boots on a star or galaxy, it starts querying its parent's `/burden` path. (Galaxies query ~zod.)
390−2. Upon receiving that query, the parent sends a `%burden` prize containing all state of its channels (fully public circles) to the child. It also subscribes to `/report` on that child.
391−3. When a new story gets created on the parent, its children get a `%burden` rumor with a `%bear` story diff, and they create a local copy of that channel.
392−4. When something about a parent's story changes, a `%burden` rumor is sent to all its children (because they're querying `/burden`). The children apply this change to their local version of the story.
393−5. When a child's story has a `%grams` or `%status` change, a `%burden` rumor is sent to the parent (because they're querying `/report`). The parent applies this change to their local version of the story, and #4 happens.
394−
395−
396−## Hall implementation
397−
398−Now that we know what gets sent over the wire and why, let's see what happens whenever such events happen. We won't be covering everything, but enough to illustrate the general flow.
399−
400−First though, it's useful to understand how Hall's code is structured. It consists of primary cores, designed to work optimally with Gall.
401−
402−- `++ta` is the transaction core. For every event that happens, be it a poke, peer or diff, the transaction core gets put to work to process it. Once it's done, it produces a list of deltas that describe how our state needs to be modified.
403−- `++da` is the delta application core. It is used to apply `++ta`'s deltas to our application state, and produce a list of side-effects.
404−
405−Both those cores also have a core within themselves dedicated solely to dealing with stories, `++so` and `++sa` respectively.
406−
407−Once all work in an engine core has finished, its `-done` arm is called to produce the result of all the core's computation.
408−
409−In the diagrams that follow, regular lines indicate flows that always happen. Dashed lines indicate flows that are traversed if the described condition is met.
410−Below the diagrams you will find brief explanations of the involved arms. In a particularly bright future, these might be available on-hover instead.
411−For brevity, utility arms that aren't a direct and important part of the flow have been omitted.
412−
413−(You will find that the origins still use old Gall arms, with some glue code in between. At the time of writing, new Gall has not yet been implemented, so this will have to do.)
414−
415−We will only display the delta generation parts of the flow. Delta application is usually implemented simply enough to deduce what it does from looking at the label.
416−
417−### Subscriptions
418−
419−Hall-to-Hall subscriptions happen when a source gets added to a story. This is done with a `%source` action, and results in a `%peer` move being sent (prompted by a `%story %follow` delta).
420−Upon receiving a valid peer on a `/circle` path, the subscribing ship is added to that circle's presence map.
421−
422−![subscriptions implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-subscriptions.png)
423−
424−```hoon
425−++ poke-talk-action :< we got poked with an action.
426− ++ ta-action :< applies an action.
427− ++ ta-config :< (re)configures a story.
428−:: ::
429−++ peer :< we got peered.
430− ++ g-query :< resolves query to prize.
431− ++ ta-subscribe :< act upon subscription.
432− ++ so-attend :< adds a ship's status to the story.
433−```
434−
435−### Rumors
436−
437−Once a query has opened, Hall will receive updates on it, rumors. The changes describes in these rumors are applied via the following flow.
438−
439−![rumor implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-rumors.png)
440−
441−```hoon
442−++ diff-talk-rumor :< we got a query update.
443− ++ ta-hear :< applies a rumor to the story it's intended for.
444− ++ so-hear :< applies a %circle rumor to the story.
445− ++ so-config-full :< splits a %full diff-config into separate changes.
446− ++ so-bear :< accept burden, assimilate into the story's state.
447− ++ so-lesson :< sends a report with presences.
448−```
449−
450−### Messaging
451−
452−To send messages, the user sends a `%convey` or `%phrase` action, resulting in a `%publish` command being sent to the involved partners. Receiving a `%publish` command causes its messages to be added to the story through the creation of a `%story %grams` delta.
453−
454−![messaging implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-messaging.png)
455−
456−```hoon
457−++ poke-talk-action :< we got poked with an action.
458− ++ ta-action :< applies an action.
459−:: ::
460−++ poke-talk-command :< we get poked with a command.
461− ++ ta-apply :< applies a command.
462− ++ ta-think :< consumes each message in the given list.
463− ++ ta-consume :< conducts a message to each partner in audience.
464− ++ ta-conduct :< records or sends a message.
465− ++ ta-transmit :< sends a message to a partner.
466− ++ ta-record :< stores a message in a story.
467− ++ so-learn :< either adds or modifies a message.
468−```
469−
470−
471−## The future
472−
473−Hall is neither complete nor perfect. There are features that need to be implemented, varying from small quality of life changes to broad-reaching functionality.
474−
475−### Features and functionality
476−
477−To turn Talk into a [sustainable social platform](https://urbit.org/fora/posts/~2017.4.26..18.00.25..b93c~/), it needs a number of things.
478−
479−We want to have some kind of discoverability for circles. This could be realized by making it possible for users to add friends, who would have their Hall subscribe to a list of circles the added friends are in. The existing public membership functionality can be leveraged for this.
480−
481−Eventually, content self-moderation might need to be implemented. Users would flag their content if it is potentially offensive. Others would easily be able to filter out content that might offend them.
482−This functionality brings its own large sets of challenges that need to be tackled.
483−
484−Additionally, federation might be put to broader use. Knowing that a circle is federated could help fall back to alternative hosts in case the one Hall originally subscribed to is unavailable. Implementation-wise, care would need to be taken for this to not get ugly. Not to mention, when/how would availability of a host be verified?
485−
486−Other changes that might have a fair impact on the functioning of Hall are un/read states for messages, and being able to use moons to allow your friends to chat with you in a local channel.
487−
488−More minor functionalities that need to be implemented include:
489−- Extended permissions management. Being able to black-/whitelist entire ship classes.
490−- Improved presence functionality. Actually using the presence system, and sending "typing", "idle", etc. statuses.
491−- Polls.
492−
493−And, of course, there's a lot that the Talk client can improve on as well.
494−
495−
496−## Further reading
497−
498−To gain a more thorough understanding of Hall's inner workings, take a look at its source code. It comes with inline documentation.
499−[On Github.](https://github.com/urbit/urbit/blob/master/pkg/arvo/app/hall.hoon)
500−
501−To see an expansive example of a Hall client, take a look at the code of Talk. It, too, comes with inline documentation.
502−[On Github.](https://github.com/urbit/urbit/blob/master/pkg/arvo/app/talk.hoon)
503−
504−# The Hall Interface
505−
506−This document describes the different interfaces Hall provides and the data that is accessible and modifiable through them. Knowledge of the Urbit application model (including [new gall](#the-new-gall-model)) and [Hall's architecture](#hall-architecture) is assumed.
507−
508−While the structures here are given in Hoon, they match fairly closely to their JSON equivalent. Most important to note is that `$%({$x y/z})` becomes accessible as `json.x.y`.
509−
510−## Queries
511−
512−Queries are the paths you pass into `%peer` moves. Internally, they get translated to a `++query` structure for easier handling. We'll be giving examples of valid query paths alongside the structures themselves.
513−
514−### /client
515−
516−To be able to keep certain UI elements like glyphs and local nicknames consistent across different Hall clients, they can query Hall for the current UI state.
517−
518−```hoon
519−++ query ::
520− $% {$client $~} :< shared ui state
521− :: .... ::
522− == ::
523−```
524−
525−Valid paths include:
526−
527−```
528−:> all shared ui state
529−/client
530−```
531−
532−#### /client prize
533−
534−Contains a map of glyphs and the audiences that they map to, as well as a map of ships and their locally set nicknames.
535−
536−```hoon
537−++ prize :> query result
538− $% {$client prize-client} :< /client
539− :: ... ::
540− == ::
541−++ prize-client :> shared ui state
542− $: gys/(jug char audience) :< glyph bindings
543− nis/(map ship nick) :< local nicknames
544− == ::
545−```
546−
547−#### /client rumor
548−
549−Contains either a bound or unbound glyph and its target, or a ship with its new nickname. A nickname of `''` means the associated ship no longer has a nickname set for it.
550−
551−```hoon
552−++ rumor :> query result change
553− $% {$client rum/rumor-client} :< /client
554− :: ... ::
555− == ::
556−++ rumor-client :< changed ui state
557− $% {$glyph diff-glyph} :< un/bound glyph
558− {$nick diff-nick} :< changed nickname
559− == ::
560−++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
561−++ diff-nick {who/ship nic/nick} :< changed nickname
562−```
563−
564−
565−### /public
566−
567−To aid in circle discoverability, users can add circles to their "public membership" list. This can then be queried for by, for example, a profile page.
568−
569−```hoon
570−++ query ::
571− $% {$public $~} :< public memberships
572− :: .... ::
573− == ::
574−```
575−
576−Valid paths include:
577−
578−```
579−:> all public memberships
580−/public
581−```
582−
583−#### /public prize
584−
585−Contains the set of circles the user has on their public list.
586−
587−```hoon
588−++ prize :> query result
589− $% {$public cis/(set circle)} :< /public
590− :: ... ::
591− == ::
592−```
593−
594−#### /public rumor
595−
596−Contains a circle that was either added or removed from the public list.
597−
598−```hoon
599−++ rumor :> query result change
600− $% {$public add/? cir/circle} :< /public
601− :: ... ::
602− == ::
603−```
604−
605−### /peers
606−
607−To allow a circle owner to inspect who is currently subscribed to their stories, they can issue a query to retrieve subscription data.
608−
609−```hoon
610−++ query ::
611− $% {$peers nom/naem} :< readers of story
612− :: .... ::
613− == ::
614−```
615−
616−Query paths are structured as follows:
617−
618−```
619−/peers/[circle-name]
620−```
621−
622−Valid paths include:
623−
624−```
625−:> peers for circle %urbit-help
626−/peers/urbit-help
627−```
628−
629−#### /peers prize
630−
631−Contains a map of ships and the different queries they currently have active for the selected story.
632−
633−```hoon
634−++ prize :> query result
635− $% {$peers pes/(jar ship query)} :< /peers
636− :: ... ::
637− == ::
638−```
639−
640−#### /peers rumor
641−
642−Contains a ship and a query, and a flag to indicate whether that subscription has started or ended.
643−
644−```hoon
645−++ rumor :> query result change
646− $% {$peers add/? who/ship qer/query} :< /peers
647− :: ... ::
648− == ::
649−```
650−
651−### /circle
652−
653−Circle queries allow for the retrieving of data from stories. Their messages, configuration, and presences can all be accessed. Since this is a lot of data, there are lots of possibilities for filtering it built in to the query itself.
654−
655−
656−A quick refresher on the difference between "local" and "remote" presence and configuration: "local" means it pertains to the circle itself; "remote" means it pertains to one of its configured sources. The latter is primarily useful to clients when using a circle for aggregation, like the `%inbox`.
657−
658−```hoon
659−++ query ::
660− $% $: $circle :> story query
661− nom/naem :< circle name
662− wer/(unit circle) :< from source
663− wat/(set circle-data) :< data to get
664− ran/range :< query duration
665− == ::
666− :: .... ::
667− == ::
668−++ circle-data :> kinds of circle data
669− $? $grams :< messages
670− $group-l :< local presence
671− $group-r :< remote presences
672− $config-l :< local config
673− $config-r :< remote configs
674− == ::
675−++ range :> inclusive msg range
676− %- unit :< ~ means everything
677− $: hed/place :< start of range
678− tal/(unit place) :< opt end of range
679− == ::
680−++ place :> range indicators
681− $% {$da @da} :< date
682− {$ud @ud} :< message number
683− == ::
684−```
685−
686−Query paths are structured as follows:
687−
688−```
689−/circle/[circle-name]/(from-circle)/[what/data]/(range-start(/range-end))
690−(from-circle) : optional message source, ~ship/circle
691−[what/data] : one or more of grams, group, group-l, group-r,
692− : config, config-l, config-r, combined using /
693−(range) : an optional range with an optional end, its points denoted
694− : in either message number (@ud) or date (@da)
695−```
696−
697−Valid paths include:
698−
699−```
700−:> get all messages from circle %urbit-help
701−/circle/urbit-help/grams
702−:> get all messages, all presences and local configs from %urbit-help
703−/circle/urbit-help/grams/group/config-l
704−:> get all messages %urbit-help has heard from its source ~zod/fora
705−/circle/urbit-help/~zod/fora/grams
706−:> get the first 100 messages from %urbit-help
707−/circle/urbit-help/grams/0/99
708−:> get the first 100 messages %urbit-help has heard from its source ~zod/fora
709−/circle/urbit-help/~zod/fora/grams/0/99
710−:> get all messages from %urbit-help, starting now
711−/circle/urbit-help/grams/group/(scow %da now)
712−:> get all messages from %urbit-help, starting now, ending at the 100th message
713−/circle/urbit-help/grams/(scow %da now)/99
714−:> get local presences from %urbit-help for a week
715−/circle/urbit-help/group-l/(scow %da now)/(scow %da (add now ~d7))
716−```
717−
718−#### /circle prize
719−
720−Contains (where applicable) messages in envelopes (with message numbers), as well as local and remote configurations and presences.
721−
722−```hoon
723−++ prize :> query result
724− $% {$circle package} :< /circle
725− :: ... ::
726− == ::
727−++ package :> story state
728− $: nes/(list envelope) :< messages
729− cos/lobby :< loc & rem configs
730− pes/crowd :< loc & rem presences
731− == ::
732−```
733−
734−#### /circle rumor
735−
736−Contains a detailed change description of the data relevant to the query that changed.
737−
738−Messages are wrapped in envelopes to include their sequence number, and note the source they were heard from. Configuration and status changes specify the circle they apply to.
739−
740−```hoon
741−++ rumor :> query result change
742− $% {$circle rum/rumor-story} :< /circle
743− :: ... ::
744− == ::
745−++ rumor-story :> story rumor
746− $% {$new cof/config} :< new story
747− {$gram src/circle nev/envelope} :< new/changed message
748− {$config cir/circle dif/diff-config} :< new/changed config
749− {$status cir/circle who/ship dif/diff-status} :< new/changed status
750− {$remove $~} :< removed story
751− == ::
752−++ diff-config :> config change
753− $% {$full cof/config} :< set w/o side-effects
754− {$source add/? src/source} :< add/rem sources
755− {$caption cap/cord} :< changed description
756− {$filter fit/filter} :< changed filter
757− {$secure sec/security} :< changed security
758− {$permit add/? sis/(set ship)} :< add/rem to b/w-list
759− {$remove $~} :< removed config
760− == ::
761−++ diff-status :> status change
762− $% {$full sat/status} :< fully changed status
763− {$presence pec/presence} :< changed presence
764− {$human dif/diff-human} :< changed name
765− {$remove $~} :< removed status
766− == ::
767−++ diff-human :> name change
768− $% {$full man/human} :< fully changed name
769− {$handle han/(unit cord)} :< changed handle
770− {$true tru/(unit truename)} :< changed true name
771− == ::
772−```
773−
774−
775−## Actions
776−
777−Actions can be sent by poking Hall with data marked as `%hall-action`. Actions are used for all user operations. If an error or other unexpected behavior occurs while executing an action, Hall notifies the user by sending an `%app` message to their `%inbox`.
778−
779−### Circle configuration
780−
781−Since all of these apply to a specific circle, they all specify a name `nom` of the circle to operate on.
782−
783−```hoon
784−++ action :> user action
785− $% {$create nom/naem des/cord sec/security} :< create circle
786− {$delete nom/naem why/(unit cord)} :< delete + announce
787− {$depict nom/naem des/cord} :< change description
788− {$filter nom/naem fit/filter} :< change message rules
789− {$permit nom/naem inv/? sis/(set ship)} :< invite/banish
790− {$source nom/naem sub/? srs/(set source)} :< un/sub to/from src
791− :: ... ::
792− ==
793−```
794−
795−`%create`: Creates a circle with description `des` and security mode `sec`. If this mode is a whitelist, the user is automatically added to it.
796−
797−`%delete`: Deletes the circle. If a reason `why` is provided, posts that as the last message to the circle before deleting it.
798−
799−`%depict`: Set the description of the circle to `des`.
800−
801−`%filter`: Set the filter (message sanitation rules) for the circle to `fit`.
802−
803−`%permit`: Either invite or banish ships to/from the circle, modifying the access control list accordingly. Regardless of whether this actually makes any changes, sends an `%inv` message to the involved ships' `%inbox`es.
804−
805−`%source`: Add or remove sources to/from the circle, un/subscribing it to/from the `grams`, `group-l` and `config-l` each one.
806−
807−### Messaging
808−
809−There are two interfaces for telling Hall to send a message. The first takes entire `thought`s, the second only `speech`es and the audience to send them to.
810−
811−```hoon
812−++ action :> user action
813− $% {$convey tos/(list thought)} :< post exact
814− {$phrase aud/audience ses/(list speech)} :< post easy
815− :: ...
816− ==
817−```
818−
819−`%convey`: Sends the thoughts to their audiences.
820−
821−`%phrase`: Turns the speeches into thoughts by applying sane defaults for metadata (auto-generated `uid`, `now` for `wen`), and then sends those thoughts.
822−
823−### Personal metadata
824−
825−These concern the presence users have in circles they are participating in.
826−
827−```hoon
828−++ action :> user action
829− $% {$notify aud/audience pes/(unit presence)} :< our presence update
830− {$naming aud/audience man/human} :< our name update
831− :: ... ::
832− ==
833−```
834−
835−`%notify`: Sets the user's presence in the audience circles to `pes`. A good client will automatically set these based on the user's activity. (`%talk` on typing, `%idle` on idle, `%gone` on sign-off.)
836−
837−`%naming`: Sets the user's name (handle and real name) for the given audience. Good clients can display these in place of ship names.
838−
839−### Changing shared UI
840−
841−When the user makes any changes to shared UI elements (elements that should persist between clients), this has to be communicated to Hall.
842−
843−```hoon
844−++ action :> user action
845− $% {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
846− {$nick who/ship nic/nick} :< new identity
847− :: ... ::
848− ==
849−```
850−
851−`%glyph`: Adds or removes a binding of a glyph to an audience.
852−
853−`%nick`: Sets a local nickname for a ship. An empty nickname `''` means the ship has no nickname.
854−
855−### Miscellaneous changes
856−
857−```hoon
858−++ action :> user action
859− $% {$public add/? cir/circle} :< show/hide membership
860− :: ... ::
861− ==
862−```
863−
864−`%public`: Adds or removes a circle to/from the user's public membership list.
865−
866−# The New Gall Model
867−
868−This document is complemented by the source code of applications that use the new Gall model (like [Hall](https://github.com/urbit/urbit/blob/master/pkg/arvo/app/hall.hoon)), but doesn't require it. Code snippets will be provided where useful. Some knowledge of Hoon and the functioning of Hoon apps is assumed.
869−
870−New `%gall` has not yet fully solidified. As such, its structure and naming are tentative.
871−
872−## Renewing a pillar of Arvo
873−
874−When you write an app, Gall is responsible for making sure its event arms like `++poke` get called when they need to. In essence, it provides developers with a consistent interface for hooking their app up to the operating system.
875−
876−It's not doing a lot to make sure this is done in a structured way, though, which results in apps (especially larger ones) feeling like big, tangled messes. Something needs to be done about this.
877−
878−### Problems
879−
880−Imagine a `++poke`, `++diff`, or even a `++peer` arm. In current implementations, you'll often see their product defined through cast as the following:
881−`^- (quip move +>)`
882−Or (sadly) more commonly:
883−`^- {(list move) _+>.$}`
884−
885−These arms are producing both side-effects and new state. To do this, their code has to simultaneously figure out "how does this poke/diff/whatever change our state?" and "what side-effects does this change have?"
886−
887−You'll find that the logic relating to these two often becomes tangled, making the flow of the whole more difficult to understand. And the side-effects more often than not relate to subscriptions, for which the developer may be writing a lot of boilerplate code. Gall currently does not help in either of these places.
888−
889−> The main significant cost of software development is the cost of untangling what the computer is doing, and or is supposed to be doing, over and over again in your head. Any way of lowering this untangling cost is extremely welcome.
890−
891−**~sorreg-namtyv**
892−
893−### Solutions
894−
895−Let's imagine a world in which Gall **does** help, in both of those places.
896−
897−It would be wonderful if Gall could take care of all standard subscription management logic for you, and direct the flow of code as it concludes is appropriate. Applications, then, would have to help Gall by providing the different parts of this flow, and providing the checks that allow Gall to make the right decisions. This takes some work out of the developer's hands and results in more structured application code.
898−
899−If we expand on that a bit, then we can even have Gall help us in untangling state changes from side effects. We do so by separating state changes into two phases: **analyzing** what changes need to be made, and **applying** those changes.
900−
901−But where do the side-effects go, then? We need to realize there's two kinds: side-effects that are subscription updates, and side-effects that aren't. The latter get produces by applying state changes, while the former get integrated into the Gall flow we described above.
902−
903−Since subscriptions are essentially queries to an app, requesting a specific part of its data/state, we can deduce subscription updates from state changes. We merely provide the logic, and Gall chains it all together. Having Gall support all this allows us to cleanly and structurally untangle state change analysis, application, and subscription logic into their own arms.
904−
905−For trivial apps, this might result in some arms with trivial code. Though it may feel like writing cruft, it makes understanding the app just as simple as it actually as. For more complex apps, all logic is no longer a big chunk of "what do we do when x happens?" Rather, it's a few smaller chunks, like "x happened, how does that change our state?" and "if our state changes like y, what does that mean for subscription z?" These are precisely the kinds of questions that application developers should be asked.
906−
907−
908−## As seen in new Gall
909−
910−Of course, for the above to be made into reality, Gall will need to see some changes. Let's outline the new structures and the arms they get passed between.
911−
912−### Structures
913−
914−This wouldn't be Urbit if we didn't have cool terminology for people to learn. These ones are (for the most part) semantically sensible, and you might already see how they relate to the story above.
915−
916−`brain`: application state.
917−`delta`: change to application state.
918−`opera`: side-effect, operation, move.
919−`query`: request (to an app) for data on a specific path.
920−`prize`: query result.
921−`rumor`: change to a query result.
922−
923−These should be fairly straightforward. Like packets are to Urbits, `delta`s are to `brain`s and `rumor`s are to `prize`s. If one diligently updates the `prize` they received using all the `rumor`s that are relevant to it, they will always have the same `prize` as if they queried for it all over again.
924−
925−### Arms
926−
927−This also wouldn't be Urbit if we couldn't boil that down to a few simple pseudocode functions. Let's try, shall we?
928−
929−```hoon
930−++ bake |= {brain delta} ^- {brain opera}
931−++ peek |= {brain query} ^- (unit (unit prize))
932−++ feel |= {query delta} ^- (unit rumor)
933−++ gain |= {prize rumor} ^- prize
934−
935−:: for any given brain, delta and query:
936−.= (peek brain:(bake brain delta) query)
937− (gain rumor:(feel query delta) prize:(peek brain query))
938−```
939−
940−There. In the first three arms we already have the bulk of new Gall! `++gain` won't be part of it, since most applications don't need to keep track of `prize`s directly. Those that do may still implement and hook it up themselves though.
941−
942−Of course, these aren't all of the new Gall arms. Most important to still mention is `++leak`, which takes a `ship` and `query` and checks if the former has permission to ask for the latter.
943−
944−There's also `++look` for asynchronous reads, `++hear` for subscription updates (rumors), `++fail` for dealing with process errors, `++cope` for dealing with transaction results, and `++pour` for dealing with responses from Arvo.
945−`++prep`, `++poke` and `++pull` continue to function as they do right now.
946−
947−For a more verbose specification of all of these, see the new Gall spec.
948−
949−
950−## By example
951−
952−To help solidify this and see what this would looks like in the wild, let's make a very simple example app. It's a counter that can go up and down, and can be queried for its value, or whether or not its value is a multiple of x. First we write all the structures that will support our app, and then we implement the arms that operate on them.
953−(The app code in its entirety can be found [here](example).)
954−
955−### State & deltas
956−
957−Below is the application state, and the deltas we'll be using to modify it.
958−
959−```hoon
960−|%
961−++ brain {num/@ud $~} :< application state
962−++ delta :> state change
963− $% {$increment $~} :< +1
964− {$decrement $~} :< -1
965− == ::
966−```
967−
968−Fairly simple, right? We store a number, and every change either in- or decrements it.
969−
970−### Queries & rumors
971−
972−Let's also define the queries we'll be supporting, their results, and the changes to their results. Instead of only allowing people to query the current number, let's make it a tad more interesting by allowing them to query whether or not the current number is a multiple of something.
973−
974−```hoon
975−++ query :> valid queries
976− $% {$number $~} :< current number
977− {$mul-of val/@ud} :< is num multiple of?
978− == ::
979−++ prize :> query results
980− $% {$number num/@ud} :< /number
981− {$mul-of mul/?} :< /mul-of
982− == ::
983−++ rumor :> query result changes
984− $% {$number delta} :< /number
985− {$mul-of mul/?} :< /mul-of
986− == ::
987−--
988−```
989−
990−You'll see the `rumor` for a `/number` query just contains a delta. In this specific case, a change in state maps directly to a change to `prize`. For `/mul-of` queries, things aren't that simple.
991−
992−### Responding to queries
993−
994−Now, let's implement all the arms that will be called as things start happening. First, we want to implement `++leak`, which checks if a given `ship` is allowed to make a certain `query`. In this case, we're fine with everyone checking out our application's data.
995−
996−```hoon
997−|_ {bol/bowl brain}
998−::
999−++ leak :> read permission
1000− |= {who/ship qer/query}
1001− ^- ?
1002− & :: everyone's allowed
1003−```
1004−
1005−Next, let's create the `prize`s for the folks that make it through `++leak`. We'll be producing a `(unit (unit prize))` so we can potentially say `~` for "unavailable" and `[~ ~]` for "invalid query."
1006−
1007−```hoon
1008−++ peek :> synchronous read
1009− |= qer/query
1010− ^- (unit (unit prize))
1011− ?- -.qer
1012− $number ``[%number num]
1013− $mul-of ?: =(0 mul.qer) [~ ~]
1014− ``[%mul-of =(0 (mod num mul.qer))]
1015− ==
1016−```
1017−
1018−
1019−### Updating state & query results
1020−
1021−Our app can be queried! If they're interested enough, they'll want to receive updates on that whenever relevant state changes. First, let's see how state changes happen. We still have regular old `++poke` arms, let's use that to prompt our application to change its state.
1022−
1023−```hoon
1024−++ poke-loob :> regular old poke
1025− |= inc/?
1026− ^- (list delta)
1027− :_ ~
1028− ?: inc [%increment ~]
1029− [%decrement ~]
1030−::
1031−++ bake :> apply delta to state
1032− |= del/delta
1033− ^- (quip opera +>)
1034− :- ~
1035− ?- -.del
1036− $increment +>(num +(num))
1037− $decrement +>(num (dec num))
1038− ==
1039−```
1040−
1041−`delta`s get redirected into `++bake` so that our state can get changed as described. After this happens the same `delta`s get, for each active query, routed into `++feel`. That then figures out what the `rumor` relevant to the query is, if applicable.
1042−
1043−```hoon
1044−++ feel :> delta to rumor
1045− |= {qer/query del/delta}
1046− ^- (unit rumor)
1047− ?- -.qer
1048− $number
1049− `[%number del]
1050− ::
1051− $mul-of
1052− :: since we only want to send a rumor if result
1053− :: changed, we need to deduce the old state from
1054− :: the current state and the delta. depends on the
1055− :: fact that state changes before ++feel. funky!
1056− :: we could, of course, store mul/? in state, and
1057− :: make a delta for it, but should we need to?
1058− =/ old
1059− .= 0
1060− %+ mod
1061− ?- -.del
1062− $increment (dec num)
1063− $decrement +(num)
1064− ==
1065− mul.qer
1066− =/ new =(0 (mod num mul.qer))
1067− ?: =(old new) ~
1068− `[%mul-of new]
1069− ==
1070−```
1071−
1072−As we saw earlier, for `/number` queries the `delta`s match one-on-one with the relevant `rumor`s. For `/mul-of` queries we do a little bit of work to see if anything actually changed. No need to send a `rumor` if it hasn't.
1073−
1074−
1075−## Criticism
1076−
1077−- Where event arms currently get passed a `wire`, and the new Gall described above passes them a custom `query` structure, the original new Gall spec gave them `(list coin)`, a "pre-parsed wire". These structures (eg `[%$ p=[p=~.ud q=123]]`) are uncomfortable to work with. Even with a "coin list parsing library" it still doesn't feel ideal. Because of custom structures being easier to work with than lists of `++knot`s or `++coin`s, writing a `++path-to-query` arm by hand is a small cost for huge gains.
1078−
1079−- Why do `prize` units mean what they do? One would expect `~` to mean "invalid" and `[~ ~]` to mean "unavailable" as opposed to the other way around.
1080−
1081−- The original new Gall spec mentions output lists (like `(list delta)` etc.) to be in reverse order. This was done because adding to the head of a list (`[item list]`) is easier than appending to the tail of a list (`(weld list [item ~])` or other). While it's technically easier to produce a list in reverse order, semantically it's yet another thing to keep in mind. Luckily, most of the "add to x, produce all of it later" code is set-and-forget, so probably not a huge deal. But do we really fear a few stray `++flop`s that much?
1082−
1083−- There's some weirdness with relation to relying on old state in `++feel` to determine whether a query result actually changed. Just relying on state in general for delta-to-rumor conversion may or may not violate the new Gall spec.
1084−
1085−- The original new Gall spec specifies `++leak` as taking a `(unit (set ship))`, where `~` means public. Is there a use case for checking more than just a single ship?
1086−
1087−- Gall should probably cache `++feel` results during a single pass, to avoid the cycles of generating what it can be certain of is the same `(unit rumor)`. (But then for eg `/circle/nom/13` and `/circle/nom/14` it would still recalculate. Better than nothing.)
1088−
1089−
1090−## The original new-Gall spec
1091−
1092−`~sorreg-namtyv`
1093−
1094−```hoon
1095−=> |%
1096− --
1097−|* $: :> vinyl: historical state (including version)
1098− :> brain: working state of the application (not including version)
1099− :> delta: grain of change across all state
1100− :> prize: (pair mark noun) for namespace value
1101− :> rumor: (pair mark noun) for namespace diff
1102− :> opera: (pair bone card) for operation (old ++move)
1103− :>
1104− vinyl/mold
1105− brain/mold
1106− delta/mold
1107− prize/mold
1108− rumor/mold
1109− opera/mold
1110− ==
1111−|_ $: :> ops: pending operations, in reverse order
1112− :> ego: current state
1113− :>
1114− ops/(list opera)
1115− ego/brain
1116− ==
1117−:: :: ++bake
1118−++ bake :< apply delta
1119− |= $: :> del: change
1120− :>
1121− del/delta
1122− ==
1123− :> core after change (including operations)
1124− ^- _+>
1125− !!
1126−:: :: ++cope
1127−++ cope :< transaction result
1128− |= $: :> weg: forward identity
1129− :> het: success or error report
1130− :>
1131− weg/(list coin)
1132− het/(unit tang)
1133− ==
1134− :> actions in reverse order
1135− :>
1136− ^- (list delta)
1137− !!
1138−:: :: ++fail
1139−++ fail :< process error
1140− |= $: :> why: error dump
1141− :>
1142− why/tang
1143− ==
1144− :> actions in reverse order
1145− :>
1146− ^- (list delta)
1147− !!
1148−:: :: ++feel
1149−++ feel :< update
1150− |= $: :> del: change
1151− :> pex: preparsed path, inside-first
1152− :>
1153− del/delta
1154− pex/(list coin)
1155− ==
1156− :> query updates in reverse order
1157− :>
1158− ^- (list rumor)
1159− !!
1160−:: :: ++hear
1161−++ hear :< subscription update
1162− |= $: :> weg: forward identity
1163− :>
1164− weg/(list coin)
1165− ==
1166− :> actions in reverse order
1167− :>
1168− ^- (list delta)
1169− !!
1170−:: :: ++pull
1171−++ pull :< subscription cancel
1172− |= $: :> weg: forward identity
1173− :> het: error report, if any
1174− :>
1175− weg/(list coin)
1176− het/(unit tang)
1177− ==
1178− :> actions in reverse order
1179− :>
1180− ^- (list delta)
1181− !!
1182−:: :: ++leak
1183−++ leak :< check access
1184− |= $: :> lec: leakset (~ means public)
1185− :> pex: preparsed path, inside-first
1186− :>
1187− lec/(unit (set ship))
1188− pex/(list coin)
1189− ==
1190− :> if path `pex` is visible to ships in `lec`
1191− ^- ?
1192− !!
1193−:: :: ++load
1194−++ look :< asynchronous read
1195− |= $: :> pex: preparsed path, inside-first
1196− :>
1197− pex/(list coin)
1198− ==
1199− :> actions in reverse order
1200− ^- _+>
1201− !!
1202−:: :: ++prep
1203−++ prep :< load system
1204− |= $: old/vinyl
1205− ==
1206− :> core after boot
1207− ^- _+>
1208− !!
1209−:: :: ++peek
1210−++ peek :< synchronous read
1211− |= $: :> pex: preparsed path, inside-first
1212− :>
1213− pex/(list coin)
1214− ==
1215− :> value at `pec`; ~ for unavailable, [~ ~] for invalid
1216− :>
1217− ^- (unit (unit prize))
1218− !!
1219−:: :: ++poke
1220−++ poke :< generic poke
1221− |= $: :> ost: opaque cause
1222− :> msg: message with mark and vase
1223− :>
1224− ost/bone
1225− msg/cage
1226− ==
1227− :> actions in reverse order
1228− :>
1229− ^- (list delta)
1230− !!
1231−:: :: ++pour
1232−++ pour :< arvo response
1233− |= $: :> weg: forward identity
1234− :> sin: response card
1235− :>
1236− weg/(list coin)
1237− sin/sign
1238− ==
1239− :> actions in reverse order
1240− :>
1241− ^- (list delta)
1242− !!
1243−--
1244−```
1245−
1246−## A new-Gall example app
1247−
1248−```hoon
1249−:: counter app
1250−:: new gall example, may or may not compile.
1251−::
1252−|%
1253−++ query :> valid queries
1254− $% {$number $~} :< current number
1255− {$mul-of val/@ud} :< is num multiple of?
1256− == ::
1257−++ prize :> query results
1258− $% {$number num/@ud} :< /number
1259− {$mul-of mul/?} :< /mul-of
1260− == ::
1261−++ rumor :> query result changes
1262− $% {$number delta} :< /number
1263− {$mul-of mul/?} ::TODO or just flip? :< /mul-of
1264− == ::
1265−:: the above would ordinarily be placed in sur/, ::
1266−:: since other apps might want to use it. ::
1267−++ brain {num/@ud $~} :< application state
1268−++ delta :> state change
1269− $% {$increment $~} :< +1
1270− {$decrement $~} :< -1
1271− == ::
1272−--
1273−::
1274−|_ {bol/bowl brain}
1275−::
1276−++ leak :> read permission
1277− |= {who/ship qer/query}
1278− ^- ?
1279− & :: everyone's allowed
1280−::
1281−++ peek :> synchronous read
1282− |= qer/query
1283− ^- (unit (unit prize))
1284− ?- -.qer
1285− $number ``[%number num]
1286− $mul-of ?: =(0 mul.qer) [~ ~]
1287− ``[%mul-of =(0 (mod num mul.qer))]
1288− ==
1289−::
1290−++ poke-loob :> regular old poke
1291− |= inc/?
1292− ^- (list delta)
1293− :_ ~
1294− ?: inc [%increment ~]
1295− [%decrement ~]
1296−::
1297−++ bake :> apply delta to state
1298− |= del/delta
1299− ^- (quip opera +>)
1300− :- ~
1301− ?- -.del
1302− $increment +>(num +(num))
1303− $decrement +>(num (dec num))
1304− ==
1305−::
1306−++ feel :> delta to rumor
1307− |= {qer/query del/delta}
1308− ^- (unit rumor)
1309− ?- -.qer
1310− $number
1311− `[%number del]
1312− ::
1313− $mul-of
1314− :: since we only want to send a rumor if result
1315− :: changed, we need to deduce the old state from
1316− :: the current state and the delta. depends on the
1317− :: fact that state changes before ++feel. funky!
1318− :: we could, of course, store mul/? in state, and
1319− :: make a delta for it, but should we need to?
1320− =/ old
1321− .= 0
1322− %+ mod
1323− ?- -.del
1324− $increment (dec num)
1325− $decrement +(num)
1326− ==
1327− mul.qer
1328− =/ new =(0 (mod num mul.qer))
1329− ?: =(old new) ~
1330− `[%mul-of new]
1331− ==
1332−::
1333−:: not pictured: ++path-to-query
1334−--
1335−```
arvo/sail-and-udon.mddeleted−1234
@@ -1,1234 +0,0 @@
1−+++
2−title = "Sail and Udon"
3−weight = 7
4−template = "doc.html"
5−aliases = ["docs/using/sail-and-udon/"]
6−+++
7−
8−Sail is Hoon markup that’s used to render a web page with XML. But what makes it special is that you can run arbitrary Hoon code within such a web page without using a separate markup language.
9−
10−Udon is a way to write content for the web. It's a minimalist markup language for creating and rendering text documents, with a Markdown-inspired syntax. It's integrated with our Hoon programming language, allowing it to be used as standalone prose in its own file or embedded inside a Hoon source file, in which case it will be parsed into a tree of HTML nodes using Sail.
11−
12−This document will be divided into two main sections: the Sail guide and the Udon guide. Also, you should read the Getting Started section below, which applies to both Udon and Sail.
13−
14−## Table of Contents
15−
16−- [Getting Started](#getting-started)
17−
18−- [Sail: A Guide](#sail)
19−
20−- [Udon: A Guide](#udon)
21−
22−## Getting Started {#getting-started}
23−
24−Before starting with either Sail or Udon, make sure that your ship is
25−[mounted to Unix](@/install.md)
26−
27−To host that output, your ship also has a web-server that can be found at
28−`localhost` (default port 80) if it’s your first ship that’s running on the
29−machine, `http://localhost:8081/` if it’s the second ship on that same machine,
30−and so on. In the startup messages, a ship will tell you which HTTP port it's
31−using.
32−
33−Udon and Sail files are often run as independent files (`.udon` and `.hoon`
34−respectively), but for the purpose of this guide, we will run them out of the
35−`frontpage.hoon` file located in the `/gen` directory. The default content of
36−`frontpage.hoon` is Sail code.
37−
38−To use `frontpage.hoon`, we use a `|serve` command like this one in your ship's
39−Dojo:
40−
41−```
42−|serve /test %home /gen/frontpage/hoon
43−```
44−
45−This command has three arguments:
46−- The first is the URL we want to bind our site to. We chose `/test`, so the URL
47−we will find our site at is `localhost/test`.
48−- The second is the desk we want to serve. We will be serving from `%home` in
49−this tutorial.
50−- The third is the file that we want to serve. In this tutorial, we will be
51−using `/gen/frontpage/hoon`, which refers to `frontpage.hoon`.
52−
53−Run the command `|serve /test %home /gen/frontpage/hoon`. Now navigate to
54−`localhost/test` (or `localhost:8081/test` if your ship is on that port) in your
55−browser, and you should see the rendered Sail.
56−
57−**Note:** Important to remember that every time you edit a file in your ship's
58−pier (Unix directory), including `frontpage.hoon`, you need to run `|commit %home`
59−to copy those changes to Urbit.
60−
61−## <a name="sail"></a>Sail: A Guide
62−
63−It’s easy to see how Sail can directly translate to HTML:
64−
65−### Sail code
66−
67−```
68−;html
69− ;head
70− ;title: My first webpage
71− ==
72− ;body
73− ;h1: Welcome!
74− ; Hello, world!
75− ; We're on the web.
76− ;div;
77− ;script@"http://unsafely.tracking.you/cookiemonster.js";
78− ==
79−==
80−```
81−
82−### HTML code
83−
84−```
85−<html>
86− <head>
87− <title>My first webpage</title>
88− </head>
89− <body>
90− <h1>Welcome!</h1>
91− Hello, world!
92− We’re on the web.
93− <div></div>
94− <script src="http://unsafely.tracking.you/cookiemonster.js"></script>
95− </body>
96−</html>
97−```
98−
99−You can test above Sail code by placing it
100−under `^- manx` in your `frontpage.hoon` file, and then running `|commit %home`
101−in the Dojo. If you've already run the `|serve` command code from the first
102−section, the new content should appear at `localhost/test`.
103−
104−It shouldn't be hard to see the similarities between Sail and HTML. So let's go
105−into more detail about what the differences are.
106−
107−### Tags and Closing
108−
109−In Sail, tag heads are written with the tag name prepended by `;`. Unlike in
110−HTML, there are different ways on closing tags, depending on the needs of the
111−tag. One of the nice things about Hoon is that you don’t have to be constantly
112−closing expressions; Sail inherits this convenience.
113−
114−#### Empty
115−
116−Empty tags are closed with a `;` following the tag. Example:
117−
118−```
119−;div;
120−```
121−
122−Equals:
123−
124−```
125−<div></div>
126−```
127−
128−#### Filled
129−
130−Filled tags are closed via line-break. To fill text inside, add `:` after the
131−tag name, then insert your plain text following a space. Example:
132−
133−```
134−;h1: The title
135−```
136−
137−Equals:
138−
139−```
140−<h1>The title</h1>
141−```
142−
143−#### Nested
144−
145−To nest tags, simply create a new line. Nested tags need to be closed
146−with `==`, because they expect a list of sub-tags. If we nest a line of plain
147−text with no tag, a `<p>` is prepended.
148−
149−Sail, like Hoon, is white-space sensitive. Unlike in Hoon, however, two spaces
150−(called a "gap") is not necessarily equivalent to a line-break in Sail.
151−
152−```
153−;body
154− ;h1: Blog title
155− This is some good content.
156−==
157−```
158−
159−Equals:
160−
161−```
162−<body>
163− <h1>Blog title</h1>
164− <p>This is some good content.</p>
165−</body>
166−```
167−
168−
169−Conversely, if we want to write a string with no tag at all, then we can prepend
170−those untagged lines with `;`.
171−
172−```
173−;body
174− ;h1: Welcome!
175− ; Hello, world!
176− ; We’re on the web.
177−==
178−```
179−
180−Equals:
181−
182−```
183−<body>
184− <h1>Welcome!</h1>
185− Hello, world!
186− We’re on the web.
187−</body>
188−```
189−
190−
191−#### Attributes
192−
193−Attributes are key-value pairs that go into an HTML node.
194−
195−Adding attributes is simple: just add the desired attribute between parentheses,
196−right after the tag name without a space. We separate different attributes of
197−the same node by using `,`.
198−
199−Attributes can be used in two forms: flat, which uses one line; and tall, which
200−uses multiple lines, when a single line would not be practical. Flat forms and
201−flat forms are two syntaxes of semantically equivalent expressions.
202−
203−
204−#### Generic
205−
206−The code below produces a “Submit” button on the page.
207−
208−Wide-form Sail:
209−
210−```
211−;input(type "submit", value "Submit");
212−```
213−
214−Tall-form Sail:
215−
216−```
217−;input
218− =type "submit"
219− =value "Submit";
220−==
221−```
222−
223−Equals:
224−
225−```
226−<input type="submit" value="Submit">`
227−```
228−
229−#### IDs
230−
231−```
232−;nav#header: Menu
233−```
234−
235−Equals:
236−
237−```
238−<nav id="header">Menu</nav>
239−```
240−
241−Add `#` after tag name to add an ID.
242−
243−#### Classes
244−
245−`;h1.text-blue: Title` equals `<h1 class="text-blue">Title</h1>`
246−
247−Add `.` after tag name to add a class. However, if you want a class name that
248−contains a space, you will need to use use the syntax of a generic attribute:
249−
250−`;div(class "logo inverse");` equals `<div class="logo inverse"></div>`
251−
252−
253−#### Image
254−
255−`;img@"example.png";`
256−
257−Equals
258−
259−`<img src="example.png"/>`
260−
261−Add `@` after the tag name to link your source.
262−
263−To add attributes to the image, like size specifications, add the
264−desired attribute after the `"` of the image name and before the final `;` of
265−the `img` tag.
266−
267−For example:
268−
269−`;img@"https://urbit.org/example.png"(width "100%");`
270−
271−#### Linking
272−
273−`;a/"urbit.org": A link to Urbit.org`
274−
275−Equals
276−
277−`<a href="urbit.org">A link to Urbit.org</a>`
278−
279−Add `/` after tag name to start an href.
280−
281−### Hoon in Sail
282−
283−Our first example is useful to understand how Sail syntax translates to HTML
284−syntax, but Sail finds its usefulness in the fact that it can be used seamlessly
285−with Hoon code.
286−
287−One place where Sail diverges from HTML is that it supports string
288−interpolation. In Sail, the contents of all tags are a string type called `tape`
289−unless otherwise designated. Tapes are delineated by the double quotes `""`.
290−That’s important, because tapes can be interpolated with Hoon expressions,
291−provided that those expressions produce something a tape as well. Interpolation
292−is done by wrapping the code to be inserted in `{}`. In your Dojo prompt, try
293−the command below (without the `>`):
294−
295−```
296−> "I am a l{(mul 3 11)}t Urbit user."
297−! exit
298−```
299−
300−Oh no! That command produced a nest-fail error, which indicates that there was
301−a problem related to Hoon type-system. We used the proper `{}` syntax for
302−interpolation, and we used the proper function-call syntax inside of it. So
303−what happened?
304−
305−Trying the `mul` function on its own will help answer this question. Try the
306−following command in your Dojo:
307−
308−```
309−> (mul 3 11)
310−33
311−```
312−
313−This should work, producing `33`, an atom. That’s our problem. The
314−interpolation expression expects a tape, but our first command tried to
315−interpolate with something that results in an atom. Try this now:
316−
317−```
318−> <(mul 3 11)>
319−"33"
320−```
321−
322−We get a similar result, but we know that it’s a tape because it’s wrapped in
323−`""`. Bingo! With this knowledge, let’s perform a successful interpolation:
324−
325−```
326−> "I am a l{<(mul 3 11)>}t Urbit user."
327−"I am a l33t Urbit user."
328−```
329−
330−Great!
331−
332−### The Subject
333−
334−The default subject of a Sail file is different from the subject that
335−expressions in the Dojo or a Hoon generator are evaluated against.
336−
337−To see this difference, first save the code below to a file at
338−`home/web/pages/sub.hoon` and view the rendering at
339−`http://localhost:8080/pages/sub`.
340−
341−```
342−;html
343− ;head;
344− ;body
345− {<.>}
346− ==
347−==
348−```
349−
350−Then enter the following command in the Dojo:
351−
352−```
353−> .
354−```
355−
356−You'll notice that the Sail subject is like a stripped-down version of the Dojo
357−subject. Its final line should match the Dojo subject.
358−
359−Now swap the code below into your Sail file.
360−
361−```
362−/= gas /$ fuel:html
363−;html
364− ;head;
365− ;body
366− {<.>}
367− ==
368−==
369−```
370−
371−You'll find that the resulting Sail subject is much larger. If you look closely,
372−you'll see that there's some new similarities with the Dojo subject, such as
373−containing the name of your ship. There's also some new differences, since
374−`fuel:html` contains things that are specifically useful for performing
375−web-related operations.
376−
377−### A More Interesting Example
378−
379−Now let’s apply knowledge of string interpolation and the Sail subject in a Sail
380−source file. The following code produces more interesting things than the
381−example we saw before.
382−
383−```
384−/= gas /$ fuel:html
385−=/ show-list &
386−=+ wid=(met 3 p.bem.gas)
387−=/ what-kind
388−?: (lte wid 1) "galaxy"
389−?: =(2 wid) "star"
390−?: (lte wid 4) "planet"
391−?: (lte wid 8) "moon"
392− "comet"
393−;html
394− ;head
395− ;meta(charset "utf-8");
396− ;title: A more advanced page
397− ==
398− ;body
399− ;h1: This is the Title
400− ; This is a
401− ;a/"http://urbit.org": link to Urbit.org.
402− ;span: Check it out!
403− ;+ ?: show-list
404− ;ol
405− ;li(style "color: green"): We're doing interesting stuff now.
406− ;li: We're pretty-printing this sum with Hoon: {<(add 50 50)>}.
407− ;li: The code above is shorthand for {(scow %ud (add 50 50))}.
408− ;li: I am {(trip '~lodleb-ritrul')}.
409− ;li: Actually, my name is {<p.bem.gas>}. I'm a {what-kind}.
410− ==
411− ;div: My name is {<p.bem.gas>}. I'm a {what-kind}.
412− ==
413−==
414−```
415−
416−Save the above Sail code in to `home/web/pages/secondsail.hoon` and access the
417−resulting page by navigating to `http://localhost:8080/pages/secondsail` in
418−your browser.
419−
420−There are some interesting things here. Let’s go through this code piece by
421−piece.
422−
423−```
424−/= gas /$ fuel:html
425−```
426−
427−Later in this code we want produce the name of the ship is hosting it, something
428−that looks like ~lodleb-ritrul. In a generator, we could produce our ship name
429−by writing `our` -- try it in the Dojo. But remember that Sail is rendered
430−against its own subject, `our` is not part of the default subject. To augment
431−our subject with the information that we need, we use `/= gas /$ fuel:html`.
432−
433−The above expression uses two Ford runes, `/=` and `/$`, to add the relevant
434−information to the current subject. We can pull the ship’s name out of this
435−augmented subject later. It's important to note that these runes are not part of
436−Hoon. They are part of Ford, our build system.
437−
438−`/$` is used to get data from the environment, and `/=` adds that data to
439−subject in the face `gas`. The
440−[Ford user manual](https://urbit.org/docs/arvo/internals/ford/runes/) has
441−details on these and other Ford runes, but understanding these runes isn’t
442−necessary for the purposes of this tutorial.
443−
444−`fuel:html` gets extra data from your ship’s Eyre module, which handles all
445−things HTTP, and sticks it in the subject when Eyre renders a page. This
446−includes the name of the ship, which is what we look for in the next line, but
447−it includes much more.
448−
449−`p.bem.gas` is an expression that looks for `p` within `bem` within `gas`, the
450−face that we stored the above `fuel:html` expression in. That wing happens to
451−resolve to the name of the ship that is hosting the web-server. If we wanted to
452−access the current desk, we would use the wing expression `q.bem.gas`.
453−
454−You can take a look at what you can access by typing `fuel:html` in the Dojo,
455−and then explore it by modifying your wing expression in your Sail file
456−accordingly.
457−
458−```
459−=/ show-list &
460−```
461−
462−The above line of code stores a variable used later for a conditional. `&` means
463−`true`, meaning that any evaluation of `show-list` will be true until changed in
464−the source code.
465−
466−```
467−=+ wid=(met 3 p.bem.gas)
468−=/ what-kind
469− ?: (lte wid 1) "galaxy"
470− ?: =(2 wid) "star"
471− ?: (lte wid 4) "planet"
472− ?: (lte wid 8) "moon"
473− "comet"
474−```
475−
476−This code chunk is a series of conditionals that checks the host ship’s name to
477−see what its value is.
478−
479−The first line, `=+ wid=(met 3 p.bem.gas)`, combines a new noun with the
480−subject and gives it the face `wid`. This noun is produced by the the
481−standard-library function [`met`](/docs/reference/library/2c), which measures the number of
482−[blocks](/docs/reference/library/1c/) of size `a` within `b`. Blocks are units that have a
483−bitwidth of `2^a`. So, in this case, it measures how many bytes (blocks of size
484−3 are bitwidths of 8; `2^3 = 8`) are fully contained in your ship's address.
485−
486−Galaxies contain zero to one 3-blocks; stars contain two 3-blocks; planets
487−contain three to four 3-blocks; moons contain five to eight 3-blocks; comets
488−contain nine to sixteen 3-blocks. Each test uses `lte`, the
489−less-than-or-equal-to function, to determine if `wid` is of a given size. The
490−result of this series of tests is added to the subject and given the face
491−`what-kind`.
492−
493−Ship names are simply another representation of atoms, and ship
494−categories are different ranges of possible atomic values. Because of this, we
495−perform less-than tests to see what kind of ship is running the web-server.
496−
497−```
498−;html
499− ;head
500− ;meta(charset "utf-8");
501− ;title: A more advanced page
502− ==
503−```
504−
505−Sail proper begins here. These four lines are four nodes. The `;html` node
506−indicates that the contained code should be rendered as HTML; this tag is closed
507−on the final line. The `;head` node contains metadata, and is closed three lines
508−later. The `;meta` node sets the character set to UTF-8, and the `;title` node
509−sets the title of the page that shows up in the browser tab.
510−
511−```
512− ;body
513− ;h1: This is the Title
514− ; This is a
515− ;a/"http://urbit.org": link to Urbit.org.
516− ;span: Check it out!
517−```
518−
519−The first line here opens, of course, the body node. The second line creates
520−header text.
521−
522−The third, fourth, and fifth lines of code here construct a single line with an
523−inline link.
524−`; This is a` begins the rendered line with plain text.
525−
526−`;a/"http://urbit.org": link to Urbit.org.` continues that same rendered line,
527−and creates hyperlinked text out of `link to Urbit.org.`
528−
529−`;span: Check it out!` continues that same rendered line further. `;span:`
530−has the same use as `<span>` in HTML, and by following it with just a `:` and no
531−attributes, it continues the line without formatting. Following `;span:` with
532−**two** spaces causes there to be single space following the produced `<span>`
533−element, because one of those spaces is syntactically necessary.
534−
535−In the following lines, we beginning to use some Hoon expressions again.
536−
537−```
538− ;+ ?: show-list
539− ;ol
540−```
541−
542−In the top line in the chunk above, we use the `;+` Sail rune, which
543−resolves an expression to a single node. That expression, in this case, is
544−`?:`, which tests the truth value of `show-list`, which we assigned the value
545−`&` (meaning “true”) at the beginning of the program. It’s closed by the `==` on
546−the last line.
547−
548−Thus, this program resolves to the first child of `show-list`, the node `;ol`.
549−That node creates an ordered list, and the items contained within that node.
550−
551−```
552− ;li(style "color: green"): We're doing more interesting stuff now.
553−```
554−
555−The line above is the only element of this list that does not use
556−Hoon proper. The line renders as green, as interpreted by the browser,
557−because of the Sail attribute.
558−
559−The next items in the list use `{}`. Recall that these braces, pronounced “lob”
560−and “rob” in Hoon-speak, allow for the interpolation of code within a string.
561−
562−```
563− ;li: We're pretty-printing this sum with Hoon: {<(add 50 50)>}.
564−```
565−
566−The line above is interpolated with Hoon code that produces the sum of 50 plus
567−50, which is wrapped in `<>` to put the product in double quotes to make it a
568−tape, like the rest of the line.
569−
570−
571−```
572− ;li: The code above is shorthand for {(scow %ud (add 50 50))}.
573−```
574−
575−The `{(scow %ud (add 50 50)}` on this line is just a different way
576−writing the `{<(add 50 50)>}` expression. `scow` is a Hoon function that turns a
577−noun into a `tape`, Hoon’s string type. `%ud` tells `scow` that its argument
578−should be displayed in the form of an unsigned decimal.
579−
580−
581−```
582− ;li: I am {(trip '~lodleb-ritrul')}.
583−```
584−
585−`trip` is a function that takes a `cord` and produces a `tape`. A piece of
586−data of the cord type is one big atom formed from adjacent unicode bytes and
587−delineated by `''`. Remember that all text rendered in Sail is treated as a
588−tape. So, by converting `~lodleb-ritrul` to a tape, it can be included in the
589−tape that we are trying to insert it into without getting a type error.
590−
591−```
592− ;li: Actually, my name is {<p.bem.gas>}. I'm a {what-kind}.
593− ==
594−```
595−
596−The line above has interpolated code that uses a wing expression to access the
597−name of the host ship, and then accesses the face `what-kind` contains a string
598−describing what type of ship it is. We declared `gas` on the very first line so
599−that we could add that sort of information to the subject that our Sail is
600−rendered against. The wing expression `p.bem.gas` looks for `p` within `bem`
601−within `gas`, which happens to be where the name of the ship is located.
602−
603−Note that `{what-kind}` does not have a `<>` wrapper. Why do you think this is?
604−
605−```
606− ;div; My name is {<p.bem.gas>}. I'm a {ship}.
607− ==
608−==
609−```
610−
611−The `;div;` node above is only rendered, as an alternative to the above list,
612−if `show-list` is evaluated as true. This means it won’t be shown with your
613−default code. To show this line, change the `&` on line 2 to `|` (“false”).
614−
615−### Sail Runes
616−
617−In the previous example, we used a few special runes that aren’t used in typical
618−Hoon code. But there are others that are worth learning about at this point.
619−
620−`;+` is an expression that resolves to a single node. We saw this on line 20
621−in our Sail example above: `;+ ?: show-list` resolves to the node `;ol` and
622−all of that node’s children.
623−
624−`;*` is an expression that resolves to a list of nodes. If we want to render
625−multiple nodes side-by-side, and not just the children of a single node, this
626−is the expression that we use.
627−
628−`;=` turns a tuple of nodes into a list of nodes.
629−
630−
631−To see how these runes work, let’s take a chunk of our previous code starting at
632−line 20 and modify it a bit:
633−
634−```
635− ;* ?: show-list
636− ;=
637− ;li: I am {(trip '~lodleb-ritrul')}.
638− ;li: Actually, my name is {<p.bem.gas>}.
639− ==
640− ;=
641− ;div: My name is {<p.bem.gas>}. I'm a {what-kind}.
642− ;div: No list here!
643− ==
644− ==
645−```
646−
647−We changed the conditional branches so that each contains two Sail nodes,
648−side-by-side -- notice that the `;ol` is absent from the first branch.
649−
650−We begin with the `;*` rune, which resolves to a list of nodes, instead of the
651−`;+` rune, which only resolves to a single node.
652−
653−But that’s not enough on its own. `;*` needs to resolve to a list, and a few
654−Sail nodes aren’t lists until they are explicitly made into lists. Until we wrap
655−those nodes in `;=`, the nodes treated as mere tuples. All branches must be
656−valid lists for the `;* ?: show-list` expression to resolve.
657−
658−### Further Reading
659−
660−You should now have foundational knowledge for making web pages with Sail. There
661−is, of course, more to learn.
662−
663−The [Ford manual](https://urbit.org/docs/arvo/internals/ford/runes/)
664−can show you how to access various ship resources for user in your pages. To
665−learn more about how the renderer works, take a look at the
666−`/home/ren/urb.hoon` file inside your urbit.
667−
668−## Udon: A Guide {#udon}
669−
670−Udon is a way to write content for the web. It's a minimalist
671−markup language for creating and rendering text documents, with a
672−Markdown-inspired syntax. It's integrated with our Hoon programming language,
673−allowing it to be used as standalone prose in its own file or embedded inside a
674−Hoon source file, in which case it will be parsed into a tree of HTML nodes
675−using Hoon's XML-templating syntax, Sail.
676−
677−There are quite a few similarities between Udon and the
678−CommonMark standard, but there are enough differences that you shouldn't rely on
679−existing knowledge of the latter. Udon generally supports only one
680−syntax for each type of HTML node it emits. Udon is also stricter than
681−Markdown: some syntax errors will prevent the file from being parsed at all.
682−
683−## Testing Udon
684−
685−Udon files use the `.udon` file extension, but for this entry-level guide, we
686−will use the `frontpage.hoon` method that we are already familiar with.
687−
688−To test out Udon, put a `;>` under the `^- manx` in your `frontpage.hoon` file,
689−and then put all your Udon code under that `;>`. Then run `|commit %home`
690−in the Dojo. If you've already run the `|serve` command code from the first
691−section, the new content should appear at `localhost/test`.
692−
693−## Udon Syntax
694−
695−### Front Matter
696−
697−> Note: The Front Matter section only applies to .udon files, and not the
698−frontpage.hoon testing method.
699−
700−The first thing on a `.udon` file is a chunk of code called the front matter. It
701−contains metadata about your page, such as date, title, and position relative
702−to sibling pages.
703−
704−As an example, let's look at the front matter of this very page:
705−
706−```
707−:- :~ navhome/'/docs/'
708− sort/'11'
709− title/'Udon'
710− ==
711−;>
712−```
713−
714−What's going on here?
715−
716−`:-`, the Hoon rune for creating a cell, creates a cell composed of
717−the `:~` Hoon rune for creating a list, and `;>`, which is a Sail rune
718−for Udon.
719−
720−`:~` creates a list out of the three elements: `navhome/'/docs/'`, which
721−indicates that navigating "home" will bring you to the urbit.org/docs section
722−of the website; `sort/'28',` which assigns it the 28th position of the
723−immediate section that contains it, the one you see in the sidebar;
724−and `title/'Udon'`, which gives the page its title. The `==` digraph
725−terminates the list.
726−
727−`;>` is a Sail rune that creates a node that contains everything that follows
728−it, telling the parser that that text should be interpreted as Udon.
729−It's not technically front matter, but you'll always find it following the
730−front matter, since all Udon must come after this rune.
731−
732−The categories listed in the example above -- `navhome`, `sort`, and `title` --
733−make sense to Eyre by default, but any arbitrary category can be used. The code
734−below is valid front matter.
735−
736−```
737−:- :~ date/~2018.9.12
738− author/~lodleb-ritrul
739− music/'rad'
740− ==
741−```
742−
743−Note that `~2018.9.12`, `~lodleb-ritrul`, and `'rad'` are all of of atom
744−types: `@da`(date), `@p` (ship name), and `@t` (cord), respectively. Only atom
745−types work here. Having `music/"rad"` would prevent the source file from
746−parsing.
747−
748−### Headers
749−
750−Headers in Udon begin the line with one or more `#` characters,
751−followed by a single space. After that space comes the actual text to be
752−displayed. The number of leading `#`s corresponds to the resulting HTML
753−header-size element: `#` yields an `<h1>`, `##` yields an `<h2>`, and so on,
754−through `<h6>`. The header for this section is `### Headers`.
755−
756−**Example:**
757−```
758−#### Header (h4)
759−
760−##### Header (h5)
761−```
762−**Produces:**
763−
764−#### Header (h4)
765−
766−##### Header (h5)
767−
768−### Italics and Bold
769−
770−Enclosing text with `_` will cause that text to appear italicized, using an `<i>`
771−element.
772−
773−Enclosing text with `*` will cause that text to appear bolded, using a `<b>`
774−element.
775−
776−
777−**Example:**
778−
779−```
780−To get their *attention*, you need that _je ne sais quoi_.
781−```
782−
783−**Produces:**
784−
785−To get their **attention**, you need that _je ne sais quoi_.
786−
787−### Line Break
788−
789−A blank line is interpreted as a line break, creating a distinct
790−paragraph. However, a newline on its own is merely interpreted as a space on
791−the _same line_.
792−
793−**Example:**
794−
795−```
796−Here's the first line.
797−
798−This second line is separated by two newlines, so it's a separate paragraph.
799−
800−This line looks like a distinct paragraph, but...
801−It's only separated by a single newline, so it's included in the same paragraph.
802−```
803−**Produces:**
804−
805−
806−Here's the first line.
807−
808−This second line is separated by two newlines, so it's a separate paragraph.
809−
810−This line looks like a distinct paragraph, but...
811−It's only separated by a single newline, so it's included in the same paragraph.
812−
813−#### Backslash Line Break
814−
815−A backslash at the end of a line inserts a line break (`<br>`)
816−after that line. This contrasts with the normal udon behavior of
817−converting newlines to spaces.
818−
819−**Example:**
820−```
821−I wonder how long each line
822−will be if I put backslashes\
823−at the ends of the lines.
824−```
825−**Produces:**
826−
827−I wonder how long each line
828−will be if I put backslashes\
829−at the ends of the lines.
830−
831−### Escape
832−
833−A backslash directly _before_ a word (with no spaces) will be interpreted
834−as an escape character, causing it to be rendered raw.
835−
836−**Example:**
837−
838−```
839−Here is some *bold* text.
840−Here is some \*not bold* text.
841−```
842−
843−**Produces:**
844−
845−Here is some **bold** text.
846−Here is some \*not bold* text.
847−
848−
849−### List
850−
851−A line beginning with a `-` followed by a space is interpreted as an
852−element of an **unordered list** (`<ul>`). Each line in an unordered list is
853−prepended with a bullet point.
854−
855−A line beginning with a `+` followed by a space is interpreted as an element
856−of an **ordered list** (`<ol>`). Each line in an ordered list is prepended with
857−a number corresponding to its position in that list.
858−
859−New list elements are delineated by newlines beginning with list symbols of
860−the appropriate type (`-` or `+`).
861−
862−Just as with non-list text, text on a bare newline will appear on line before,
863−separated by a space. A `\\` is used to create a line-break that isn't the list
864−itself and isn't a list. Both of these kinds of newlines must be indented by two
865−spaces, or else the page will not parse.
866−
867−Indentation is also used for creating nested sub-lists. Sub-lists of one kind
868−can be used with parent lists of the other kind. Sub-lists can't be nested
869−directly after either kind of aforementioned newline that isn't a list element;
870−only lines that are themselves list elements can nest sub-lists.
871−
872−A newline after a blank line is interpreted as a new paragraph in normal text.
873−Between to list elements, however, a blank line is semantically equivalent to
874−a bare newline. To separate two lists with blank space, create a blank line
875−followed by a `\\` on its own line.
876−
877−**Example:**
878−
879−```
880−- Eggs
881− (cage-free)
882−- Milk
883−- Butter
884−- Chicken\
885− Make sure that you get enough for the barbecue
886−- Bread
887− + Ask the baker what's fresh
888− + Buy the second-freshest batch
889−- Cereal
890−
891−\
892−+ First, separate eggs into a bowl
893−+ Then, add a splash of cream
894− - If you don't have cream, you can use milk, but cream is preferred
895− + If you don't have milk or cream, melt an eighth of a stick of butter on
896− a skillet
897− + Scramble the eggs in the bowl
898− + Pour the eggs onto the skillet before the butter browns
899−+ Heat the skillet
900−
901−+ Scramble eggs and put them into skillet
902−
903−\
904−+ Cool
905−+ Alright
906−```
907−
908−Produces
909−
910−- Eggs
911− (cage-free)
912−- Milk
913−- Butter
914−- Chicken\
915− Make sure that you get enough for the barbecue
916−- Bread
917− 1. Ask the baker what's fresh
918− 1. Buy the second-freshest batch
919−- Cereal
920−
921−\
922−1. First, separate eggs into a bowl
923−1. Then, add a splash of cream
924− - If you don't have cream, you can use milk, but cream is preferred
925− 1. If you don't have milk or cream, melt an eighth of a stick of butter on
926− a skillet
927− 1. Scramble the eggs in the bowl
928− 1. Pour the eggs onto the skillet before the butter browns
929−1. Heat the skillet
930−
931−1. Scramble eggs and put them into skillet
932−
933−\
934−1. Cool
935−1. Alright
936−
937−### Link
938−
939−There are two ways to create links, but both contain the text be hyperlinked
940−in `[]` followed by the destination in `()`.
941−
942−The first type is an inline-style link, which simply uses the full URL as its
943−destination.
944−
945−**Example:**
946−
947−```
948−[I'm an inline-style link](https://urbit.org/operations/#using-the-shell)
949−```
950−
951−**Produces:**
952−
953−[I'm an inline-style link](https://urbit.org/operations/#using-the-shell)
954−
955−The second type is a reference-style link, which uses a relative path, based on
956−the current page's location. Instead of the full url, we use `..` to fill in
957−the all of the URL that the destination has in common with the origin page.
958−
959−**Example:**
960−
961−```
962−[I'm a reference-style link](../shell)
963−```
964−
965−**Produces:**
966−
967−[I'm a reference-style link](../shell)
968−
969−If this page is located at `https://www.urbit.org/docs/reference/`, then these two
970−examples should have the same destination.
971−
972−#### Anchor Link
973−
974−A link to a section of the same page is in the style of
975−`[text to be linked](#the-destination)`.
976−
977−The destination for the anchor link is designated with the HTML element `id`,
978−so we need to use some [Sail](#sail). If there are two or more anchors with
979−the same `id` on the page, you will arrive at the earliest instance of the the
980−anchor.
981−
982−**Example:**
983−
984−```
985−Check out this [section](#here-we-are) that we want to jump to.
986−
987−Four score and seven years ago....
988−
989−It was the best of times, it was the worst of times...
990−
991−## Here we are!
992−```
993−
994−**Produces:**
995−
996−Check out this [section](#here-we-are) that we want to jump to.
997−
998−Four score and seven years ago....
999−
1000−It was the best of times, it was the worst of times...
1001−
1002−## Here we are!
1003−
1004−### Double Quote
1005−
1006−Text enclosed in double quotes (`"`) will be rendered with
1007−opening and closing quotes -- that is, `“` and `”`.
1008−
1009−**Example:**
1010−```
1011−"Yes," he said. "That is the way with him."
1012−```
1013−
1014−**Produces:**
1015−
1016−“Yes,” he said. “That is the way with him.”
1017−
1018−
1019−### Code Literal
1020−
1021−There are two ways to show the literal text of code without running it: inline
1022−and block. Both highlight the contained text in another color.
1023−
1024−Note that the backslash, due to its role as the escape character, can only be
1025−displayed in a code block literal and not as inline code literal. This is a
1026−bug.
1027−
1028−```
1029−\
1030−```
1031−
1032−#### Inline Code Literal
1033−
1034−Enclosing some text in `` ` `` characters will cause it to be displayed as code,
1035−inside a `<code>` HTML element with monospace font and highlighted with a
1036−different background color.
1037−
1038−Using `` ` `` is useful when you want to designated only part of a line as code.
1039−Since this page is written in Udon, we've been using this operation
1040−throughout this guide to `format text` to distinguish code from prose.
1041−
1042−**Example:**
1043−```
1044−`*[a 2 b c] -> *[*[a b] *[a c]]` is like lisp's `apply`.
1045−```
1046−**Produces:**
1047−
1048−`*[a 2 b c] -> *[*[a b] *[a c]]` is like lisp's `apply`.
1049−
1050−Also, using the `++` prefix before a word will cause the word to be rendered as
1051−code with the `++` displayed, since that's the standard notation for an arm in
1052−Hoon.
1053−
1054−**Example:**
1055−
1056−```
1057−The ++add arm is used to sum two numbers.
1058−```
1059−
1060−**Produces:**
1061−
1062−The `++add` arm is used to sum two numbers.
1063−
1064−#### Block Code Literal
1065−
1066−By enclosing a block of text in a tick on their own lines
1067−before and after the contained text, the text will be treated as a code block.
1068−
1069−Most of our examples so far have used.
1070−
1071−**Example:**
1072−
1073−
1074− ```
1075− (def Y (fn [f]
1076− ((fn [x]
1077− (x x))
1078− (fn [x]
1079− (f (fn [y]
1080− ((x x) y)))))))
1081− ```
1082−
1083−**Produces:**
1084−
1085−```
1086−(def Y (fn [f]
1087− ((fn [x]
1088− (x x))
1089− (fn [x]
1090− (f (fn [y]
1091− ((x x) y)))))))
1092−```
1093−
1094−### Hoon Constants
1095−
1096−Hoon has several syntactic forms for literals (numbers, strings, dates, etc.)
1097−that can be used in udon as well. Udon detects such code, and so these
1098−forms will automatically appear inside a `<code>` element like inline code.
1099−
1100−Example:
1101−
1102−```
1103−~2017.8.29 \
1104−0xdead.beef \
1105−%term
1106−```
1107−
1108−produces:\
1109−
1110−`~2017.8.29` \
1111−`0xdead.beef` \
1112−`%term`
1113−
1114−
1115−### Horizontal Rule
1116−
1117−Three or more hyphens, such as `---`, on their own line produce an `<hr>`
1118−element, the 'horizontal rule'. This is rendered as a horizontal line the
1119−width of its containing paragraph.
1120−
1121−**Example:**
1122−
1123−```
1124−Above the line
1125−---
1126−Below the line
1127−-----
1128−And below this line, too
1129−```
1130−
1131−**Produces:**
1132−
1133−
1134−Above the line
1135−
1136−---
1137−
1138−Below the line
1139−
1140−-----
1141−
1142−And below this line, too
1143−
1144−### Block Quote
1145−
1146−A section of text with the first line beginning with `>` and a space,
1147−and each successive newline indented by two spaces yields a
1148−`<blockquote>` HTML element. This block quote can itself contain more Udon,
1149−including more block quotes to render nested levels of quotation.
1150−
1151−Blank newlines do not end the block quote, but a blank newline followed by an
1152−unindented line of text _will_ end the quote.
1153−
1154−**Example:**
1155−
1156−```
1157−> As Gregor Samsa awoke one morning from uneasy dreams, he
1158− found himself transformed in his bed into a *monstrous* vermin.
1159−
1160−Quote break.
1161−
1162−> _See_ the child.
1163−
1164− He is pale and thin, he wears a thin and ragged linen shirt.
1165−```
1166−
1167−**Produces:**
1168−
1169−> As Gregor Samsa awoke one morning from uneasy dreams
1170− he found himself transformed in his bed into a **monstrous** vermin.
1171−
1172−Quote break.
1173−
1174−> _See_ the child.
1175−
1176−> He is pale and thin, he wears a thin and ragged linen shirt.
1177−
1178−
1179−### Poem
1180−
1181−A poem is a section of text with meaningful newlines. Recall that,
1182−normally in Udon, newlines are treated as spaces and do not create a
1183−new line of text. If you want to embed text where newlines are retained, then
1184−indent the text in question with **eight spaces**.
1185−
1186−**Example:**
1187−
1188−```
1189− A shape with lion body and the head of a man,
1190− A gaze blank and pitiless as the sun,
1191− Is moving its slow thighs, while all about it
1192− Reel shadows of the indignant desert birds.
1193−```
1194−**Produces:**
1195−
1196− A shape with lion body and the head of a man,
1197− A gaze blank and pitiless as the sun,
1198− Is moving its slow thighs, while all about it
1199− Reel shadows of the indignant desert birds.
1200−
1201−
1202−## Sail Expressions
1203−
1204−It's possible to use Udon as an HTML templating language akin to
1205−PHP, ERB, JSP, or Handlebars templates. This facility derives
1206−in part from the support for embedding Hoon code inside the markup.
1207−
1208−
1209−Sail is a domain-specific language within Hoon for creating XML nodes,
1210−including HTML. It can be used directly within Udon to provide
1211−scripting capability with Hoon and also to provide more precise control over the
1212−resulting HTML. The [Sail guide](#sail) is a good place to learn the
1213−specifics.
1214−
1215−Example:
1216−
1217−```
1218−;=
1219− ;p
1220− ;strong: Don't panic!
1221− ;br;
1222− ;small: [reactive publishing intensifies]
1223− ==
1224−==
1225−```
1226−
1227−Produces:
1228−
1229−
1230−<p>
1231− <strong>Don't panic!</strong>
1232− <br>
1233− <small>[reactive publishing intensifies]</small>
1234−</p>
arvo/ship-troubleshooting.mddeleted−174
@@ -1,174 +0,0 @@
1−+++
2−title = "Ship Troubleshooting"
3−weight = 8
4−template = "doc.html"
5−aliases = ["docs/using/ship-troubleshooting/"]
6−+++
7−
8−Urbit is still in the development stage, so there's a chance that your ship won't start properly, or will stop working properly when you. That's ok! This document is intended to help you in such an event.
9−
10−## Table of Contents
11−
12−- [Best practices](#best-practices)
13−- [Operation issues](#operation-issues)
14−- [Connectivity issues](#connectivity-issues)
15−- [Booting issues](#booting-issues)
16−- [Crashing issues](#crashing-issues)
17−
18−## Best Practices {#best-practices}
19−
20−An ounce of prevention is worth a pound of cure, so let's first go over some best practices to keep your ship in working order.
21−
22−**Only boot with your keyfile once.** Once your ship is booted with your keyfile, you should never use that same keyfile again. If you do boot with the same keyfile twice, any other ship on the network that your ship has communicated with will never be able to talk to it again.
23−
24−If you accidentally booted with the same keyfile twice, the only remedy is performing a [personal breach](#personal-breach), which is explained in the next section.
25−
26−**Do not delete your pier.** Urbit is stateful, meaning that it needs to hold onto all your data. If you delete your pier and start your ship again, you won't be able to talk to any ship you've talked to before. The only solution to this is performing a [personal breach](#personal-breach)
27−
28−**Keep track of the directory that you put your ship in.** When you first start your ship, you should make sure you put it a place where you can find it again and where it won't get accidentally deleted. Remember that you must perform `|mount %` in your ship's Dojo to make your ship visible as a directory in the Unix file system.
29−
30−**Avoid killing the Urbit process directly.** The best way to end an urbit process is to use `ctrl-d` from the Dojo. Unix methods to kill the process, such as with `ctrl-z` or with the `kill` Bash command, or simply closing the window, should only be used if `ctrl-d` does not work.
31−
32−**Keep up-to-date builds.** Check for latest Urbit version at https://github.com/urbit/urbit/releases. If you're behind, update using [this guide](/operations/)
33−
34−**`|hi` your star to see if you're connected.** Find out who your star is by running `(sein:title our now our)` in the Dojo. Then, run `|hi ~star`, where `~star` is the star's name, and if things are working properly, you should get the message `hi ~star successful`. It could also be helpful to use `|hi` to check connectivity with `~zod` or another planet that you're in a Talk channel with.
35−
36−**Turn your ship off and on again.** Use `ctrl-d` to gracefully exit your ship, and then start it again. This can solve many issues.
37−
38−### Perform a personal breach. {#personal-breach}
39−
40−A breach is when ships on the network reset their continuity. The breaching ship clears its own event log and sends an announcement to the network, asking all ships that have communicated with it to reset its networking information in their state. This makes it as though the ship was just started for the first time again, since everyone has network has forgotten about it.
41−
42−Personal breaches often fix connectivity issues, but should only be used as a last resort.
43−
44−## Operation Issues {#operation-issues}
45−
46−### My urbit is very slow
47−
48−Run `|wash-gall`. This clears caches in Gall, and may result in steep performance improvements.
49−
50−### My urbit is frozen
51−
52−Sometimes this happens if you're processing a very large event, or if you're in an infinite loop, or for a variety of other reasons.
53−
54−Before doing anything, try waiting for a minute: an event might finish processing. If it doesn't clear up, then use Unix kill-command, `ctrl-z`, to end your ship's process. Then restart your ship.
55−
56−### When I try to type into the Dojo, it prints `dy-noprompt`
57−
58−This happens when your Dojo is waiting on a request, such as an HTTP request. You can fix it simply by typing `backspace` or (`delete` on Mac).
59−
60−### My ship doesn't recognize file changes that I make in my pier
61−
62−Since version `0.8.0`, changes no longer automatically sync between the Unix side (your pier) and your ship. To sync your file changes, you must run `|commit %desk` in your Dojo, where `%desk` is the desk you'd like to sync.
63−
64−## Connectivity Issues {#connectivity-issues}
65−
66−### I can `|hi` my sponsor star, but I cannot get syncs from it or discover peers
67−
68−This means you have one-way connectivity with your star, with your star being unable to send your messages; many connectivity problems are derived from this. Run `|nuke ~star`, where `~star` is your sponsor star in the Dojo. Then run `|nuke ~star` again. This can solve various communication problems. You can find your sponsor by running `(sein:title our now our)`.
69−
70−### I can't communicate with anyone
71−
72−You may have booted a ship with your keyfile twice in the same era. To fix this, you must perform a [personal breach](#personal-breach).
73−
74−### I keep getting an `ames` error stack-trace
75−
76−You may see a message like this one: `/~zod/home/~2019.7.22..18.55.46..83a3/sys/vane/ames:<[line column].[line column]>`. This is a clay path to a Hoon file, pointing to the line and column where an expression crashed. This kind of error might be accompanied by a `crud` message.
77−
78−This means that another ship is sending invalid packets to you. This could be because one of the ships has not updated the other ship's "life number," which is the number that starts at one and increments every time that ship performs a personal breach.
79−
80−This can happen if they have the wrong keys of yours, or if you have the wrong keys of theirs. You can figure out who has the wrong keys by running this scry command in your dojo: `.^(* %j /=life=/shipname)`, where shipname is the other ship's name. Save that information. Then, go to the [Azimuth contract on Etherscan](https://etherscan.io/address/0x223c067f8cf28ae173ee5cafea60ca44c335fecb#readContract), scroll down to `32. points`, and put in the hexadecimal representation of the other ship's `@p`. You can find the hexadecimal representation by running...
81−
82−```
83−`@ux`~sampel-palnet
84−```
85−
86−in the Dojo, where `~sampel-palnet` is the other ship's name. Then, compare it to the scry information that you saved. If that information matches up, it means that the other ship is the problem. If it **doesn't** match up, your ship has wrong information about the other ship. If you have such wrong information, you can fix this by running:
87−
88−```
89−|start %eth-manage
90−:eth-manage %look-ethnode
91−```
92−
93−If they have wrong keys of yours, you need to somehow ask them to to run that same command.
94−
95−### I can talk to some ships, but I can't talk to my sponsor and some other ships
96−
97−This is the result of deleting your pier and starting your ship again. To fix this, you must perform a [personal breach](#personal-breach).
98−
99−### I have two ships, and only one can connect with the other
100−
101−One-way connectivity (OWC) means that ship `~A` can't `|hi` ship `~B`, but ship `~B` can `|hi` ship `~A`. If you have two ships that are suffering from this problem, it can be solved by a series of steps.
102−
103−1. Turn both ships off and on again. This sometimes solves this problem.
104−
105−2. On ship `~B` -- the ship that can connect to the other -- `|nuke ~A`, where `~A` is the ship that cannot `|hi` the other. Wait several minutes. Do you see any messages in your console? If not, try sending a `|hi ~A` from `~B`. If “blocked” or similar messages start appearing, `|nuke ~A` again to unblock, and check if connectivity has been restored.
106−
107−3. If you can’t get any packets to be sent to `~B`, you’re going to have to temporarily modify your ship’s Ames to trick it into sending packets. Make sure to do this on its home desk so as to not impact any syncs. Open `~A/home/sys/vanes/ames.hoon` and find `++ harv`. Just above `(gth caw nif) check`, insert the a line of this code: `=? caw =(caw nif) +(caw)`. Save the file and run `|commit %home`.
108−
109−4. Try running `|hi ~B`. Wait a bit. Are you seeing `%blocked` or `%bad-ack` messages yet? If not, send another `|hi ~B`.
110−
111−5. Once the messages start rolling in, revert the Ames change that you made on `~A` in step 3. Then `|nuke ~A` again from `~B`. Wait a little bit, then check if this resolved the OWC.
112−
113−6. If the OWC is still not resolved, try step 6.
114−
115−7. Be patient. After following these steps, your |hi may still not go through instantly even though OWC has silently been fixed: there could be something like a very large sync queued up.
116−
117−## Booting Issues {#booting-issues}
118−
119−### My ship won't boot and gets a `terminals database is inaccessible` message
120−
121−This happens when you try to run the Urbit binary through your `$PATH`. When running the command, you need to be explicit and specify the actual path to it in the filesystem. This is a side-effect of the way we build the release binaries, which will be fixed.
122−
123−### My ship booted for the first time, but it turned into a comet instead of my planet or star
124−
125−You may have used the wrong arguments when booting your ship for the first time. Delete this comet and try again.
126−
127−### My development ship ("fakezod") gets a `boot: malformed` failure
128−
129−This means that you gave your development ship an invalid `@p`. So, you will get this error if you write, for example, `urbit -F zodzod` instead of `urbit -F zod`.
130−
131−## Crashing Issues {#crashing-issues}
132−
133−### I got a `bail` error and my ship crashed
134−
135−Try just bringing it back up; it will often start working just fine again.
136−
137−However, if you get a `bail` error again, you should perform a personal breach.
138−
139−#### Making a GitHub issue out of your `bail`
140−
141−You can get help with you problem by creating an issue at github.com/urbit/urbit. But to make a good issue, you need to include some information.
142−
143−When your urbit crashes with a `bail`, you'll probably get a core dump, which is a file that contains the program state of your urbit when it crashed. On Mac, core dumps can be found in `/cores`. On Linux, cores can often be found in `/var/crash`, or the home directory.
144−
145−Navigate to the folder containing your core dumps. Find the most recent core dump by looking at the dates after you run `ls -l`. Then `lldb -c <corename>`. Once that loads, you'll be at an `(lldb)` prompt; type `bt` at this prompt. This will create a stack trace that looks like this:
146−
147−```
148−(lldb) bt
149−* thread #1, stop reason = signal SIGSTOP
150− * frame #0: 0x000000010583d871 urbit`_box_free + 17
151− frame #1: 0x0000000105845ee6 urbit`u3j_boot + 182
152− frame #2: 0x000000010584d1f9 urbit`u3m_boot + 89
153− frame #3: 0x000000010583d15d urbit`main + 2765
154− frame #4: 0x00007fff75cb83d5 libdyld.dylib`start + 1
155−(lldb)
156−```
157−
158−Copy this stack trace and include it in your GitHub issue.
159−
160−### My ship crashed with a `bail: meme` error.
161−
162−1. Make sure you are running version to `0.8.2` if you are not already on it.
163−
164−2. Restart your ship. If you don't crash again, everything may be fine. If you **do** crash again, then you should perform a [personal breach](#personal-breach).
165−
166−### My ship crashed with a `bail: oops` error
167−
168−Restart your ship. These issues often just go away on their own. If this error repeats after restart two or more times, post the messages in an issue at github.com/urbit/urbit/issues.
169−
170−This same error might also appear with a message like `Assertion '0'`.
171−
172−### My ship crashed with an `pier: work error` error
173−
174−This means that the Urbit worker process has shut down for one reason or another. Just restart your ship; this is not a notable or reportable error.
azimuth/_index.mddeleted−5
@@ -1,5 +0,0 @@
1−+++
2−title = "Azimuth"
3−weight = 1
4−template = "sections/docs/chapters.html"
5−+++
azimuth/azimuth.mddeleted−12
@@ -1,12 +0,0 @@
1−+++
2−title = "Azimuth"
3−weight = 2
4−template = "doc.html"
5−aliases = ["/docs/learn/azimuth"]
6−+++
7−
8−Azimuth is a general-purpose public-key infrastructure (PKI) on the Ethereum blockchain, used as a decentralized ledger for Urbit identities that we call **Urbit identities**. Having an identity is necessary to use the Urbit network, which makes it important to have a neutral ledger to determine who owns what.
9−
10−Azimuth is not, however, part of the Arvo stack. Azimuth is a parallel system that be used as a generalized identity system for other projects. Azimuth "touches" the Urbit ecosystem when an identity is used to boot a virtual computer on the Urbit network for the first time. When that happens, the identity considered **linked** to Azimuth and the identity’s full powers are available for use. Once an identity is linked, it cannot be unlinked.
11−
12−A metaphor might make the relationship between these two systems easier to understand: Azimuth is the bank vault that stores the deed to your house. The Urbit network is the neighborhood that you live in.
azimuth/creating-an-invite-pool.mddeleted−41
@@ -1,41 +0,0 @@
1−+++
2−title = "Creating an Invite Pool"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−If you’re a star owner, you have the ability to create **invite pools**. These invite pools let you give your friends a piece of the network in the form of planets. This document will give you an explanation of how to create an invite pool and how to share it with your friends using our tool [Bridge](bridge.urbit.org).
8−
9−## Anatomy of an Invite Pool
10−
11−An invite pool is a set of planet invites that can be distributed via email; each invite is worth one planet when redeemed. An invite pool can be as big as you’d like, providing that you have enough planets left to spawn. All invite pools must be created by a star, but they must be given to a planet. If you’re interested in how this works technically, take a look at the [DelegatedSending.sol contract](https://github.com/urbit/azimuth/blob/master/contracts/DelegatedSending.sol).
12−
13−Keep in mind that all planets will have access to the invite pool until the invite pool expires.
14−
15−For example: As `~marzod`, I spawn `~wicdev-wisryt` and give it an invite pool of 100 planets. `~wicdev-wisryt` can now send an invite to a friend at galen@tlon.io. When Galen claims his planet (`~ravmel-ropdyl`), `~ravmel-ropdyl` can now invite his friend — or 99 of them.
16−
17−## How to Invite Friends
18−
19−Giving your friends a piece of Urbit only takes a few minutes: spawn a planet, send it an invite pool, and use that planet to email an invite to a friend (or friends)
20−
21−1. Log into Bridge using your ownership address for your star.
22−
23−2. Go to Admin > Edit Permissions and copy your ownership address.
24−
25−![](https://storage.cloud.google.com/media.urbit.org/docs/invite-pool/browser-settings.png)
26−
27−3. Spawn a planet to the same ownership address as your star (for the sake of convenience).
28−
29−4. Click “Manage Invite Pools” to assign an invite pool to the planet you just spawned. You may receive a notification that you need to assign your spawn proxy to the address of the Delegated Sending contract. This is so that the contract can send invites on your behalf when the recipient claims them.
30−
31−![](https://storage.cloud.google.com/media.urbit.org/docs/invite-pool/browser-point.png)
32−
33−5. Enter the planet name and the number of invites you’d like to assign them.
34−
35−![](https://storage.cloud.google.com/media.urbit.org/docs/invite-pool/browser-create-pool.png)
36−
37−The planet you created should be accessible from the Bridge homepage. Click the Planet, then “Invite” to create invites for your friends.
38−
39−![](https://storage.cloud.google.com/media.urbit.org/docs/invite-pool/browser-invite.png)
40−
41−Your friend will get an email shortly with your gift of an identity for life!
azimuth/glossary.mddeleted−118
@@ -1,118 +0,0 @@
1−+++
2−title = "Azimuth Glossary"
3−weight = 3
4−template = "doc.html"
5−aliases = ["/docs/reference/azimuth-glossary/"]
6−+++
7−
8−
9−Azimuth is a general-purpose public-key infrastructure (PKI) on the Ethereum blockchain, used as a platform for Urbit identities. You need an Azimuth identity to use the Arvo network. All identity-related operations are governed at this layer For more information, see the [Azimuth documentation](azimuth).
10−
11−This glossary is intended to familiarize you with Azimuth-related terminology. To brush up on terminology related to Arvo, check out the [Arvo glossary](../arvo/glossary).
12−
13−### Azimuth identity
14−
15−An Azimuth identity, previously known as a _point_, is a non-fungible Ethereum token ([ERC-271](https://medium.com/@brenn.a.hill/noobs-guide-to-understanding-erc-20-vs-erc-721-tokens-d7f5657a4ee7)) that represents a digital identity. The ERC-721 standard, having been made specifically to provide a smart-contract interface for non-fungible assets, allows Azimuth identity ownership to be take advantage of existing third-party tools and systems.
16−
17−#### Planet
18−
19−An Azimuth identity to be used as a personal identity. Issued by stars.
20−
21−#### Star
22−
23−An Azimuth identity meant to be used as network infrastructure. Issued by galaxies, issues planets.
24−
25−#### Galaxy
26−
27−An Azimuth identity meant to be used as top-level network infrastructure, with governance powers. Issues stars.
28−
29−### Bridge
30−
31−A tool that's the primary way to interact with Azimuth and manage your identities. It can be accessed at bridge.azimuth.network.
32−
33−### Master Ticket
34−
35−Think of your master ticket as a very high-value password. The master ticket is the secret code from which all of your other secrets are derived. Technically, your master ticket is seed entropy. You should never share it with anyone, and store it very securely. This ticket can derive all of your other keys: your ownership key and all of the related proxies.
36−
37−### Multipass
38−
39−Multipass is a planned feature of an Azimuth point that can be used as a universal, real-world identity. It will be able to hold money and have packets routed to it. See this [blog post](https://urbit.org/posts/azimuth-as-multipass/) for more information.
40−
41−#### Network Explorer
42−
43−A Bridge-based interface for browsing Azimuth identities. You can do things such as see which ships are on which invite pools, and much more.
44−
45−### Ownership Address
46−
47−The Ethereum address that owns a point. As the owner, it can perform all possible operations for that point.
48−
49−### Invite Pool
50−
51−Also called an _invite tree_. A host starts a pool and all individuals invited to it have the ability to share remaining, unclaimed invites with others; when an invite is sent to someone, they become a full member of the invite pool and themselves have the ability to invite. So membership of the invite pool grows like a tree.
52−
53−#### Pool Host
54−
55−The ship that generates the invite pool. It's most often a star.
56−
57−#### Guest List
58−
59−The names of planets invited to the same invite pool, as viewed by the pool host.
60−
61−#### Invite Cohort
62−
63−The names of planets invited to the same invite pool, as viewed by the pool's member's.
64−
65−#### Sending Invites
66−
67−The action of giving someone a planet using Bridge.
68−
69−#### Code
70−
71−Activation code from an email that allows you to claim an invite
72−
73−#### Birth Time
74−
75−When a ship is claimed from an invite
76−
77−### Passport
78−
79−The Passport is a folder of files one downloads that contains the secrets of your point and should be stored securely. As long as you own the passport, you own the point. The master ticket is stored in the Passport.
80−
81−### Proxy Address
82−
83−An Ethereum address that's allowed to perform a specific subset of the operations the owner of the point can perform. Useful for allowing some control over a point while keeping its ownership address in cold storage. Below, the specific kinds of proxy addresses are listed.
84−
85−#### Management Proxy Address
86−
87−An Ethereum address used for managing a point. This means it can only configure public (aka networking) keys, and perform sponsorship-related operations (requesting sponsor changes & approving/rejecting those).
88−Use cases:
89−- Keeping this handy so you can put the ownership/master ticket in a super safe place
90−- Allowing someone to manage your ship (by setting/deriving networking keys, managing sponsorship)
91−- Allowing a smart contract to manage sponsorship ops (ie star service smart contract)
92−
93−#### Network Keys
94−
95−Your public key contains Authentication and Encryption addresses, and also have Revision, Continuity Era, and Crypto Suite versions. Resetting Network Keys increases the revision number on the key. A main use case would be if your Network Keys were compromised, so you can use your Management Address to re-derive your Network Keys to another revision.
96−
97−#### Spawn Proxy Address
98−
99−An Ethereum address used for spawning children of a point. It can only perform the spawn operation (creating child points) and can do nothing else.
100−
101−Use cases:
102−- Keeping this handy so you can put the ownership/master ticket in a super safe place
103−- Allowing a smart contract to spawn on your behalf (delegated sending/invites, planet sale)
104−
105−#### Voting Proxy Address
106−An Ethereum address used for voting as a point.
107−
108−Use cases:
109−- Keeping this handy so you can put the ownership/master ticket in a super safe place
110−- Delegating your voting rights to someone else
111−
112−#### Transfer Proxy Address
113−
114−An Ethereum address that's allowed to transfer ownership of a point. Generally not used outside of transfers-in-progress. Using a transfer proxy allows one to give the recipient the power to take ownership of a point, rather than being given it. This "control check" is a strong safety mechanism commonly used in many (Ethereum-based) cryptographic assets.
115−
116−### Sponsorship
117−
118−Azimuth registers hierarchical dependence of identities on other identities; planets depend on stars, and stars depend on galaxies. Applications that use Azimuth can use this to set up things like network topology. In Arvo's case, the sponsor promises to provide software updates and peer discovery.
components/BackgroundImage.jsnew file+9
@@ -0,0 +1,9 @@
1+// Easily crops images
2+export default function BackgroundImage(props) {
3+ return (
4+ <div
5+ className={`bg-img bg-cover ${props.className || ""}`}
6+ style={{ backgroundImage: `url(${props.src})`, ...props.style }}
7+ />
8+ );
9+}
components/BasicPage.jsnew file+46
@@ -0,0 +1,46 @@
1+import { useRouter } from "next/router";
2+import Head from "next/head";
3+import Meta from "../components/Meta";
4+import ErrorPage from "../pages/404";
5+import {
6+ Container,
7+ SingleColumn,
8+ Section,
9+ Markdown,
10+ IntraNav,
11+ TableOfContents,
12+} from "@urbit/foundation-design-system";
13+import Header from "./Header";
14+import Footer from "./Footer";
15+import classNames from "classnames";
16+
17+export default function BasicPage({ post, markdown, search, index = false }) {
18+ const router = useRouter();
19+ if (!router.isFallback && !post?.slug) {
20+ return <ErrorPage />;
21+ }
22+ return (
23+ <Container>
24+ <Head>
25+ <title>{post.title}</title>
26+ {Meta(post)}
27+ </Head>
28+ <IntraNav ourSite="https://urbit.org" search={search} />
29+ <SingleColumn>
30+ <Header search={search} />
31+ <Section>
32+ <h1>{post.title}</h1>
33+ </Section>
34+ <Section>
35+ <div className={classNames("flex", { sidebar: index })}>
36+ <div className={classNames("markdown", { "max-w-prose": index })}>
37+ <Markdown.render content={JSON.parse(markdown)} />
38+ </div>
39+ {index && <TableOfContents />}
40+ </div>
41+ </Section>
42+ </SingleColumn>
43+ <Footer />
44+ </Container>
45+ );
46+}
components/Contact.jsnew file+16
@@ -0,0 +1,16 @@
1+import NewsletterSignup from "./NewsletterSignup";
2+
3+export default function Contact({
4+ emphasize,
5+ ecosystem = false,
6+ className = "",
7+}) {
8+ const linkText = emphasize ? "text-green-400" : "text-wall-600";
9+ const border = emphasize ? "border-green-400" : "border-wall-600";
10+
11+ return (
12+ <div className={className}>
13+ <NewsletterSignup color={border} />
14+ </div>
15+ );
16+}
components/ContentArea.jsnew file+86
@@ -0,0 +1,86 @@
1+import { useState, useEffect, useRef } from "react";
2+import { useRouter } from "next/router";
3+import { TableOfContents } from "@urbit/foundation-design-system";
4+
5+export default function ContentArea(props) {
6+ const [shortcut, setShortcut] = useState("");
7+
8+ const detectOS = () => {
9+ const agent = window.navigator.appVersion;
10+ if (agent.includes("Win")) {
11+ return "Ctrl+K";
12+ } else if (agent.includes("Mac")) {
13+ return "⌘K";
14+ } else if (agent.includes("Linux")) {
15+ return "Ctrl+K";
16+ }
17+ };
18+
19+ useEffect(() => {
20+ setShortcut(detectOS());
21+ }, []);
22+
23+ const scrollBox = useRef();
24+
25+ const router = useRouter();
26+
27+ useEffect(() => {
28+ const handleRouteChange = () => {
29+ if (scrollBox.current === null) return;
30+ scrollBox.current.scrollTop = 0;
31+ };
32+
33+ router.events.on("routeChangeComplete", handleRouteChange);
34+
35+ // If the component is unmounted, unsubscribe
36+ // from the event with the `off` method:
37+ return () => {
38+ router.events.off("routeChangeStart", handleRouteChange);
39+ };
40+ }, []);
41+
42+ return (
43+ <div className="w-full min-w-0 flex flex-col items-center bg-white">
44+ <div
45+ ref={scrollBox}
46+ className="px-4 md:px-12 lg:px-24 pt-8 md:pt-10 lg:pt-16 flex flex-col w-full max-w-screen-xl max-h-screen h-screen overflow-y-scroll"
47+ >
48+ <div className="flex justify-between w-full items-center shrink-0">
49+ <div className="font-semibold antialiased text-lg text-black">
50+ {props.breadcrumbs}
51+ </div>
52+ <div className="hidden md:block">
53+ <button
54+ onClick={(e) => {
55+ e.stopPropagation();
56+ props.search.toggleSearch();
57+ }}
58+ className="bg-wall-100 text-wall-500 flex px-4 py-1 rounded-lg type-ui"
59+ >
60+ Search<div className="ml-4 text-wall-400">{shortcut}</div>
61+ </button>
62+ </div>
63+ </div>
64+ <div className="flex justify-between">
65+ <div className="min-w-0 max-w-screen-md">
66+ <div className="mb-16">
67+ <h2 className="mt-24">{props.title}</h2>
68+ {props?.description && (
69+ <p className="text-wall-400 font-regular mt-2 text-xl">
70+ {props.description}
71+ </p>
72+ )}
73+ </div>
74+ {props.children}
75+ <div className="pb-24" />
76+ </div>
77+ {!props?.disableToC && (
78+ <TableOfContents
79+ key={props.params.slug?.join("/") || Math.random()}
80+ />
81+ )}
82+ </div>
83+ </div>
84+ </div>
85+ );
86+}
components/CopyLink.jsnew file+61
@@ -0,0 +1,61 @@
1+import { useCopyToClipboard } from "../lib/hooks";
2+
3+export default function CopyLink({ content, className }) {
4+ const [copyStatus, copy] = useCopyToClipboard(content);
5+
6+ const buttonIcon =
7+ copyStatus === "inactive" ? (
8+ <svg
9+ width="16"
10+ height="16"
11+ viewBox="0 0 16 16"
12+ className="fill-white"
13+ xmlns="http://www.w3.org/2000/svg"
14+ >
15+ <path
16+ fillRule="evenodd"
17+ clipRule="evenodd"
18+ d="M3.2 1.6C3.2 0.716344 3.91634 0 4.8 0H11.3615L14.9333 2.38124V12.2667C14.9333 13.1503 14.217 13.8667 13.3333 13.8667H12.8V14.4C12.8 15.2837 12.0837 16 11.2 16H2.66667C1.78301 16 1.06667 15.2837 1.06667 14.4V3.73333C1.06667 2.84968 1.78301 2.13333 2.66667 2.13333H3.2V1.6ZM3.2 3.2H2.66667C2.37211 3.2 2.13333 3.43878 2.13333 3.73333V14.4C2.13333 14.6946 2.37211 14.9333 2.66667 14.9333H11.2C11.4946 14.9333 11.7333 14.6946 11.7333 14.4V13.8667H4.8C3.91634 13.8667 3.2 13.1503 3.2 12.2667V3.2Z"
19+ />
20+ </svg>
21+ ) : copyStatus === "copied" ? (
22+ <svg
23+ width="16"
24+ height="16"
25+ viewBox="0 0 16 16"
26+ xmlns="http://www.w3.org/2000/svg"
27+ >
28+ <path
29+ fillRule="evenodd"
30+ clipRule="evenodd"
31+ d="M0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8ZM7.54325 11.4247L12.1498 5.66647L11.3169 5.00013L7.39013 9.90859L4.60812 7.59025L3.92526 8.40969L7.54325 11.4247Z"
32+ />
33+ </svg>
34+ ) : (
35+ <svg
36+ width="16"
37+ height="16"
38+ viewBox="0 0 16 16"
39+ className="fill-white"
40+ xmlns="http://www.w3.org/2000/svg"
41+ >
42+ <path
43+ fillRule="evenodd"
44+ clipRule="evenodd"
45+ d="M0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8ZM10.8229 11.5772L8.00004 8.75429L5.17716 11.5772L4.42292 10.8229L7.24579 8.00004L4.42292 5.17716L5.17716 4.42292L8.00004 7.24579L10.8229 4.42292L11.5772 5.17716L8.75429 8.00004L11.5772 10.8229L10.8229 11.5772Z"
46+ />
47+ </svg>
48+ );
49+
50+ return (
51+ <button
52+ className={`bg-wall-600 p-4 rounded-xl button-sm text-white flex items-center justify-center space-x-2 ${className}`}
53+ onClick={() => copy()}
54+ >
55+ <p className="leading-5">
56+ {copyStatus === "copied" ? "Copied" : "Shortcode"}
57+ </p>
58+ {buttonIcon}
59+ </button>
60+ );
61+}
components/DocsSidebar.jsnew file+32
@@ -0,0 +1,32 @@
1+import Link from "next/link";
2+import { useState } from "react";
3+import { MenuTray } from '@urbit/foundation-design-system'
4+
5+export default function Sidebar(props) {
6+ const [isOpen, setTray] = useState(false);
7+ return (
8+ <>
9+ <div className="hidden md:flex flex-col w-96 bg-wall-100 max-h-screen h-screen">
10+ <header className="flex shrink-0 justify-between items-center pl-6 pt-12 mt-5 pb-8">
11+ <Link href="/" passHref>
12+ <a className="font-semibold antialiased text-lg text-wall-500">Urbit</a>
13+ </Link>
14+ </header>
15+ <div className="overflow-y-auto p-6 pt-16">
16+ {props.children}
17+ <div className="pb-32" />
18+ </div>
19+ </div>
20+
21+ <MenuTray isOpen={isOpen} setTray={setTray} search={props.search}>
22+ <header className="flex shrink-0 justify-between items-center pb-8">
23+ <Link href="/" passHref>
24+ <a className="type-ui text-wall-500">Urbit</a>
25+ </Link>
26+ </header>
27+ {props.children}
28+ <div className="pt-64" />
29+ </MenuTray>
30+ </>
31+ );
32+}
components/EventPreview.jsnew file+92
@@ -0,0 +1,92 @@
1+import Link from "next/link";
2+import { DateTime } from "luxon";
3+import { DateRange } from "../components/Snippets";
4+import {
5+ generateDisplayDate,
6+ generateRealtimeDate,
7+} from "@urbit/foundation-design-system";
8+import classNames from "classnames";
9+
10+export default function EventPreview({ event, className, big }) {
11+ // Event tiles have a 'dark mode' used when their background images are dark and white text is needed for legibility.
12+ const grayText = event?.dark ? "text-white dark:text-black" : "text-wall-400";
13+ const blackText = event?.dark
14+ ? "text-white dark:text-black"
15+ : "text-wall-600";
16+
17+ const starts = generateDisplayDate(event.starts, event.timezone);
18+ const ends = generateDisplayDate(event.ends, event.timezone);
19+
20+ const inFuture = generateRealtimeDate(starts) > DateTime.now();
21+
22+ const happeningNow =
23+ generateRealtimeDate(event.starts) > DateTime.now() && !inFuture;
24+
25+ return (
26+ <div className={`cursor-pointer h-full ${className}`}>
27+ <div
28+ key={event.slug}
29+ className={`bg-wall-100 min-h-[320px] h-full flex flex-col rounded-xl bg-cover bg-center bg-no-repeat `}
30+ style={{ backgroundImage: `url(${event.image})` || "" }}
31+ >
32+ <Link href={`/events/${event.slug}`}>
33+ <div
34+ className={classNames(
35+ "flex flex-col p-6 min-h-[320px] justify-between items-between h-full relative",
36+ {
37+ "backdrop-brightness-50 rounded-xl": Boolean(
38+ event?.darken_image
39+ ),
40+ }
41+ )}
42+ >
43+ <div
44+ className={`grow-1 flex ${big ? "justify-center" : ""
45+ } flex-col h-full`}
46+ >
47+ <h3 className={`${blackText} mb-2`} id={event.title}>{event.title}</h3>
48+ <p className={blackText + " truncate text-sm"}>
49+ {event.description}
50+ </p>
51+ </div>
52+
53+ <div className="flex justify-between items-end">
54+ <div className="">
55+ <p className={`${blackText} type-sub mb-1`}>{event.location}</p>
56+ <DateRange
57+ starts={starts}
58+ ends={ends}
59+ className={`${grayText} type-sub`}
60+ />
61+ </div>
62+
63+ {inFuture && event.registration_url ? (
64+ <div>
65+ <a
66+ className="button-sm bg-green-400 text-white"
67+ href={event.registration_url}
68+ onClick={(e) => e.stopPropagation()}
69+ target="_blank"
70+ >
71+ RSVP
72+ </a>
73+ </div>
74+ ) : event.youtube ? (
75+ <div className="shrink-0">
76+ <a
77+ className="button-sm bg-wall-600 text-white shrink-0"
78+ href={`https://www.youtube.com/watch?v=${event.youtube}`}
79+ onClick={(e) => e.stopPropagation()}
80+ target="_blank"
81+ >
82+ ▶ Watch
83+ </a>
84+ </div>
85+ ) : null}
86+ </div>
87+ </div>
88+ </Link>
89+ </div>
90+ </div>
91+ );
92+}
components/Footer.jsnew file+6
@@ -0,0 +1,6 @@
1+import { Footer as FooterComponent } from "@urbit/foundation-design-system";
2+import { footerData } from "../lib/constants";
3+
4+export default function Footer() {
5+ return <FooterComponent data={footerData} />;
6+}
components/GrantPreview.jsnew file+63
@@ -0,0 +1,63 @@
1+import classnames from "classnames";
2+import Link from "next/link";
3+
4+export default function GrantPreview({ grant }) {
5+ const isCompleted = grant.extra.completed;
6+ const isOpen = !isCompleted && grant.extra.assignee?.[0] === "";
7+ const type = grant.taxonomies.grant_type;
8+
9+ const className = classnames({
10+ "bg-lightBlue": type.includes("Proposal") && isOpen,
11+ "bg-purple-200": type.includes("RFP") && isOpen,
12+ "bg-yellow-100": type.includes("Bounty") && isOpen,
13+ });
14+
15+ return (
16+ <div
17+ key={grant.slug}
18+ className={`mb-4 cursor-pointer bg-wall-100 rounded-lg ${className}`}
19+ >
20+ <Link href={`/grants/${grant.slug}`} passHref>
21+ <a>
22+ <div className="p-8">
23+ <div className="flex items-center mb-4">
24+ <h3 className="type-ui" id={grant.slug}>
25+ {grant.title}
26+ </h3>
27+ <div className={`bg-wall-500 text-wall-100 badge-sm ml-2`}>
28+ {!isCompleted ? (isOpen ? "Open" : "In Progress") : "Completed"}
29+ </div>
30+ </div>
31+ <p className="mb-4">{grant.extra.description}</p>
32+ <div className="flex w-full flex-col md:flex-row md:items-center justify-between">
33+ <p className="text-wall-500">
34+ <strong>Reward: </strong>
35+ {grant.extra.reward}
36+ </p>
37+ <div className="flex items-center flex-wrap md:mt-0 mt-4">
38+ {grant.taxonomies.grant_type.map((category) => {
39+ const className = classnames({
40+ "bg-blue-400 text-white": category === "Proposal",
41+ "bg-purple text-white": category === "RFP",
42+ "bg-green-400 text-white": category === "Apprenticeship",
43+ "bg-yellow-300": category === "Bounty",
44+ });
45+ return (
46+ <div className={`${className} badge-sm mr-1 my-1`}>
47+ {category}
48+ </div>
49+ );
50+ })}
51+ {grant.taxonomies.grant_category.map((category) => (
52+ <div className="bg-wall-500 text-wall-100 badge-sm mr-1 my-1">
53+ {category}
54+ </div>
55+ ))}
56+ </div>
57+ </div>
58+ </div>
59+ </a>
60+ </Link>
61+ </div>
62+ );
63+}
components/GrantProgramOverview.jsnew file+59
@@ -0,0 +1,59 @@
1+import { useRouter } from "next/router";
2+import Link from "next/link";
3+import Head from "next/head";
4+import Meta from "../components/Meta";
5+import ErrorPage from "../pages/404";
6+import {
7+ Container,
8+ Section,
9+ SingleColumn,
10+ Markdown,
11+ IntraNav,
12+ formatDate,
13+} from "@urbit/foundation-design-system";
14+import Header from "./Header";
15+import Footer from "./Footer";
16+import { DateTime } from "luxon";
17+
18+export default function GrantProgramOverview({
19+ post,
20+ markdown,
21+ search,
22+ program,
23+ actionLink,
24+ actionText,
25+}) {
26+ const router = useRouter();
27+ if (!router.isFallback && !post?.slug) {
28+ return <ErrorPage />;
29+ }
30+
31+ const title = program.charAt(0).toUpperCase() + program.slice(1);
32+ return (
33+ <Container>
34+ <Head>
35+ <title>{title} • Grants</title>
36+ {Meta(post)}
37+ </Head>
38+ <IntraNav ourSite="https://urbit.org" search={search} />
39+ <SingleColumn>
40+ <Header search={search} />
41+ <Section narrow short>
42+ <h1>{post.title}</h1>
43+ <div className="type-ui text-wall-500 mt-4 md:mt-8 lg:mt-10">
44+ Last Revision: {formatDate(DateTime.fromISO(post.date))}
45+ </div>
46+ <Link href={actionLink} passHref>
47+ <a className="button-sm bg-green-400 text-white mt-8 max-w-fit">
48+ {actionText}
49+ </a>
50+ </Link>
51+ </Section>
52+ <Section narrow short className="markdown">
53+ <Markdown.render content={JSON.parse(markdown)} />
54+ </Section>
55+ </SingleColumn>
56+ <Footer />
57+ </Container>
58+ );
59+}
components/Header.jsnew file+169
@@ -0,0 +1,169 @@
1+import Link from "next/link";
2+import { useRouter } from "next/router";
3+import { useState } from "react";
4+import classnames from "classnames";
5+import { capitalize, MenuTray } from "@urbit/foundation-design-system";
6+
7+function ActiveLink({ children, href, className, currentPath }) {
8+ const firstCrumb = currentPath.split("/")[1];
9+
10+ const activeClassName = classnames({
11+ "text-wall-900": "/" + firstCrumb === href,
12+ "text-wall-500": "/" + firstCrumb !== href,
13+ });
14+
15+ return (
16+ <Link href={href} passHref>
17+ <a className={`${className} ${activeClassName}`}>{children}</a>
18+ </Link>
19+ );
20+}
21+
22+export default function Header(props) {
23+ const [isOpen, setTray] = useState(false);
24+
25+ const currentPath = useRouter().asPath;
26+
27+ const routeDepth = currentPath.split("/").length;
28+
29+ const firstCrumb = currentPath.split("/")[1];
30+
31+ return (
32+ <header className="layout px-4 md:px-8 flex justify-between items-center pt-8 md:pt-10 lg:pt-12 pb-10 md:pb-12 lg:pb-24">
33+ <div>
34+ <Link href="/" passHref>
35+ <a className="font-semibold text-lg">Urbit</a>
36+ </Link>
37+ {routeDepth > 2 ? (
38+ <Link href={`/${firstCrumb}`} passHref>
39+ <a className="inline md:hidden type-ui text-wall-500 ml-2">
40+ {capitalize(firstCrumb)}
41+ </a>
42+ </Link>
43+ ) : null}
44+ </div>
45+ {
46+ // Large screen header
47+ }
48+ <nav className="items-center hidden md:flex">
49+ <ActiveLink
50+ currentPath={currentPath}
51+ className="mr-5 type-ui"
52+ href="/getting-started"
53+ >
54+ Get Started
55+ </ActiveLink>
56+
57+ <ActiveLink
58+ currentPath={currentPath}
59+ className="mr-5 type-ui"
60+ href="/overview"
61+ >
62+ Overview
63+ </ActiveLink>
64+
65+ <ActiveLink
66+ currentPath={currentPath}
67+ className="mr-5 type-ui"
68+ href="/ecosystem"
69+ >
70+ Ecosystem
71+ </ActiveLink>
72+
73+ <ActiveLink
74+ currentPath={currentPath}
75+ className="mr-5 type-ui"
76+ href="/grants"
77+ >
78+ Grants
79+ </ActiveLink>
80+
81+ <ActiveLink
82+ currentPath={currentPath}
83+ className="mr-5 type-ui"
84+ href="/events"
85+ >
86+ Events
87+ </ActiveLink>
88+
89+ <ActiveLink
90+ currentPath={currentPath}
91+ className="mr-5 type-ui"
92+ href="/blog"
93+ >
94+ Blog
95+ </ActiveLink>
96+ </nav>
97+
98+ {
99+ // Small screen header
100+ }
101+ <MenuTray isOpen={isOpen} setTray={setTray} search={props.search}>
102+ <Link href="/" passHref>
103+ <a className="font-semibold mb-4">Urbit</a>
104+ </Link>
105+ <Link href="https://urbit.org" passHref>
106+ <a className="font-semibold mt-2">Urbit.org</a>
107+ </Link>
108+ <Link href="https://operators.urbit.org" passHref>
109+ <a className="mt-2">Operators</a>
110+ </Link>
111+ <Link href="https://developers.urbit.org" passHref>
112+ <a className="mt-2">Developers</a>
113+ </Link>
114+ <Link href="https://roadmap.urbit.org" passHref>
115+ <a className="mt-2 mb-4">Roadmap</a>
116+ </Link>
117+ <hr className="border-wall-200" />
118+
119+ <ActiveLink
120+ currentPath={currentPath}
121+ className="mr-5 mt-4 mb-4 text-green-400"
122+ href="/getting-started"
123+ >
124+ Get Started
125+ </ActiveLink>
126+
127+ <ActiveLink
128+ currentPath={currentPath}
129+ className="mr-5 mb-4"
130+ href="/overview"
131+ >
132+ Overview
133+ </ActiveLink>
134+
135+ <ActiveLink
136+ currentPath={currentPath}
137+ className="mr-5 mb-4"
138+ href="/ecosystem"
139+ >
140+ Ecosystem
141+ </ActiveLink>
142+
143+ <ActiveLink
144+ currentPath={currentPath}
145+ className="mr-5 mb-4"
146+ href="/grants"
147+ >
148+ Grants
149+ </ActiveLink>
150+
151+ <ActiveLink
152+ currentPath={currentPath}
153+ className="mr-5 mb-4"
154+ href="/events"
155+ >
156+ Events
157+ </ActiveLink>
158+
159+ <ActiveLink
160+ currentPath={currentPath}
161+ className="mr-5 mb-4"
162+ href="/blog"
163+ >
164+ Blog
165+ </ActiveLink>
166+ </MenuTray>
167+ </header>
168+ );
169+}
components/HighlightCard.jsnew file+22
@@ -0,0 +1,22 @@
1+import Link from "next/link";
2+export default function HighlightCard({ slug, highlight }) {
3+ return (
4+ <Link href={highlight.url}>
5+ <div className="cursor-pointer bg-wall-100 rounded-xl min-h-0 flex-1">
6+ <div className="flex flex-col p-4 h-full relative">
7+ {highlight.image ? (
8+ <div className="w-64 md:w-full rounded-xl object-cover overflow-hidden basis-3/5">
9+ <img className="h-full w-64 md:w-full object-cover" src={highlight.image} />
10+ </div>
11+ ) : (
12+ <div className="rounded-xl w-full"/>
13+ )}
14+ <div className="pt-4">
15+ <p className="mb-2 font-semibold leading-5">{highlight.title}</p>
16+ <p className="text-sm leading-5">{highlight?.description}</p>
17+ </div>
18+ </div>
19+ </div>
20+ </Link>
21+ );
22+}
components/JoinGroup.jsnew file+79
@@ -0,0 +1,79 @@
1+import { useCopyToClipboard } from "../lib/hooks";
2+
3+export default function Contact({ emphasize, groupName, label, className }) {
4+ const [copyStatus, copy] = useCopyToClipboard(groupName);
5+
6+ const linkText = emphasize ? "text-green-400" : "text-wall-600";
7+ const border = emphasize ? "border-green-400" : "border-wall-600";
8+ const washedBg = emphasize ? "bg-green-100" : "bg-wall-100";
9+ const iconColor = emphasize ? "#00B171" : "#24221E";
10+
11+ const buttonIcon =
12+ copyStatus === "inactive" ? (
13+ <svg
14+ width="16"
15+ height="16"
16+ viewBox="0 0 16 16"
17+ fill="none"
18+ xmlns="http://www.w3.org/2000/svg"
19+ >
20+ <path
21+ fillRule="evenodd"
22+ clipRule="evenodd"
23+ d="M3.2 1.6C3.2 0.716344 3.91634 0 4.8 0H11.3615L14.9333 2.38124V12.2667C14.9333 13.1503 14.217 13.8667 13.3333 13.8667H12.8V14.4C12.8 15.2837 12.0837 16 11.2 16H2.66667C1.78301 16 1.06667 15.2837 1.06667 14.4V3.73333C1.06667 2.84968 1.78301 2.13333 2.66667 2.13333H3.2V1.6ZM3.2 3.2H2.66667C2.37211 3.2 2.13333 3.43878 2.13333 3.73333V14.4C2.13333 14.6946 2.37211 14.9333 2.66667 14.9333H11.2C11.4946 14.9333 11.7333 14.6946 11.7333 14.4V13.8667H4.8C3.91634 13.8667 3.2 13.1503 3.2 12.2667V3.2Z"
24+ fill={iconColor}
25+ />
26+ </svg>
27+ ) : copyStatus === "copied" ? (
28+ <svg
29+ width="16"
30+ height="16"
31+ viewBox="0 0 16 16"
32+ fill="none"
33+ xmlns="http://www.w3.org/2000/svg"
34+ >
35+ <path
36+ fillRule="evenodd"
37+ clipRule="evenodd"
38+ d="M0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8ZM7.54325 11.4247L12.1498 5.66647L11.3169 5.00013L7.39013 9.90859L4.60812 7.59025L3.92526 8.40969L7.54325 11.4247Z"
39+ fill={iconColor}
40+ />
41+ </svg>
42+ ) : (
43+ <svg
44+ width="16"
45+ height="16"
46+ viewBox="0 0 16 16"
47+ fill="none"
48+ xmlns="http://www.w3.org/2000/svg"
49+ >
50+ <path
51+ fillRule="evenodd"
52+ clipRule="evenodd"
53+ d="M0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8ZM10.8229 11.5772L8.00004 8.75429L5.17716 11.5772L4.42292 10.8229L7.24579 8.00004L4.42292 5.17716L5.17716 4.42292L8.00004 7.24579L10.8229 4.42292L11.5772 5.17716L8.75429 8.00004L11.5772 10.8229L10.8229 11.5772Z"
54+ fill={iconColor}
55+ />
56+ </svg>
57+ );
58+
59+ return (
60+ <div className={className}>
61+ <h4 className="text-wall-500 flex items-baseline flex-wrap">
62+ {label ? label + " " : ""}
63+ <div className="rounded-lg flex items-stretch">
64+ <code
65+ className={`rounded-l-lg px-2 md:px-4 py-2 ${washedBg} flex items-center h-full ${linkText}`}
66+ >
67+ {groupName}
68+ </code>
69+ <button
70+ className={`rounded-r-lg px-4 ml-0.5 flex-1 flex justify-center items-center ${washedBg}`}
71+ onClick={() => copy()}
72+ >
73+ {buttonIcon}
74+ </button>
75+ </div>
76+ </h4>
77+ </div>
78+ );
79+}
components/Meta.jsnew file+54
@@ -0,0 +1,54 @@
1+export default function Meta(post, disableImage, large = false) {
2+ const author = post?.extra?.author || "urbit.org";
3+ const title = post?.title ? post.title : "";
4+ const description =
5+ post?.description || "Urbit is a new kind of computer that you can own completely in ways that matter: networking, identity, & data.";
6+ const image =
7+ post?.extra?.image ||
8+ post?.image ||
9+ "https://storage.googleapis.com/media.urbit.org/site/opengraph/sig-white.png";
10+ return (
11+ <>
12+ <link rel="icon" type="image/png" href="/images/favicon.ico" />
13+ <link
14+ rel="apple-touch-icon"
15+ sizes="180x180"
16+ href="/images/apple-touch-icon.png"
17+ />
18+ <link
19+ rel="icon"
20+ type="image/png"
21+ sizes="32x32"
22+ href="/images/favicon-32x32.png"
23+ />
24+ <link
25+ rel="icon"
26+ type="image/png"
27+ sizes="16x16"
28+ href="/images/favicon-16x16.png"
29+ />
30+ <link rel="manifest" href="/images/site.webmanifest" />
31+
32+ <meta
33+ name="twitter:card"
34+ content={large ? "summary_large_image" : "summary"}
35+ key="twitter-card"
36+ />
37+ <meta name="twitter:site" content="@urbit" key="twitter-site" />
38+ <meta name="twitter:creator" content="@urbit" key="twitter-creator" />
39+ <meta name="og:title" content={title} key="title" />
40+ <meta name="og:description" content={description} key="description" />
41+ <meta name="description" content={description} />
42+ <meta name="author" content={author} key="author" />
43+ {!disableImage && (
44+ <meta name="twitter:image" content={image} key="image" />
45+ )}
46+ <link
47+ rel="alternative"
48+ type="application/rss+xml"
49+ title="RSS"
50+ href="/rss.xml"
51+ />
52+ </>
53+ );
54+}
components/NewsletterSignup.jsnew file+38
@@ -0,0 +1,38 @@
1+export default function NewsletterSignup(props) {
2+ return (
3+ <form
4+ action="https://urbit.us11.list-manage.com/subscribe/post?u=972a03db9e0c6c25bb58de8c8&amp;amp;id=be143888d2"
5+ method="post"
6+ id="mc-embedded-subscribe-form"
7+ name="mc-embedded-subscribe-form"
8+ className="validate form max-w-screen-sm"
9+ target="_blank"
10+ noValidate
11+ >
12+ <div className="input-group" id="mc_embed_signup_scroll">
13+ <div className="mc-field-group w-full relative">
14+ <input
15+ className={`appearance-none outline-none text-wall-500 type-ui bg-white black ${
16+ props.color || "border-wall-600"
17+ } border-4 px-3 w-full mb-2 h-16 rounded-xl`}
18+ type="email"
19+ name="EMAIL"
20+ id="mce-EMAIL"
21+ placeholder="your@email.com"
22+ />
23+ <div className="flex h-16 items-center justify-center absolute top-0 right-6">
24+ <button
25+ id="mc-embedded-subscribe"
26+ className="type-ui dark:text-green-400 text-wall-500 bg-transparent"
27+ type="submit"
28+ name="subscribe"
29+ >
30+ {/* onClick={() => _paq.push(['trackEvent', 'Mailing List', 'Subscribe'])}> */}
31+ Sign Up
32+ </button>
33+ </div>
34+ </div>
35+ </div>
36+ </form>
37+ );
38+}
components/Pagination.jsnew file+22
@@ -0,0 +1,22 @@
1+import Link from "next/link";
2+export default function Pagination(props) {
3+ return (
4+ <Link
5+ href={`/${props.section}/${props.post.slug}`}
6+ key={`post-${props.post.slug}`}
7+ >
8+ <div
9+ className="bg-wall-100 cursor-pointer font-semibold p-2 px-4 rounded-xl flex"
10+ style={{ maxWidth: "45%" }}
11+ >
12+ <p className="shrink-0 pr-1">{props.previous ? "<- " : ""}</p>
13+ <p className="text-wall-600 truncate">{props.post.title}</p>
14+ <p className="shrink-0 pl-1">{props.next ? " ->" : ""}</p>
15+ </div>
16+ </Link>
17+ );
18+}
19+
20+Pagination.defaultProps = {
21+ className: "",
22+};
components/PostPreview.jsnew file+27
@@ -0,0 +1,27 @@
1+import {
2+ Card,
3+ formatDate,
4+ generateDisplayDate,
5+} from "@urbit/foundation-design-system";
6+
7+export default function PostPreview(props) {
8+ const section = props?.section ? props.section : "blog";
9+
10+ const date = generateDisplayDate(props.post.date);
11+ return (
12+ <Card
13+ slug={`/${section}/${props.post.slug}`}
14+ image={props.post.extra.image}
15+ title={props?.title || props.post?.title || ""}
16+ author={props.post?.extra?.author || ""}
17+ ship={props.post?.extra?.ship || ""}
18+ content={
19+ <div className="text-wall-500 type-sub mt-1">{formatDate(date)}</div>
20+ }
21+ />
22+ );
23+}
24+
25+PostPreview.defaultProps = {
26+ className: "",
27+};
components/Sidebar.jsnew file+21
@@ -0,0 +1,21 @@
1+import { useState } from "react";
2+import { MenuTray } from '@urbit/foundation-design-system';
3+
4+export default function Sidebar(props) {
5+ const [isOpen, setTray] = useState(false);
6+ return (
7+ <>
8+ <div className="hidden md:flex flex-col h-full sticky top-8">
9+ <div className="overflow-y-auto">
10+ {props.children}
11+ <div className="pb-32" />
12+ </div>
13+ </div>
14+
15+ <MenuTray isOpen={isOpen} setTray={setTray} search={props.search}>
16+ {props.children}
17+ <div className="pt-64" />
18+ </MenuTray>
19+ </>
20+ );
21+}
components/Snippets.jsnew file+111
@@ -0,0 +1,111 @@
1+import Link from "next/link";
2+import {
3+ formatDate,
4+ formatTime,
5+ formatTimeZone,
6+} from "@urbit/foundation-design-system";
7+
8+export function Name({ children, className }) {
9+ return <b className={`font-normal ${className || ""}`}>{children}</b>;
10+}
11+
12+export function Patp({ children, className }) {
13+ return (
14+ <Link href={`/ids/${children}`} passHref>
15+ <a>
16+ <code className={`font-mono ${className || ""}`}>{children}</code>
17+ </a>
18+ </Link>
19+ );
20+}
21+
22+// Used to render a human name alongside their @p
23+export function Person({
24+ name,
25+ patp,
26+ nameClassNames,
27+ patpClassNames,
28+ className,
29+}) {
30+ return (
31+ <>
32+ {patp && name ? (
33+ <>
34+ <Name className={nameClassNames}>{name}</Name>{" "}
35+ <Patp className={patpClassNames + " opacity-60"}>{patp}</Patp>
36+ </>
37+ ) : patp ? (
38+ <Patp className={patpClassNames}>{patp}</Patp>
39+ ) : name ? (
40+ <Name className={nameClassNames}>{name}</Name>
41+ ) : null}
42+ </>
43+ );
44+}
45+
46+// This goes inside a <p/> tag
47+export function ReadableList({ children, serial = ",", conjunction = "and" }) {
48+ return (
49+ <>
50+ {children.map((Child, index) => {
51+ if (index < children.length - 2) {
52+ return (
53+ <>
54+ {Child}
55+ {serial}
56+ </>
57+ );
58+ } else if (index < children.length - 1) {
59+ return (
60+ <>
61+ {Child} {conjunction}{" "}
62+ </>
63+ );
64+ }
65+ return <>{Child}</>;
66+ })}
67+ </>
68+ );
69+}
70+
71+export function ShowOrHide({ children, condition }) {
72+ if (condition) {
73+ return children;
74+ }
75+ return null;
76+}
77+
78+export function DateRange({ starts, ends, className, short }) {
79+ // For events which have no end datetime
80+ if (!ends.isValid) {
81+ return (
82+ <div>
83+ <p className={className}>
84+ {`${formatDate(starts)} • ${formatTime(starts)} ${formatTimeZone(
85+ starts
86+ )}`}
87+ </p>
88+ </div>
89+ );
90+ }
91+ // For events which start and end on the same day
92+ if (starts.hasSame(ends, "day")) {
93+ return (
94+ <div>
95+ <p className={className}>
96+ {`${formatDate(starts)} • ${formatTime(starts)} to ${formatTime(
97+ ends
98+ )} ${formatTimeZone(starts)}`}
99+ </p>
100+ </div>
101+ );
102+ }
103+ // For multi-day events
104+ return (
105+ <div>
106+ <p className={className}>{`${starts.toFormat(
107+ "cccc, LLLL d"
108+ )} to ${formatDate(ends)}`}</p>
109+ </div>
110+ );
111+}
components/TabCarousel.jsnew file+9
@@ -0,0 +1,9 @@
1+// Given multiple children, returns only 1 to be rendered based on props.index
2+export default function TabCarousel(props) {
3+ if (props.children) {
4+ if (props.children[props.index]) {
5+ return props.children[props.index]
6+ }
7+ }
8+ return null
9+}
components/ecosystem/Badge.jsnew file+20
@@ -0,0 +1,20 @@
1+import classnames from "classnames";
2+export default function EcosystemBadge({ type }) {
3+ return (
4+ <div
5+ className={classnames(
6+ "uppercase font-bold text-white text-xs w-fit rounded-lg mb-2 px-2 py-1",
7+ {
8+ "bg-[#B37ED7]": type === "Organization",
9+ "bg-[#83b2d4]": type === "Application",
10+ "bg-wall-600": type === "Podcast",
11+ "bg-[#8dd5b1]": type === "Marketplace",
12+ "bg-[#B5966D]": type === "Article",
13+ "bg-[#219DFF]": type === "Group",
14+ }
15+ )}
16+ >
17+ {type}
18+ </div>
19+ );
20+}
components/ecosystem/BasicPage.jsnew file+146
@@ -0,0 +1,146 @@
1+import { useRouter } from "next/router";
2+import Head from "next/head";
3+import Link from "next/link";
4+import Meta from "../Meta";
5+import ErrorPage from "../../pages/404";
6+import classnames from "classnames";
7+import {
8+ Container,
9+ SingleColumn,
10+ Section,
11+ Markdown,
12+ IntraNav,
13+} from "@urbit/foundation-design-system";
14+import Header from "../Header";
15+import Footer from "../Footer";
16+import MetadataBlock from "./MetadataBlock";
17+
18+export default function BasicPage({
19+ section,
20+ post,
21+ markdown,
22+ search,
23+ children,
24+}) {
25+ const router = useRouter();
26+ if (!router.isFallback && !post?.slug) {
27+ return <ErrorPage />;
28+ }
29+ const metaPost = Object.assign({}, post);
30+ metaPost.title = `${post.title} - ${section}`;
31+ metaPost.description =
32+ section === "Podcast" ? `${post.podcast} - ${post.date}` : post.description;
33+ section === "Article" ? `${post.publication} - ${post.date}` : post.description;
34+ return (
35+ <Container>
36+ <Head>
37+ <title>
38+ {post.title} • {section}
39+ </title>
40+ {Meta(metaPost)}
41+ </Head>
42+ <IntraNav ourSite="https://urbit.org" search={search} />
43+ <SingleColumn>
44+ <Header search={search} />
45+ <Section narrow className="space-y-12">
46+ <div className="flex items-center space-x-4">
47+ <img src={post.image} className="w-36" />
48+ <div className="flex flex-col pl-2">
49+ <h1 className="text-3xl">
50+ {post.title}
51+ </h1>
52+ <p>{section}</p>
53+ </div>
54+ </div>
55+ {/* General purpose metadata bar -- podcast listen button is special-cased URL, flexed at the end of the row */}
56+ <div className="flex justify-between">
57+ <div className="flex space-x-12">
58+ {post?.podcast && (
59+ <MetadataBlock
60+ title="Podcast"
61+ content={post.podcast}
62+ />
63+ )}
64+ {post?.publication && (
65+ <MetadataBlock
66+ title="Publication"
67+ content={post.publication}
68+ />
69+ )}
70+ {post?.author && (
71+ <MetadataBlock
72+ title="Author"
73+ content={post.author}
74+ />
75+ )}
76+ {post?.date && (
77+ <MetadataBlock
78+ title="Date"
79+ content={post.date}
80+ />
81+ )}
82+
83+ {post?.twitter && (
84+ <div className="flex flex-col">
85+ <p className="font-bold text-wall-400">Twitter</p>
86+ <Link href={"http://twitter.com/" + post.twitter}>
87+ <a className="text-green-400 text-sm font-semibold font-mono">@{post.twitter}</a>
88+ </Link>
89+ </div>
90+ )}
91+
92+
93+ {post?.URL && section !== "Podcast" && section !== "Article" && (
94+ <div className="flex flex-col">
95+ <p className="font-bold text-wall-400">Website</p>
96+ <a
97+ className="text-green-400 text-sm font-semibold font-mono"
98+ href={post.URL}
99+ >
100+ {post.URL.slice(post.URL.indexOf("://") + 3)}
101+ </a>
102+ </div>
103+ )}
104+
105+ {post?.URL && section === "Urbit Marketplace" && (
106+ <div className="flex flex-col">
107+ <p className="font-bold text-wall-400">Accepts</p>
108+ <p className="text-sm font-semibold font-mono">
109+ {post.payment.join(", ")}
110+ </p>
111+ </div>
112+ )}
113+ </div>
114+
115+
116+
117+ {post?.URL && section === "Podcast" && (
118+ <a
119+ href={post.URL}
120+ className="button-lg bg-green-400 text-white cursor-pointer flex space-x-2"
121+ >
122+ <img src="/images/sound.svg" />
123+ &nbsp;Listen
124+ </a>
125+ )}
126+ {post?.URL && section === "Article" && (
127+ <a
128+ href={post.URL}
129+ className="button-lg bg-green-400 text-white cursor-pointer flex space-x-2"
130+ >
131+ Read
132+ </a>
133+ )}
134+ </div>
135+ <div className="flex">
136+ <div className="markdown w-full">
137+ <Markdown.render content={JSON.parse(markdown)} />
138+ {children}
139+ </div>
140+ </div>
141+ </Section>
142+ </SingleColumn>
143+ <Footer />
144+ </Container>
145+ );
146+}
components/ecosystem/EcosystemSidebar.jsnew file+86
@@ -0,0 +1,86 @@
1+import { useRouter } from "next/router";
2+import Link from "next/link";
3+import classnames from "classnames";
4+function ActiveLink({ children, href, className, currentPath }) {
5+ // special casing this behaviour which overloads one nav
6+ const archive = Boolean(
7+ currentPath === "/ecosystem?type=archive" && href === "/ecosystem"
8+ );
9+ const activeClassName = classnames({
10+ "text-wall-800": currentPath === href || archive,
11+ "text-wall-400": currentPath !== href && !archive,
12+ });
13+
14+ return (
15+ <Link href={href} passHref>
16+ <a className={`${className} ${activeClassName}`}>{children}</a>
17+ </Link>
18+ );
19+}
20+
21+export default function EcosystemSidebar() {
22+ const router = useRouter();
23+ let currentPath = router.asPath;
24+ return (
25+ <div className="flex flex-col space-y-4 pr-24">
26+ <ActiveLink
27+ currentPath={currentPath}
28+ className="type-ui"
29+ href="/ecosystem"
30+ >
31+ Spotlight
32+ </ActiveLink>
33+ <ActiveLink
34+ currentPath={currentPath}
35+ className="type-ui"
36+ href="/ecosystem?type=communities"
37+ >
38+ Communities
39+ </ActiveLink>
40+ <ActiveLink
41+ currentPath={currentPath}
42+ className="type-ui"
43+ href="/ecosystem?type=organizations"
44+ >
45+ Organizations
46+ </ActiveLink>
47+
48+ <ActiveLink
49+ currentPath={currentPath}
50+ className="type-ui"
51+ href="/ecosystem?type=applications"
52+ >
53+ Applications
54+ </ActiveLink>
55+ <ActiveLink
56+ currentPath={currentPath}
57+ className="type-ui"
58+ href="/ecosystem?type=groups"
59+ >
60+ Groups
61+ </ActiveLink>
62+ <ActiveLink
63+ currentPath={currentPath}
64+ className="type-ui"
65+ href="/ecosystem?type=marketplaces"
66+ >
67+ Marketplaces
68+ </ActiveLink>
69+ <ActiveLink
70+ currentPath={currentPath}
71+ className="mr-5 type-ui"
72+ href="/ecosystem?type=podcasts"
73+ >
74+ Podcasts
75+ </ActiveLink>
76+
77+ <ActiveLink
78+ currentPath={currentPath}
79+ className="mr-5 type-ui"
80+ href="/ecosystem?type=articles"
81+ >
82+ Articles
83+ </ActiveLink>
84+ </div>
85+ );
86+}
components/ecosystem/IndexCard.jsnew file+34
@@ -0,0 +1,34 @@
1+import Link from "next/link";
2+import EcosystemBadge from "./Badge";
3+export default function IndexCard({ slug, feat }) {
4+ return (
5+ <Link href={slug}>
6+ <div className="cursor-pointer bg-wall-100 rounded-xl min-h-0 flex-1">
7+ <div className="flex flex-col p-4 h-full relative">
8+ {feat.image ? (
9+ <div
10+ className="w-64 md:w-full rounded-xl object-cover overflow-hidden basis-1/2"
11+ style={{
12+ backgroundColor: feat?.matchedPost?.bgColor || "rgba(0,0,0,0)",
13+ }}
14+ >
15+ <img className="h-full w-64 md:w-full object-cover" src={feat.image} />
16+ </div>
17+ ) : (
18+ <div
19+ className="rounded-xl w-full"
20+ style={{
21+ backgroundColor: feat?.matchedPost?.bgColor || "rgba(0,0,0,0)",
22+ }}
23+ />
24+ )}
25+ <div className="pt-4">
26+ <p className="mb-2 font-semibold leading-5">{feat.title}</p>
27+ <EcosystemBadge type={feat.type} />
28+ <p className="text-sm leading-5">{feat?.description}</p>
29+ </div>
30+ </div>
31+ </div>
32+ </Link>
33+ );
34+}
components/ecosystem/MetadataBlock.jsnew file+7
@@ -0,0 +1,7 @@
1+export default function MetadataBlock({ title, content }) {
2+ return <div className="flex flex-col py-2 basis-1/2">
3+ <p className="font-bold text-wall-400">{title}</p>
4+ <p>{content}</p>
5+ </div>
6+
7+}
components/ecosystem/Post.jsnew file+107
@@ -0,0 +1,107 @@
1+import { Markdown } from "@urbit/foundation-design-system";
2+import EcosystemBadge from "./Badge";
3+
4+import Link from "next/link";
5+export default function Post({ post }) {
6+ return ["featured-1", "featured-2", "featured-3"].map((feat) => {
7+ const childPath =
8+ post[feat] && (post[feat]?.matchedPost?.type === "Application" || post[feat]?.matchedPost?.type === "Group")
9+ ? `${post[feat]?.matchedPost.ship}/${post[feat].matchedPost.slug}`
10+ : `${post[feat].matchedPost?.slug}`;
11+ const href = post[feat]?.matchedPost
12+ ? `/${post[feat].matchedPost.type.toLowerCase()}s/${childPath}`
13+ : null;
14+ return post?.[feat] ? (
15+ <div
16+ className="mt-8 mb-24"
17+ id={post?.[feat].title.toLowerCase().replace(/ /, "-")}
18+ >
19+ <div className="flex space-x-4 items-center">
20+ <div
21+ className="h-24 w-24 rounded-xl items-center justify-center shrink-0 overflow-hidden"
22+ style={{
23+ backgroundColor:
24+ post[feat]?.matchedPost?.bgColor || "rgba(0,0,0,0)",
25+ }}
26+ >
27+ {(post[feat]?.matchedPost?.image || post[feat]?.matchedPost?.tile) && (
28+ <img
29+ className="rounded-xl w-24 object-cover"
30+ src={post[feat]?.matchedPost?.image || post[feat]?.matchedPost?.tile}
31+ />
32+ )}
33+ </div>
34+ <div className="flex flex-col">
35+ <h4 className="text-xl pb-2 leading-6 font-bold">
36+ {post?.[feat].title}
37+ </h4>
38+ <EcosystemBadge type={post[feat].type} />
39+ </div>
40+ </div>
41+ <div className="markdown mt-8 mb-8">
42+ <Markdown.render content={JSON.parse(post[feat].content)} />
43+ </div>
44+
45+ {post[feat].type === "Podcast" && (
46+ <Link href={href || "#"} passHref>
47+ <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
48+ Listen to {post[feat].type}
49+ </a>
50+ </Link>
51+ )}
52+
53+ {post[feat].type === "Article" && (
54+ <Link href={href || "#"} passHref>
55+ <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
56+ Read {post[feat].type}
57+ </a>
58+ </Link>
59+ )}
60+
61+ {post[feat].type === "Application" && (
62+ <Link href={href || "#"} passHref>
63+ <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
64+ View {post[feat].type}
65+ </a>
66+ </Link>
67+ )}
68+
69+ {post[feat].type === "Organization" && (
70+ <Link href={href || "#"} passHref>
71+ <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
72+ More about {post[feat].title}
73+ </a>
74+ </Link>
75+ )}
76+
77+ {post[feat].type === "Community" && (
78+ <Link href={href || "#"} passHref>
79+ <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
80+ More about {post[feat].title}
81+ </a>
82+ </Link>
83+ )}
84+
85+
86+ {post[feat].type === "Marketplace" && (
87+ <Link href={href || "#"} passHref>
88+ <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
89+ More about {post[feat].title}
90+ </a>
91+ </Link>
92+ )}
93+
94+ {post[feat].type === "Group" && (
95+ <Link href={href || "#"} passHref>
96+ <a class="button-sm text-white flex-col bg-green-400 cursor-pointer pr-4 w-fit">
97+ More about {post[feat].title}
98+ </a>
99+ </Link>
100+ )}
101+
102+ </div>
103+ ) : null;
104+ });
105+}
106+
107+
components/ecosystem/SpotlightArchive.jsnew file+66
@@ -0,0 +1,66 @@
1+import { Container, IntraNav, SingleColumn, Section } from "@urbit/foundation-design-system";
2+import Header from "../Header";
3+import Footer from "../Footer";
4+import Meta from "../Meta";
5+import Head from "next/head";
6+import Link from "next/link";
7+import EcosystemSidebar from "./EcosystemSidebar";
8+import Sidebar from "../Sidebar";
9+
10+export default function SpotlightArchive({ posts, search }) {
11+ const post = {
12+ title: "Spotlight Archive",
13+ description: "The archive of ecosystem spotlights.",
14+ };
15+ return (
16+ <Container>
17+ <Head>
18+ <title>Archive • Spotlight • Urbit</title>
19+ {Meta(post)}
20+ </Head>
21+ <IntraNav ourSite="https://urbit.org" search={search} />
22+ <SingleColumn>
23+ <Header search={search} />
24+ <Section>
25+ <div className="measure">
26+ <h1>Ecosystem</h1>
27+ </div>
28+ </Section>
29+ <Section className="flex">
30+ <Sidebar>
31+ <EcosystemSidebar />
32+ </Sidebar>
33+ <div>
34+ <h3 className="mb-12">Spotlight Archive</h3>
35+ {posts.map((post) => {
36+ return (
37+ <div key={post.slug} className="mb-24 cursor-pointer">
38+ <Link href={`/ecosystem/spotlight/${post.slug}`}>
39+ <div>
40+ <h3 className="text-green-400">{post.title}</h3>
41+ <div className="type-ui mt-2">
42+ {["featured-1", "featured-2", "featured-3"].map(
43+ (feat, i) => {
44+ if (post?.[feat]) {
45+ return (
46+ <>
47+ {i ? ", " : ""}
48+ <span>{post[feat].title}</span>
49+ </>
50+ );
51+ }
52+ }
53+ )}
54+ </div>
55+ </div>
56+ </Link>
57+ </div>
58+ );
59+ })}
60+ </div>
61+ </Section>
62+ </SingleColumn>
63+ <Footer />
64+ </Container>
65+ );
66+}
components/gateway/Description.jsnew file+19
@@ -0,0 +1,19 @@
1+import { Markdown } from "@urbit/foundation-design-system";
2+
3+const Description = ({ description, fallback, markdown }) => {
4+ return (
5+ (description !== fallback || markdown) && (
6+ <div className="flex flex-col space-y-4">
7+ {markdown ? (
8+ <div className="markdown">
9+ <Markdown.render content={JSON.parse(markdown)} />
10+ </div>
11+ ) : (
12+ <p>{description}</p>
13+ )}
14+ </div>
15+ )
16+ );
17+};
18+
19+export default Description;
components/gateway/Gateway404.jsnew file+29
@@ -0,0 +1,29 @@
1+import GatewayHeader from "./GatewayHeader";
2+import {
3+ Container,
4+ SingleColumn,
5+ Section,
6+} from "@urbit/foundation-design-system";
7+import Link from "next/link";
8+
9+const Gateway404 = ({ type }) => {
10+ return (
11+ <Container>
12+ <SingleColumn>
13+ <Section narrow className="space-y-12">
14+ <GatewayHeader
15+ title="Error 404"
16+ error
17+ item={`No ${type} at this address`}
18+ />
19+ <hr className="text-wall-200" />
20+ <Link href="/" passHref>
21+ <a className="text-xl block font-semibold">Urbit.org</a>
22+ </Link>
23+ </Section>
24+ </SingleColumn>
25+ </Container>
26+ );
27+};
28+
29+export default Gateway404;
components/gateway/GatewayHeader.jsnew file+29
@@ -0,0 +1,29 @@
1+import GatewayImage from "./Image";
2+
3+const GatewayHeader = ({
4+ image,
5+ patp,
6+ color,
7+ subtitle,
8+ subtitleMono,
9+ error,
10+ title,
11+ item,
12+}) => {
13+ return (
14+ <div className="flex items-center space-x-4">
15+ <GatewayImage patp={patp} color={color} image={image} error={error} />
16+ <div className="flex flex-col">
17+ <h2>{title}</h2>
18+ {subtitle && (
19+ <p className={(subtitleMono ? "font-mono" : "font-sans") }>
20+ {subtitle}
21+ </p>
22+ )}
23+ <p className="mt-1">{item}</p>
24+ </div>
25+ </div>
26+ );
27+};
28+
29+export default GatewayHeader;
components/gateway/Image.jsnew file+62
@@ -0,0 +1,62 @@
1+import { Sigil } from "@urbit/foundation-design-system";
2+const GatewayImage = ({
3+ error = false,
4+ patp = false,
5+ color = "transparent",
6+ image = "",
7+ size = 100,
8+}) => {
9+ if (error) {
10+ return (
11+ <div className="overflow-hidden rounded-xl shrink-0">
12+ <svg
13+ width={size}
14+ height={size}
15+ viewBox="0 0 100 100"
16+ fill="none"
17+ xmlns="http://www.w3.org/2000/svg"
18+ >
19+ <rect width="100" height="100" rx="10" className="fill-wall-600" />
20+ <path
21+ d="M28.8906 27.9844C28.5019 28.0215 28.1699 28.2833 28.043 28.6524C27.914 29.0235 28.0137 29.4336 28.2969 29.7032L70.2969 71.7032C70.4844 71.8965 70.7402 72.0059 71.0098 72.0059C71.2773 72.0079 71.5352 71.9004 71.7246 71.709C71.9141 71.5176 72.0176 71.2598 72.0137 70.9903C72.0098 70.7227 71.8984 70.4668 71.7031 70.2813L66.2501 64.8283C69.8204 60.9181 72.0001 55.7073 72.0001 50.0003C72.0001 37.8618 62.1386 28.0003 50.0001 28.0003C44.2931 28.0003 39.0976 30.1956 35.1876 33.7658L29.7031 28.2813C29.4922 28.0645 29.1934 27.9551 28.8906 27.9844L28.8906 27.9844ZM50.0001 30C61.0566 30 70.0001 38.9435 70.0001 50C70.0001 55.17 68.0411 59.8575 64.8281 63.406L36.5936 35.1715C40.1405 31.9606 44.8336 29.9995 49.9996 29.9995L50.0001 30ZM32.1721 37.8125C31.842 37.8321 31.5452 38.0137 31.3752 38.2969C29.2424 41.6856 28.0002 45.7029 28.0002 49.9999C28.0002 62.1384 37.8617 71.9999 50.0002 71.9999C54.2951 71.9999 58.3147 70.7558 61.7032 68.6249C62.1739 68.3319 62.3165 67.7128 62.0235 67.2421C61.7305 66.7714 61.1114 66.6288 60.6407 66.9218C57.5587 68.8593 53.9122 69.9999 50.0002 69.9999C38.9437 69.9999 30.0002 61.0564 30.0002 49.9999C30.0002 46.0878 31.1233 42.4414 33.0627 39.3594C33.2697 39.043 33.2815 38.6387 33.092 38.3125C32.9045 37.9844 32.5491 37.7929 32.1721 37.8125L32.1721 37.8125Z"
22+ className="fill-white"
23+ />
24+ </svg>
25+ </div>
26+ );
27+ }
28+
29+ if (patp) {
30+ return (
31+ <div className="rounded-xl overflow-hidden shrink-0">
32+ <Sigil patp={patp} size={size} color={color} />
33+ </div>
34+ );
35+ }
36+
37+ if (image?.startsWith("#")) {
38+ return (
39+ <div
40+ style={{ height: size, width: size, backgroundColor: image }}
41+ className="rounded-xl shrink-0"
42+ />
43+ );
44+ }
45+
46+ return image ? (
47+ <div
48+ className="rounded-xl overflow-hidden shrink-0"
49+ style={{ backgroundColor: color }}
50+ >
51+ <img src={image} style={{ height: size, width: size }} />
52+ </div>
53+ ) : (
54+ <img
55+ className="object-contain shadow-sm rounded-xl"
56+ style={{ height: size, width: size }}
57+ src="https://media.urbit.org/public-links/placeholder-image.png"
58+ />
59+ );
60+};
61+
62+export default GatewayImage;
components/gateway/MetadataBlock.jsnew file+8
@@ -0,0 +1,8 @@
1+const MetadataBlock = ({ title, content }) => (
2+ <div className="flex flex-col basis-1/2 pr-2 sm:basis-1/4 mb-4 md:mb-0 flex-1">
3+ <p className="font-bold text-wall-400">{title}</p>
4+ <p className="font-mono">{content}</p>
5+ </div>
6+);
7+
8+export default MetadataBlock;
components/gateway/MetadataLink.jsnew file+14
@@ -0,0 +1,14 @@
1+import Link from "next/link";
2+
3+const MetadataLink = ({ title, href, content }) => (
4+ <div className="flex flex-col basis-1/2 sm:basis-1/4 pr-2 mb-4 min-w-0 flex-1">
5+ <p className="font-bold text-wall-400">{title}</p>
6+ <Link href={href}>
7+ <div className="flex truncate">
8+ <a className="truncate font-mono text-green-400">{content}</a>
9+ </div>
10+ </Link>
11+ </div>
12+);
13+
14+export default MetadataLink;
components/gateway/ResourceCard.jsnew file+24
@@ -0,0 +1,24 @@
1+import Link from "next/link";
2+import GatewayImage from "./Image";
3+import classNames from "classnames";
4+import { capitalize } from "@urbit/foundation-design-system";
5+
6+const ResourceCard = ({ type, shortcode, title, description = "", color, image, full }) => (
7+ <Link href={`/${type}s/${shortcode}`}>
8+ <div className={classNames("cursor-pointer rounded-xl bg-wall-100 p-4 flex items-center space-x-4 mr-2 my-1", {
9+ "basis-full": full
10+ })}>
11+ <GatewayImage color={color} image={image || color} size={50} />
12+ {full
13+ ? <><div className="flex flex-col w-full">
14+ <a className="font-semibold">{title}</a>
15+ <p className="hidden lg:block">{description}</p>
16+ </div>
17+ <a className="button-lg bg-green-400 text-white shrink-0">View {capitalize(type)}</a>
18+ </>
19+ : <a className="font-semibold">{title}</a>}
20+ </div>
21+ </Link>
22+);
23+
24+export default ResourceCard;
components/icons/Cross.jsnew file+11
@@ -0,0 +1,11 @@
1+export default function Cross(props) {
2+ return (
3+ <svg {...props} viewBox="0 0 12 12">
4+ <path
5+ fillRule="evenodd"
6+ clipRule="evenodd"
7+ d="M0.292893 10.2942C-0.0976311 10.6847 -0.0976311 11.3179 0.292893 11.7084C0.683417 12.0989 1.31658 12.0989 1.70711 11.7084L6.00063 7.41487L10.2948 11.7091C10.6853 12.0996 11.3185 12.0996 11.709 11.7091C12.0996 11.3185 12.0996 10.6854 11.709 10.2949L7.41484 6.00066L11.7084 1.70711C12.0989 1.31658 12.0989 0.683417 11.7084 0.292894C11.3179 -0.0976312 10.6847 -0.0976312 10.2942 0.292894L6.00063 4.58645L1.70775 0.293571C1.31723 -0.0969534 0.684061 -0.0969534 0.293536 0.293571C-0.0969879 0.684095 -0.0969879 1.31726 0.293536 1.70778L4.58641 6.00066L0.292893 10.2942Z"
8+ />
9+ </svg>
10+ );
11+}
components/index/BubbleLink.jsnew file+25
@@ -0,0 +1,25 @@
1+export default function BubbleLink(props) {
2+ return (
3+ <li className={"list-none " + props.className}>
4+ <a className={"flex"} href={props.href} target={props.target}>
5+ <div>{props.children}</div>
6+ <div className="flex flex-col ml-4">
7+ <p className="font-bold">{props.title}</p>
8+ <p className="text-wall-400 dark:text-antiwall-400 font-bold leading-snug">
9+ {props.caption}
10+ </p>
11+ </div>
12+ </a>
13+ </li>
14+ );
15+}
16+
17+BubbleLink.defaultProps = {
18+ className: "",
19+ title: "",
20+ caption: "",
21+ children: (
22+ <div className="w-12 h-12 bg-wall-500 dark:bg-antiwall-500 rounded-full" />
23+ ),
24+ target: "_blank",
25+};
content/applications/_index.mdnew file+3
@@ -0,0 +1,3 @@
1++++
2+title = "Application Directory"
3++++
content/applications/~bacwyl-samweg/templeochess.mdnew file+22
@@ -0,0 +1,22 @@
1++++
2+title = "Temple O Chess"
3+shortcode = "~bacwyl-samweg/templeochess"
4+license = "MIT"
5+image = "https://0x0.st/oFuT.png"
6+bgColor = "#FFFF55"
7+developer = "~bacwyl-samweg"
8+website = "https://youtu.be/Raej8C2yIEc"
9+description = "chess game from Temple OS"
10++++
11+
12+### Chess from Temple OS
13+![Screenshot](https://0x0.st/oORF.png)
14+
15+Temple O Chess is a pixel-for-pixel reproduction of the chess game from Temple OS.
16+
17+It was created using [this youtube video](https://youtu.be/Raej8C2yIEc) as a reference.
18+
19+It's a fully playable online chess game. Instead of a challenge system, games are formed using a naive public queue.
20+
21+Just queue up, and you will be automatically matched with the next (or previous) player.
22+
content/applications/~datder-sonnet/hodl.mdnew file+16
@@ -0,0 +1,16 @@
1++++
2+title = "hodl"
3+description = "Track your digital hodlings"
4+shortcode = "~hodler-datder-sonnet/hodl"
5+license = "MIT"
6+image = "https://user-images.githubusercontent.com/16504501/194947852-8802fd63-5954-4ce8-b147-2072bd929242.png"
7+bgColor = "#b8a3d1"
8+developer = "~datder-sonnet"
9+website = "https://github.com/tomholford/hodl"
10++++
11+
12+A portfolio app for tracking your digital assets.
13+
14+Add transactions to get a summary of your crypto net worth.
15+
16+Supports over 13K coins via the Coingecko API.
content/applications/~disreb-winner-mittec/urbit-go.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Go"
3+shortcode = "~disreb-winner-mittec/urbit-go"
4+license = "GPLv3"
5+image = "https://winnermittec.space/icon.svg"
6+bgColor = "#D37504"
7+developer = "~winner-mittec"
8+website = "https://winnermittec.space/"
9+description = "Go on Urbit"
10++++
11+
12+The classic board-game Go, now on Urbit!
content/applications/~dister-dister-datryn-ribdun/campfire.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Campfire"
3+shortcode = "~dister-dister-datryn-ribdun/campfire"
4+description = "Voice and video chat"
5+license = "MIT"
6+image = "https://raw.githubusercontent.com/datryn-ribdun/urbit-webrtc/master/campfire/logo.svg"
7+bgColor = "#FFC179"
8+developer = "~datryn-ribdun"
9+website = "https://github.com/datryn-ribdun/urbit-webrtc"
10++++
11+
12+Hang out with your friends. Voice and video chat by Holium.
content/applications/~dister-dister-sidnym-ladrut/quorum.mdnew file+17
@@ -0,0 +1,17 @@
1++++
2+title = "Quorum"
3+shortcode = "~dister-dister-sidnym-ladrut/quorum"
4+developer = "Quorum Team"
5+description = "A choral explanations app for Urbit"
6+license = "MIT"
7+website = ""
8+bgColor = ""
9+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/quorum-logo.png"
10++++
11+
12+Quorum is a Stack Overflow/Quora style application that allows individuals to submit and vote on questions and answers in threads.
13+
14+To join the Urbit Foundation's [battery payload] board, when prompted to add a board, enter `~dister-dozzod-lapdeg` as the provider, and `battery-payload` as the board.
15+
16+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/quorum.png)
17+
content/applications/~dister-dozzod-bacdun/uqbar-suite.mdnew file+20
@@ -0,0 +1,20 @@
1++++
2+title = "Uqbar Development Suite"
3+shortcode = "~dister-dozzod-bacdun/zig"
4+developer = "Uqbar"
5+description = "The contract & app development, wallet, and block explorer suite from Uqbar."
6+license = "MIT"
7+website = "https://uqbar.network"
8+bgColor = ""
9+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/uqbarsuite.png"
10++++
11+
12+The Uqbar Development Suite, also known as Ziggurat, is an all-in-one developer suite designed to give programmers a seamless coding experience as they create and deploy smart contracts and blockchain-integrated Urbit apps to our testnet. The Ziggurat suite consists of:
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/ziggurat-1.png)
15+
16+
17+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/ziggurat-2.png)
18+
19+
20+For more information, read our [Developer Docs](https://uqbar-network.gitbook.io/uqbar-developer-documentation/developer-documentation/developer-documentation).
content/applications/~dister-dozzod-dalten/books.mdnew file+20
@@ -0,0 +1,20 @@
1++++
2+title = "Books"
3+developer = "Quartus Co."
4+shortcode = "~dister-dozzod-dalten/books"
5+description = "It just makes cents"
6+license = "MIT"
7+website = "https://dalten.org"
8+bgColor = "#E44D11"
9++++
10+
11+Books is an application for managing your crypto wallets, transactions, and counterparties. It allows you to add your wallet and other people’s, track balances and transactions, and add private annotations to all of the above.
12+
13+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/books.png)
14+
15+## Books in a Nutshell
16+If you spend much time interacting with crypto, you probably have a few wallets: a few hot wallets in metamask, a ledger or two, perhaps an Urbit ID on a master ticket, and that’s just Ethereum.
17+
18+To get a good picture of your aggregate activity you can use a variety of chain analytics tools, but there’s always a sizable catch: there’s nowhere to record the identities of the counter parties you transact with, or the purpose of the transactions. To do this now, your options are to either keep your own records (offline), use a local-storage based address book like Metamask’s, or put your data on someone else’s servers.
19+
20+Books provides an ideal solution: annotate on-chain, public information with private data stored on your urbit, your personal server. This lets you account for your spending, keep records of the people you transact with, and organize your wallets without compromising on privacy or mobility.
content/applications/~dister-dozzod-dalten/gora.mdnew file+24
@@ -0,0 +1,24 @@
1++++
2+title = "Gora - ピタゴラ装置"
3+developer = "~dalten"
4+shortcode = "~mister-dozzod-dalten/gora"
5+description = "A Proof of Attendance Protocol for Urbit"
6+license = "MIT"
7+website = "https://dalten.org"
8+bgColor = "#FCD977"
9++++
10+
11+### A Proof of Attendance Protocol for Urbit
12+
13+Gora is a proof of presence protocol (POPP) that is
14+intended to be extensible, flexible and educational
15+(at least for new hooners).
16+
17+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/gora.png)
18+
19+
20+Gora has two distros in
21+circulation - these can be found at:
22+~laddys-dozzod-dalten (Vue.js frontend)
23+~mister-dozzod-dalten (sail frontend)
24+The canonical distro for all Quartus and Dalten Collective apps can always be found at ~dister-dozzod-dalten
content/applications/~dister-dozzod-dalten/keep.mdnew file+13
@@ -0,0 +1,13 @@
1++++
2+title = "Keep"
3+developer = "Quartus Co."
4+shortcode = "~dister-dozzod-dalten/keep"
5+description = "State backup for your agents"
6+license = "MIT"
7+website = "https://dalten.org"
8+bgColor = "#E44D11"
9++++
10+
11+Keep is backup utility for preserving the state of your applications across breaches. Unlike [peat](https://urbit.org/ecosystem/applications/~dister-dozzod-dalten/peat), Keep can backup the state of any arbitrary agent, but does not offer granular control of specific graphs or other targeted contexts.
12+
13+For support with any of Quartus' applications, please visit the [Quartus public group](https://urbit.org/ecosystem/groups/~mister-hilper-dozzod-dalten/quartus)
content/applications/~dister-dozzod-dalten/orca.mdnew file+17
@@ -0,0 +1,17 @@
1++++
2+title = "Orca"
3+developer = "Quartus Co."
4+shortcode = "~dister-dozzod-dalten/orca"
5+description = "Now THIS is podchatting"
6+license = "MIT"
7+website = "https://dalten.org"
8+bgColor = "#13181C"
9++++
10+
11+** ocra has been deprecated and will soon be replaced with updated tooling supporting chat federation for the new Groups backend **
12+
13+Now THIS is podchatting
14+
15+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/orca.png)
16+
17+
content/applications/~dister-dozzod-dalten/peat.mdnew file+36
@@ -0,0 +1,36 @@
1++++
2+title = "peat"
3+developer = "Quartus Co."
4+shortcode = "~dister-dozzod-dalten/peat"
5+description = "Graph Backup and Restoration Utility"
6+license = "REKT"
7+website = "https://dalten.org"
8+bgColor = "#574D5A"
9++++
10+
11+Peat is Urbit's first backup utility and works with the %graph-store backend. Quartus is also working to support backup and recovery for arbitrary agent state via %keep, as well as updated utility tooling that supports the new Groups backend.
12+
13+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/peat.png)
14+
15+## Peat in a Nutshell
16+- Import
17+ - Recover a Social `graph` from a saved file - transferrable between ships
18+- Export
19+ - Export a Social `graph` to a file on underlying file system (e.g. Unix)
20+- Backup/Restore
21+ - Local recreation of a `graph` that exists, 're-basing' the `graph` to be hosted by the local ship
22+## Import from Disk - Details
23+- User has a `/path/to/pier/<project-desk>/hav` directory for importing (though they could import from anywhere, really).
24+- User also has a form interface, through Peat's webapp allowing them to import without tracking the files in their loom.
25+### From Clay
26+- User gets instructions from the frontend as to how to add files to this directory and commit the desk so the files are available in the OS
27+ - NOTE: This should be converted to using `drum`'s `get` functionality at some point, but this hasn't been wired up yet in `drum`.
28+- User can see all files available for restoration in the default `hav` directory, delineated by whether they represent Agent `state` or `graph`s
29+- User can select a file for restoration
30+- User can apply the file for restoration
31+ - Potentially needing to specify additional details, for a `graph` (e.g. what `group` to associate it with, and what to call the new `resource`)
32+User is informed that the restoration is underway/has completed
33+### From Web
34+- User gets instructions from the frontend as to how to upload files through the frontend, resulting in their unpacking and importing to graph store
35+- User can select from local files on the computer through which they're accessing the frontend.
36+- Note: This method avoids polluting loom with transient files - it is to be the preferred method
content/applications/~dister-dozzod-dalten/wrdu.mdnew file+15
@@ -0,0 +1,15 @@
1++++
2+title = "wrdu"
3+developer = "Quartus Co."
4+shortcode = "~dister-dozzod-dalten/wrdu"
5+description = "Word game by ~dalten for our mothers"
6+license = "MIT"
7+website = "https://dalten.org"
8+bgColor = "#79A86B"
9++++
10+
11+word game by ~dalten for our mothers
12+
13+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/wrdu.png)
14+
15+
content/applications/~donpub-datdux/forms.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Forms"
3+shortcode = "~donpub-datdux/forms"
4+developer = "~nallux-dozryl"
5+description = "Publish and Respond to Forms."
6+license = "MIT"
7+website = "https://github.com/nallux-dozryl/urbit-forms"
8+bgColor = "#AFC4E0"
9+image = ""
10++++
11+
12+Create and fill out forms and surveys on Urbit.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/new-form.png)
content/applications/~fabnev-hinmur/escape.mdnew file+16
@@ -0,0 +1,16 @@
1++++
2+title = "EScape"
3+shortcode = "~dister-fabnev-hinmur/escape"
4+developer = "Uqbar"
5+description = "EScape from Eternal September. The UI from Uqbar."
6+license = "MIT"
7+website = "https://uqbar.network"
8+bgColor = "#f2f3ef"
9+image = "https://escape-app-dist.s3.us-east-2.amazonaws.com/escape-logo.png"
10++++
11+
12+EScape is a fully-integrated social management and DAO Tooling system. EScape provides a simple, intuitive, and unified interface for managing groups, messaging ships, receiving notifications, and interacting with other Urbit apps.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/escape2.png)
15+
16+Get EScape on [iOS](https://apps.apple.com/my/app/escape-by-uqbar/id1610194217) and [Android](https://play.google.com/store/apps/details?id=network.uqbar.escape).
content/applications/~fabnev-hinmur/handshake.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Handshake"
3+developer = "Uqbar"
4+shortcode = "~dister-fabnev-hinmur/handshake"
5+description = "Confirm Urbit IDs via QR code."
6+license = "MIT"
7+website = "https://uqbar.network"
8+bgColor = "#df828b"
9+image = "https://static.thenounproject.com/png/2002633-200.png"
10++++
11+
12+Handshake generates and verifies QR codes for admission into IRL events.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/handshake.png)
content/applications/~finmep-lanteb/chess.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Chess"
3+shortcode = "~finmep-lanteb/chess"
4+developer = "~bonbud-macryg, ~finmep-lanteb, ~nordus-mocwyl, ~rovmug-ticfyn, ~sigryn-habrex"
5+description = "Fully peer-to-peer chess over Urbit"
6+license = "GPL3"
7+website = "https://github.com/thecommons-urbit/chess"
8+bgColor = "#ffffff"
9+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/finmep-chess.svg"
10++++
11+
12+Fully decentralized, peer-to-peer Chess app for Urbit
13+
14+![chess example](https://raw.githubusercontent.com/thecommons-urbit/chess/master/images/urbit-chess-demo.png)
content/applications/~haddef-sigwen/transit.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Transit"
3+shortcode = "~haddef-sigwen/transit"
4+license = "MIT"
5+image = "https://haddefsigwen1.s3.us-east-1.amazonaws.com/haddef-sigwen/2022.5.07..20.27.02-image.png"
6+bgColor = "#38285c"
7+developer = "~haddef-sigwen"
8+description = "Planetary transit occurs once per day."
9+website = ""
10++++
11+
12+Planetary transit occurs once per day.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/transit.png)
content/applications/~hanfel-dovned/board.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Board"
3+shortcode = "~dister-hanfel-dovned/board"
4+license = "MIT"
5+image = ""
6+bgColor = "#9E34EB"
7+developer = "~hanfel-dovned"
8+website = "https://github.com/hanfel-dovned/Board"
9+description = "A digital bulletin-board"
10++++
11+
12+An implementation of [Robin Sloan’s Spring ‘83](https://www.robinsloan.com/lab/specifying-spring-83/) concept as an Urbit app called %board. Imagine a digital bulletin-board where each item is a person’s miniature homepage, and the pages you see are based on who you know.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/board.png)
content/applications/~hanfel-dovned/pony.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Pony"
3+shortcode = "~dister-hanfel-dovned/pony"
4+license = "MIT"
5+image = ""
6+bgColor = "#232323"
7+developer = "~hanfel-dovned"
8+website = "https://github.com/hanfel-dovned/Pony"
9+description = "Pony is an app for longform threaded conversations"
10++++
11+
12+Pony is an app for longform threaded conversations, like a blend of email and message boards. Create private threads with arbitrary sets of ships, fork threads to new sets of participants, schedule messages to be sent later, and much more.
content/applications/~hanfel-dovned/slam.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Slam"
3+shortcode = "~dister-hanfel-dovned/slam"
4+license = "MIT"
5+image = "https://hanfel-dovned.sfo3.digitaloceanspaces.com/slam-tile.png"
6+bgColor = "#100032"
7+developer = "~hanfel-dovned"
8+website = "https://github.com/hanfel-dovned/Slam"
9+description = "A social arcade game"
10++++
11+
12+Slam is a social arcade game where you battle waves of enemies that are generated from your pals' gorae.
13+
14+Requires [gora](https://urbit.org/applications/~dalten/gora) and [pals](https://urbit.org/applications/~paldev/pals).
content/applications/~hanrut-sillet-dachus-tiprel/blog.mdnew file+16
@@ -0,0 +1,16 @@
1++++
2+title = "%blog"
3+shortcode = "~hanrut-sillet-dachus-tiprel/blog"
4+license = "MIT"
5+image = ""
6+bgColor = "#533E78"
7+developer = "~dachus-tiprel"
8+website = "https://dachus-tiprel.tlon.network/blog/introducing-blog"
9+description = "The easiest and most versatile publishing app on Urbit"
10++++
11+
12+A publishing tool for creating a basic blog with markdown and css.
13+
14+Blog is just what it sounds like. A new tool from Uqbar, the app lets anyone on Urbit spin up and customize a blog that displays to the net at an auto-generated URL. Nothing could be breezier. Plus it’s got payments through Uqbar and group-blogging settings on the roadmap. Find out more about it on it's [creator's blog](https://dachus-tiprel.tlon.network/blog/introducing-blog).
15+
16+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/blog.png)
content/applications/~larryx-woldyr/osmosis.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Osmosis"
3+shortcode = "~larryx-woldyr/osmosis"
4+license = "MIT"
5+image = "https://holium-app-globs.nyc3.cdn.digitaloceanspaces.com/osmosis/osmosis-logo-wc.png"
6+bgColor = "#180D39"
7+developer = "~larryx-woldyr"
8+website = "https://https://osmosis.zone/"
9+description = "Interchain liquidity lab."
10++++
11+
12+A fully self-hosted Osmosis frontend, deployed via Urbit.
content/applications/~larryx-woldyr/safe.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Safe"
3+shortcode = "~larryx-woldyr/safe"
4+license = "MIT"
5+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/safe.jpeg"
6+bgColor = "#180D39"
7+developer = "~larryx-woldyr"
8+website = "https://safe.global/"
9+description = "Safe front-end"
10++++
11+
12+A fully self-hosted Safe frontend, deployed via Urbit.
content/applications/~larryx-woldyr/uniswap.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Uniswap"
3+shortcode = "~larryx-woldyr/uniswap-v3"
4+license = "MIT"
5+image = "https://cryptologos.cc/logos/uniswap-uni-logo.png"
6+bgColor = "0xffffff"
7+developer = "~larryx-woldyr"
8+website = "http://uniswap.org"
9+description = "Self-hosted Uniswap interface"
10++++
11+
12+A self-hosted Uniswap interface for swapping assets on Ethereum.
content/applications/~larryx-woldyr/urbhue.mdnew file+18
@@ -0,0 +1,18 @@
1++++
2+title = "Hue"
3+shortcode = "~larryx-woldyr/urbhue"
4+license = "MIT"
5+image = "https://i.imgur.com/czmkmoK.png"
6+bgColor = "#F0B43D"
7+developer = "~larryx-woldyr"
8+website = "https://ajlamarc.com"
9+description = "Controlling Philips Hue"
10++++
11+
12+In this prototype, Philips Hue Lightbulbs and groups can be controlled from a standard Urbit application by using the Hue Remote API.
13+
14+History and logging of the bulb are collected to provoke consideration of what should be controlled and tracked by the people living in a smart home.
15+
16+This app will hopefully inspire people to think of the potential utility of Urbit in the smart home, inspire non-Urbit users to think of Urbit in non-community driven scenarios, and be a small step forward in understanding the affordances for Urbit in the home.
17+
18+For more information on `%urbhue`, check out our Urbit group: `~pilwyc-fastec/communal-computing-for-urbit`
content/applications/~lomder-librun/ballot.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Ballot"
3+shortcode = "~livdel-binmun-lomder-librun/ballot"
4+license = "MIT"
5+image = "https://lomder-librun.sfo3.digitaloceanspaces.com/tiles/ballot-app-tile.svg"
6+bgColor = "#cebef0"
7+developer = "~lomder-librun"
8+website = "https://www.holium.com"
9+description = "An app that allows you to vote with other ships."
10++++
11+
12+Ballot allows you to create and vote on proposals, delegate votes to other urbit ships, and trigger actions based on results.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/ballot.png)
content/applications/~lomder-librun/realm.mdnew file+18
@@ -0,0 +1,18 @@
1++++
2+title = "Realm"
3+shortcode = "~lomdyr-librun/realm"
4+license = ""
5+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/realm-icon.png"
6+bgColor = ""
7+developer = "Holium"
8+website = "https://www.holium.com/"
9+description = "A desktop interface for Urbit"
10++++
11+
12+Realm is a desktop app for Urbit communities (currently in private alpha).
13+
14+[Sign up for the alpha.](https://www.holium.com/)
15+
16+<iframe width="560" height="315" src="https://www.youtube.com/embed/gdu4QtFR-Bs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
17+
18+Note that the shortcode will not install this application.
content/applications/~midlev-mindyr/astrolabe.mdnew file+30
@@ -0,0 +1,30 @@
1++++
2+title = "Astrolabe"
3+shortcode = "~dister-midlev-mindyr/astrolabe"
4+license = ""
5+image = "https://raw.githubusercontent.com/johnhyde/astrolabe/main/ui/src/assets/astrolabe-tile.svg"
6+bgColor = ""
7+developer = "~midlev-mindyr"
8+website = "https://github.com/johnhyde/astrolabe"
9+description = "Astrolabe is a one-stop shop app for exploring Urbit address space."
10++++
11+
12+### Astrolabe is a one-stop shop app for exploring Urbit address space.
13+
14+Features:
15+
16+- **ID Search**:
17+When you search a partial @p (or use wildcards), it will show you the spawned/owned ships which match your search.
18+
19+- **Sigil Search**:
20+You can use a visual interface to enter sigils, either just general shapes, or specific shape/pattern combos
21+
22+- **Sky Chart**:
23+ Astrolabe integrates with %pals to highlight your pals on the sky chart. Clicking/tapping on a point opens a small modal with basic info and a button to take you to a Ship View of the point.
24+
25+- **Ship View**:
26+Summary view for any ship. As on urbit.live or urbit.me, it shows the @p, owner, parent, etc. Allows PNG or SVG download of sigils. Displays tags from %pals, and potentially allows you to add pals and/or edit tags from that screen.
27+
28+
29+
30+Astrolabe integrates with pals wherever possible, and contains documentation to explain the many quirks of Urbit address space to a new user.
content/applications/~midsum-salrux/faux.mdnew file+11
@@ -0,0 +1,11 @@
1++++
2+title = "Faux"
3+developer = "~midsum-salrux"
4+shortcode = "~tindys-botter-dozzod-tomdys/faux"
5+description = "An Urbit-native Discord bridge"
6+license = "MIT"
7+website = "https://github.com/midsum-salrux/faux"
8+bgColor = "#000000"
9++++
10+
11+Faux, a bridge between discord and urbit groups. When a member posts a new message in your discord group, a bot reposts it in your urbit group, and vice versa. This is implemented as a native gall agent and includes a frontend app to configure the connections between your discord and urbit servers.
content/applications/~migmeg-fidlen-sillus-mallus/kenning.mdnew file+17
@@ -0,0 +1,17 @@
1++++
2+title = "kenning"
3+shortcode = "~migmeg-fidlen-sillus-mallus/kenning"
4+license = "MIT"
5+image = "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Voiced_dental_fricative_%28vector%29.svg/1920px-Voiced_dental_fricative_%28vector%29.svg.png"
6+bgColor = "#a59a2d"
7+developer = "~sillus-mallus"
8+website = "https://lovecrypt.net"
9+description = "Memorization tool for text passages."
10++++
11+
12+Memorize passages of text. Every passage is called a “kenning”.
13+
14+1. Every kenning is assigned a kelvin version based on word count.
15+1. You may test your knowledge by filling in the blanks.
16+1. As kelvin decreases, the number of blanks increases.
17+1. For large passages, split the text into several kens for best results.
content/applications/~mister-dister-dozzod-dozzod/terminal.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Terminal"
3+developer = "Tlon"
4+shortcode = "~mister-dister-dozzod-dozzod/webterm"
5+description = "A web interface to your Urbit's command line."
6+license = "MIT"
7+website = "https://tlon.io"
8+bgColor = "#324246"
9++++
10+
11+
12+Terminal is a command line interface for your urbit. You can run commands, script, and program your Urbit directly, even if your urbit is located on a remote server. Discover the gratification of programming a computer that is truly yours.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/terminal.png)
content/applications/~niblyx-malnus/gol-cli.mdnew file+15
@@ -0,0 +1,15 @@
1++++
2+title = "Goals"
3+shortcode = "~dister-dozzod-niblyx-malnus/gol-cli"
4+license = "MIT"
5+image = ""
6+bgColor = "#362711"
7+developer = "~niblyx-malnus"
8+website = ""
9+description = "Hierarchically nested goals and projects"
10++++
11+
12+### Goals helps you track and share interrelated tasks
13+
14+
15+Goals is primarily dealing with four kinds of relationships: containment/ownership, virtual nesting, precedence, and priority. These fundamental relationships between goals and that any other important information about a goal does not require any complex sort of topological representation, but can simply be a piece of data associated with the goal.
content/applications/~nocsyx-lassul/silo.mdnew file+20
@@ -0,0 +1,20 @@
1++++
2+title = "silo"
3+shortcode = "~dister-nocsyx-lassul/silo"
4+license = "MIT"
5+image = ""
6+bgColor = "#4f46e5"
7+developer = "~nocsyx-lassul"
8+description = "An S3 storage manager"
9+website = "https://github.com/arthyn/silo"
10++++
11+
12+### An S3 storage manager
13+
14+Silo is an application for viewing and managing your urbit's file storage. Currently that means the files in an S3-compatible storage system, but hopefully soon we'll also be able to provide an interface for your local urbit's filesystem too.
15+
16+![](https://nyc3.digitaloceanspaces.com/hmillerdev/nocsyx-lassul/2022.7.23..19.23.39-Screen%20Shot%202022-07-23%20at%202.23.07%20PM.png)
17+
18+Currently silo allows you to upload, delete, add folders, and otherwise manage your files like you expect. It also offers easy access to downloading files and copying their URLs.
19+
20+In the future we hope to add the ability to easily share files with others, offer storage to friends or groups, a fully urbit-side S3 and virtual filesystem API, and a drop-in file-picker component that devs can use to easily add image uploads to their apps.
content/applications/~nocsyx-lassul/sphinx.mdnew file+20
@@ -0,0 +1,20 @@
1++++
2+title = "sphinx"
3+shortcode = "~dister-nocsyx-lassul/sphinx"
4+license = "MIT"
5+image = "https://nyc3.digitaloceanspaces.com/hmillerdev/nocsyx-lassul/2022.7.16..04.35.22-sphinx-web-shifted.svg"
6+bgColor = "#b25068"
7+developer = "~nocsyx-lassul"
8+website = "https://github.com/arthyn/sphinx"
9+description = "Community powered search"
10++++
11+
12+### Community powered search
13+
14+Sphinx is a search engine powered by you and your pals. Using the gossip mechanism developed by ~paldev for [%rumors](https://urbit.org/applications/~paldev/rumors), anytime you post a listing it gets indexed on your urbit and then shared with your friends and friends of friends.
15+
16+![](https://nyc3.digitaloceanspaces.com/hmillerdev/nocsyx-lassul/2022.7.23..19.04.39-Screen%20Shot%202022-07-23%20at%202.04.05%20PM.png)
17+
18+Currently sphinx is probably best as a tool for finding groups and apps, but will likely index content soon too. It uses exact, phonetic, and unordered trigram matching to index the keywords in your listings. This allows you to type a query inconsistently and still get similar results as if it was spelled right.
19+
20+Future features include tag aggregation for more "classifieds"-type browsing, browsing by who shared something, ability to specify who a listing gets shared with (private/pals/pals+sponsor), and the ability to add search providers who might host non-gossiped indexes.
content/applications/~nodmyn-dosrux/basket.mdnew file+34
@@ -0,0 +1,34 @@
1++++
2+title = "basket"
3+shortcode = "~nodmyn-dosrux/basket"
4+license = "MIT"
5+image = "https://0x0.st/oFHB.png"
6+bgColor = "#F2F2F2"
7+developer = "Assembly Capital"
8+website = "https://github.com/bacwyls/basket"
9+description = "show off your meme collection"
10++++
11+
12+
13+### Basket is a simple db of tagged images
14+
15+The frontend displays the most recent image in the full window,
16+so it can be used to add some personal style to an urbit desktop environment.
17+
18+In addition to being a personal db, basket is an experimental app on top of the 'rooms' primitive in [Realm](https://twitter.com/HoliumCorp).
19+
20+Members of a room have temporary write-access to each others basket db.
21+The frontend makes it ergonomic and fun to share / collaboritively create this data.
22+
23+In theory (at scale), this creates a kind of decentralized giphy.
24+
25+The images you know about are the images your friends have shared with you.
26+It gamifies the creation of rich, human curated image metadata.
27+One obvious use case for this is keeping track of memes.
28+
29+To export the full dataset you can GET `http://yoururbitship.com/~/scry/basket/images.json`
30+Then you might want to use a python script to actually download the images to local storage.
31+
32+Eventually, it would be nice to have a simple way to export and share the dataset.
33+
34+Read full documentation on the [Github repository](https://github.com/bacwyls/basket).
content/applications/~nodmyn-dosrux/houston.mdnew file+17
@@ -0,0 +1,17 @@
1++++
2+title = "houston"
3+shortcode = "~nodmyn-dosrux/houston"
4+license = "MIT"
5+image = "https://0x0.st/ojrj.png"
6+bgColor = "#FFFFFF"
7+developer = "Assembly Capital"
8+website = "https://github.com/assemblycapital/houston"
9+description = "Moon Management Dashboard"
10++++
11+
12+### Moon Management Dashboard
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/houston.png)
15+
16+Keeps track of the moons you've spawned and exposes a poke API for the standard moon utilities: `|moon`, `|moon-breach` and `|moon-cycle`
17+
content/applications/~nodmyn-dosrux/radio.mdnew file+15
@@ -0,0 +1,15 @@
1++++
2+title = "radio"
3+shortcode = "~nodmyn-dosrux/radio"
4+license = "MIT"
5+image = "https://0x0.st/o4--.png"
6+bgColor = "#f2f2f2"
7+developer = "Assembly Capital"
8+website = "https://github.com/bacwyls/radio"
9+description = "an app for urbit disc jockeys"
10++++
11+
12+Create and tune into virtual radio stations where you can chat and play Youtube videos with your friends.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/radio.png)
15+
content/applications/~nodmyn-dosrux/vita.mdnew file+20
@@ -0,0 +1,20 @@
1++++
2+title = "vita"
3+shortcode = "~nodmyn-dosrux/vita"
4+license = "MIT"
5+image = "https://bwyl.nyc3.digitaloceanspaces.com/vita%2Fvita.png"
6+bgColor = "#F2F2F2"
7+developer = "Assembly Capital"
8+website = "https://github.com/assemblycapital/vita"
9+description = "monitor your app distributions"
10++++
11+
12+### Keep track of your app distributions
13+
14+To get downloads, `:vita` periodically scrys %cs /subs for each desk and caches the results.
15+
16+`:vita` accepts foreign pokes attesting to activity on a desk.
17+`/lib/vita-client.hoon` helps any agent send vita activity pokes.
18+It sends a maximum of one poke per day, and allows users to opt-in / opt-out depending on developer preference.
19+
20+Read full documentation on the [Github repository](https://github.com/assemblycapital/vita).
content/applications/~norsyr-torryn/canvas.mdnew file+29
@@ -0,0 +1,29 @@
1++++
2+title = "canvas"
3+shortcode = "~dister-norsyr-torryn/canvas"
4+license = "MIT"
5+image = "https://yosoyubik.fra1.digitaloceanspaces.com/canvas/tile.svg"
6+bgColor = "#3787B9"
7+developer = "~norsyr-torryn"
8+website = "https://github.com/yosoyubik/canvas"
9+description = "Collaborative Pixel Art"
10++++
11+
12+### Collaborative Pixel Art
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/canvas.png)
15+
16+#### Features
17+- Each stroke is stored automatically on your Urbit.
18+- Export Canvas Images as SVG.
19+- Image files are stored on S3 Storage, if configured.
20+- Allows creation of public or private canvases.
21+- Others can join a public canvas and work collaboratively in a cool art project.
22+
23+#### Access
24+Search for ~dister-norsyr-torryn in Grid to find the Canvas app, and install it from there
25+
26+A public canvas is hosted at: ~picsel-norsyr-torryn/public
27+
28+
29+Come and join the group to share your creations and see what others are doing: ~norsyr-torryn/canvas
content/applications/~paldev/face.mdnew file+13
@@ -0,0 +1,13 @@
1++++
2+title = "face"
3+developer = "~paldev"
4+shortcode = "~paldev/face"
5+description = "see your friends"
6+license = "MIT"
7+website = "https://pal.dev/suite/face"
8+bgColor = "#3b5998"
9++++
10+
11+Face is an image rolodex of your urbit friends. Compatible with [pals](/applications/~paldev/pals), face lets you share a photo of yourself with mutuals and also see a gallery of their faces. To share, enter an image link in the url field.
12+
13+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/face.png)
content/applications/~paldev/fafa.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "fafa"
3+developer = "~paldev"
4+shortcode = "~paldev/fafa"
5+description = "2fa otp authenticator app"
6+license = "MIT"
7+website = "https://pal.dev/suite/fafa"
8+bgColor = "#1a1a2a"
9++++
10+
11+
12+Fafa is a two-factor authentication app. Log in to your saved accounts with a one-time passcode generated on your urbit. (Only access this app over a secure connection and remember to also save your backup codes somewhere secure.)
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/fafa.png)
content/applications/~paldev/pals.mdnew file+15
@@ -0,0 +1,15 @@
1++++
2+title = "pals"
3+shortcode = "~paldev/pals"
4+developer = "~paldev"
5+description = "friendlist for peer discovery"
6+license = "MIT"
7+website = "https://pal.dev/suite/pals"
8+bgColor = "#99D3BD"
9++++
10+
11+Pals is a contact list for your urbit friends. Send and receive friend requests with intuitive ease. Once you're pals, a smiley face icon indicates mutual status.
12+
13+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/pals.png)
14+
15+Keep track of who your pals are or how you know them with tags, which exist mostly for your own book-keeping, but could be used in the future by other applications to group content. Similarly, some apps work better with pals, like [rumors](/applications/~paldev/rumors), an anonymous gossip app, and [sphinx](/applications/~nocsyx-lassul/sphinx), an Urbit search engine.
content/applications/~paldev/picture.mdnew file+13
@@ -0,0 +1,13 @@
1++++
2+title = "picture"
3+developer = "~paldev"
4+shortcode = "~paldev/picture"
5+description = "a picture frame for the garden"
6+license = "MIT"
7+website = "https://pal.dev/suite/picture"
8+bgColor = "#DDDDDD"
9++++
10+
11+Picture is a digital frame for your urbit. Simply upload an image to see it every time you open up Landscape. (Refrain from uploading huge images to avoid memory pressure.)
12+
13+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/picture.png)
content/applications/~paldev/rumors.mdnew file+15
@@ -0,0 +1,15 @@
1++++
2+title = "rumors"
3+shortcode = "~paldev/rumors"
4+developer = "~paldev"
5+description = "anonymous gossip from friends of friends"
6+license = "MIT"
7+website = "https://pal.dev/suite/rumors"
8+bgColor = "#bb77dd"
9++++
10+
11+Rumors is an anonymous gossip feed powered by [pals](/applications/~paldev/pals). The more mutuals you have, the more rumors you'll see: messages posted by your pals, and their pals, populate the feed.
12+
13+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/rumors.png)
14+
15+Built using a p2p gossip protocol, rumors anonymizes posts and orders them chronologically. Drop links, ask questions, lurk, or whisper secrets into the void …
content/applications/~paldev/scooore.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "sc'o're"
3+developer = "~paldev"
4+shortcode = "~paldev/scooore"
5+description = "leaderboard for groups' ['o']s, as seen on tv!"
6+license = "MIT"
7+image ="https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/scooore.svg"
8+website = "https://pal.dev/suite/scooore"
9+bgColor = "#FDFF54"
10++++
11+
12+A leaderboard of your peers' emoji reactions in Groups.
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/scooore.png)
content/applications/~paldev/verse.mdnew file+13
@@ -0,0 +1,13 @@
1++++
2+title = "verse"
3+developer = "~paldev"
4+shortcode = "~paldev/verse"
5+description = "a random Bible verse, every day"
6+license = "MIT"
7+website = "https://pal.dev/suite/verse"
8+bgColor = "#EEEEDD"
9++++
10+
11+Verse displays a random Bible verse. Whenever you open Landscape, a new daily passage awaits.
12+
13+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/verse.png)
content/applications/~pocwet/docs.mdnew file+17
@@ -0,0 +1,17 @@
1++++
2+title = "Docs"
3+developer = "~pocwet"
4+shortcode = "~pocwet/docs"
5+description = "User and developer documentation for Urbit apps"
6+license = "MIT"
7+website = "https://github.com/tinnus-napbus/docs-app"
8+bgColor = "#FBCF44"
9+image = "https://m.tinnus-napbus.xyz/pub/books.svg"
10++++
11+
12+
13+Docs is an Urbit app for documenting other Urbit apps - it finds docs in other desks and displays them for users and deveopers to browse.
14+
15+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/docs.png)
16+
17+The docs folder contains the source of the app, and the docs-dev folder contains the files necessary for including docs in your app. Note that the files in docs-dev are symlinked, so the'll need to be copied with cp -rL or equivalent.
content/applications/~pocwet/straw.mdnew file+13
@@ -0,0 +1,13 @@
1++++
2+title = "Straw"
3+developer = "~pocwet"
4+shortcode = "~pocwet/straw"
5+description = "Vote on what to publish."
6+license = "MIT"
7+website = "https://urbit.org"
8+bgColor = "#6C6973"
9+image = ""
10++++
11+
12+
13+This app lets group members vote on whether a post is published to a notebook. It is intended for use with Studio, which you can install from ~tirrel/studio.
content/applications/~ribben-donnyl/funes-notes.mdnew file+15
@@ -0,0 +1,15 @@
1++++
2+title = "Funes Notes"
3+shortcode = "~ribben-donnyl/funes-notes"
4+license = "MIT"
5+image = "https://is4-ssl.mzstatic.com/image/thumb/Purple112/v4/64/64/8b/64648bfc-02b2-b955-6230-b86af334b6b1/AppIcon-0-1x_U007emarketing-0-10-0-85-220.png/230x0w.webp"
6+bgColor = ""
7+developer = "~ribben-donnyl"
8+website = "https://funes.app"
9+description = "Mobile notetaking application using urbit as a back-end."
10++++
11+
12+Funes Notes is a mobile notetaking application [available for iOS](https://apps.apple.com/us/app/funes-notes/id1627315560), using urbit's `%graph-store` as a backend.
13+
14+
15+Initial development funded by the Urbit Foundation via [Urbit Notes](https://urbit.org/grants/urbit-notes) proposal grant.
content/applications/~sitden-sonnet/channel.mdnew file+20
@@ -0,0 +1,20 @@
1++++
2+title = "Channel"
3+shortcode = "~sitden-sonnet/channel"
4+license = "REKT"
5+image = "https://s3.us-east-1.amazonaws.com/haddefsigwen1/reciprocal/2022.7.09..22.54.53-channel.png"
6+bgColor = "#000000"
7+developer = "Quartus Co., Reciprocal Ltd."
8+website = "https://reciprocal.ltd"
9+description = "A distributed imageboard platform, with love"
10++++
11+
12+### An imageboard platform, with love
13+
14+Developed as a collaboration between the Quartus Corporation and [Reciprocal Ltd.](https://reciprocal.ltd), Channel is an imageboard platform that leverages graph-store to allow any ship on the Urbit network to create and manage their own imageboard.
15+
16+![](https://s3.us-east-1.amazonaws.com/haddefsigwen1/channel/2022.7.14..05.09.33-Screen%20Shot%202022-07-13%20at%2010.09.16%20PM.png)
17+
18+Incoming posts have their authors scrambled with a per-ship, per-installation SHA-256 salt and thus get rotated into a "tripcode comet" visible when viewing the graph outside the interface. The interface by default hides all authors.
19+
20+Board owners can ban ships (using their rotated names), delete threads, and ban words and URLs, as well as assign janitors. You can even connect two boards using Quartus' Orca tool to syndicate posts across boards.
content/applications/~sogryp-dister-dozzod-dozzod/groups.mdnew file+40
@@ -0,0 +1,40 @@
1++++
2+title = "Groups"
3+shortcode = "~sogryp-dister-dozzod-dozzod/groups"
4+license = "MIT"
5+image = "https://bootstrap.urbit.org/icon-groups.svg"
6+bgColor = "#EFF0F4"
7+developer = "Tlon"
8+website = "https://github.com/tloncorp/landscape-apps"
9+description = "Groups is a decentralized platform that integrates with Talk, Notebook, and Gallery for a full, communal suite of tools."
10++++
11+
12+Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Groups is a decentralized platform that integrates with Talk, Notebook, and Gallery for a full, communal suite of tools.
13+
14+ <video autoPlay muted loop playsInline>
15+ <source
16+ src="https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/groups-create-a-group.webm"
17+ type="video/webm"
18+ />
19+ </video>
20+
21+Teams, clubs, DAOs, and secret societies use Groups to digitally congregate, using channel integrations to extend their capabilities.
22+
23+ <video autoPlay muted loop playsInline>
24+ <source
25+ src="https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/groups-create-a-channel.webm"
26+ type="video/webm"
27+ />
28+ </video>
29+
30+Write, edit, and publish longform or shorter documents with Notebook, a basic text editor for announcements, internal meeting minutes, blogs, and everything in between.
31+
32+ <video autoPlay muted loop playsInline>
33+ <source
34+ src="https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/notebooks.webm"
35+ type="video/webm"
36+ />
37+ </video>
38+
39+
40+Gather links to images, articles, and web pages to maintain a collection of references with Gallery, a versatile and interoperable repository for day-to-day digital trawling.
content/applications/~sogryp-dister-dozzod-dozzod/talk.mdnew file+21
@@ -0,0 +1,21 @@
1++++
2+title = "Talk"
3+shortcode = "~sogryp-dister-dozzod-dozzod/talk"
4+license = "MIT"
5+image = "https://bootstrap.urbit.org/icon-talk.svg"
6+bgColor = "#2B5DC0"
7+developer = "Tlon"
8+website = "https://github.com/tloncorp/landscape-apps"
9+description = "Talk is a decentralized chat app that integrates with Groups, Notebook, and Gallery for a full, communal suite of tools."
10++++
11+
12+Send peer-to-peer direct messages to one or many friends. Talk is a simple chat tool for catching up, getting work done, and everything in between.
13+
14+ <video autoPlay muted loop playsInline>
15+ <source
16+ src="https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/talk.webm"
17+ type="video/webm"
18+ />
19+ </video>
20+
21+Start threads. React with emojis. Respond to your Groups chat channels from Talk. When integrated with Groups, both direct messages and team chats appear in Talk. Two apps in one place.
content/applications/~sortug/gate.mdnew file+27
@@ -0,0 +1,27 @@
1++++
2+title = "Gate"
3+shortcode = "~dister-dozzod-sortug/gate"
4+license = "MIT"
5+image = "https://s3.sortug.com/img/fav.png"
6+bgColor = "#000000"
7+developer = "Sortug Development"
8+website = "https://sortug.com"
9+description = "Seamless QR login"
10++++
11+
12+# Secure, seamless login for Urbit
13+
14+Let's make joining Urbit easier!
15+
16+Why do this?
17+![code](https://s3.sortug.com/img/gate-code.png)
18+When you can do this?
19+![gate](https://s3.sortug.com/img/gate-gate.png)
20+
21+Logging in to any Urbit app requires you to input your ship's URL and the `+code` generated on dojo. This requires people to login to their ship's terminal, output the code on dojo, then copy and paste it in their browser or app. This is bad enough if you have a ship running locally, but if you have it running remotely (as is common) the process becomes seriously annoying.
22+
23+Mainstream mobile apps such as Signal handle first login much more seamlessly; after registration is done, further logins are done via QR code. The app produces a QR code, you scan it, and that's it. That's the state-of-the-art, battle-tested user experience for modern applications. Now available on Urbit.
24+
25+Gate makes it easier for newcomers to use Urbit, and greatly enhances the user experience of native applications, desktop and mobile, that Urbit deserves.
26+
27+Users can login to Urbit just by scanning a QR code, receive a URL link and login to an Urbit ship instantly by clicking on it. That simple. Most importantly, hosting providers can use Gate to send a QR code or a URL link to a user, and have the user access his Urbit apps with a simple camera scan or click of a link, making the onboarding process much easier for non-technical users.
content/applications/~sortug/trill.mdnew file+27
@@ -0,0 +1,27 @@
1++++
2+title = "Trill"
3+shortcode = "~dister-dozzod-sortug/trill"
4+license = "MIT"
5+image = "https://s3.urbit.cloud/img/trill-logo.png"
6+bgColor = "#000000"
7+developer = "Sortug Development"
8+website = "https://sortug.com"
9+description = "Urbit Native Microblog"
10++++
11+
12+### Your own social feed, forever.
13+
14+Urbit is a networked personal server. It is the ideal stack to host a microblog service.
15+
16+For years Urbit users have been busy chatting to each other, coordinating to build the network. But it is time that we lay back a little and just post at our leisure.
17+
18+Trill is an Urbit native microblog. You can post text or media links into your feed, make threads, and share it with your friends and followers. You can also build a timeline of your favorite Urbit users, and keep lists of users, categorized as you want.
19+
20+Unlike other microblogs, however, users of Trill truly own their feed. Users host their own content. They can even program it; tinker with the source as much as you want.
21+
22+There are no ads in Trill, no "trends", no analytics. We don't even know how many people are using Trill. And we don't care. We just want to trill. Please join the party.
23+
24+### More information
25+You can install the app by searching for ~dister-dozzod-sortug on your Grid interface, or by running `|install ~dister-dozzod-sortug %trill` in Dojo.
26+
27+The official group of the app is at ~hoster-dozzod-sortug/trill on the Groups app.
content/applications/~sortug/ufa.mdnew file+27
@@ -0,0 +1,27 @@
1++++
2+title = "Urbit Feed Aggregator"
3+shortcode = "~dister-dozzod-sortug/ufa"
4+license = "MIT"
5+image = "https://s3.urbit.cloud/img/lan.png"
6+bgColor = "#000000"
7+developer = "Sortug Development"
8+website = "https://sortug.com"
9+description = "Bring all the web into Urbit"
10++++
11+
12+### Own your content, share it with your friends
13+
14+Urbit is your personal server. Why do you want a personal server? Many things. But one of them, part of the initial vision of Urbit's development, was to use to interact programatically with the Web. To interact with Web services, but in your own terms. Using your chosen frontend, blocking all tracking, telemetry, analytics and other malicious code. Urbit as an API aggregator.
15+
16+The Urbit Feed Aggregator (aka UFA) makes that vision true. Now you will be able to browse the best content on the internet, but really own it, like people used to own books, magazines and newspapers. Control, curate, save and share your the content you like, with complete freedom.
17+
18+UFA is not just an app, it's a platform to which a myriad apps will be added in the future. As of present (August 2022) UFA includes support for Trill (our sister app, the Urbit native microblog) and Twitter. You can read and keep lists of Twitter content without having to login to Twitter.com, and you can save and share that content inside Urbit, via the Trill or Groups apps.
19+
20+### More information
21+You can install the app by searching for ~dister-dozzod-sortug on your Grid interface, or by running `|install ~dister-dozzod-sortug %ufa` in Dojo.
22+
23+The official group of the app is at ~hoster-dozzod-sortug/ufa on the Groups app.
24+
25+You can also follow ~sortug on Trill for announcements.
26+
27+Within 2022 RSS, Instagram and Email support will be added. For the future, the sky is the limit. If you want to help create a new plugin for UFA, please contact us at the official group.
content/applications/~tiller-tolbus/membrane.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Membrane"
3+shortcode = "~mister-master-tiller-tolbus/membrane"
4+license = "MIT"
5+image = "https://tiller-tolbus.nyc3.digitaloceanspaces.com/membrane.png"
6+bgColor = ""
7+developer = "~tiller-tolbus"
8+website = ""
9+description = "Spreadsheets and databases"
10++++
11+
12+### Membrane is a spreadsheet tool for Urbit
13+
14+Spreadsheets were the original tool for the productivity power user, so it is only fitting that we bring them to Urbit. Keep a budget, run a formula, and share your sheets with friends using Membrane.
content/applications/~tirrel/scene.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Scene"
3+shortcode = ""
4+license = ""
5+image = "https://tirrel.io/assets/scene-logo-stroke.svg"
6+bgColor = "rgb(0, 0, 0)"
7+developer = "Tirrel Corp."
8+website = "https://tirrel.io"
9+description = "The new Urbit desktop, by ~tirrel corp."
10++++
11+
12+![Screenshot](https://tirrel.io/assets/scene-demo-screenshot.webp)
13+
14+[Download scene here](https://tirrel.io/scene/index.html).
content/applications/~tirrel/studio.mdnew file+21
@@ -0,0 +1,21 @@
1++++
2+title = "Studio"
3+shortcode = "~tirrel/studio"
4+license = ""
5+image = "https://tirrel.io/assets/stool.svg"
6+bgColor = "rgb(160, 226, 167)"
7+developer = "Tirrel Corp."
8+website = "https://tirrel.io"
9+description = "Tools for making money."
10++++
11+
12+### Studio is a publishing tool for Urbit
13+
14+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/studio.png)
15+
16+Need a personal website, fast? Studio can set one up in under a minute. For writers, Studio connects you with your legacy-web audience, even if they’re not on Urbit yet. With a click, you can share your newsletter or blog via auto-generated blog or email distribution list
17+
18+Studio pulls content from your Groups notebooks. Notebooks from any group you own will appear.
19+
20+If you need any help, we’re always available in our group: ~tirrel/tirrel-support
21+
content/applications/~worpet-bildet/portal.mdnew file+16
@@ -0,0 +1,16 @@
1++++
2+title = "Portal"
3+shortcode = "~worpet-bildet/portal"
4+license = ""
5+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/portal.svg"
6+bgColor = "rgb(0,0,0)"
7+developer = ""
8+website = ""
9+description = "Portal is the front page"
10++++
11+
12+### Portal is the front page for urbit
13+
14+Portal made its debut as the solution to decentralized discovery on Urbit. Portal enables anyone on Urbit to curate content, apps, and groups for other ships to discover
15+
16+![Screenshot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/portal-screenshot.png)
content/apprenticeships.mdnew file+38
@@ -0,0 +1,38 @@
1++++
2+title = "Become an Apprentice"
3+date = "2023-01-04"
4+weight = 1
5+description = "Everything you need to know about applying for an apprenticeship"
6++++
7+
8+Apprenticeships are practical learning opportunities for new Urbit developers provided by experienced members of the Urbit development community. As an apprentice, you'll have the opportunity to:
9+
10+- Learn from an experienced Urbit contributor
11+- Make helpful contributions to an active project, and
12+- Earn address space for learning
13+
14+Becoming an apprentice is easily one of the best ways to level up your skills, and perhaps even land a job.
15+
16+## Get started
17+
18+Apprenticeships are for those that are new to Urbit development (or an area of it), and would like to find their grounding by working on a pre-existing codebase and problem set. Nearly all apprenticeships involve some degree of Hoon work, so you should make sure that you've completed [Hoon School](https://developers.urbit.org/guides/core/hoon-school) and [App School](https://developers.urbit.org/guides/core/app-school/intro) in either their asychronous or [cohort formats](https://developers.urbit.org/courses) prior to signing up.
19+
20+To become an apprentice, [apply for an open apprenticeship](/grants?program=apprenticeship&open=true&wip=false&completed=false#view-grants)
21+
22+Although some apprenticeships are posted on this site to be claimed, more often than not they emerge out of a conversation between a mentor and an enthusiastic potential apprentice. This is because mentors are generally busy engineering, and while they know many things that need to be done, getting those ideas into writing is difficult.
23+
24+## How it works
25+
26+Once a mentor has written up an apprenticeship, and approved an apprentice, The Urbit Foundation will perform a quick KYC step and send contracts to all parties for signing. Once those contracts are executed, work can proceed.
27+
28+Mentors and apprentices work together by having weekly pairing sessions and maintaining an open line of communication over Urbit. It's expected that mentors put at least two hours per week into supporting their apprentice.
29+
30+## Funding
31+
32+Apprenticeships pay 1 star upon the sucessful completion of the apprenticeship, for an apprenticeship of a duration of up to three months.
33+
34+## Getting Paid
35+
36+When you have completed the scope of your grant, you will create a detailed writeup of the work completed and your learnings, share the writeup with your mentor, and get your approval of completion. After recieving this approval from your mentor, please [submit an invoice here](https://airtable.com/shrXXCs1uaxtNSBcg). Your mentor must also contact `~marfun-pacpet` to confirm completion of the apprenticeship and approve the payment. Once the Urbit Foundation receives approval from your champion and an invoice for the amount agreed upon in your grant or milestone, the Foundation will pay your star allocation to the Ethereum address you have provided.
37+
38+We approve and issue payments within 30 days of invoice receipt and approval, although often payment is made more quickly. If you have any questions regarding getting paid or submitting an invoice, please contact `~marfun-pacpet` for assistance.
content/articles/2022-09-24_urbit-courts-daos-crypto.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "Urbit Courts DAOs, Crypto Teams in Quest to Make Internet P2P Again"
3+publication = "Coindesk"
4+author = "March Hochstein and Daniel Kuhn"
5+date = "2022-09-24"
6+URL = "https://www.coindesk.com/layer2/2022/09/24/urbit-courts-daos-crypto-teams-in-push-to-make-internet-p2p-again/"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/coindesk.jpg"
8++++
9+
10+A wildly ambitious project to reinvent the entire internet computing stack is finally shipping usable apps after a decade-plus of laying groundwork. Can it overcome a “janky” UX?
content/articles/2022-09-24_urbit-is-web3-weird-and-wonderful.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "Urbit Is Web3, Weird and Wonderful and I Don’t Care Who Made It"
3+publication = "Coindesk"
4+author = "March Hochstein"
5+date = "2022-09-24"
6+URL = "https://www.coindesk.com/layer2/2022/09/24/urbit-is-web3-weird-and-wonderful-and-i-dont-care-who-made-it/"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/coindesk.jpg"
8++++
9+
10+Software can have bugs, but it doesn’t have cooties.
content/articles/2022-09-28_college-course-on-urbit.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "Why Would Anyone Take a College Course on Urbit?"
3+publication = "Coindesk"
4+author = "Daniel Kuhn"
5+date = "2022-09-28"
6+URL = "https://www.coindesk.com/layer2/2022/09/28/why-would-anyone-take-a-college-course-on-urbit/"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/coindesk.jpg"
8++++
9+
10+Neal Davis taught the first graduate-level seminar on the controversial computing platform Urbit. Here’s why.
content/articles/2022-09-29_assembly-miami-dispatch.mdnew file+11
@@ -0,0 +1,11 @@
1++++
2+title = "Urbit Assembly: If We’re All Here, Who’s Watching The Internet?"
3+publication = "Zora Zine"
4+author = "Madeline Cash"
5+date = "2022-09-29"
6+URL = "https://zine.zora.co/urbit-assembly-miami-dispatch"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/zorazine.png"
8++++
9+
10+Forever Magazine founder and Zora Zine contributor Madeline Cash reports on secret societies, subjective idealism, and digital intimacy in her dispatch from Urbit Assembly in Miami
11+
content/articles/2022-09-29_the-dream-of-digital-homesteading.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "The Dream of Digital Homesteading"
3+publication = "Compact"
4+author = "Geoff Schullenberger"
5+date = "2022-09-29"
6+URL = "https://compactmag.com/article/the-dream-of-digital-homesteading"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/compactmag.png"
8++++
9+
10+Geoff Schullenberger attends Assembly 2022 and chronicles his impressions and thoughts.
content/articles/2022-10-04_a-more-beautiful-computer.mdnew file+11
@@ -0,0 +1,11 @@
1++++
2+title = "User Error: A More Beautiful Computer"
3+publication = "Spike Art Magazine"
4+author = "Adina Glickstein"
5+date = "2022-10-04"
6+URL = "https://www.spikeartmagazine.com/?q=articles/user-error-more-beautiful-computer"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/spike-logo-text.jpg"
8++++
9+
10+From Dimes Square to the Network State, new frontiers are in the making. Adina Glickstein attends Urbit Assembly and considers the politics of tech-augmented exit.
11+
content/articles/2022-10-13_my-weekend-with-the-martians.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "My Weekend With the Martians"
3+publication = "Astra"
4+author = "Ruby Sutton"
5+date = "2022-10-13"
6+URL = "https://astra-mag.com/articles/my-weekend-with-the-martians/"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/astra.png"
8++++
9+
10+At the Assembly, a conference of Urbit denizens, Ruby Sutton discovers a community of eccentrics who dare to dream of a different internet.
content/articles/2022-10-23_three-things.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "Three Things #40: October 23, 2022"
3+publication = "Three Things"
4+author = "Lane Rettig"
5+date = "2022-10-23"
6+URL = "https://rettig.substack.com/p/three-things-40-october-23-2022"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/3things40.jpg"
8++++
9+
10+Lane Rettig outlines three unique aspects of Urbit in an attempt to answer the eternal question "What is Urbit?"
content/articles/2023-02-20_trailblazing-urbit-startup-makes-earth-shaking-acquisition.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "Trailblazing Urbit Startup Makes Earth Shaking Acquisition"
3+publication = "Globe Newswire"
4+author = "Globe Newswire"
5+date = "2023-02-20"
6+URL = "https://www.globenewswire.com/en/news-release/2023/02/20/2611391/0/en/Trailblazing-Urbit-Startup-Makes-Earth-Shaking-Acquisition.html"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/globe-newswire.jpeg"
8++++
9+
10+Holium Corp closes $2.9 million in seed funding and acquires Third Earth in record pace.
content/articles/2023-05-10_urbit-a-network-older-and-weirder-than-bitcoin.mdnew file+10
@@ -0,0 +1,10 @@
1++++
2+title = "Urbit, a Network Older and Weirder Than Bitcoin, Finally Turns Toward Growth"
3+publication = "Coindesk"
4+author = "Bradley Keoun"
5+date = "2023-05-10"
6+URL = "https://www.coindesk.com/tech/2023/05/10/urbit-a-network-older-and-weirder-than-bitcoin-finally-turns-toward-growth/"
7+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/articles/coindesk.jpg"
8++++
9+
10+The peer-to-peer network started in 2002 says it's taking on "MEGACORP," much in the same vein as many blockchain networks. A bit more fun are the "secret code names" that users are assigned.
content/audits.mdnew file+22
@@ -0,0 +1,22 @@
1++++
2+title = "Audits"
3+date = "2021-10-10"
4+weight = 1
5+description = "Urbit Security Audits"
6++++
7+
8+Confidence and trust are fundamental to Urbit's ethos. The strength of our smart contract protocols are regularly scrutinized for potential vulnerabilities and enhanced when weaknesses are identified.
9+
10+To that end, we continue to maintain a robust security protocol. Our smart contracts are generally healthy and secure, but the process of auditing is never fully complete. As our ecosystem evolves, our security protocols evolve with it.
11+
12+Since transparency is an integral feature of trust, we've made our security audits publicly available. Please refer to the below documents for a more thorough analysis.
13+
14+### Security Audits
15+
16+- [Ames Networking Protocol Review](<https://storage.googleapis.com/media.urbit.org/site/audits/Tlon.io%20-%20Urbit%20AMES%20Networking%20Protocol%20Review%20Final%20Report%20(1).pdf>), Leviathan, November 2020
17+- [Urbit Constitution Audit](https://storage.googleapis.com/media.urbit.org/site/audits/Urbit%20Constitution%20Audit%20-%20OpenZeppelin.pdf), OpenZepplin, September 2021
18+- [Urbit Constitution JS Library Audit](https://storage.googleapis.com/media.urbit.org/site/audits/Urbit%20Constitution%20JS%20Audit.pdf), bloctrax, July 2018
19+- [Urbit Constitution JS Library Code Review](https://storage.googleapis.com/media.urbit.org/site/audits/Urbit%20Constitution%20JS%20Library%20Report%20-%20December%202018%20Review.pdf), bloctrax, December 2018
20+- [Urbit Keygen JS Library Report](https://storage.googleapis.com/media.urbit.org/site/audits/Urbit%20Keygen%20JS%20Library%20Report.pdf), bloctrax, September 2018
21+- [Urbit Keygen JS Library Report, 2nd Review](https://storage.googleapis.com/media.urbit.org/site/audits/Urbit%20Keygen%20JS%20Library%20Report%20-%20Second%20Review%20with%20Resolutions.pdf), bloctrax, November 2018
22+- [Urbit Security Audit](https://storage.googleapis.com/media.urbit.org/site/audits/Urbit%20Security%20Audit.pdf), bloctrax, June 2018
content/bitcoin-wallet.mdnew file+60
@@ -0,0 +1,60 @@
1++++
2+title = "Bitcoin Wallet"
3++++
4+
5+The latest Urbit release includes a native Bitcoin wallet. Please read the following security recommendations and disclaimers carefully. Urbit.org cannot recover any lost keys.
6+
7+### Instructions
8+
9+Run `|start %btc-wallet` in the dojo. After refreshing Landscape you should see an orange bitcoin tile in the first row. Clicking on it will prompt a two-step process:
10+
11+1. Enter a provider who is connected to a full-node (such as `~zod`). The provider will maintain a synced Bitcoin ledger, index your public addresses to determine your balance, and process your transactions.
12+
13+2. The next step is to provide an extended public key (or xpub). Providing your xpub allows the Bitcoin Wallet to automatically generate new public addresses (called _child public keys_—you can learn more about this [here](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)) when bitcoin is sent to your ship. To provide an xpub you can either enter your master ticket (which can be downloaded from [Bridge](https://bridge.urbit.org)), or directly import your xpub (such as from a hardware wallet like [Ledger](https://support.ledger.com/hc/en-us/articles/360011069619-Extended-public-key) or [Trezor](<https://wiki.trezor.io/User_manual:Displaying_account_public_key_(XPUB)>)).
14+
15+Clicking on the Landscape tile will take you to the Bitcoin Wallet application, where you can view your balance and send bitcoin. All that you'll need to do is enter the recipient's Urbit ID (if they have configured the wallet using the above steps) or a Bitcoin address.
16+
17+If you are interested in [being a provider](https://subject.network/posts/btc-wallet-config/#connecting-a-provider-to-a-full-node) or [running a bitcoin full node](https://subject.network/posts/pi-fullnode-urbit/#bitcoind) on the Urbit network please check out `~sitful-hatred`’s excellent tutorials.
18+
19+### Verify
20+
21+You should verify your version of this Bitcoin wallet. To do so, follow the instructions in the README in our [Github](https://github.com/urbit/urbit/blob/master/pkg/btc-wallet/README) repo.
22+
23+Instructions reproduced here:
24+
25+To verify your version of the bitcoin wallet, run the following command in the dojo:
26+`> +btc-wallet-check`
27+It should return with the following hash:
28+`0v9t022.n8kv1.5emkt.s2p9i.hvsa9`
29+
30+### Disclaimer Statement
31+
32+The Urbit Bitcoin Wallet and its related components are experimental pieces of software. You are free to review the open-source code before using:
33+
34+- [Wallet](https://github.com/urbit/urbit/tree/master/pkg/btc-wallet)
35+- [Full Node Provider Agents](https://github.com/timlucmiptev/btc-agents)
36+
37+No guarantees are made about the security of this software. It may contain vulnerabilities that could lead to loss of funds. This wallet software has not had a formal security audit.
38+
39+You can read about the security audit for Urbit's networking protocol in this [post](https://urbit.org/blog/security-audit/). This audit does not encompass the wallet, except to the extent that the wallet operates on Urbit's networking architecture.
40+
41+If you decide to use this wallet, please store responsible amounts of Bitcoin, and use best security practices. The developers of this software cannot help you recover your keys / funds, if lost.
42+
43+### License
44+
45+With the exception of its external dependencies, this software is a component of Urbit, and is released under Urbit's MIT License, reproduced below.  [View Original](https://raw.githubusercontent.com/urbit/urbit/master/LICENSE.txt)
46+
47+The MIT License (MIT)
48+
49+Copyright (c) 2015 Urbit
50+
51+Permission is hereby granted, free of charge, to any person obtaining a copy
52+of this software and associated documentation files (the "Software"), to deal
53+in the Software without restriction, including without limitation the rights
54+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55+copies of the Software, and to permit persons to whom the Software is
56+furnished to do so, subject to the following conditions:
57+
58+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
59+
60+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
content/bitcoin.mdnew file+125
@@ -0,0 +1,125 @@
1++++
2+title = "Bitcoin Development on Urbit"
3++++
4+
5+### Overview
6+
7+Urbit OS currently ships with our Bitcoin wallet, %btc-wallet, released in 2021,
8+and our Lightning implementation, %volt, is almost ready for live use on the network. Several integrations with the app ecosystem are planned immediately following its release, including subscription publishing, social payments, and more.
9+
10+**The Urbit Advantage**
11+
12+- Composability: Modular userspace applications expose a consistent API format to each other locally and over the network, making seamless integration of Lightning payments, Taro assets, and other protocols easy
13+- Networking and identity: Exactly-once message delivery, NAT traversal, and E2E encryption come built into Urbit's P2P protocol, and Urbit identities are sybil-resistant, human-readable network addresses bound to BIP32 extended public keys
14+- Efficient, secure development: Urbit OS is strictly typed and purely functional, and apps have reproducible builds on all client machines, removing much of the complexity, risk, and pain points from development
15+
16+**Getting Involved**
17+
18+Interested in contributing to or supporting Bitcoin development on Urbit? GitHub repos for individual projects and information on the Urbit Foundation grant program are linked below, and dedicated Urbit groups and Bitcoin node operators on Urbit are listed in the Community section. You can also reach out to current contributors ~tondes-sitrym and ~pindet-timmut on Urbit or at urbitcoin@protonmail.com.
19+
20+### Wallet
21+
22+Urbit's Bitcoin wallet consists of two agents: %btc-provider, which communicates with an external full node; and %btc-wallet, which handles transaction generation and signing, and uses a %btc-provider instance (on the same ship or elsewhere on the Urbit network) to broadcast transactions and receive data from the Bitcoin network.
23+
24+Wallet users can receive payments using the xpub associated with their Urbit ID, allowing Bitcoin payments to be sent between ships with a persistent, human-readable network address without compromising on-chain privacy.
25+
26+**Resources**
27+
28+GitHub
29+
30+- Agents: [https://github.com/urbit/urbit/tree/master/pkg/bitcoin](https://github.com/urbit/urbit/tree/master/pkg/bitcoin)
31+- UI: [https://github.com/urbit/urbit/tree/master/pkg/btc-wallet](https://github.com/urbit/urbit/tree/master/pkg/btc-wallet)
32+- Provider utilities: [https://github.com/urbit/urbit-bitcoin-rpc](https://github.com/urbit/urbit-bitcoin-rpc)
33+
34+Writeups
35+
36+- Grant proposal: [https://urbit.org/grants/bitcoin-full-node-provider-and-wallet](https://urbit.org/grants/bitcoin-full-node-provider-and-wallet)
37+- Architecture document: [https://gist.github.com/jalehman/e0c91071427ca4c349c0673f376945cb](https://gist.github.com/jalehman/e0c91071427ca4c349c0673f376945cb)
38+- Provider setup guide: [https://subject.network/posts/pi-fullnode-urbit/#bitcoind](https://subject.network/posts/pi-fullnode-urbit/#bitcoind)
39+
40+
41+**Continuing Work**
42+
43+The current %btc-wallet implementation is not a modern BIP-157/158 light client. While users who depend on another ship's %btc-provider/full node for communication with the Bitcoin network do not risk loss of on-chain funds, their lack of visibility on the network will be more problematic for those also using it with Lightning. Funding is available for developers interested in contributing: reach out to the Urbit Foundation, ~tondes-sitrym on Urbit, or urbitcoin@protonmail.com.
44+
45+### Lightning
46+
47+Volt, Urbit's Lightning implementation, like our Bitcoin wallet consists of two agents: %volt, the primary agent that manages channels, payments, invoices, and chain monitoring; and %volt-provider, which connects to an external LND node for handling payments with endpoints outside the Urbit network.
48+
49+All Volt nodes will run %volt, and be able to operate channels with Urbit peers without maintaining an LND instance or depending on another ship that does. To transact with non-Urbit Lightning peers, and in the short term (see below) to perform multi-hop payments inside Urbit, they will need to open a channel with a node that uses %volt-provider to connect with LND. Chain monitoring likewise requires connecting to a local or remote %btc-provider agent (see Wallet above). For more details on the network architecture, see the grant proposal linked below.
50+
51+Volt implements BOLTs 2, 3, 5, and 11, and in the near future will add onion routing (variants on BOLTs 4 and 7). Because %ames, Urbit's networking module, already handles transport, guarantees required message delivery properties, and furnishes persistent, unique 'domain names', implementation of BOLTs 1, 8, and 9 is unnecessary for Volt nodes.
52+
53+Beta release of Volt is planned for the end of 2022, and additional features including multi-hop/onion routing implementation are proposed for completion by mid-2023.
54+
55+**Resources**
56+
57+GitHub: [https://github.com/dasrun-fadben/volt/tree/on-chain](https://github.com/dasrun-fadben/volt/tree/on-chain)
58+
59+Initial grant proposal and spec: [https://urbit.org/grants/volt-lightning-on-urbit](https://urbit.org/grants/volt-lightning-on-urbit)
60+
61+Proposal for further work: [https://urbit.org/grants/lightning-development](https://urbit.org/grants/lightning-development)
62+
63+**Continuing Work**
64+
65+The primary element currently missing from Volt is onion routing of multi-hop payments for full privacy and efficiency of payments to and from nodes that don't also operate LND. This has been partially specified in the second proposal linked above: funding and collaborators are available for this as well as work described there on application integrations, submarine swaps, and more, so interested developers should take a look and get in touch.
66+
67+### Roadmap
68+
69+**2022**
70+
71+- *Volt Beta Release*
72+Final work on channel sweeps, remaining safety checks, and UI development is currently ongoing and expected to be complete by EOY 2022.
73+
74+**2023**
75+
76+- *Initial Ecosystem Integrations*
77+ - Submarine swaps: Implementation of the PeerSwap protocol, fallback use of the Loop API, and UI targeted at merchant use-cases. Funded, expected completion in spring 2023.
78+ - Apps: Integration of Lightning subscription and one-time paygates into Groups, social payments and %volt-provider discovery with %pals, and app tipjar module. Specified and proposed for grant funding.
79+- *Lightning Routing*
80+Payments with multiple intra-Urbit hops and via multiple %volt-provider channels are the last remaining component for full-featured and private payments with Volt. Specified and proposed for grant funding.
81+- *Wallet Improvements*
82+Work on feature, security, and UI upgrades for the Bitcoin wallet and node provider, aimed at making the application a full-featured and BIP157/158-compliant light client, should begin before EOY 2023.
83+
84+**Future**
85+
86+- *Taro Implementation*
87+Implementation of Taproot Asset Representation Overlay, with an initial focus on using nonfungible Taro assets to represent credentials, permissions, and reputation of Urbit identities.
88+- *Atomic Streaming Payments*
89+ - Integration of Volt payments with streaming apps like %radio and the Holium WebRTC client via HTLC-DASH or similar implementation.
90+ - Generic protocol for non-media pay-to-stream data
91+
92+### Grants
93+
94+The Urbit Foundation operates a grant program aimed at new Urbit developers, network public goods, and community development. Work on the Bitcoin wallet, Lightning implementation, and submarine swaps for Volt (Urbit Lightning) users all has received funding from UF, and interesting non-technical proposals with social value to the network are also considered.
95+
96+Grants homepage: [https://urbit.org/grants](https://urbit.org/grants)
97+
98+Past Bitcoin-related grants
99+
100+- [https://urbit.org/grants/bitcoin-full-node-provider-and-wallet](https://urbit.org/grants/bitcoin-full-node-provider-and-wallet)
101+- [https://urbit.org/grants/volt-lightning-on-urbit](https://urbit.org/grants/volt-lightning-on-urbit)
102+- [https://urbit.org/grants/lightning-development](https://urbit.org/grants/lightning-development)
103+
104+## Bitcoiners on Urbit
105+
106+### Groups
107+
108+Urbitcoiners: ~pindet-timmut/urbitcoiners
109+
110+### Providers
111+
112+**Bitcoin Full Nodes**
113+
114+~tirrel
115+~zod
116+
117+**Lightning Nodes**
118+
119+~tondes-sitrym
120+~bosdys
121+
122+### Guides
123+
124+Running %btc-provider with a full node on Raspberry Pi: [https://subject.network/posts/pi-fullnode-urbit/](https://subject.network/posts/pi-fullnode-urbit/)
125+
content/blog/2019-10-3-roadmap.mdnew file+112
@@ -0,0 +1,112 @@
1++++
2+title = "~2019.10 Roadmap"
3+date = "2019-10-02"
4+description = "Galen Wolfe-Pauly on the road ahead for the identity/OS/interface/community stack."
5+aliases = [
6+ "/posts/essays/2019-10-3-roadmap",
7+ "/posts/2019-10-3-roadmap"
8+]
9+
10+[extra]
11+author = "Galen Wolfe-Pauly"
12+ship = "~ravmel-ropdyl"
13+image = "https://media.urbit.org/site/posts/essays/2019-10-3-roadmap.jpg"
14++++
15+
16+![](https://media.urbit.org/site/posts/essays/2019-10-3-roadmap.jpg)
17+
18+The daily work of building a new OS from scratch is so engaging and exciting that we habitually forget to even take stock of what we’ve accomplished. We’re fixated on the prospect of moving the world on to Urbit, starting with ourselves.
19+
20+It’s a good thing I have a recurring reminder to write these updates. While our focus is on the future, it’s good to get a sense of the rate that we’re moving forward, and to let everyone know what’s been going on. We’ve made great progress over the past few months.
21+
22+We’ve got a new interface, Urbit 0.8.0, Hoon School, and a grants program among lots of other updates. We’ll go into detail about all of these, and talk a bit about where we’re headed next. The system is improving at a really good pace. We intend to keep it up.
23+
24+## Identity (Azimuth)
25+
26+The other day I got an email, clicked a link, and got a planet. A real, live, piece of cryptographic property with paper wallets and everything. It took about two minutes. And at the end, I could have easily sent invites to my friends.
27+
28+This experience is part of a completely new Bridge, the interface for interacting with your Urbit identity. The beta experience we’re testing today is quite stripped down, but it’s a huge improvement over the last Bridge release. Clicking a link is a lot easier than downloading source code, running it from the command-line, and probably running into a python-related error.
29+
30+Getting to this point involved rewriting Bridge from scratch, figuring out how to host it securely, building infrastructure to fund the requisite transactions involved in registering a new identity, and setting up a service to send emails (and dispose of them afterward). We've also redesigned our paper wallets to make them simpler and clearer.
31+
32+We still want to get this new version of Bridge a bit further along before releasing it to everyone — but we’re excited about it. We didn’t quite get to the point of building an affordance for payments, which we had hoped to do, but that’s coming later.
33+
34+We want everyone to have an Urbit identity. And we want it to be incredibly easy to get one, so we’ll get Bridge out this month with a new urbit.org (more on that below).
35+
36+The other area of identity-related work was Sigils — the algorithmically generated images that go with every Urbit identity. (We’ve got a blog post in the works that covers how we created these, which is a good story that needs to be told.) The original version of Sigils didn’t look very good at small sizes and a few collisions were found (thanks to [urbit.live](https://urbit.live) for helping to discover the collisions). The [new, improved sigils](https://github.com/urbit/sigil-js) have no collisions and look great at small sizes.
37+
38+**Q4 2019**
39+
40+- Release Bridge to the public
41+- Get Bridge working well on mobile
42+- Add payments support, hopefully including BTC
43+- Add a network explorer
44+
45+**Q1 2020**
46+
47+- Integrate Bridge with a native app for Arvo
48+
49+## OS (Arvo)
50+
51+As a team, we want Urbit to be our primary computer, our last computer, our permanent computer. And we want this now — or at least as soon as we possibly can. We’re both ambitious and impatient.
52+
53+The frustration that we can’t move onto Urbit today propels us forward. The system saw major updates over the past few months all the way through the stack. On the Arvo side, we divide our work into Infrastructure (everything in the kernel and interpreter) and Interface (everything in userspace and the front-end). We’ll start with Infrastructure progress first.
54+
55+We’re very nearly to the point that all the kernel-level code in the system has been written by our current team. The one remaining vane that deserves a rewrite (Gall) has had a major cleanup by Jared just recently. The [Ship of Theseus](https://en.wikipedia.org/wiki/Ship_of_Theseus) approach does appear to be working. The infrastructure team is doing fantastic work and has really deepened their ownership of the system. The Urbit of today is on the road to becoming a great piece of system software.
56+
57+The biggest infrastructure-level milestone was the release of [Urbit 0.8.0](https://github.com/urbit/urbit/releases/tag/v0.8.0). We introduced a new process-separation architecture, implemented the correct bootstrap sequence, moved to LMDB for persistence, replaced our http vane (%eyre) and moved to Nix for our build system.
58+
59+To put it simply, Arvo is now much more stable and durable. During the beginning of the year we were seeing bugs and instability that were frustrating and unacceptable. While there are still issues on the live network, none of them terrify us much. We also implemented the ability for users to ‘individually breach’, which means that you can now reset your Urbit without waiting for us to reset the network.
60+
61+### Landscape (Arvo UI)
62+
63+We don’t just build infrastructure for others to develop on top of. We build interfaces too. At the top of the stack, we released a completely new Landscape, the interface for Arvo. This new interface makes it possible to build other ‘modules’ for Arvo that go beyond chat and publishing.
64+
65+This new Landscape is a complete departure from the last direction. Your Urbit now has a simple home screen that launches individual modules and it’s [relatively easy](https://github.com/urbit/create-landscape-app) to create new ones. We’re all enjoying using Landscape around the office. It’s still a bit of a prototype — but it’s quite a good one, I think.
66+
67+In moving to this new model we decided to narrow our focus to desktop only for now. We’ll return to mobile again next year — but first we want to get the desktop experience right. We’ve pulled the iOS app from the app store for the time being. I’m personally sad to see it go, since I enjoyed using it. But our prior iteration of Landscape just wasn’t quite right.
68+
69+This version of Landscape is, I think, the last one that we’ll call a prototype. Over the past few weeks, since shipping this, some amazing work has been happening on the interface front. We have a systematic approach to building interfaces on top of Urbit that’s very promising, albeit just getting started. We’ve already put out [one post](https://urbit.org/posts/landscape-a-portrait/) about Landscape's future, with more posts to come.
70+
71+**Q4 2019**
72+
73+- Improved Arvo-level error handling
74+- Implementation plan for ‘telescoping kelvins’ — or [how we plan to future proof Arvo](https://groups.google.com/a/urbit.org/forum/#!topic/dev/6Mwn6TQFVwc)
75+- Versioning scheme between Arvo and Vere
76+- A new Haskell implementation of the daemon
77+- A native client (instead of just a browser tab)
78+- A [new user-space architecture](https://docs.google.com/document/d/1hS_UuResG1S4j49_H-aSshoTOROKBnGoJAaRgOipf54/edit)
79+- Hoon.hoon that’s OTA upgradeable
80+- Working Jacque prototype, a graal-truffle-based implementation of vere
81+
82+**Q1 2020**
83+
84+- Integrated client with Bridge and Arvo
85+- New interface framework, codenamed ‘Widescreen’
86+
87+## Docs + Community
88+
89+We had quite a bit of interest in our second session of Hoon School. We ended up with 150 people enrolled in Hoon 101, and 42 in 201. The 101 session just ended, with a lot of positive responses and feedback from the participants. We learned a lot doing it and got quite a bit of interesting new example code.
90+
91+Hoon 101 started with students with little to no programming experience. Hoon 201, which is just getting underway, covers more advanced topics. We’re quite curious to see what comes out of it.
92+
93+We’re also adding features to Landscape to make it more amenable to use by Hoon Schoolers. Good examples include code evaluation within Chat (for office hours), and the ability to pin posts in Publish. The next crop of Hoon learners will be able to use Urbit to learn about Urbit.
94+
95+Aside from Hoon School we’re always updating our documentation. Most notably, we added search to the docs (finally). This was a much needed feature that makes the docs much more usable.
96+
97+We also launched our [grants program](https://grants.urbit.org/) quietly, but all of our available bounties were quickly claimed nonetheless. We’re ready to give away more address space to contributors and are excited by how quickly people got involved.
98+
99+We also did some experimentation with holding events on Arvo. We held weekly AMAs for while, and hosted a few meetings with the community. With the new UI out, our public channels have been a lot more active. We’ll surely be holding more on-urbit events in the future — but for the time being the conversation in urbit-help is a lot of fun.
100+
101+**Q4 2019**
102+
103+- Vane level documentation
104+- An active grant program
105+
106+## urbit.org
107+
108+Urbit.org is about ready for a refresh — so we’re in the process of rebuilding it. We have, for a long time, told the story of Urbit by describing the system technically. We think Urbit can be explained much more simply and much more concisely. We’re working to put together a new set of materials in this direction.
109+
110+We’d also like to populate urbit.org with a lot more content about what we’re working on and thinking about. We do a reasonable job of writing updates, but many of our projects get released without any background info. Tlon and the Urbit community are full of smart, thoughtful people — and we’d like to do a lot more to surface their work. We plan to close out the year with both a new website and a lot of writing about what we’ve been building. Not everyone wants to read the source code!
111+
112+That covers it for now. If you have questions or want to chat — find us in `~dopzod/urbit-help`. See you online!
content/blog/2019-5-roadmap.mdnew file+103
@@ -0,0 +1,103 @@
1++++
2+title = "~2019.5 Roadmap"
3+date = "2019-05-15"
4+description = "Where we are and where we're going as of mid-2019."
5+aliases = [ "/posts/essays/2019-5-roadmap", "/posts/2019-5-roadmap" ]
6+
7+[extra]
8+author = "Galen Wolfe-Pauly"
9+ship = "~ravmel-ropdyl"
10+image = "https://media.urbit.org/site/posts/essays/2019-5-roadmap-1.png"
11++++
12+
13+![](https://media.urbit.org/site/posts/essays/2019-5-roadmap-1.png)
14+
15+We often get so busy that we forget to tell you what we’ve been up to. Here’s an update on what we’re doing and where we’re headed with each layer of the stack.
16+
17+At a very high level we have two goals for 2019: make Azimuth easier to use, and get Arvo to a 1.0.
18+
19+Next year we’ll begin to move away from some of the MEGACORP software we use in the office, and replace it with our own tooling. There’s some exciting work happening in that department, but we’ll cover that in a future post.
20+
21+For some related recent thinking on all of this, see [The 100 Year Computer](/posts/essays/the-100-year-computer/), [The State of Landscape](/posts/essays/the-state-of-landscape/) and [Azimuth as MultiPass](/posts/essays/azimuth-as-multipass/).
22+
23+For now, let’s just look at what’s on the immediate horizon:
24+
25+## Azimuth
26+
27+At lunch the other day someone on our team said something like, ‘We built a complete and working public key infrastructure, but we haven’t told anyone.’
28+
29+It’s true. Azimuth is operational, secure, and well tested. It’s a pretty cool piece of technology and it’s out there in the world for anyone to use. It also doesn’t require that you use Arvo — Arvo happens to make use of Azimuth, but Azimuth itself is a completely separate system.
30+
31+So the question is why haven’t we told the world about it?
32+
33+I tend to think that in order for a technology to succeed it has to not only be an important technical innovation, it also has to be easy to understand as a product. And that’s our answer: we’ve undersold Azimuth because we want it to be easier to understand by _using_, not just by reading the code. Azimuth is quite an elegant piece of technology — but that doesn’t matter until it has a great user experience to match.
34+
35+That’s why, in the near term, we’re focused on building on top of Azimuth ourselves. We can’t ask others to go down roads if we haven’t already been down them.
36+
37+Here’s what we’re building first:
38+
39+### Q2 2019
40+
41+- A simplified onboarding flow for getting an Azimuth point that’s simple to share with friends over email, text or as a URL.
42+- A redesigned and improved Bridge for managing your points.
43+- An interface that allows you to easily send money between Azimuth points without running Arvo.
44+
45+### Q3 2019
46+
47+- Expanded Azimuth-centric example modules, documentation and developer tooling.
48+
49+Still under consideration:
50+
51+- An OAuth server or JWT flow for logging into any service with an Azimuth point.
52+- A mobile app for point to point payments using Azimuth.
53+
54+### 2020
55+
56+Azimuth is beginning to feel like [multipass](/posts/essays/azimuth-as-multipass/), with a variety of ways to use Azimuth points without ever booting Arvo
57+
58+## Arvo
59+
60+The Arvo interface has always been held back by Arvo’s technical immaturity. This is still true to some degree. The system has not stabilized completely.
61+
62+But! We’ve been using Landscape quite a lot lately. I use it daily, in fact — even [on my phone](https://itunes.apple.com/us/app/landscape-urbit/id1393148862). An encrypted (although not audited — so let’s not call it ‘secure’), authenticated chat where I own the keys and can read the source code feels really nice to use. The interface isn’t as good as we’d like, but it’s not bad. Landscape is a great preview of where we’re going: a simple, permanent, self-sovereign computer.
63+
64+There are still rough edges, and Landscape is not nearly general purpose enough, but we have plans:
65+
66+### Q2 2019
67+
68+- A new update to the Arvo interface that we’re calling Modulo. Modulo expands beyond chat and longform discussion to make your Arvo interface feel much more like the computer it actually is.
69+- Upgrades to our event persistence, networking, and DNS integration aimed at much better stability. Arvo instances don’t crash that often, but with these changes it should be very rare.
70+- Significant improvements to testing with a new simulation testing framework and integration testing pipelines.
71+
72+### Q3 2019
73+
74+- A significant overhaul to Gall, our application model, making it much simpler for users to write apps or ‘agents’ in Arvo.
75+- A new version of the compiler that makes us less reliant on jets. This will eliminate a major obstacle to achieving network continuity, or the ability for ships to upgrade themselves totally over-the-air, forever.
76+- A significant overhaul and stability update to Clay, our filesystem, making it possible for us to trust it for self-hosting, search it easily, and depend on it for long-term data storage.
77+- Tooling for hosting and hopefully a beta program for hosted Arvo instances run by Tlon.
78+
79+### 2020
80+
81+- A completely overhauled Arvo interface, Daigo, with a complete but simple set of messaging and collaboration tools. Modulo is meant to be fun to experiment with, but we aim to make Daigo part of our daily workflow.
82+- We come to work every day, use Arvo, go home.
83+
84+## Community
85+
86+We’ve often felt like it was far too early to invite others in to the system.
87+
88+As long as we’re up front about the state of this 100 year computer -- that it’s live, but incomplete — I think it’s a good thing to welcome people on board. There’s plenty to play with, experiment with and explore.
89+
90+Hoon school was the first effort in this direction. We intend to do a lot more:
91+
92+### Q2 2019
93+
94+- Scaling Hoon school up to include both a track for experts and for beginners, and allowing many more participants.
95+- Holding more meetings and events on Landscape, experimenting with Arvo-native discussion.
96+- A clear program for address space grants for developers + contributors.
97+- New documentation site with searchable library docs.
98+
99+### Q3 2019
100+
101+- Hoon School participants understand clearly how to build a Modulo agent, and invite others into it.
102+- The road toward building an Azimuth module is well understood, paved, and clear.
103+- We have clear instructions and tutorials for building Azimuth modules and using Azimuth as a login or reputation primitive.
content/blog/2020-to-2021.mdnew file+45
@@ -0,0 +1,45 @@
1++++
2+title = "2020 -> 2021"
3+description = "Reflecting and looking forward."
4+date = "2021-01-20"
5+
6+[extra]
7+author = "Josh Lehman"
8+ship = "~wolref-podlex"
9+image = "https://media.urbit.org/site/posts/essays/arch-sunrise-2.jpeg"
10++++
11+
12+![arch](https://media.urbit.org/site/posts/essays/arch-sunrise-2.jpeg)
13+
14+In this post, which has been adapted from our most recent [newsletter](https://urbit.us11.list-manage.com/subscribe/post?u=972a03db9e0c6c25bb58de8c8&id=be143888d2), we'll take a moment to reflect on the events of the last year, and then turn our attention to the next one.
15+
16+## 2020
17+
18+In spite of the many challenges presented over the last year, it was a resoundingly good one for Urbit.
19+
20+It seems like a long time ago now that the folks at Tlon rolled out OS1 (now called Landscape), just as the pandemic forced everyone into their homes throughout the world. At the time, [Urbit is for Communities"](https://urbit.org/blog/urbit-is-for-communities/) was just a vision, but now it’s been transformed into reality—there are more thriving communities in Landscape than any of us can keep track of, with new faces popping onto the network on a daily basis.
21+
22+Landscape brought many new ships onto the network which helped identify those areas in which Urbit’s infrastructure could be most improved. [Ford Fusion](https://urbit.org/blog/ford-fusion/) eliminated the possibility of a partially-applied over-the-air (OTA) update through a drastic reduction in the size and complexity of the codebase. The efficiency of the OTA process was improved by several orders of magnitude, and many long-standing memory issues were resolved. Now we deploy code on our infrastructure nodes and see users receive an update, over a decentralized network, often in less than a minute.
23+
24+After improving the stability of the system Tlon turned its attention to bringing more ships onto the network. A long-standing barrier to Urbit’s adoption has been the technical knowledge required to host one’s own ship—this prompted Tlon to build and launch an Urbit [hosting service](https://tlon.io), the waitlist for which is now thousands deep.
25+
26+With Tlon becoming more singularly focused on building products on Urbit, concrete steps have been taken towards making urbit.org a separate organization that’s focused on long-term development of Urbit’s platform. I joined to [lead that effort](https://urbit.org/blog/first-steps-towards-urbit-org/) back in August and have since spent the majority of my time working with dozens of contributors on projects spanning documentation, education, external integrations, and much more.
27+
28+We rounded out the year with a full network reset (called a “continuity breach”), which has in the past has been synonymous with loss of all data on the network. This time things went differently: tooling was made available to the community that allowed ships to preserve their data, which enabled most to seamlessly rejoin post-reset. This is a significant milestone for the project as it signifies not only a commitment to technical excellence, but to supporting our budding community.
29+
30+## 2021
31+
32+In the last three weeks we’ve seen a huge amount of inbound interest as people are waking up to the inherent problems with using centralized services run by MEGACORPs—we’re just happy we started working on Urbit all those years ago. While we tend to not plan more than about six months in advance, I can still talk at a high level about what urbit.org will be focusing on in the immediate future.
33+
34+Growth in Urbit’s developer community has been growing organically in lockstep with the overall network growth. This means, happily, that there’s a pretty large pool of people eager to contribute to Urbit. The priority for urbit.org, therefore, is to improve its capacity to effectively assist contributors. In broad strokes, this means:
35+
36+- Rework urbit.org to better help developers learn how to contribute to Urbit
37+- Since Urbit is ready to build on top of, provide practical guides that demonstrate how to do so
38+- Guide developers to make high-value contributions to Urbit and its ecosystem
39+- Build community amongst contributors
40+
41+My strategy to date has been heavily focused on working directly with contributors to provide technical guidance and direction, and it’s been working really well. To that end I’ll also be scaling our ability to provide such support by bringing more individuals into urbit.org that can mentor, review work, and provide guidance on where to best direct contributors' energy.
42+
43+2021 is shaping up to be a big year for Urbit, and we'd [love your help](https://grants.urbit.org) in building it. If you want to see what we're working on in real time, join us in Landscape at ~wolref-podlex/foundation.
44+
45+See you on the network!
content/blog/20200929-state-of-urbit.mdnew file+72
@@ -0,0 +1,72 @@
1++++
2+title = "Late 2020 Progress Update: OS 1 -> OS 1.N"
3+date = "2020-09-28"
4+description = "When we announced OS 1, in April, we started to disappear into Urbit. Since then, we’ve been living on Urbit like we never have before."
5+
6+[extra]
7+author = "Galen Wolfe-Pauly"
8+ship = "~ravmel-ropdyl"
9+image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/state-of-urbit-1.jpg"
10++++
11+
12+![Grassy Knoll](https://storage.googleapis.com/media.urbit.org/site/posts/essays/state-of-urbit-1.jpg)
13+
14+When we announced OS 1, in April, we started to disappear into Urbit. Since then, we’ve been living on Urbit like we never have before. This has been our goal for years: to mature the system we’re building by becoming its first committed users. We knew that critical step toward Urbit’s maturity was being able to depend on it ourselves, but the system itself had to mature to the point that we could do that practically.
15+
16+We’ve done this in fits and starts. We’ve _tried_ and failed a few times over the years. We’ve always _used_ Urbit to some extent, but we’ve never _relied_ on it. These past six months have been different. I can’t tell whether it was out of sheer determination and commitment, or that the system was just genuinely ‘there’. Either way, both Tlon and the Urbit Community genuinely live on Urbit now.
17+
18+In a way, our ability to use Urbit day to day doesn’t make sense. When we shipped OS 1, it was full of holes. There were serious performance, stability, and reliability issues. Plenty of people showed up and thought, ‘I don’t understand why you think this is useful.’ But, it was good enough that we wanted to use it. And since we wanted to use it, we put our energy into making it better like we hadn’t ever before. Being able to use a system that you can really trust is a wonderful feeling. It’s Computing Without Compromises.
19+
20+All of the sudden, it’s Fall. We never found the time to name any of our releases or write announcements. We’ve just been making the system better in every way we can find. We’ve got a lot of exciting things planned for the last few months of the year — but I wanted to recap the progress we’ve made for those following along from the outside. If you haven’t been on the network, it’d be impossible to see.
21+
22+The tl;dr is that Urbit is much faster, more reliable, and nicer to use than it was six months ago. Things have gotten much better, across the board. We threw ourselves into OS 1 admittedly underprepared, but we’ve learned a lot and matured the system a lot along the way.
23+
24+Anyway, let’s walk through the details. We’ll talk about our infrastructure and interface work independently, since that’s how we organize things internally. Then we’ll talk a bit about what’s going on on the network.
25+
26+### Infrastructure
27+
28+![Debugging Interface](https://storage.googleapis.com/media.urbit.org/site/posts/essays/state-of-urbit-2.png)
29+
30+In April, Urbit was slow, fragile, and didn’t always update itself properly. We made enormous progress on all of these.
31+
32+First off, Urbit is about 10x faster for most users. With some careful debugging, we were able to locate a few really [high](https://github.com/urbit/urbit/pull/3029) [impact](https://github.com/urbit/urbit/pull/3054) [improvements](https://twitter.com/pcmonk/status/1276327036722704385). There’s still performance work to do, but the effects of this work are widespread. Boot times are faster, local compute is faster, the network is faster. It’s a huge improvement.
33+
34+Second, we got our memory usage under control. Urbit still uses a 2GB memory arena. If the state of your Urbit grows to over 2GB things, uh, fall apart. This used to happen regularly, and now it’s pretty much unheard of. We implemented [tooling](https://github.com/urbit/urbit/pull/3235) to compact and deduplicate the memory image when it’s growing too large. We brought the memory usage of the compiler [down ~90%](https://github.com/urbit/urbit/pull/3041). There are areas where we can be more disciplined about how we use memory, but this is more or less a solved problem for the near term.
35+
36+Third, we implemented a completely new build system. Well, we actually [got rid of the build system](https://urbit.org/blog/ford-fusion/) altogether and [made it a part of the filesystem](https://github.com/urbit/urbit/pull/3060). This made it possible for us to fix our over the air (OTA) updates and make them both fast and reliable. In April, an OTA could bring down your node and would take hours or even days to apply. Today, we regularly deploy OTAs with no fear of them breaking any nodes — they often go from galaxy → planet in a minute or less.
37+
38+We also rewrote a large part of our runtime in Haskell and made overall progress on [network scaling](https://github.com/urbit/urbit/pull/3174). And: we implemented a [principled approach](https://github.com/urbit/urbit/pull/2366) to [error handling](https://github.com/urbit/urbit/pull/3064), making nodes much less likely to become unrecoverable.
39+
40+The network is stable, fast, and safe from day to day. We’re pretty confident it can grow quite a bit without serious issues. When we shipped OS 1 we really weren’t sure what we could handle. Now we’re standing on much more solid ground.
41+
42+### Interface
43+
44+![](https://storage.googleapis.com/media.urbit.org/site/posts/essays/state-of-urbit-3.jpg)
45+
46+When we shipped OS 1 it was a bunch of separate pages (that were slow to load), all with separate ways of storing and processing data. Our interface work over the past six months is all about unification and simplification.
47+
48+First, we pulled OS 1 together as a [single page app](https://github.com/urbit/urbit/pull/3025). Using OS 1 involves a good amount of moving around and refreshing the page each time was pretty painful. Now it’s snappy to move between pages and keep up with what’s going on. In tandem, we started using our own component library, [Indigo](https://github.com/urbit/indigo-react). This makes frontend development much cleaner and more efficient.
49+
50+Next, we unified the way we store data and compute. It used to be that each individual module (chat, publish, and links) used their own ‘agents’ to store and process data on the Urbit side. (An agent is the Urbit equivalent of a datastore + business logic.) With a lot of moving parts, this approach caused all kinds of synchronization challenges. Rather than a module-per-agent model we’ve started to move toward a type-of-data-per-agent model. The first of these is [graph store](https://github.com/urbit/urbit/pull/3110). We’re presently in the process of migrating all our modules to graph store.
51+
52+Those two are by far the most significant, but there’s so much more. We [rewrote](https://github.com/urbit/urbit/pull/2937) the `group-store`, allowing for different roles (admin, moderators, and so on) in a group. We shipped better debugging tools, automatic reconnection, a settings panel, and overall visual polish and refinement.
53+
54+![](https://storage.googleapis.com/media.urbit.org/site/posts/essays/state-of-urbit-4.jpg)
55+
56+And I almost forgot [Leap](https://github.com/urbit/urbit/pull/3231): an omnibox for navigating around OS 1 with the keyboard. We have plans to make Leap much more powerful — but it’s a great first start toward making OS 1 keyboard accessible. I almost exclusively use [Leap](https://upload.wikimedia.org/wikipedia/commons/0/06/Canon_Cat_keyboard.jpg) to get around OS 1 these days.
57+
58+### Community + network
59+
60+![Fishing Village](https://storage.googleapis.com/media.urbit.org/site/posts/essays/state-of-urbit-5.png)
61+
62+Our primary goal with OS 1 was to get both Tlon and the Urbit Community living entirely on Urbit. We did that, and in doing so we’ve seen how nice it is to grow a community in a calm, non-invasive environment. We started doing regular [Urbit](https://twitter.com/urbit/status/1308875082312364048) [Dialogues](https://twitter.com/urbit/status/1304139629948329985) with friends and peers in the absence of physical meetups, which have been fun.
63+
64+Getting onto Urbit is still relatively challenging. By the standards of software you run yourself, it’s not so bad at all. But by comparison to ordinary consumer software, it’s way too hard. Tlon is [working on that](https://tlon.io) — but these last six months have been only for the brave. That is, those that want to host their own nodes.
65+
66+Turns out, there are plenty of people who are up for running Urbit themselves and quite a few small communities have sprouted around the network. Overall the network has a fun, cozy feeling. It’s nice.
67+
68+### What’s next
69+
70+We’re still more or less flat-out, full speed ahead into an even better Urbit-world. The seeds of change were planted when we made Josh the [interim technical director of urbit.org](https://urbit.org/blog/first-steps-towards-urbit-org/). Urbit itself is getting close to the point where the separation between Urbit and Tlon has to become more real. Urbit is aimed at being an ubiquitous platform, Tlon is aimed at making it as usable and useful as possible.
71+
72+We’ll talk about some of this on [October 9th](https://www.meetup.com/urbit-sf/events/273439025/), and you can see a bit of what’s coming on [tlon.io](https://tlon.io) today. If you tried booting Urbit in April and it was tough, try again. We’re easy to find on the network, and we’d love to get reacquainted.
content/blog/20201119-models-of-society.mdnew file+65
@@ -0,0 +1,65 @@
1++++
2+title = "Models of Society"
3+description = "Conversations compose society. What composes conversation — how do we digitize it in a way that enhances society without imposing upon it? How do we form this new medium, both to facilitate natural human behavior and to inspire the best of it?"
4+date = "2020-11-18"
5+
6+[extra]
7+author = "Tyler Shuster"
8+ship = "~radbur-sivmus"
9+image = "https://media.urbit.org/site/posts/essays/cochno-stone.png"
10++++
11+
12+_I had used Facebook and Google for my entire adult life. I knew they were toxic but I didn't know why. For a few weeks I tried to create a website that would scrape data from Facebook’s API and push data back, puppetting it from my own server. But as I stared headlong into the ever-shifting darkness of the modern web, I despaired and abandoned my attempt. Less than a year later I heard about Urbit. Technically, it went way over my head&mdash;but socially I knew exactly what it was, what it always had to be, why it was a discovery and not an invention, a place and not a product. I've watched the settlers there for four years, only just now using the opportunity of the pandemic to swim to this new landscape and gaze upon this young nation, this digital city, this urbis ec bit. I do not work for Tlon. I just live here._
13+
14+<hr>
15+
16+All people like to talk. Society is built by talking. In this&mdash;the year of our Lord two thousand and twenty&mdash;for many (maybe most) talking means typing on computers: handheld, laptop, or desktop. Computers can do all sorts of interesting things, like aid in designing buildings or simulate protein folding&mdash;fundamentally, a computer is a machine for doing math really fast. But computers can be networked, which turns them into tools for communication. Because society runs on talking and because computers enable us to do that, the most common thing that computers end up doing is to transmit human thoughts in text. Normal people call this writing, which is a kind of talking. Let’s call it messaging. When we think about building a good computer&mdash;and computer network&mdash;one that serves society in the best ways needs to do messaging well. Only a small percentage of people will regularly do anything else. (Urbit does serve those needs but I will leave that explanation to more capable minds.)
17+
18+## Modes of Messaging
19+
20+![Ludovic Maclellan Mann examining the Cochno Stone](https://media.urbit.org/site/posts/essays/cochno-stone.png)
21+
22+In general, technology serves humanity as a kind of appendage&mdash;instead of thinking new thoughts or acting on its own, it does what we command. Technology never creates new social structures&mdash;it merely makes existing ones easier, or it facilitates the creation of new ones. We use our tools to expand our capacities, and once we are capable of doing more, we can imagine new things to do. Inventing the wheel did not invent motorized transportation&mdash;but it did facilitate it and it was a necessary step, even an inspirational one. Similarly, the invention of writing made new forms of human interaction and new tools for organization possible.
23+
24+Consider the following conversational conventions, or modes of messaging: a letter; a dialogue; a book; a meeting; minutes of that meeting. These are each pieces of technology: finely constrained solutions to human problems. Now, we have digital forms of each of these which diverge variously from the original. A letter becomes an email. A dialogue becomes a chat room, or a series of blog posts, or a twitter spat. A book becomes a website or an ebook. Meetings in 2020 have virtually been replaced by their virtual counterparts. Minutes become recordings or transcripts.
25+
26+Although we do not have a clear picture of how humanity developed the technology of writing out of the basic capacity for speech, we can imagine that the computerization of writing has many parallels. It does not make the old tools obsolete, nor does it immediately introduce new social structures. It does create the potential, however. On the timeline of human existence, we have only had digitized text for a relatively short time. Because we want to understand how to best use these new forms, we should look at their underlying structure.
27+
28+In order to digitize messages well, computers need to reconcile two facts about all modes of messaging. They have:
29+
30+1. One basic shape, and
31+2. An infinite variety of forms.
32+
33+1 &mdash; The basic shape: all these modes have one common substance: human language. Any conversation is made of words. At first we only had spoken language. Then we discovered writing. Writing allows us to encode our words as glyphs to transmit them over time or distance. The internet extends this capacity. We called this "hypertext"&mdash;like good old fashioned text, but one level up. A staggering amount of messaging now takes place over this hypertext transfer protocol (http). In the process of digitizing language, we have learned the basic shape of a message. We can see this in how every social network shares messages in basically the same shape: an author, some content, references, an audience. We can confirm this basic shape by comparing it against our experience of the real world, and the previous comparison between speech and writing. Speech and writing both use the same substance, and take the same basic shape. They all have an author, content, references, and an audience.
34+
35+2 &mdash; Our experience of this one basic shape takes an infinite number of forms. The examples above (letter, meeting, &c) are just a few. These forms depend on the content of the message, the people involved, and the place they occur. All three aspects contribute significantly to its form, but the one that computerized messaging has not adequately compensated for is the place. Content depends only on the author and their intent. Getting certain people to view that content might be more difficult but most know how to use a computer. The place however, has not yet been adequately compensated for, and I think that has contributed seriously to our lack of civil and serious discourse over the internet. A president would not give an address in a bar, and a prospective lover would not utter his advances on stage. In writing, we can use the different physical forms to distinguish place. You shouldn’t read a book by the pool. You might not read a letter in public. You wouldn’t put a billboard in your bedroom.
36+
37+Furthermore, it seems possible that in our eagerness to "connect the world," we focused injudiciously on creating communities around "interests." Evidence suggests that unless the interest has a highly refined focus, these communities devolve into pandering, self-reference, and exploitation. In this way, the internet is something like a convention of conventions, where you wander in a sea of foreigners loosely affiliated by interest and surrounded by advertising booths. In physical space, people do gather by interest but they also gather by physical proximity&mdash;they are grounded and bound in place.
38+
39+Having an indistinct sense of place makes the form of conversation ambiguous and the participants of the conversation disconnected. Consequently, people are unsure how to interact. One need only know the term "comments section" to understand that.
40+
41+## People in Places
42+
43+![Halle Saale Marktplatz](https://media.urbit.org/site/posts/essays/halle-saale-marktplatz.jpg)
44+
45+As the internet grew to accommodate new conversation forms using the basic substrate of hypertext, web developers began to conceive of "digital spaces" through analogy&mdash;chat "rooms" and "forums,” or the "silo" and the "walled garden." Today, most of our conversation takes place in these walled gardens&mdash;privately-owned places which may be beautiful on the inside, but inaccessible from elsewhere. While some of these walled gardens are very large, our conversation is essentially confined to them. There is no roaming from one space to another while keeping one’s identity. We create new identities for new spaces both because we must and because we are afraid of repercussions on one platform for what we say on another. This is because we do not own our identity; we merely have a key&mdash;our password. The owners of the walled garden still own the artifacts of our tenure there, and can revoke our access to them at any time.
46+
47+The concept of identity and the concept of place are fundamentally linked. We imagine the prince who travels overseas where no one knows his name, or we imagine the old prospect of traveling to a new world to make a fortune. While those both exemplify a dramatic change in identity and place, we usually want to keep our identity consistent. We want to be recognized by friends whichever place we go, and we all strive toward having a good reputation, which is a consistent identity across places. This consistent identity also allows control of that reputation per place. A man is not judged in public by the words he says among friends. And there is no way to search what someone has said except by asking him. With our current system of identity providers (an absurd term, but a real one), we surrender our rights to selectively expose our thoughts, regardless of the place they have been uttered. A data breach or a weak password might lay bare our most private thoughts. We run the real risk of being confronted by an old conversation presented out of context or after we have learned better.
48+
49+People need distinct spaces to form conversations in distinct modes, and they need to have a consistent identity that controls how public their words are.
50+
51+In theory, we would have a digital city with unique regions, public fora, and sovereign parcels, into which one person might travel at will. In practice, we see this pattern: an app emerges to facilitate a mode of conversation. It gains popularity. Facebook (or Google, or Microsoft) buys and absorbs it. As monolithic empires, they can use the same format for all their messages. This gives them a great amount of power. They use this power to create things like "Sign in with Facebook" (or Google, or Microsoft) that benefit the user by consolidating their identity, but fail to solve the underlying problem. Their problem is that in order to allow people to communicate using the current technology stack, they need to be in control of everything.
52+
53+## Urbis ec Bit
54+
55+![View of Florence from San Miniato](https://media.urbit.org/site/posts/essays/view-of-florence.jpg)
56+
57+Urbit does solve this underlying problem. At this point the explanation goes so far down the stack that you could spend years tracing it all, but the relevant part is this: Urbit is not an empire; it’s a territory. An empire is an entangling of land and rule: within the bounds of said empire, you agree to be bound by its laws and the penalties for transgression. The laws exist at the whim of a despot or cabal. Your standing as a Roman citizen buys you no favors in Persia. In contrast, a territory imposes only physical laws. For example, in the desert, you will die faster. The only way to change that is to alter the desert. Urbit imposes nothing but the digital equivalent of physical laws. You have an identity which can be said to be truly yours, and you have a piece of software that runs on whatever computer you choose and can do anything you want with the messages sent to your identity. There are no social protocols enforced, because no one can control what software you run on your computer. As long as you agree to communicate using the same basic substrate, you can communicate with anyone using Urbit. This is the digital equivalent of speaking the same language. Whether or not others will accept you into their coalitions is not the technology's concern.
58+
59+In the same way that the land provides clay and timber, Urbit also provides the tools and material for building places both public and private. These include the aforementioned consistent message substrate (content), as well as tools for organizing people/audiences, structure for referencing other content, and an identity system that is owned only by you while being verified by all. The places are being built&mdash;private rooms with just a few people, meeting halls, club houses, huge public spaces, and countless personal encounters, the contents of which are known to none but the participants.
60+
61+The default tools work with messages in a few of the ways with which we've grown familiar: chat, direct messaging, publishing, link-sharing. They map onto existing forms of messaging because as I said earlier, the technology does not create new social structures; it just facilitates them. We have only seen the beginning of what the internet is capable of doing. Within a few decades it replaced the majority of letters, phone calls, and text dissemination&mdash;that was just the first phase of getting up to parity with what written text and speech could already do. In order to get to the next phase of creating new social processes, we need our technology to be organic and democratic, in the sense that everyone can participate and shape it. It needs to have a consensual foundation&mdash;a common substrate&mdash;and infinite possibility for expression. Urbit provides both of those.
62+
63+Similar to working undeveloped land, it takes a lot of hard work, which is why Urbit is not ready for mainstream adoption yet, and why I alluded to the idea of settlers in my opening paragraph. Traveling to the new world is not for everyone, but everyone is welcome.
64+
65+_How could one do other than submit to Tlön, to the minute and vast evidence of an orderly plant? It is useless to answer that reality is also orderly. Perhaps it is, but in accordance with divine laws&mdash;I translate: inhuman laws&mdash;which we never quite grasp. Tlön is surely a labyrinth, but it is a labyrinth devised by men, a labyrinth destined to be deciphered by men._
content/blog/2021-11-18-report-from-the-field.mdnew file+94
@@ -0,0 +1,94 @@
1++++
2+title = "Report from the field: Assembly 2021"
3+date = "2021-11-18"
4+description = "The system builds the community and the community builds the system."
5+[extra]
6+author = "Galen Wolfe-Pauly"
7+ship = "~ravmel-ropdyl"
8+image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/galen-at-assembly.JPG"
9++++
10+
11+![Galen at Assembly](https://storage.googleapis.com/media.urbit.org/site/posts/essays/galen-at-assembly.JPG)
12+
13+Before Assembly I committed to write a ‘recap’ post for everyone who couldn’t make it. Originally I figured this post would be an opportunity to walk through the list of things that we shipped and showed off in Austin. But it turns out that the most important thing about Assembly was simply the way it felt to be there.
14+
15+I’m not sure it’s possible to really do the feeling in the room justice, but I’m going to try. Then I’ll get into the announcements and happenings for those of you who couldn’t make it.
16+
17+But first, a quick note:
18+
19+We ran Assembly under the [Chatham House rule](https://en.wikipedia.org/wiki/Chatham_House_Rule). Basically, you can talk about what happens at Assembly—but you can’t name anyone.
20+
21+I’ve run many of our Urbit events this way because I think it puts people at ease. Everyone in the room can just relax, connect with one another, and hang out without worrying about being named on the internet.
22+
23+I’ll try to abide by the Chatham rule in this post which is why no one is named specifically.
24+
25+![secret society shirt](https://storage.googleapis.com/media.urbit.org/site/posts/essays/secret-society-shirt.JPG)
26+
27+New world energy -
28+
29+In the months leading up to Assembly we were totally focussed on using the event as a release date for a bunch of different lines of work. Coming out of that sprint, we didn’t really know what to expect. We wanted to make sure Urbit was ready for people to build on and that everything we were going to ship worked well. What we didn’t realize was just how emphatically people are *ready to build*.
30+
31+When I got up on stage on Friday night to welcome everyone I was really impressed by the room itself. It was packed with people who looked excited and motivated. The room just looked amazing. There were so many different kinds of people staring back at me. Some who I recognized from the earliest days of the project, and lots I had never seen before. I’ve been at my share of Urbit events, but this was something totally different.
32+
33+We didn’t have much scheduled during Assembly. Most of the time was unstructured to allow for freeform discussion, sunbathing on the lawn, and gathering at picnic tables. The panels that we did schedule will go down in history. Panelists discussed questions about creators, escaping reward systems, and the role of DAOs from governance to governments. There was hard money with a computer on it, Moloch shoes, community members grabbing the mic, and a talk written two hours before it was delivered about the relationship between centralization and decentralization when it comes to UX that blew our minds.
34+
35+I spent the weekend of Assembly in almost constant conversation with people building Urbit hardware, experimenting with different kinds of Urbit software, and thinking about incredible things like a Nock chip. I talked to the lead architect of a CPU from the 90s, a former senior US government official, an editor of a well-known literary magazine, the inventor of a new display technology, musicians whose work I already admired, a fragrance designer, writers, and, of course, lots of engineers and designers from many different backgrounds. Data scientists, systems hackers, language nerds, someone running a successful currency. I watched these people get projects off the ground, start raising money, plan the future of Urbit hosting companies, and plan new features for Landscape. I saw a last-minute warehouse party come together that kept people talking well into the early hours of the morning.
36+
37+Where did these people come from? All over the place. They have this incredible *new world energy*. They understand immediately, intuitively that Urbit has the potential to be a foundation for the society they want to live in. I’ve never seen anything like it.
38+
39+This energy seems to have come from the very practical work we do day-to-day: building Urbit, refining it, making it easier to use. The crowd at Assembly was somehow brought together by Urbit itself. It’s insanely exciting. It makes working on Urbit feel even more like a form of definite optimism. The system builds the community and the community builds the system.
40+
41+![Use only beautiful computers](https://storage.googleapis.com/media.urbit.org/site/posts/essays/use-only-computers.JPG)
42+
43+Urbit is ready to be built upon -
44+
45+Sometime in early 2021 we realized that there were many lines of work converging on a single theme: ‘Urbit is ready to be built upon’. This is the spirit we wanted to bring to Assembly, and it was very much in the room in Austin. Some of that feeling is still lingering on the network. I think it comes from some very concrete improvements that have been made to the system.
46+
47+We’ve always wanted Urbit to be maintained by a self-sustaining ecosystem and, early this year, we could see what needed to be done to really let others begin doing so. There were four parallel projects that came together to hit this milestone: Software distribution, star.market, developer and operator guides, and the Foundation roadmap. We talked about all of these things in the Assembly keynote (which you can watch [here](https://www.youtube.com/watch?v=ywj36TUtbS4)), but let’s touch on them one by one.
48+
49+Software distribution
50+
51+The most important thing that we shipped just before Assembly is the ability to actually package and distribute software over Urbit itself. It’s now possible for someone to build an app, package it up, and share it with a friend directly over the network.
52+
53+For their friend, the experience is incredibly nice. You can simply send someone a link and they can install the app and run it themselves, on their own urbit, right away. The whole thing is peer-to-peer, of course. There’s no app store, no vetting process. It’s networked software like it’s supposed to be: people computing together freely.
54+
55+We’ve been saying for years that we want people to build on top of Urbit and we always meant it. Now it’s possible in a way it never has been before. To check it out, watch [this segment](https://www.youtube.com/watch?v=MA8sqFi8Bd8) from Assembly.
56+
57+Software distribution can get better in _a lot_ of ways, and we’re continuing to work on it. But it’s live, and people are experimenting with it already. There’s Chess, there’s Pokur, there are video calls (although they’re still a little buggy). Everyone seems to love ‘pals’ and ‘zone’—but you’ll have to get on the network to check those out.
58+
59+star.market
60+
61+We’ve always used the address space to fund our work as one of the primary Urbit developers. As Urbit has become more useful, and address space has become more expensive, it’s more and more difficult for others to do this. The community saw the need for developers to easily use their granted address space to fund their work and a higher resolution for the Foundation to fund contributions to Urbit.
62+
63+This is what [star.market](https://star.market/) and the WSTR project are for. WSTR is an ERC-20 token that is backed 1:1 by ERC-721 Urbit stars. Unlike a star, a WSTR token can be fractionally divided, allowing for a broader distribution of ownership of Urbit. WSTR was built by the community over the past couple of months with no involvement from Tlon. Tlon did, eventually, help to put together star.market—the interface for interacting with the WSTR contracts safely and securely.
64+
65+I’ve come to think that WSTR can be a powerful tool for funding new Urbit projects. I’m excited to see what both our early community of developers and operators can do with it, as well as the nascent Urbit Foundation.
66+
67+Guides
68+
69+As we make it easier for developers to build software, operators to participate in the economy, and communities to make Urbit their home, we need to improve our documentation. We always like to do things bottom-up: the product work comes first. Well, the product is now live.
70+To this end we recently launched:
71+
72+[operators.urbit.org](https://operators.urbit.org/) collects all of the information about participating in the Urbit economy, running infrastructure nodes, and participating in governance in one place.
73+
74+[developers.urbit.org](https://developers.urbit.org/) has an overhauled program for learning about Urbit as a system and beginning to develop on top of it.
75+
76+[network.urbit.org](https://network.urbit.org/) allows anyone to explore the network. View galaxy transfers or how many planets a star has spawned.
77+
78+We’ve got a lot more planned in this area of work in the coming months, and these three sites are a great start.
79+
80+Urbit Foundation
81+
82+Over these past few years we’ve operated the Urbit Foundation as a ‘protocol’ inside of Tlon. Our goal has been to develop that protocol to the point that it’s refined, working, and can run on its own outside of Tlon.
83+
84+Josh has done an exceptional job running the foundation protocol at Tlon over the last year or so. He and I have been working closely together on everything that Tlon builds, while also coordinating our community of contributors. I’m very excited that the Foundation, with Josh as its Director, is now separating from Tlon as a fully independent entity focussed on supporting the ecosystem.
85+
86+Assembly was the perfect moment to begin formally separating out the Foundation and, as of a week ago, it is an independent entity. We’ve thought long and hard about how to make the Foundation an enduring, stable organization. Josh will be the first Executive Director but, ultimately, the Senate of Galaxies will elect the Board. This will keep the Foundation accountable to the network as a whole and I’m optimistic it can work well.
87+
88+If you’re on the network, you can read more about the Foundation in ~wolref-podlex/foundation.
89+
90+Assembly 2022 -
91+
92+I had more than a few enthusiastic people come up to me at Assembly and ask what we were planning for Assembly 2022. I have absolutely no idea, of course. We poured all our energy into making Assembly 2021 a success.
93+
94+Given what I saw in Austin, I’m pretty confident that next year we’ll be in completely new territory. The goal of this project has always been to build a completely new digital world. And now, it seems to be building itself.
content/blog/2021-11-18-the-promise-and-paradox-of-decentralization.mdnew file+55
@@ -0,0 +1,55 @@
1++++
2+title = "The Promise and Paradox of Decentralization"
3+date = "2021-11-17"
4+description = "Is centralization just a natural tendency of all networks? Are we destined to have a 'decentralization sandwich?'"
5+[extra]
6+author = ""
7+ship = "~lableg-tadrex"
8+image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/ux-centralization.JPG"
9++++
10+
11+![Presentation](https://storage.googleapis.com/media.urbit.org/site/posts/essays/ux-centralization.JPG)
12+
13+Every so often, a platform will do something outrageous—changing its terms of use, kicking off API partners, restricting [the content category it was built on](https://www.theverge.com/2018/12/3/18123752/tumblr-adult-content-porn-ban-date-explicit-changes-why-safe-mode), banning Donald Trump, failing to ban Donald Trump, etc.—and we'll all realize we're utterly dependent on centralized entities that can make arbitrary and unaccountable decisions. Sure, you can build your own minimal Facebook or Twitter clone, if you really want, but can you build your own Cloudflare? How about your own payment network? If your company does something legal in your country but banned in America, and the US decides to sanction you, which leads to local banks cutting you off because they can't survive without access to the dollar, are you going to build your own reserve currency? Your own Taiwan Semiconductor Manufacturing Co. or ASML?
14+
15+There are, to varying extents, efforts to do all of the above. But what's worth considering is that *all of these bans happen through centralized actors running on decentralized systems*. The Internet was supposed to be a totally open set of protocols that anyone could interact with, and for a long time it was, and yet getting kicked off Facebook and Twitter means being exiled from public discourse. Banks are regulated, but every country can set up their own banking regulations, and different countries see the social role of banks very differently; for some countries they're a tool of economic planning, for others a way to help connect local companies to global markets, for others a source of money that can be channeled to politically favored groups. The chip industry was historically very open to new entrants; the transistor was developed at Bell Labs, and for political reasons AT&T licensed it to all comers at a low price.
16+
17+And yet all of these originally decentralized systems end up facing some degree of centralization.
18+
19+The promise of a decentralized system is that anyone can build anything they want, because no one owns it. There are three important features of this; two downsides and a caveat:
20+
21+- The first downside to "Anyone can build anything" is that "anyone" means *anyone*, and the people to whom decentralized systems are the most attractive are the ones who are banned from other systems, often for good reasons. Free speech absolutists want to be defending Aleksandr Solzhenitsyn or Eugene V. Debs or even Lenny Bruce, but if you want to get a sense for the typical piece of content enabled by a totally uncensored communications system, check your spam folder.
22+
23+- The second downside is that a lack of ownership means that no one is responsible when things go wrong. Bitcoin doesn't have a way to censor your decision to move money from one address to another or even a protocol-level sense of whether you're buying Alpaca socks or a rocket launcher. (nb: You are almost certainly not buying a rocket launcher with Bitcoin; you are at best getting scammed, and at worst [getting in trouble](https://www.justice.gov/usao-cdca/pr/los-angeles-county-man-pleads-guilty-federal-charge-attempting-obtain-biological-toxin)). But this also means that the protocol can't tell when you meant to send your life savings to your cold wallet and sent it to the wrong address instead.
24+
25+- The caveat is that, to quote a [*Diff* piece from last year](https://www.thediff.co/p/amazon-a-new-kind-of-antitrust-risk#:~:text=does%20it%2C%20too.-,Technology-Governance%20Fit,-Pondering%20Durian%20has) ($), "[A]ny decentralized order requires a centralized substrate, and the more decentralized the approach is the more important it is that you can count on the underlying system." This applies to cryptocurrencies (you can trust the protocols) and to the Internet (ditto). It also applies, in an interesting way, to the increasingly decentralized world of free trade and free-flowing capital: money can only flow and deals can only be made if everyone has a consistent sense of property rights and contracts, and the definition of those concepts will typically be determined by whichever participant in a transaction has the more sophisticated financial and legal system. Globalization ends up being a bit like Henry Ford's pitch: you can use any economic paradigm you want, as long as it's the American one.1
26+
27+An open, decentralized system is *sparse*: there's room for anything, which means that most of the possibility space consists of nothing at all. This creates a natural demand for onramps—Coinbase for figuring out Bitcoin, portals for figuring out the Internet, TSM for turning chip designs into functioning products, and the like. These create a complicated dynamic: these onramps are built on an open system, but part of their function is to close off some of it. And the better they do that, the more value they can capture. Meanwhile, because they have a monopoly on what they've fenced off, their economics support providing a better user experience. Make a really helpful update to the Bitcoin wiki, and you can feel good about yourself and perhaps contribute to the price of Bitcoin in a highly indirect way; design and launch an improved onboarding process at Coinbase and your contribution is quantifiable, and affects your next cycle's equity grants.
28+
29+This privatization proceeds in three different ways:
30+
31+- Some companies start building on an open protocol and then slowly make it their own. Chrome's decision to make the search bar synonymous with the address bar was a slight improvement in the interface, but also a very strong statement that Google had replaced manually typing in URLs as the default way to navigate. (The strongest evidence for this is the frequency of navigational searches; [the most commonly-searched term on Google](https://www.mondovo.com/keywords/) is "Facebook" and [the most frequently searched term on Bing is "Google"](https://www.bloomberg.com/news/articles/2021-09-28/google-tells-judges-it-s-so-popular-it-s-bing-s-top-search-term).) Typing in URLs is a sometimes-decent way to find what you're looking for, though [the half-life of links is about two years](https://blog.zomdir.com/2017/10/the-half-life-of-link-is-two-year.html). But guessing at URLs can be [perilous](https://en.wikipedia.org/wiki/Whitehouse.com). No one is responsible for fixing this, but Google is the closest approximation, because what they are responsible for is solving the "look for something on the Internet and get the wrong result" problem, a different but related one from the broader task of allowing arbitrary site owners to host arbitrary content. Privatizing is effective, and solves problems for users rather than protocol designers. But it does go against the spirit of the original network.
32+
33+- Twitter is another example, except that they basically created their own open mostly-open protocol and then slowly took control of it. Tweets were originally a simple format, with 140 characters of text and a bit more metadata (this made it compatible with SMS, which had a 160-character limit). For a while, Twitter looked like it would operate a novel protocol and let third parties decide what to put on it and what to read off it. And then the company started to realize that an open system was also one where it was trivial to filter out ads and recommendations. So the outside partners gradually got cut off.
34+
35+- Facebook—the product, not the company—is a third example. It essentially implemented a missing element to the protocol: *identity matters*. When the original protocols were being hammered out, identity was a problem taken care of by the fact that getting online required steep hurdles; if everyone involved is affiliated with a university that trusts them to use a PDP-10 responsibly, spam or abuse were not big concerns. (Not that early usage was [strictly professional](https://www.theguardian.com/science/2013/apr/19/online-high-net-drugs-deal).) With billions of people online, accessing relevant information can mean traversing a graph of people rather than links, so the identities of those people becomes important. To the user, if not to the network itself, a name and relationship is a far more important unique identifier than an IP address.
36+
37+This pattern raises a question: is centralization just a natural tendency of all networks? Are we destined to have a "decentralization sandwich," where there's a hard-to-change set of protocols, something open built on top of *that*, and a series of closed systems built on top of that, which are the only ones the average person interacts with?
38+
39+One of the interesting alternatives to this is [Urbit](https://urbit.org), which is trying to build a network in which identity exists from the start, and is neither free nor monopolized. One of Urbit's principles is that users own their data, and while they can use third-party services, they're sharing their data with services, not using a login to access information that lives on someone else's servers.
40+
41+This is a nice theoretical solution to the "build your own" problem above: if someone tries to start Twitter-but-without-banning-X, they begin with "Twitter-but-it's-100%-X," which seems bad until they reach the next stage where trolls arrive and they start to learn that Online Censorship is mostly about spam and gore and only occasionally about politics. But if they're moving their data around, and their friends graph with it, then spinning up a separate instance of the same service, pulling in the same content from their friends, and whitelisting someone who's blacklisted elsewhere is a lot more feasible.
42+
43+At least at first. One of the problems with owning your own data is that it ignores the question of what format that data is in. Data formats are sometimes considered carefully, but they can also be hammered out fast to get a minimum viable product out the door. Then they evolve over time, accumulating cruft and complexity, until they might as well be encrypted.
44+
45+And indeed, what's to stop someone from having a proprietary format that's literally encrypted? Or one that gets changed to an encrypted version later on? This is not a trivial point; if you're ever in a position where you absolutely have to share some information that you want to keep secret, the smartest thing to do is share a huge amount of confusing and poorly-explained information, or use an [annoying but technically accurate format](https://www.vice.com/en/article/gv5vxb/crypto-keys-printout-of-edward-snowdens-email-service-lavabit-ladar-levison). Strict and unalterable rules are no match for determined adversaries, whether they're trying to play a prank, make a point, or maximize shareholder value.
46+
47+But the data format questions are not rhetorical: there is actually an answer of sorts, though it's a frustrating one. Software systems are not just lines of code, but the entire extended system of people who maintain, host, and build on platforms. And the norms of those communities can push back against market pressures. I've been spending an increasing amount of time around Urbit users and devs, and they really do view the current centralized model of the Internet as anathema. They are aware that the fun apps we use are all either designed to be addictive from the start or subject to relentless evolutionary pressure to get more addictive. There's a history of [norms evolving in response to new addictive behavior](https://gist.github.com/jm3/6724931). And Urbit's architecture is a lot closer to norms than to the clumsy mechanism of laws; instead of centralized services that own data, there's a set of 256 Urbit identities that can route messages between users. Instead of single points of failure, there are a few hundred fallback options; instead of the binary of on-Facebook-or-anathematized, there's a 2^8 bit gradient.
48+
49+One possibility for the successor to the current Internet is that it will end up being a system designed to support communities that achieve cohesion based on which forms of addictive or socially corrosive technology they reject. Sort of a digital version of the Amish, [not rejecting technology wholesale but carefully considering every new technology before adopting it](https://kk.org/thetechnium/amish-hackers-a/). If you assume that the pace of change in consumer-facing Internet stays high, and that it gets more compelling over time, then in the long run the only options are a) be careful what you use, or b) accept that you're outsourcing a growing share of your decisions to product managers and growth hackers who do not necessarily have your interests at heart.
50+
51+Norms are not a perfect solution to these problems (if they were, we'd only know about issues like novel addictive behaviors, monopolies, and the homogenization of entertainment from history books). And technology can't fully solve social problems. But it can certainly have an effect on them—"you can't solve a social problem with technology" is a good guideline, but technologies mitigate them all the time. What's a streetlight if not a technological solution to the social problem that there are places where it's dangerous to be out when it's dark? What's asymmetric-key cryptography if not a technological solution to the social problem that it's hard to keep secrets? There's still a fundamental tension with open systems, where they get mature enough to be useful at which point the median user's priority is getting things done rather than adhering to the network's original design principles. But a design that recognizes this from the beginning, and a community that wants to make it happen, can stave off decline for a long time. And that's the positive story of technology: we're all fighting against entropy, which is a hard fight to win, but there are long and fascinating stalemates ahead.
52+
53+(Disclosure: I'm long decentralization by way of Bitcoin and Urbit. If you're on Urbit and would like to discuss *The Diff*, go to ~lableg-tadrex/the-diff.)
54+
55+1. There is naturally some resistance to this, both because of conflicts with different countries' norms and with other countries' natural desire to determine their own destiny. So it's a leaky abstraction, but it gets less leaky over time as economies get more integrated and thus more of the world has to standardize. The most direct example of this is the fact that [the dollar's share of global invoices is 4.7x the US's share of global imports](https://www.economist.com/schools-brief/2020/08/27/global-trades-dependence-on-dollars-lessens-its-benefits) ($, *Economist*). In the same way that English is most likely to be the shared second language of any two randomly-selected people who don't speak it as a first language, the dollar is most likely to be the second most useful currency to anyone in a country that doesn't use dollars.
content/blog/a-founders-farewell.mdnew file+619
@@ -0,0 +1,619 @@
1++++
2+title = "A Founder's Farewell"
3+date = "2019-01-13"
4+description = "My goal was always to fire myself at the first possible opportunity. I'm super happy to reach it."
5+aliases = [
6+ "/posts/essays/a-founders-farewell",
7+ "/posts/a-founders-farewell"
8+]
9+
10+[extra]
11+author = "Curtis Yarvin"
12+ship = "~sorreg-namtyv"
13+image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/farewell.png"
14++++
15+
16+![Curtis Yarvin portrait](https://storage.googleapis.com/media.urbit.org/site/posts/essays/farewell.png)
17+
18+After 17 years, I've left the Urbit project.
19+
20+I've resigned as CTO, board member, and voting shareholder of
21+Tlon (Urbit's corporate sponsor). I've also reassigned my
22+personal galaxies to urbit.org (Urbit's embryonic foundation,
23+still in Tlon's custody).
24+
25+My family still has a few thousand Urbit stars (in long timelock
26+contracts), plus a nonvoting minority in Tlon. This isn't
27+authority, just compensation: I have zero central power over
28+either Urbit or Tlon. Nor will I contribute code to Urbit, nor
29+write nor speak publicly about it. I am actually done here.
30+
31+From the very start, I knew Urbit could not succeed until it
32+ceased to be mine and became the world's. Urbit works; its PKI
33+is on the Ethereum mainnet; it's open source; in every way,
34+technical, legal, and mathematical, it is the world's.
35+
36+(What _is_ Urbit? Please read the [primer](/primer).)
37+
38+Let's talk about: why I've left; the state of Tlon; and the state
39+of Urbit. If there's any time left, we'll read some poetry.
40+
41+## Why I left
42+
43+No one had the power to fire me. (If anyone wanted to, they kept
44+it to themselves.) I wanted to quit; I could; I should have; I did.
45+
46+I'm a thinker, not a doer; an explorer, not a leader; an author,
47+not a maintainer. My goal was always to fire myself at the
48+first possible opportunity. I'm super happy to reach it.
49+
50+Any creator is a sort of parent – where control is dependence,
51+powerlessness is independence, and independence is victory.
52+There are a lot of ways to light a fire. The last step is just
53+getting out of the way – which must be done not too late, not
54+too soon, and just right. No one can beat Satoshi in this act;
55+anyone should be delighted to follow him.
56+
57+I worked full-time on Urbit, alone and self-funded, for eleven
58+years. From 2002 to 2013, I wrote an end-to-end clean-slate
59+system-software stack: an axiomatic interpreter that fits on a
60+T-shirt, a typed functional language that doesn't use abstract
61+math, and a purely functional operating system. I didn't patent
62+any of this; I put it all in the public domain. (Not a valid
63+open-source license; Urbit is now MIT licensed.)
64+
65+By 2013 I had a stack that worked well enough to make [a
66+video](https://vimeo.com/75312418), then raise a 1.5M seed round. Urbit in 2013 was a
67+working product – in fact, Urbit has had a live global network
68+since November 2013. But in a new platform, the distance between
69+_working_ and _compelling_ is nontrivial. Especially for a seed
70+company with just a few young engineers, building something like
71+nothing ever built before.
72+
73+Urbit in 2013 had roughly the same feature set as Slack in 2013,
74+but less polished, and decentralized. It was pretty buggy and
75+slow. But had we put all our resources into debugging and
76+optimization, it would not have taken five years.
77+
78+My instinct was always that Urbit's delivery schedule should be
79+as long as possible. For me, there are always two Urbits: the
80+Urbit that exists, and the Urbit that should exist. To invent
81+the latter I have to inhabit it. When I look at the present,
82+I try as hard as possible to look at it from the perspective of
83+the future – that's where my head should be.
84+
85+This always makes me think Urbit sucks. And the last thing you
86+want to do is evangelize anything that sucks. This is a bias,
87+but that doesn't make it wrong. For instance: the 2013 Urbit had
88+a shell and a persistent distributed chat – but the shell was
89+mixed in with the kernel, and the chat with the network protocol.
90+As seen from the 2019 Urbit, this is very lame indeed.
91+
92+The conventional wisdom is to ship your embarrassing "MVP." For
93+several reasons, Urbit occupies a unique strategic position.
94+Urbit just isn't relevant until Urbit is, if not perfect,
95+uniformly excellent. It can't just work. It has to work right.
96+Urbit has to be amazing – which is hardly a useless discipline.
97+
98+I still did not think it would take five years to make Urbit
99+work right – or to get the resources to make it work right
100+(which only happened in 2018). But founders always delude
101+themselves, or no one would do it.
102+
103+Urbit is not uniformly excellent quite yet. There are a few
104+medium-sized cleanups in the near-term pipeline. But this is a
105+matter of months, not years. I don't see any unknown unknowns.
106+The adventure isn't over – but the exploration is over.
107+
108+A clean-slate system software stack, from fundamental interpreter
109+to social network, through typed functional language and
110+deterministic OS, is an enormous architectural journey – so
111+long and winding that it's easy for anyone to get lost in any
112+detail. Isn't that any explorer's first job: not getting lost?
113+
114+But once the route is marked, there is a second duty: getting out
115+of the way. It's time for surveyors, not explorers, to map,
116+measure and smooth every wrinkle on the map. That's how system
117+software matures. Lines first ripped in one long slash are
118+polished, straightened and refined across years and decades.
119+
120+And Urbit is too deep and interesting for one technical leader.
121+Every part of it needs its own owner. But others can't build a
122+real sense of ownership while the founder is still around. I'm
123+not even the best engineer on the project; I just got here first.
124+
125+This codebase is very young and very general; there is a lot of
126+fun left to be had with it; others deserve to have that fun.
127+
128+I have no successor as "BDFL." Technical leadership passes to
129+Tlon as a company. Urbit is open source and anyone may play, but
130+anyone who wants to catch up to Tlon still has a lot to learn.
131+Not that that should stop them!
132+
133+I can't make Urbit technically transparent in one speech. But
134+maybe I can shed a little light on the strategy, organization,
135+history and future of the company and the project. It's easier
136+to be frank on the way out.
137+
138+## Tlon, boiling oceans since 2013
139+
140+First of all: why did we do what we did?
141+
142+An ambitious system software project can inhabit one of four
143+institutional forms: bigco, startup, academia, or community.
144+
145+None of these is a fit for a clean-slate system software stack.
146+The startup is the least worst. I'd do it again.
147+
148+A normal startup lifecycle (Tlon actually got into YC, but
149+declined – this was either cool or lame) looks nothing like a
150+normal system-software lifecycle. Nor is Urbit normal. But
151+while Silicon Valley is absurd, it still fits Marianne Moore's
152+line: "with a perfect contempt for it, one discovers that there
153+is in it after all a place for the genuine."
154+
155+The less said about big companies and big science, the better.
156+But the choice between startup and community is interesting.
157+Let's talk a little about why Tlon, this corporation, exists,
158+then a little more about what it actually is.
159+
160+### Tlon, from cathedral to bazaar
161+
162+I used to think I could give Urbit directly to the world – that
163+I could just post the code and an open-source community could
164+take it from there. That'd probably work now, but it's not yet
165+the right thing – and not because nobody wants a revolution.
166+
167+I've never been an open-source person myself. But the model has
168+fascinated me since I encountered Nethack in the '80s. Now that
169+open-source software is a mature field, we can see what kinds
170+of problems the open-source "bazaar" mode is and isn't good at,
171+versus the corporate "cathedral" mode.
172+
173+One problem open source isn't good at is creative collaboration
174+on large and novel systems. For example, if we consider the set
175+of people creating Google's new Fuchsia OS, and the set of people
176+contributing npm modules, we see that it's almost impossible to
177+imagine something like Fuchsia as a community effort – but this
178+is not for lack of talent-hours. Imagine a bazaar creating a
179+feature film, and you'll get the picture. (And Fuchsia seems
180+like a fairly traditional OS.)
181+
182+Why is creative work so hard for bazaars? We could take this as
183+an axiom – but it's worth understanding.
184+
185+The path from concept to product is an annealing process. Your
186+code starts as a gas and ends as a metal. It must cool gradually
187+under precise control. When parts cool too fast, flaws appear.
188+Where flaws appear, the code must be reheated: ie, rewritten.
189+
190+Except for ASCII and a few algorithms, Nock, Hoon and Arvo didn't
191+really rely on anything from 20th-century CS. We didn't drop any
192+off-the-shelf parts into the oven; the whole stack is made from
193+gas. So the code in Urbit has been rewritten at least once; the
194+best code has been rewritten four or five times; perhaps some has
195+been rewritten ten, fifteen, even twenty times.
196+
197+In 2002, I started out with no idea what I was doing. Urbit was
198+interstellar vapor. I did have a decent grounding in 20th
199+century CS, academic and practical. In the '90s I was a grad
200+student in OS at Berkeley, then spent eight years on system
201+software projects (a language, an OS and a browser) in industry.
202+What I wanted, I did not know; what I knew, I did not want.
203+
204+In a long annealing process, it's important to triage the order
205+in which you solve problems. There are three kinds of problems:
206+problems you can't solve now, problems you don't have to solve
207+now, and hard problems. Unless you postpone anything that isn't
208+a hard but solvable problem, your gas will never turn into steel.
209+There are lots and lots and lots of ways to go nowhere fast.
210+
211+Somehow it's 2019. Urbit is hot iron under the hammer. It is
212+solid, but not yet hard. It has shape, but can yet be shaped.
213+It is done, but ought to be finished. It is a sword; you don't
214+want to get stabbed with it; it is not Excalibur, the blade to
215+end all blades.
216+
217+The bazaar is great. But cathedrals still exist for a reason.
218+The challenge for an ambitious system-software project is not
219+whether to choose the cathedral or bazaar model, but when and
220+how to transition from cathedral to bazaar.
221+
222+A cathedral – the same classic pyramid org-chart no doubt used
223+by the builders of the actual pyramids, or the actual cathedrals
224+– is economically less efficient than a bazaar. Why?
225+
226+Even on the world's most fun project, working for some dumb boss
227+is no fun. The bazaar succeeds because the project extracts free
228+labor from contributors – not by cheating them, but in exchange
229+for fun, status, experience, etc. But mainly fun, honestly.
230+
231+Whereas a cathedral costs a giant ton of money. But in exchange,
232+the cathedral gets _cohesion_ – the capacity for intelligent
233+coordinated action. Bazaars can coordinate, but not easily.
234+
235+Because a cathedral can coordinate, a cathedral can _create_ –
236+acting at a scale above individual action. A bazaar is very
237+useful, but a bazaar does not create. It can grow; it can heal,
238+harden, extend, and expand; but creation requires an individual
239+or a coordinated group.
240+
241+But a bazaar can get a lot more done, a lot faster and a lot
242+cheaper. So the right starting point for a bazaar is an existing
243+system which is very clear, very final, and very simple. So any
244+new system should be created by a cathedral and perfected by a
245+bazaar. Since these institutions share little or no structure,
246+the transition is by no means straightforward.
247+
248+### Tlon, just a little startup
249+
250+Tlon is Urbit's little corporate cathedral. It's about 20
251+people, about 15 of them engineers. Everyone is working on
252+Urbit, but not everyone is writing Hoon; there is client-side
253+work, Ethereum work, etc.
254+
255+The team is comfortably funded and more than competent. One Tlon
256+engineer is a 10-year, level 6 Google veteran; another is a YC
257+alum; these people are great, but not really outliers. And not
258+to be credentialist – there are plenty of dropouts, too.)
259+
260+Today, there's almost no part of the Urbit codebase that I still
261+know better than anyone else. There are even design areas that
262+others know better. When we transitioned from Nock 5 to Nock 4,
263+all I contributed was a suggestion. The same for our Ethereum
264+address collection, which our customers absolutely loved.
265+
266+Who's responsible for growing and maintaining this team? Who's
267+the stone at at the top of the pyramid? Not me: if you gave me a
268+goat to feed, the goat would die. The stone that holds the arch
269+together is Tlon's CEO and my cofounder, Galen Wolfe-Pauly.
270+
271+Tlon was founded in 2013; Galen led it through its long seed
272+stage, with only a few engineers, to 2018, when he finally
273+secured the resources to do the project justice. (Although way
274+too much of Tlon's energy in 2018 had to go into Ethereum.)
275+
276+Galen's previous project was the social meta-network Ost. He has
277+an architecture degree from Cooper Union; he is a great designer,
278+a good front-end engineer, and a pretty good surfer. (He also
279+runs the @urbit Twitter.)
280+
281+Galen sets Tlon's product vision and is responsible for both
282+visual appearance and human experience. Basically, Galen is the
283+Steve Jobs of Urbit, with only two differences: Galen's not an
284+asshole, and Steve wasn't short.
285+
286+Galen is joined in the new leadership team by Erik Newton
287+(operations, legal) and Anthony Arroyo (product, engineering).
288+Erik used to run a divorce-law firm and still is a relationship
289+coach. Anthony was a grad student in comparative literature and
290+managed engineering prototypes at Applied Minds.
291+
292+With my departure, Galen is in exclusive control of Tlon and
293+holds the only board seat. Tlon did take seed funding from VCs.
294+But outside investors have never held any management role.
295+
296+## Urbit, in the rear-view mirror
297+
298+Since I'm not going to talk about Urbit again, let me say a few
299+words that might otherwise go unsaid.
300+
301+### Urbit, a level and neutral platform
302+
303+Urbit's distribution and sponsorship hierarchy of galaxies,
304+stars and planets is _not_ designed as a political structure,
305+or even a social structure. The actual social layer is in
306+userspace -- one layer up.
307+
308+Socially and politically, Urbit is a flat network of planets.
309+Galaxies and stars are plumbing. No one cares which star is your
310+sponsor, any more than your Facebook friends care who your ISP
311+is, or you care what data center Facebook is in.
312+
313+The sponsorship hierarchy and the senate of galaxies (which can
314+amend Urbit's Ethereum constitution) are _technical_ governance
315+mechanisms. They exist to react to unanticipated technical
316+issues or conflicts (like denial-of-service attacks). Because
317+sponsorship has an escape mechanism, it is not a _feudal_ bond
318+(like your relationship to Facebook).
319+
320+Urbit is a decentralized network of social networks. No one can
321+regulate it. Urbit is made to blossom into an endless garden
322+of human cultures, each of which must regulate itself, none of
323+which can bother the others. The soil in which these flowers
324+grow must be level and neutral.
325+
326+### Urbit, anything but a fair distribution
327+
328+Who got those galaxies, anyway?
329+
330+Urbit has no mining mechanism and needs none. My model was: I
331+own the whole space, since I made it; on the other hand, it's
332+worthless until I find a way to give it away.
333+
334+In the end, I am probably the only individual with a fair amount
335+of Urbit address space (no galaxies, a few percent of all stars).
336+Tlon plus urbit.org also have about the right amount (slightly
337+less than half). The rest are held by third parties – all of
338+whom have either much more, or much less, than they deserve.
339+
340+But although the distribution of Urbit space was thoroughly
341+unfair, it was always _honest_ and never _corrupt_. Everyone
342+who has galaxies or stars did _something_ for Urbit. Some gave a
343+lot of money, some gave a little; some contributed a lot of code,
344+some just showed up. We paid a lawyer by bartering a pair. A
345+bunch went to contest winners who solved a trivial Nock problem
346+in 2010.
347+
348+What's unfair: the standards changed wildly across time. What's
349+honest: they were always the same across _people_. Granted, you
350+often had to be in the right place at the right time. This is
351+another problem with life that we can't fix.
352+
353+Every real system of property is unfair. Who deserves to own
354+Manhattan? Who does own it? If property be not unfair – if it
355+is not the result of respecting past accidents – it is not
356+property at all, but something else. I certainly would not do it
357+this haphazardly again, but the outcome is no tragedy.
358+
359+When you live in Manhattan, you simply don't worry about who
360+owns it or why; and nor does it matter. Are they Jews? Muslims?
361+Christians? Communists? Italians? You don't care and you don't
362+have to. You know it's basically random and probably unfair.
363+Randomness, even blatant unfairness, creates a kind of neutral,
364+peaceful, even promising urban anonymity.
365+
366+Property is always and everywhere a kind of amnesty. It says:
367+whatever happened in the past, this is now what is. When we all
368+agree that everyone has what they now have, however they got it,
369+we have a formula for peace. When we say that everyone should
370+have what they deserve, we can never expect everyone to agree –
371+which means we have planted permanent seeds of discord.
372+
373+And randomness is a virtue – it disrupts hidden patterns. The
374+galaxy owners include famous VCs and total nobodies; a Zen monk
375+and a former Orthodox nun; a blockchain industry leader and a
376+permaculture farmer. If they do have to all agree on something,
377+they should have little to agree on but the truth.
378+
379+## Urbit, a technical report card (January 2019)
380+
381+As a system-software stack, the fundamental thesis of Urbit is
382+that technical simplicity can flow all the way up to the top of
383+the stack, where it becomes human usability. If we can build a
384+purely functional OS, we can build a zero-maintenance server,
385+which is easy to understand because how it works is simple.
386+With this problem solved – nothing else matters.
387+
388+Unfortunately, I still have to give Urbit an "incomplete" here.
389+No grade is available, because usability depends on a lot of
390+fit-and-finish issues that are naturally back-loaded. I would
391+still much rather run an Urbit ship than a Mastodon instance.
392+But still, Urbit today can't quite promise zero maintenance.
393+
394+So we have to look at smaller indicators. One way to get anyone
395+to grade their own work is to ask them for three ways they've
396+succeeded, and three ways they've failed.
397+
398+### Urbit, three battles won
399+
400+I did once want to be a real computer scientist. Before my
401+expulsion for sordid & disturbing behavior, I was once a
402+19-year-old PhD student in CS at Berkeley. I even made an
403+embarrassing bet with Raph Levien as to which of us would win the
404+Turing Award – my money is definitely on Raph at this point.
405+You can even go and read my Usenix '93 paper on ASLR-secured
406+RPC, which won Best Student Paper and has like 50 citations.
407+
408+Well. That whole scene is a bad trip, kids. Avoid it. Also, if
409+you start out as Rimbaud, you might end up as Lebowski. On the
410+other hand, to have any excuse for boiling the ocean, you do have
411+to make some serious CS problems just go away. Here are three.
412+
413+#### Validation
414+
415+20th-century languages underrate the centrality of communication
416+to computing. Their type systems expect all data to live in a
417+single memory forever. They don't consider data serialization
418+and validation to be core competencies of a programming language.
419+
420+So serialization/validation is handled either ad hoc, or by
421+intermediate data description systems which have inherent
422+impedance mismatches with the language proper. Not only is work
423+done over and over – but most network security breaches exploit
424+seams in custom or complex deserialization and validation code.
425+
426+In Urbit there is one kind of data, a noun, which is an atom
427+(unsigned integer) or a cell (ordered pair of nouns). There is
428+one serialization model, which maps noun to atom to noun, in a
429+page of code. And a type defines a set of nouns by defining a
430+function of an arbitrary noun, whose range is that set – which
431+means any data type is also its own data validation function.
432+
433+#### Idempotence
434+
435+20th-century computers have two brains: one fast and temporary,
436+the other slow and permanent. When one of these two-brained
437+computers hears a packet, and sends an acknowledgment, that only
438+means the temporary brain heard it. Acks are not end-to-end
439+transactions.
440+
441+This means you can't write a command protocol where your commands
442+get executed exactly once. You can only choose "at least once"
443+or "at most once." This problem is as ridiculous and frustrating
444+as it sounds.
445+
446+You can address it in three ways: (a) make all your commands
447+formally idempotent, so that repeating them has no additional
448+effect; (b) insert a layer of stateful middleware — a message
449+queue; (c) be fine with "almost always once." Guess which
450+approach is most popular?
451+
452+Your Urbit ship has one permanent brain. Its acks are end-to-end
453+transactions — no packet is acknowledged until all its direct
454+effects are finalized. Every message channel is its own message
455+queue. And every message is executed once.
456+
457+#### Dependencies
458+
459+20th-century languages are all at least vaguely based on a
460+formalism from the '30s called the "lambda calculus." The
461+fundamental operation in lambda calculus is variable reduction
462+from name to value. So lambda languages all have a symbol table
463+or environment which binds names to values.
464+
465+Modern build systems assemble large programs out of small files
466+by reusing this symbol table for global function names, a process
467+called "linking." Unfortunately, linking causes a problem known
468+as "dependency hell," involving baffling, unpredictable upgrade
469+failures. The fundamental problem is the "diamond dependency" —
470+when a build requires two different versions of one symbol.
471+
472+Urbit does not use the lambda calculus, an environment or symbol
473+table, or linking. Because it pushes name resolution out of the
474+fundamental interpreter and up into the language, it can play
475+many more namespace juggling tricks. And its build system has no
476+trouble including multiple versions of the same library.
477+
478+### Urbit, three battles unwon
479+
480+As I mentioned earlier, triage is essential on any long journey.
481+You have to keep moving forward, even when you have no idea where
482+you're going – which means attacking the hardest problems you
483+can solve right now.
484+
485+Unfortunately, this is a different standard than the usual rule
486+for shipping a product: solve the most important problems first.
487+This principle of triage is a general case of Knuth's apothegm
488+against premature optimization. Urbit, in fact, was absurdly
489+slow for a long time, but after a couple of engineer-months of
490+focused optimization it seems fine now.
491+
492+But there are other areas where Urbit today is surprisingly weak.
493+All look careless, but all are the result of careful triage.
494+When you find a weakness due to triage, you may think you are
495+judging Urbit's quality. You are just judging its maturity –
496+which doesn't make your judgment wrong, of course.
497+
498+#### Opacity
499+
500+Urbit's notorious opacity is the problem that makes people
501+complain the most. It's not an unwarranted complaint.
502+
503+At least, it's not all an unwarranted complaint. Part of the
504+complaint is just about novelty. Novelty is of course inherent
505+in any clean-slate stack. I do regret making 0 true and 1 false.
506+On every other count, however, I offer all critics of Urbit's
507+novelty none but the most vulgar gesture.
508+
509+But novelty is not the only problem. Urbit's external
510+documentation has gotten much better in 2018 – in particular,
511+it's now much easier to learn the language. Its _internal_
512+documentation, and general code quality, remains at best poor to
513+average. Worse: the worst code is the oldest, deepest code,
514+which is also the most fundamental. Not only is it not
515+commented, it is full of cryptic, meaningless names.
516+
517+There is now a new style guide, which should enable all reference
518+documentation to migrate into the codebase. But this style guide
519+is so new that none of the codebase complies with it. The guide
520+demands "space-rated" code that documents every variable and
521+every line – and almost none of the codebase is space-rated.
522+
523+Urbit's internal opacity persists for two reasons, one good and
524+one bad. The bad reason is just laziness. The good reason is
525+justified fear of _premature explanation_, which like premature
526+optimization ruins the annealing process.
527+
528+When you don't know exactly what you're doing, preserve as much
529+ambiguity as possible. For example, a name that means something
530+is a commitment to one specific explanation; a name that means
531+nothing is no commitment at all. A cryptic name is productive
532+procrastination; it lets the hard problem of naming get solved
533+later, and hence better.
534+
535+#### Impermanence
536+
537+Your Urbit ship needs to be _permanent_. That means it doesn't
538+lose data, sink, or get wedged, or rot. It's not complicated.
539+I wish Urbit today could make this promise, but it can't.
540+
541+There are are two problems here: short-term permanence and
542+long-term permanence. Short-term permanence means your ship
543+can't fail or lose data except via OS or hardware failure.
544+Long-term permanence means you can put your ship on a USB stick
545+in a box for 50 years, or 100, or 500, and when you turn it on
546+in a modern interpreter it will upgrade itself and work fine.
547+
548+There aren't any significant structural obstacles to each of
549+these milestones. But we can't claim them yet. We haven't
550+really even worried about them. This is another triage case:
551+in this case, the issue is _premature reliability_.
552+
553+Permanence also includes security. Except for the on-chain PKI,
554+in which case you're trusting Ethereum, you shouldn't yet trust
555+Urbit's security at all. Sorry!
556+
557+#### Duplication
558+
559+Triage can procrastinate in the other direction. It can skip
560+problems that are too hard to solve. When you procrastinate,
561+always come back – in this case, when the problem is easier.
562+Here's one way Urbit has skipped a problem that was too hard.
563+
564+Urbit, as you may recall, is a single-level store. It has only
565+one brain. And yet, we resisted the natural unification of
566+_documents_ and _applications_ and _secrets_ that a one-brained
567+computer obviously suggests.
568+
569+Instead, Urbit today is built more the Unix way (if not the
570+Windows way). It has separate subsystems for tracking and
571+updating these three kinds of data. This was my design. Like
572+Urbit's opacity or impermanence, this was always obviously lame.
573+
574+Why do it the lame way? Because, before understanding the union
575+of these problems, we had to understand each problem by itself.
576+We didn't – not even close.
577+
578+No one else ever built a purely functional operating system. No
579+one is going to go straight from zero to the right thing. You
580+have to solve a hard problem, learn from it, and do it again.
581+
582+Now that the team has built and used the specialized subsystems,
583+it's probably time to go ahead and generalize. The problem now
584+strikes me as almost straightforward. The constraints are clear
585+and so are the tools. None of this was true a year ago.
586+
587+On the low end, triage keeps you moving forward by stopping you
588+from wasting time on easy problems. On the high end, triage
589+keeps you moving forward by keeping you from leaping too far
590+ahead, and falling down an impossible rathole.
591+
592+## Further reading
593+
594+What will I do personally? I'll spend more time with my kids.
595+I'll finish reading my 1911 Britannica – I am only on the B's.
596+I have no other long-term plans.
597+
598+But I won't be back to Urbit. I am leaving not just the project
599+but the field – no less than Satoshi, or Everett, or Rimbaud.
600+Will Satoshi weigh in on the next Bitcoin Cash fork? Did Rimbaud
601+fly back from Ethiopia for his book-release tour? (Did anyone
602+want him back?) It's not so bad to be a middle-aged Rimbaud.
603+
604+Is there more to say? Of course, but not in prose. Read
605+Bunting's _Chomei at Toyama_ and _Notes on a Fly-Leaf_; Cavafy's
606+_Il Gran Rifiuto_, Keeley & Sherrard translation; Canto XV of the
607+Inferno, Pinsky translation. You might learn something.
608+
609+## Apologies and acknowledgments
610+
611+I apologize to anyone who has too little Urbit space. I refuse
612+to guilt-trip anyone who has too much.
613+
614+I appreciate my friends by not naming them. I disarm my enemies
615+by inviting them to lunch – but only if they come unarmed.
616+
617+I thank everyone who has ever worked on Urbit and everyone who
618+will work on it in the future; our backers, great and small; my
619+cofounder, Galen, and his family; my parents, wife and kids.
content/blog/a-topiary.mdnew file+38
@@ -0,0 +1,38 @@
1++++
2+title = "A Topiary: Hypertext and Urbit"
3+date = "2021-06-13"
4+description = "A brief history of hypertext and Urbit networking"
5+
6+[extra]
7+author = "Reid Scoggin"
8+ship = "~sitful-hatred"
9+image = "https://media.urbit.org/site/posts/essays/treebranches.jpeg"
10++++
11+
12+![](https://media.urbit.org/site/posts/essays/treebranches.jpeg)
13+
14+> Under the trees of England I meditated on this lost and perhaps mythical labyrinth. I imagined it untouched and perfect on the secret summit of some mountain; I imagined it drowned under rice paddies or beneath the sea; I imagined it infinite, made not only of eight-sided pavilions and of twisting paths but also of rivers, provinces and kingdoms... I thought of a maze of mazes, of a sinuous, ever growing maze which would take in both past and future and would somehow involve the stars.
15+
16+-- _The Garden of Forking Paths_, Jorge Luis Borges
17+
18+The pre-technological world was already [networked](https://en.wikipedia.org/wiki/Indra%27s_net). No material object and no idea has ever stood alone—"no man is an island". Language itself is a network of associations shared between a group of people. The question of technology is: how do we bring our web of associations into the realm of computers? The legacy internet has focused on social networks almost exclusively—our mammalian brains readily took to this, we all love to [signal](https://conversationswithtyler.com/episodes/robin-hanson/). But before “social media” there was something called hypertext: a seemingly modest way to connect documents shared between computers.
19+
20+A footnote in a book used to require a library, locating the referenced book, and finding the cited page (which might have footnotes itself)! Hypertext allows one to traverse a network quickly and easily with just mouse clicks, making information accessible to those without the time and resources to hunt down physical artifacts. Urbit’s “%graph-store” is not the same as hypertext but it does bear some familial resemblances. Fundamentally, %graph-store is a data structure that can accommodate disparate data types within a single edifice. It is based on [graph databases](https://en.wikipedia.org/wiki/Graph_database) and recent implementations such as [GraphQL](https://graphql.org/). To understand this data structure it is worth diving into the origins of hypertext—the original linked network.
21+
22+The story of hypertext begins at the end of WWII with an article in _The Atlantic_ that proposed to extend the human mind via machine. Vannevar Bush had seen first-hand the explosion of electronics manufacturing and scientific knowledge, recognizing the great peril and opportunity of such a revolution. His [description](https://www.theatlantic.com/magazine/archive/1945/07/as-we-may-think/303881/) of the Memex presaged the technological world of today, envisioning a personal device that would allow the user to draw upon a vast library of information, and link documents together arbitrarily—what he called "associative indexing"—a deliberate recreation of how the mind connects thoughts.
23+
24+The 1960s saw the first implementations of these ideas. Ted Nelson's [writing](https://archive.org/details/SelectedPapers1977/page/n15/mode/2up) around _Project Xanadu_ elaborated this linking between documents into what Nelson called _hypertext_. Nelson imagined "a text arranged in a graph structure", centered around a corpus arranged in nonlinear sequence, manipulable by author or audience. The concept was first demonstrated in 1968, at Douglas Engelbart's 'Mother of all Demos', where a vision of computers as a collaborative social environment was revealed to the world. "[The Journal](https://www.dougengelbart.org/content/view/137/#7)", presented alongside other revolutionary demos, exhibited collaboratively edited documents with hyperlinked connections. Any time-travellers in the audience would have immediately recognized the first webpage. From here, the idea of a linked network of documents would be developed through successive phases of computing, from the mainframe to the PC.
25+
26+Experimentation with these ideas continued through the 1970s and 80s. A team directed by Andy Lippman at MIT extended the concept to threaded visual hypermedia with the _Aspen Movie Map_, a user-directed virtual tour of Aspen, Colorado. Hypertext and hypermedia gained a mass audience for the first time with HyperCard, a program that shipped with Mac computers. Users were able to collect or create '[stacks](https://archive.org/details/hypercardstacks)' of interlinked cards; a personal body of text, art, and knowledge could be accrued and modified, or shared with others—though not yet with native networking capabilities.
27+
28+With the World Wide Web, hypertext achieved escape velocity. Initially a one-man [project](http://info.cern.ch/hypertext/WWW/TheProject.html), the world wide web was similar to Bush’s vision of the Memex—a way to share, index, and connect information between individuals and groups. The web succeeded by utilizing the physical infrastructure already available: PCs with graphical interfaces, DNS, and the internet. Critically, its method of transmitting and traversing texts was a standardized protocol, allowing a free body of information to assemble atop the new infrastructure by anyone willing to learn the tools. A new frontier was cleared and cultivated with open standards, but it would gradually face enclosure.
29+
30+In the following decade, after the first wave of social networking sites had crested but before phones became the primary web clients, Twitter was launched. Originally an awkward bridge between SMS and the web, its design eventually coalesced around static identity, posts with chronological sorting, and interlinked post threads. These simple primitives spawned a vast corpus of information, a graph-of-graphs intertwined and overlapped, mapping an entire platonic world. Twitter is fundamentally constrained by its very nature: it is the walled garden of an advertising company. The financial incentives of the server operators demanded seizure of the commons and the replacement of standardized protocols with proprietary databases.
31+
32+As the first networked services withered, a new critique was implicitly articulated in the construction of a [new kind of abstract machine](https://moronlab.blogspot.com/2010/01/urbit-functional-programming-from.html). Urbit learned from the past: tightly defined protocols, baked-in cryptography, and decentralization were key. If power over the network was determined by those who ran the servers, then we would run the servers ourselves.
33+
34+Urbit is not fundamentally a hypertext system; it is a new kind of computer, designed to participate in a peer-to-peer network that rejects the client-server model. All Urbit software takes its networking model for granted, it is not an ad-hoc layering of mismatched abstractions. Fundamental design decisions determine the trajectory of the future.
35+
36+Early [implementations](https://en.wikipedia.org/wiki/Neo4j) of graph databases and projects like [RDF](https://en.wikipedia.org/wiki/Resource_Description_Framework) hit on the same core idea: linked data needs its own data structure. In 2020 Urbit OS adopted an application called %graph-store that made use of a new, native [data structure](https://docs.google.com/document/d/1-Gwfg442kV3cdfG7NnWPEf2TMa3uLUTAKkZD70ALZkE/edit) which would act as a database service for social applications. Chats, long-form text, and other types of data produced in the course of social computing now share the same tent, a single structure extensible to new types of content. Each item added to it is a node in a personal graph—a tree that grows branches as your computer communicates. These nodes can be linked arbitrarily to other graphs—Urbit's global immutable namespace grants both permanence and ownership and allows the graph’s branches to intertwine with others. Graphs can accommodate a variety of content, from simple text, to code and media yet to be conceived. You own your graph, and it is a record of your digital journey with others.
37+
38+Personal hypertext graphs are leaving behind proprietary platforms and gaining independence. Graphs until now have been used as tools of surveillance and marketing, but they are being reclaimed and sewn back into the network, each bound to the cryptographic identity of an individual, permanent computer. Where the map of your life was once splintered across a thousand systems and held in the custody of strangers, it is now possessed only by you and shared only as you see fit. On Urbit, an infinite forest of digital lives can take root, nesting their boughs and stalks.
content/blog/aesthetic-culture-1.mdnew file+103
@@ -0,0 +1,103 @@
1++++
2+title = "Aesthetic Culture #1"
3+description = "One of the most exciting things about Urbit is the aesthetic and design around it, developed partly by Tlon (through the design of Urbit itself) and partly by the community (by producing great Urbit art)."
4+date = "2020-11-11"
5+
6+[extra]
7+description = "One of the most exciting things about Urbit is the aesthetic and design around it, developed partly by Tlon (through the design of Urbit itself) and partly by the community (by producing great Urbit art)."
8+author = "~nartes-fasrum"
9+ship = "~nartes-fasrum"
10+image = "https://media.urbit.org/site/posts/essays/help-the-environment.jpg"
11++++
12+
13+![A set of four sigils arranged & coloured to appear as various natural forms, above the ~sorwet sigil & the text "help the environment and help yourself"](https://media.urbit.org/site/posts/essays/help-the-environment.jpg)
14+
15+_This post is the first in a series of digests centered on art produced within and about Urbit by a member of the community, ~nartes-fasrum. Monthly digests will be available within the Urbit Community group in Landscape, and will occasionally be compiled here on the blog to give you a sneak peek at some of what’s happening on the network. Enjoy! ~wolref-podlex_
16+
17+One of the most exciting things about Urbit is the aesthetic and design around it, developed partly by Tlon (through the design of Urbit itself) and partly by the community (by producing great Urbit art). As the community grows, it creates more art, and we have the opportunity to showcase some of the pieces we love. These works can draw curious new users in, and they give existing users ways to communicate their excitement to friends.
18+
19+To that end, I wrote [the Art by Urbit proposal](https://grants.urbit.org/proposals/636838408-art-by-urbit), a regular digest for the dissemination of Urbit art and propaganda. We'll bring you the works of both familiar faces and new users, in a variety of media types from image manipulation to 3D models and physical pieces. This first digest will cover some of the art produced in the past year, but will have a focus on the last two months. Future digests will be incremental updates summarizing the artworks of the prior month.
20+
21+## ~datnut-pollen
22+
23+~datnut- made a physical representation of their sigil from maple wood & epoxy resin, and mentioned the potential to use an Arduino to cause different lighting effects for different statuses of an urbit.
24+
25+![The sigil of ~datnut-pollen glowing yellow on a black background](https://i.imgur.com/GxmO6sT.jpg)
26+
27+## ~lagrev-nocfep
28+
29+~lagrev- [made a thread of Dinosaur Comics](https://twitter.com/sigilante/status/1299101593997127680), using the Urbit Whitepaper as the seed text.
30+
31+![A Dinosaur Comics comic, with text pulled from the Urbit Whitepaper](https://pbs.twimg.com/media/EgdUaoKWoAAl6A3.jpg)
32+
33+A sweet poem about the potential for Martian felines is theirs as well:
34+
35+![A brief poem regarding cats on Mars](https://pbs.twimg.com/media/Ef_KTbqWAAAHN-k.jpg)
36+
37+## ~litmus-ritten
38+
39+~litmus- produces art full of glowing gases and colourful curves:
40+
41+![A hand holding a glowing orb, underneath the text: "Urbit - Lunar Operations"](https://i.imgur.com/fRbFIpj.png)
42+
43+~litmus- also drew Urbitan for the release of OS1:
44+
45+![An cartoon-type female character holding an orb, standing in front of a fan of Urbit sigils](https://i.imgur.com/vGqVmNM.png)
46+
47+More of their work is available in the notebooks of the Internet Weirdness Research Unit.
48+
49+## ~minder-folden
50+
51+~minder- stylistically ranges from retrofuturistic memes to flat-out classic 50s retro:
52+
53+![An image of a meteor shaped like ~minder-folden's sigil in front of Mr. Clean, with the text "Soon it will all be clean"](https://pbs.twimg.com/media/Eggk0CGU8AAJC-W.jpg)
54+
55+![A Popular Science cover advertising "Video-Disc Players", with ~minder-folden's sigil present on a television](https://minderimages.nyc3.digitaloceanspaces.com/1ib61l8ugy451.jpg)
56+
57+More of ~minder-’s work is available in his The New Era notebook.
58+
59+## ~naltyc-wornes
60+
61+~naltyc-, & by extension ~dasfeb industries, produces content related to the exploration of Urbit on small & unique computers:
62+
63+![An image of five astronauts wearing Urbit badges strapped into a spaceship cockpit, with the ~dasfeb logo & a Raspberry Pi on the wall behind them](https://pbs.twimg.com/media/EkiyfGbVgAAp8wm.jpg)
64+
65+![An image of a large, early computer control panel with the ~dasfeb sigil on the upper wall and a number of planet sigils on display readouts](https://pbs.twimg.com/media/Ejap_knXgAARo38.png)
66+
67+More of their work is available in the smol computers group.
68+
69+## ~nartes-fasrum
70+
71+I use GIMP to edit images I pull off various social media platforms, and usually post the results on Twitter at [@nartesfasrum](https://twitter.com/nartesfasrum).
72+
73+![A set of four sigils arranged & coloured to appear as various natural forms, above the ~sorwet sigil & the text "help the environment and help yourself"](https://pbs.twimg.com/media/EjuuJjTXsAIcfU9.jpg)
74+
75+## ~norsyr-torryn
76+
77+No discussion of Urbit art would be complete without mentioning [~norsyr-'s Canvas app](https://github.com/yosoyubik/canvas), which won first place in the [Hackathon 2020](https://urbit.org/blog/hackathon-results/) event.
78+
79+![A demo image of the Canvas app, with various drawn characters](https://i.imgur.com/zpm3dYX.png)
80+
81+## ~radbur-sivmus
82+
83+~radbur- writes poetry on a range of subjects, one of which could be Urbit. Interpretation of ["A Weaver's Regard"](https://t.fust.us/writing/poetry/weavers-regard) and ["Internet Absurdities"](https://t.fust.us/writing/poetry/internet-absurdities) is left as an exercise to the reader.
84+
85+## ~sitful-hatred
86+
87+~sitful- has a Martian Meme Depository chat in the Networked Subject group, which catalogs a number of the Urbit memes that have been created so far.
88+
89+![An image of a Connect-Four type game box, edited to read “Connect ~zod: The Classic Network Connectivity Game](https://i.postimg.cc/d1yH7PHL/connect.png)
90+
91+## ~tocrex-holpen
92+
93+~tocrex- has been drawing the galaxies of Urbit, and uploading results to Twitter at [@tocrexholpen](https://twitter.com/tocrexholpen). Each galaxy has a unique design and outfit, with the galactic sigil proudly displayed as its face.
94+
95+![An image of the ~feb galaxy wearing elaborately embossed armor.](https://pbs.twimg.com/media/ENeLOb4WkAApDu2.jpg)
96+
97+## Landscape
98+
99+Something that's become quickly evident with the addition of background images to Landscape is that people love to customize their ship's appearance and make it feel more like home. To close things out, we're providing a pair of backgrounds — one darker, one lighter — for use on your ship (or your desktop, should you so desire).
100+
101+![A moody Martian city](https://i.imgur.com/7Ot9Hcu.jpg)
102+
103+![A bright outing in a young ship](https://i.imgur.com/wFKt2EW.jpg)
content/blog/after-machine-war.mdnew file+40
@@ -0,0 +1,40 @@
1++++
2+title = "After the Machine War"
3+description = "The date is January 1, 2050. The place, New York City. The vibe...subdued."
4+date = "2021-03-14"
5+
6+[extra]
7+author = "Simon Kovacs"
8+ship = "~bacbec-lormur"
9+image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/berlin-wall.jpeg"
10++++
11+
12+![berlin-wall](https://storage.googleapis.com/media.urbit.org/site/posts/essays/berlin-wall.jpeg)
13+
14+> The following fictional passage, from a book being written in an Urbit Group called “the Aleph,” sketches out a dismal future for the human race. As an item of speculative fiction, the piece is not what one might call original. Anyone could have come up with these ideas. In fact, several already have. The Matrix is an obvious antecedent. Vonnegut isn’t far behind either. And the treacly humanism lodged beneath the bitter humor resembles nothing so much as the work of that beau monde satirist, George Saunders.
15+>
16+> Really the only notable thing about it is that it was written on Urbit. And that, perhaps, has made all the difference.
17+>
18+> It’s easy to be pessimistic about the future. Intellectuals, especially, are drawn to pessimism, because pessimism (falsely) implies a greater wealth of knowledge about the ways of the world. But one thing the pessimist never sees coming is a turn for the better. To wit, the future described in the below excerpt doesn’t have to take place. And Urbit is one piece of evidence for the claim that it will not.
19+>
20+> The philosopher-cum-internet comedian Slavoj Zizek likes to point out that no one was really expecting the Soviet Union to collapse in 1989. In fact, the average Soviet dissident wasn’t even gunning for it. He was haggling over small reforms, pushing to get the less corrupt politicians to the top, just going about his day eating or opening a window or walking dully along. Then, kaboom. Collapse. No more USSR.
21+>
22+> Then as now, the unexpected is more likely to occur than most would believe. One thing is not only possible, but an established fact: A brand new digital infrastructure is slowly, quietly being built. While U.S. political parties haggle over $1,400 disbursements for citizens, the rules of global finance are being re-written in code. While pundits debate the merits of Dr. Seuss’s lesser known titles, a global shift away from traditional publishing is gaining steam. And while users and social apps themselves pop up and down like whack-a-mole, folks are putting down roots with permanent peer-to-peer digital identities. If you’re anything like an optimist, you’ll probably want to get on Urbit ASAP and put down your own.
23+
24+The date is January 1, 2050. The place, New York City. The vibe...subdued. Back in 2020, you made a note to yourself to take stock of the world around you here at the half-century mark. And now the time has come. What do you find? The air quality is a bit worse, the bad parts of town are a bit more dilapidated, the Knicks are still terrible—all in all, from the outside at least, not much has changed from 30 years ago. Today you wake up groggy on your self-adjusting Smart Bed (Smart Bed Never Sleeps), you make yourself a steaming pot of coffee (locally sourced, delivered within the half-hour by a drone, now that you’ve got Titicaca Prime), you shower and get ready for work.
25+
26+But what was that dream you had last night? Only the faintest traces of it remain. A luminous rainbow, a mountain landscape, a sense of profound inner peace, mixed with euphoria, mixed with...an intense desire to go out and buy some Health Morsels cereal?
27+
28+That’s odd. You’ve never even had Health Morsels. You open up your laptop, where you can view the activity of the iThink microchip that you got implanted in your cortex a few years ago. “Ads help Elysium provide you with free, quality sleep-monitoring. To disable ads, please upgrade to Elysium Premium.” That explains it. After all—and you pause for a moment over whether the forthcoming thought is yours or the iThink’s, before deciding that it’s much the same anyway—Health Morsels probably are delicious. And healthy, too.
29+
30+As usual, they’re setting something on fire outside your home. Normally you’d scroll back through your Squawker feed to see what it was all about, but today you’re late for work, and anyway you’re in a pleasant haze after the Health Morsels dream—no point ruining it by poring over the latest Squawker pile-on. You glance at the awning. Ah, the bodega. Toilet paper and Juul Pods are cheaper in bulk from Titicaca anyway.
31+
32+Another day at the office. You were never exactly passionate about content moderation, but hey, it keeps the lights on. (And since ConEd got absorbed by Titicaca, it’s been pretty important to have a Verified Income Stream.) It’s a normal day at work. Algorithms haven’t yet been able to filter out all Unverified Content—so it’s up to you the flag Unacceptable Violence, Disputed Claims, and Unfederated Currency transactions.
33+
34+Except after your pleasant dream, it all suddenly seems so drab. You start to wonder whether there was an error last night—maybe they turned the dream levels up too high. Something from your night-time vision just won’t leave your mind, like a film strip looping over and over. It’s that river beside a sloping field, like you used to swim in when you were a kid. You can almost feel the icy cold against your skin, the sticks and mud against the soles of your feet, and then there’s the ripe, marshy scent of the riverbed. Uh oh. You realize you’re close to danger levels. This isn’t where your head’s supposed to be at. Frantically you scroll through content, seeking to moderate it. A user threatening violence against Titicaca. A stream that violates DMCA. A highly dubious Squawker claim, with no support from experts. Flagged. Flagged. Flagged.
35+
36+Yet the river remains. You see it, you feel it, just as you feel the kiss of the sun on your shoulders, the breeze rustling through your damp hair.
37+
38+Now you know what’s coming. You brace for it and wait. Three. Two. One. ZAP. Your iThink produces an electric shock: plenty painful but not permanently damaging—at least that’s what the Verified studies show. The river recedes from your mind. Following the shock, your iThink, as versatile a little machine as ever was invented, delivers a few milligrams of both amphetamine and oxycodone, bringing on a wonderful feeling of simultaneous alertness and relaxation. You look up at your monitor. Content moderation doesn’t seem so bad, with the stimulant and the barbiturate swirling paradoxically through your system. It’s true what they say in the ads: iThink doesn’t just make you think better, it makes you feel better. You dive back into your content moderation with renewed verve, even flagging a couple completely innocent posts just out of surplus exuberance. So what if you hardly get outside at all these days, so what if you’ll never swim in that stupid river. The fastest electronics, the Your Health and Wellbeing tracked and adjusted by an intelligence far greater than that which you could ever hope to possess, a gizmo that gives a whole new meaning to the term neural net.
39+
40+2050 turned out to be a pretty good year after all.
content/blog/agency-daos.mdnew file+110
@@ -0,0 +1,110 @@
1++++
2+title = "The Dream of the Agency DAO"
3+date = "2022-11-04"
4+description = "As creative studios and agencies struggle for more creative freedom, DAOs and tokenization will surely take a more central role in the marketing and branding industries. Decentralization offers such entities benefits that could fundamentally reshape creatives’ relationships with clients—reducing layers of inefficiency and anti-creative incentives."
5+
6+[extra]
7+author = "Isaac Simpson"
8+ship = "~mogmet-tadnem"
9+image = "https://storage.googleapis.com/media.urbit.org/blog/skybanner.jpg"
10++++
11+
12+![Image](https://storage.googleapis.com/media.urbit.org/blog/skybanner.jpg)
13+
14+
15+Chris Callahan runs an independent brand strategy agency called [Visitor](https://visitor.agency/). Visitor wrote the line that [emblazoned](https://astra-mag.com/articles/my-weekend-with-the-martians/) the sky over the parking lot that housed Urbit Assembly. Its work focuses on Web3 blue chips and up-and-comers: dev marketing, notoriously one of the toughest niches in the branding world.
16+
17+“Devs are very sensitive to puffery and cringe,” says Callahan. “Traditional tactics like headlines and manifestos fall flat. Clarity and vision are much more important because they showcase the benefit as well as a long term potential for use.”
18+
19+Why? Because developers eschew sales. If something is good, it will rise to the top without the help of annoying salespeople. The thing is, marketing-world creatives usually agree—we’re just bogged down by salespeople of our own. So we, like devs, yearn for the day when decentralization will save us from the social climbers and “connectors” that suck up all the oxygen.
20+
21+Enter the Agency DAO. The idea—a creative agency that solicits work, receives clients, hires creatives, and makes decisions all on the blockchain—is oft-discussed because it appeals to the crunchy, anti-establishment vibe at the core of every major ad agency. A trustless, leaderless creative community where everyone has equal voice and the best creative rises naturally to the top? The dream of the ‘90s come true!
22+
23+Unfortunately, decentralization in the ad world currently occupies much more podcast time than reality.
24+
25+## Creative by Committee
26+
27+But there are some actual attempts at making the Agency DAO a reality. Koto, a top creative agency known for creating the AirBNB brand, tried it with Web3 brand Polkadot. [It pit two pitches against each other to determine the future direction of the Polkadot brand by vote](https://vote.polkadot.network/). It used a quadratic voting via Snapshot to deliver the will of the Polkadot network to four “multisig curators” who executed the vote on chain.
28+
29+While the experiment worked, it also revealed the shortcomings of the blockchain’s ability to guide creative decisionmaking.
30+
31+“To organize Polkadot token holders who wanted to participate and create the voting parameters took very long,” says Callahan. “To have the wisdom of crowds decide on two design elements was an exemplary concept for Polkadot to own. The question is, did it push the work? Or was its value in consensus alone?”
32+
33+Quadratic voting is cool, but the creative process is long and complicated. Stakeholders chose between option A and option B. At the end of the day, that doesn’t feel like a significant innovation, especially if the vote isn’t even actually happening on chain. Rebranding sprints typically take around 3 months. This process took 11. Sure, it was a good way for Koto to play ball, but it wasn’t much more than that.
34+
35+Agency DAOs face the same central problem as ordinary DAOs, which can be summed up thusly: every decentralizing force is too costly, and every cost compromise moves the system back towards traditional hierarchies. The nature of creative work even further stymies the theoretical Agency DAO. Creative products almost always suffer when anti-hierarchical principles are put in place. As David Ogivly famously said,
36+
37+_“Some agencies pander to the craze for doing everything in committee. They boast about ‘team-work’ and decry the role of the individual. But no team can write an advertisement, and I doubt whether there is a single agency of any consequence which is not the lengthened shadow of one man.”_
38+
39+So this leaves us with the question of how exactly the DAO model can help creative agencies, and what such an organization might look like, and how Urbit can help. There are roughly three paths: 1) Project Bountification 2) Talent Retention 3) Idea Valuation.
40+
41+## Project Bountification
42+
43+In the Mad Men era, a few Agencies of Record (AORs) dominated the advertising world. These massive whales took every cent of a given big brand’s yearly advertising budget and charged a simple 15% premium on all media (e.g. radio time, TV time) purchased. A very simple and very profitable system, [now long gone](https://www.genedelibero.com/the-agency-of-record-the-shift-is-on-to-specialized-agencies/).
44+
45+Today, big brands typically have many agencies—sometimes hundreds—each with a different specialty, and each fighting for their own share of the budget. I’ve been in rooms with representatives from no less than 10 agencies—digital, DEI, experiential, CSR, influencer, etc—all pitching ideas for the same holiday campaign, and all surely billing upwards of $100/hour per person to do so.
46+
47+This sounds nice for agencies, but actually it isn’t—instead of focusing on the creative work, they must dedicate their energy towards constantly re-pitching themselves to the client and fighting with procurement people on rates. The managerial class types who control the budgets care a lot less about the quality of the creative than whether you remembered their dog’s birthday.
48+
49+Crypto could provide a solution to modern agencies’ woes by creating a flatter system for project acquisition; adopting the sort of decentralized bounty system some devs already use for Web3 projects.
50+
51+“Bounties are great,” says Callahan. “Big agency players should popularize them. I feel like if there's a way to do an on-chain bounty with select members who either hold a special token that allows participation on key briefs, that would help a lot.”
52+
53+How would such a system work? First, a brand issues a bounty for a project for work it needs done. Luckily, this basically already happens in advertising, it’s called a request for proposal, or RFP. The only difference here is instead of RFP acquisition and response being 90% schmooze-fest and 10% creativity/pitching prowess, it’s a lot more like what you’ve seen on Mad Men: the client’s RFP passes trustlessly to the bold creatives who spend many drunk, sleepless nights coming up with genius ways to knock their socks off.
54+
55+“A brand issues a bounty for a stunt activation that, for example, educates the world on the psychological benefits of calm computing,” Callahan explains. “The members of Agency DAO approve it, and create their own bounty for creatives inside the DAO. Bounties burn after 10 days. Ideas submitted and sent to client in the manner set by DAO.”
56+
57+Once the job is awarded, the chosen agency will continue this pattern, effectively removing the “account guy” layer—the sales-y middle people abhorred by both creatives and devs alike—and returning more focus to creativity.
58+
59+## Talent Retention
60+
61+“Professional creative” industries, e.g. marketing, branding, etc, suffer from turnover rates orders of magnitude higher than the industries they serve. Being a creative is both kind of awesome, because a new gig is never too far away, and also scary, your current gig reliant on the slightest whims of the client.
62+
63+This means that the market for creative talent in the form of copywriters, designers, art directors, animators, producers, editors, etc, is always choppy and competitive. Staffing sucks—it’s difficult to evaluate the quality of someone’s work until you’re actually working with them, because creatives stuff their portfolios with successful projects they’ve barely touched. Beyond that, now bloated Web2 lowballers like Fiverr and Upwork bottom out the market with garbage time labor that even the biggest brands still somehow fall for. Another great opportunity for Web3 disruption.
64+
65+The Agency DAO model provides permanence. Currently, some independent agencies offer equity packages that take a long time to vest, and are only ever worth anything if the agency sells. Owning fungible tokens from day one is a much better way to incentivize both work quality and retention.
66+
67+DAOs also offer flatter and more collaborative atmospheres, which creatives at least ostensibly want.
68+
69+“There’s total transparency of who works on what. Better collaboration between members, meaning happier, more fulfilled workers. Awards will be more meaningful and accurate,” says Callahan. “Plus, the value of your tokens naturally increases or decreases based on your performance. Just by getting hired at a successful DAO you can already be doing well.”
70+
71+Finally, a system that allows democratized voting on creative products, as opposed to traditional [Hype Dad aristocracies](https://thecarousel.substack.com/p/vibe-shift-to-destroy-marketing-world), could actually foster more Darwinistic environments where the best creative has a higher chance of rising to the top.
72+
73+“Eventually group preference will select one creative over others; causing repeat elections of the same member,” says Callahan. This could occur on both the agency level—removing the Hype Dad problem, e.g. lazy incumbents making lame decisions. “There's a sort of Darwinism that is created that can determine benefits or even redundancies for those not pulling their weight or who simply aren't as talented as others.”
74+
75+## Idea Valuation
76+
77+The creative industries are perhaps the only example of a field in which the artists retain no intellectual property right for their ideas. This is why advertising creatives make so much money—an advertiser can milk a good idea for decades and we’ll never see a dime.
78+
79+The tokenization inherent to the DAO model opens up several possibilities for valuing ideas in new ways that behave more like copyright.
80+
81+“The basic thought now is starting something I’m calling General Idea; pre-created, white label ideas based on research of real creative problems that need fixing,” says Callahan. “We NFT the ideas, sell them to clients. They make them or they resell that idea to other clients or agencies. That monetary markup value on the idea trickles down the original creator. More democratic way to share ideas and defend their ownership when they’ve been recorded on the blockchain.”
82+
83+This sort of blockchain-based soft copyright is one way to value an agency’s DAOs. Another, simpler way, is to sell NFTs or NFT-related independent creations of the agency itself. Art collective/creative agency [MSCHF](https://mschf.xyz/), for example, makes its money both via brand deals and also a la carte meme-to-merch drops. Agencies with a certain amount of clout could easily tokenize the clever side projects of its creatives—making it far less reliant on client deals and more able to capitalize on its creative prowess.
84+
85+“Pool Suite [another creative studio] does a great job of being a creative company that happens to make NFTs of music and general drops and stuff,” says Callahan. “They're a studio first and then a blockchain player after. I'd still consider them a ‘diet-DAO.’”
86+
87+[Édouard Urcades](https://fabled-faster.tlon.network/writing/stars) has designed interfaces for Tumblr and IBM, and currently serves as a design lead at Tlon. His project Structure is a “cork board” for creative projects on Urbit—sort of a “mercenary guild,” for UX/UI designers looking for work. Structure is run by a gnosis safe wallet operated by its 12 members. Beyond serving as a “soft on-ramp for Urbit-related design labor,” Ed plans to monetize Structure by selling Urbit merch designed in-house, both NFT and IRL.
88+
89+## How Urbit Can Help
90+
91+The three categories discussed above—project bountification, talent retention, idea valuation—present theoretical frameworks for the Agency DAO. However, the shortcomings of current DAO infrastructure and governance make them largely impossible. Enter Urbit.
92+
93+The creative industries rely almost entirely on reputation—so any Agency DAO without permanent pseudonymous ID is dead in the water.
94+
95+“Goodby Silverstein and Partners, for example, is widely regarded as one of the best ad agencies out there,” says Callahan. “When a big name in the creative industry goes to work there, the reputation of Goodby Silverstein increases.”
96+
97+Urbit IDs let you maintain your creative and working reputations while operating within a self-owned ecosystem that can’t be deleted. Beyond that, Urbit’s design-forward OS selects for self-expression in a way that no corporate-owned platform could.
98+
99+
100+“The sigil itself is its own design feature,” says Callahan.
101+
102+Simply put, running an Agency DAO on Discord and Google Docs would be fundamentally unserious. It’s one thing for a traditional agency to use Web2 products as _tools_ for its creatives. It’s quite another for Web2 products to be the only connection the agency has with its creatives outside of the blockchain.
103+
104+Recruitment, ideation, project sharing, and even simple chat aren’t possible on Web3 without something like Urbit to tie it all together. Sure, you could get a bunch of anonymous creatives together on a shared Figma, but there will be zero accountability and likely low participation. Whereas Urbit—particularly Holium’s forthcoming Realm—brings Urbit ID into a decentralized, permanent environment that connects members P2P, and allows on-chain transactions without leaving Urbit. All while maintaining permanent IDs.
105+
106+As creative studios and agencies struggle for more creative freedom, DAOs and tokenization will surely take a more central role in the marketing and branding industries. Decentralization offers such entities benefits that could fundamentally reshape creatives’ relationships with clients—reducing layers of inefficiency and anti-creative incentives. However, a decentralized ID layer like Urbit is needed before the Agency DAO can be practically attempted.
107+
108+–
109+
110+*Isaac Simpson is a Los Angeles based writer and the founder of the marketing agency [WILL](https://willtheagency.com/). You can read his work on his substack [The Carousel](https://thecarousel.substack.com/).*
content/blog/an-email.mdnew file+84
@@ -0,0 +1,84 @@
1++++
2+title = "An Email from the Archive"
3+description = "I found this email in my archives recently and thought it might be fun to share publicly."
4+date = "2020-11-29"
5+
6+[extra]
7+author = "Galen Wolfe-Pauly"
8+ship = "~ravmel-ropdyl"
9+image = "https://media.urbit.org/site/posts/essays/moon.jpg"
10++++
11+
12+![An email from the archive](https://media.urbit.org/site/posts/essays/moon.jpg)
13+
14+I found this email in my archives recently and thought it might be fun to share publicly.
15+
16+```
17+From: Galen Wolfe-Pauly <galen@tlon.io>
18+Date: Thu, Jul 2, 2020 at 9:50 AM
19+Subject: Continuing
20+To: XXXXXXXXXXXXX
21+```
22+
23+Here are a few things I was thinking about after we chatted. It may be that I'm just reiterating things I already said — but perhaps it's useful:
24+
25+1 -
26+
27+Our collective desire to depend on digital communication tools vastly exceeds what I would have ever guessed. Even if you somehow factor out what’s addictive about the platforms we use today: they serve a real need. The crux of the problem with our current platforms is that they don’t actually serve the need that we want them to serve. They’re not tools in the way we expect tools to be. For the most part, the platforms we depend on serve the needs of their shareholders or some graph or another that needs to go ‘up’, which makes them compromised in a very deep way.
28+
29+In the pre-digital world we enjoyed a few things about the way we communicated, collaborated and did business that are dwindling: simplicity, durability and ownership. I’ll try to give some straightforward examples of what I mean:
30+
31+A - When I talk to someone directly, I’m not worried that someone else is listening in. If they go tell someone else what I said to them, that’s something for us to work out between us — they’re not _always_ reporting our conversations back to a third party. The constraints of the interaction and the privacy implications are _simple_ — I don’t think about them at all. Good privacy guarantees flow from a strict focus on simplicity. When two people want to talk to each other: give them a secure channel to talk. Putting a centrally-controlled service between them is just an interim solution because no one could figure out a better way to do it.
32+
33+B - When I write something down on paper, or type into a typewriter, I have an intuitive sense of the durability of what I’ve made. I have notes on my shelf I took ten years ago. I don’t worry about them disappearing. This means I can have a very direct, high-resolution relationship with the medium. I can pour myself into my physically-written notes in a way I would never pour myself into a Google Doc. Our digital tools are deeply untrustworthy because we know they can disappear, that they won’t actually last forever.
34+
35+C - Around 2008 I started limiting myself to a few specific drawing and writing tools. I use them all the time and can actually refine my relationship to them since I know they’re not going to change out from under me. Perhaps at some point these pens wont be made anymore, but the ones I have are actually _mine_. Similarly, the things I make with them actually belong to me in a way that doesn’t require some ridiculous terms of service. A sense of ownership, when it comes to the medium of communication, determines our level of trust and commitment.
36+
37+Our digital tools have to achieve the same level of simplicity, durability and ownership that our pre-digital tools did. Until they do, we’re always going to be in conflict with them, full stop.
38+
39+The main thing is that exactly none of our present platform-centric world can survive when you see things this way. The digital world we live in is composed of an insanely complicated, ephemeral set of tools that distinctly _do not_ belong to the people that use them.
40+
41+We’re going to be in a constant struggle with technology until it conforms to these three very basic expectations. These are the expectations we try to get Urbit to fall in-line with, of course. Something else could also succeed by satisfying them. But I also don’t really see anything else, aside from Bitcoin and maybe Ethereum, falling in line with these core principles.
42+
43+So: while I wish that Urbit was more mature and ready to capture those that are being purged from mainstream social media, are bored with it or are frustrated with the constraints of ‘productivity software’ — I think this conflict is going to drag on until people realize that what we’re in conflict with is the structure of the software we use. Using software that’s managed by other people is always going to cause serious problems all the way up at the user level. For more speculation on how this might play out, watch Black Mirror.
44+
45+2 -
46+
47+(1) is, in a way, a long-winded way of saying that the state of the world hasn’t changed our direction all that much. In order for Urbit to be approachable to use, it has to be very nicely made and that takes time and iteration. As the system stabilizes, Urbit can evolve in a more traditional way: we, along with others in the ecosystem, release stuff, observe how people use it, and try to make it better. We’re at the point where we’re nearly ready to get into that feedback loop, and we very much need to get there. We’re close.
48+
49+Urbit is a distinctly different _kind_ of software than anything we have now. Your Urbit is something you actually own and can do whatever you want with: not unlike your furniture or your kitchen tools. An Urbit is a tool for individual, human-scale computing and our whole approach to designing and making things is completely different. Most computing is about industrial-scale computing: where the software system stores everyone’s data and is managed by the people who build it.
50+
51+Urbit is the opposite of industrial-scale. Urbit is much more like something that’s carefully crafted and delivered to you directly. This craftsman-like approach to building software really isn’t a part of most modern software engineering.
52+
53+When I think about this from the standpoint of the person using what we make, it’s especially important. Urbit should feel like something that’s purposefully made by hand — not something you picked off the shelf at Wal-Mart. Some of this ethos was present in the early PC movement, but it’s mostly lost today. The care and attention that goes into building the system is also exactly what we make money on. People pay us to own a piece of it, to use it. We’re incentivized to make nice things, in the Urbit model, and we take that responsibility seriously.
54+
55+3 -
56+
57+Networks are a really important social form that’s only just beginning to come into existence. A network is neither a state nor a company, but something in-between. Bitcoin is a network, Ethereum is network (but it’s still far too centralized). Urbit is a young network.
58+
59+(In my view, a real network is always decentralized. Centralized networks are basically just companies.)
60+
61+Urbit is controlled by the collective of people who use it — in varying degrees, of course. The main thing is that this collective is bound together only by private keys and a blockchain, not a set of legal documents. The agreements between everyone on the network are in some cases more formalized (in terms of ownership) and looser (in terms of content moderation) than what we’re used to in either a state controlled or company controlled model. This is a very unusual kind of institution.
62+
63+On a successful Urbit network, Facebook, Airtable, and Signal are just successful applications. You could probably build companies around them that ship software to Urbit — but they’re more like 5 - 10 people instead of thousands.
64+
65+Urbit doesn’t aim to eat away at the government per se. Instead, it’s an important communication tool for institutions of any scale to actually take control of their means of collaboration. The efficiency of inter-government communication and government to populace communication can clearly be improved by _a whole lot_.
66+
67+4 -
68+
69+The most important thing is that people can generate a vision of the future. This can only emerge from a small collective of motivated people. Our public life is overwhelmed by people shooting from the hip, aiming for likes.
70+
71+There are difficult, infrastructural problems _all over the place_ that desperately need the considerate attention of small groups of people. Urbit, as communication tooling, is aimed at improving the quality of the fabric that binds these groups together. Or, to put it another way, before you can solve any specific problem you have to improve the problem solving process overall. Everything is gated on solving the process.
72+
73+5 -
74+
75+Christopher Alexander is, indeed, probably the biggest influence on my thinking when it comes to paying close attention to making things that both generate a deep sense of connection and are shaped by the people who inhabit them.
76+
77+[http://en.bp.ntu.edu.tw/wp-content/uploads/2011/12/06-Alexander-A-city-is-not-a-tree.pdf](http://en.bp.ntu.edu.tw/wp-content/uploads/2011/12/06-Alexander-A-city-is-not-a-tree.pdf) is one of his early, well known essays that’s easy to find online. I think ‘The Nature of Order’ is the thing that had the biggest impact on me, but it’s harder to find. There’s probably a PDF floating around on the internet somewhere. It's also a beautiful (four volume) book. The first volume kind of nails it. This talk is also great: [https://twitter.com/urbit/status/1148030042846326784](https://twitter.com/urbit/status/1148030042846326784)
78+
79+The thing that comes to mind lately is Hejduk. He had passed away by the time I was at Cooper, but I feel like I was educated in the ghost of his work. This documentary gives a good impression of his thinking: [https://www.amazon.com/John-Hejduk-Builder-Worlds/dp/B07NKQ72C8](https://www.amazon.com/John-Hejduk-Builder-Worlds/dp/B07NKQ72C8)
80+
81+Hejduk was able to see that architecture isn’t about building buildings per se, but something else. That was always quite obvious to me.
82+
83+Talk soon!
84+G
content/blog/an-urbit-overview.mdnew file+215
@@ -0,0 +1,215 @@
1++++
2+title = "An Urbit Overview"
3+date = "2016-05-10"
4+description = "A high-level overview of Urbit."
5+aliases = [
6+ "/posts/essays/an-urbit-overview",
7+ "/posts/an-urbit-overview"
8+]
9+
10+[extra]
11+author = "Galen Wolfe-Pauly"
12+ship = "~ravmel-ropdyl"
13+image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/an-urbit-overview.jpg"
14++++
15+
16+![](https://storage.googleapis.com/media.urbit.org/site/posts/essays/an-urbit-overview.jpg)
17+
18+## What Urbit is
19+
20+Urbit is a virtual city of general-purpose personal servers.
21+
22+## Your old personal server
23+
24+What's a personal server? In a sense, you already have one. Your
25+personal server is the combination of all the cloud services you use
26+now.
27+
28+This "server" is a mess. It's broken into 17 different fragments
29+which are scattered all over the planet. You have no control at all
30+over any of the pieces. The more we depend on Web services, the more
31+we realize how unsustainable this situation is.
32+
33+Can you remember all the services you have accounts for? How about
34+the username and password for each? Some of them will let you pull
35+your data out somehow, some won't. Sometimes you can move your data
36+between them, sometimes you can't. But they're all good at
37+showing you ads.
38+
39+## Your new personal server
40+
41+Your urbit is your own general-purpose server. It holds your
42+data; runs your apps; wrangles your connected devices; and
43+defines your secure identity. If you still need your old
44+services, it drives them with APIs.
45+
46+Your urbit presents your whole digital life as a single web
47+service. And since it's yours, open source and patent-free, it
48+never shows you ads. Or loses your data. Or updates without
49+your consent.
50+
51+Technically, Urbit is a new kind of OS that has a precise formal
52+definition. (Urbit is actually a [single mathematical function](https://media.urbit.org/whitepaper.pdf).) One advantage of a math-based OS is that Urbit is perfectly
53+portable. It can't tell whether it's in a cloud data center or on
54+your home PC.
55+
56+Concerned about mass surveillance? Download your urbit and restart it
57+on your laptop, or move to a new host in Iceland. Urbit's formal
58+simplicity makes managing it as easy as managing an iPhone: all you
59+have to decide is what apps to add.
60+
61+Each urbit is a node on a global, encrypted P2P network. Your Urbit
62+name, a generated pseudonym like `~talsur-todres`, is also your
63+network address. Like Bitcoin, Urbit address space is a cryptographic
64+asset with a limited supply.
65+
66+By keeping addresses scarce, we make spam and abuse expensive. Urbit
67+is a "friendly network," like the Internet in 1986, where a stranger
68+is nice until proven nasty. As it matures, Urbit will grow into a
69+decentralized, self-governing virtual city both safe and free.
70+
71+## The Urbit future
72+
73+In an Urbit world, your data is no longer trapped in a jumble of
74+proprietary servers. Your urbit is a permanent, versioned, typed
75+archive the size of your digital life. Even before you move your data
76+from a Web service to a local Urbit app, your urbit can drive your
77+account with an API or scraper.
78+
79+And within Urbit, data is never locked inside apps. Imagine if you
80+could painlessly switch between Facebook and Google+, Asana and
81+Trello, Tumblr and WordPress. Not only does your urbit upgrade itself
82+and its apps automatically, you can "sidegrade" a running app to
83+another vendor without losing data.
84+
85+Your urbit is also your digital identity. Along with your data
86+lifestream of media, messages and documents, it has the keys and
87+tokens to manage all your legacy Web services. It holds the keys
88+for your cryptocurrency wallets, so it can buy and sell for you.
89+(With one personal server to secure, not 17 different accounts,
90+you actually have the bandwidth to take security seriously.)
91+
92+You still use network services. But instead of interacting with
93+the service provider's HTML UI, which phones home using
94+proprietary HTTP APIs, you interact with a third-party app on
95+your urbit, which talks to multiple service providers using
96+public, typed Urbit protocols. For example, your urbit runs a
97+single shopping app, which downloads catalogs and uploads orders.
98+This app is one store which sells everything in the world, with a
99+salesman who's 100% on your side and always has the best price.
100+Every computing experience is different when the UI is working
101+exclusively for the user.
102+
103+Finally, your urbit is the hub for your network of connected
104+devices. Your smart thermostat, your wristband, your phone and
105+tablet, all run satellite urbits which talk securely to your main
106+urbit in the cloud.
107+
108+## A chance for digital freedom
109+
110+The promise of the personal server isn't just convenience.
111+General-purpose computing is magic. This magic must be in the
112+hands of all, not just those who can master Unix. The computer
113+is a bicycle for the mind. It's an open vehicle for exploration
114+and discovery. It's not a way to optimize ad delivery.
115+
116+Urbit, as virtual city, is a platform that brings together all our
117+datastreams -- from emails to heartbeats -- in a way that we ourselves
118+control. Can we work together to match faces in photos, without
119+submitting to some panopticon in Mountain View? While the first step
120+in freedom is the right to be left alone, the second is the power to
121+form new intentional communities, to create and evolve a voluntary
122+definition of public space. We have no idea at all what people will
123+do with this power.
124+
125+General-purpose computing is digital freedom. And today, a cloud data
126+center is the technically optimal locus of computation. The cloud is
127+always on, always available, never loses data. Hosts are sometimes
128+attacked; but they never intentionally tamper with their virtual
129+computers. The cloud can never be secure against a global adversary;
130+but most people don't have a global adversary. A single portable
131+platform provides "herd immunity" for the few who do need direct
132+physical control over their main computers.
133+
134+Though even laptops are atrophying into mere browsers, mass-market,
135+general-purpose computing on the client side remains an endangered
136+species that must be protected. But on the server side, this species
137+has never even _existed_. There has never been anything like a
138+mass-market personal server. Why not?
139+
140+## Freedom is an engineering problem
141+
142+Urbit is not a difficult idea. Urbit is like a flying car: the idea
143+is not the hard part. Almost everyone we talk to about Urbit turns
144+out to have had pretty much the same idea themselves. The problem is
145+building it.
146+
147+A server is a computer. It's running some operating system. This OS
148+is a flavor of Unix. There are no alternatives. It's connected to
149+some network. This network is the Internet. It has no competitors.
150+You can have a personal server, if it's a Unix server on the Internet.
151+
152+Almost no one thinks being a Unix system administrator is fun. Not
153+even Unix system administrators think running an Internet server is
154+fun. So the personal Unix/Internet server is like the personal
155+bulldozer. This is not a consumer product. Any number of engineers
156+can't turn a bulldozer into a bicycle.
157+
158+How did we build the personal bulldozer? We didn't. We started
159+from scratch. (The people who built the first PCs didn't start
160+with a mainframe OS, either.) We created a new platform: Urbit.
161+
162+Urbit doesn't compete with Unix and the Internet. It's a new,
163+opaque layer on top of them. Your browser runs on a native OS,
164+but it doesn't give Web apps any way to talk to the native OS.
165+Urbit is like a browser for the server side: code within Urbit is
166+formally isolated from the platform it runs on top of.
167+
168+Your urbit is a Unix process, in a data center or your PC. It sends
169+UDP packets over the Internet. It can both load and serve web pages
170+over HTTP. Except for character sets and crypto, nothing in Urbit
171+reuses or depends on any 20th-century code.
172+
173+Urbit is a complete, clean-slate system software stack: a
174+non-lambda interpreter (Nock), a functional language (Hoon), and
175+an event-driven OS (Arvo), with its own encrypted protocol
176+(Ames), typed revision control (Clay), reactive web server (Eyre)
177+and functional build system (Ford). The full system, including
178+basic apps, is only 30,000 lines of Hoon.
179+
180+The first end-to-end prototype of Urbit took one engineer eleven
181+years. The current beta took three more years, with about three
182+engineers on average.
183+
184+How does it take 14 years to write 30,000 lines of code? The code
185+wasn't the hard part. The hard part was rewriting it until it was
186+right. We think we've solved all the real CS problems, and we're
187+certainly done changing major interfaces. But it will take more than
188+our small team to deliver a polished Urbit user experience that can
189+actually challenge modern web apps.
190+
191+## Where we are, what we're doing
192+
193+Urbit is in feature freeze. It's a minimum viable product in
194+early beta. It still needs quite a bit of fit-and-finish work.
195+We certainly don't recommend it for end users or consider it in
196+any way secure. But it's fun to play with, if you're a hacker.
197+
198+This summer, we're making the switch to an open and transparent
199+development and specification process. A system as unusual as
200+Urbit can't be invented in public. But it has to be finished and
201+maintained in public.
202+
203+Additionally, we're creating an open political and economic process,
204+with a small, fixed-price public presale of Urbit address space. Join
205+us and help make this future actually happen.
206+
207+To keep reading, learn more about [Urbit's address
208+space](/blog/the-urbit-address-space); share our vision of the Urbit user
209+experience, from the [top down](/blog/what-is-urbit-for) or the [bottom
210+up](/blog/magic); check out the [development roadmap](/blog/roadmap);
211+evaluate Urbit's [beliefs and principles](/blog/beliefs-and-principles) or its
212+[interim constitution](/blog/interim-constitution).
213+
214+(For technical readers, check out our [documentation](https://urbit.org/docs/) or
215+the [whitepaper](https://media.urbit.org/whitepaper.pdf)).
content/blog/announcing-urbit-grants.mdnew file+49
@@ -0,0 +1,49 @@
1++++
2+title = "Announcing: Urbit Grants Program"
3+date = "2019-08-05"
4+description = "Announcing Urbit Grants, a way to earn stars through contributing."
5+aliases = [
6+ "/posts/essays/announcing-urbit-grants",
7+ "/posts/announcing-urbit-grants"
8+]
9+
10+[extra]
11+author = "Robert Mariani"
12+ship = "~lodleb-ritrul"
13++++
14+
15+We’ve long been grateful for the hard work of our open-source community, so we’re pleased to announce Grants, a program that gives contributors the opportunity to be compensated for their efforts. It’s in beta right now at [grants.urbit.org](https://grants.urbit.org/).
16+
17+The Grants program will reward valuable contributions with Azimuth stars in one of three ways: Gifts, Bounties, and Proposals.
18+
19+### Gifts
20+
21+We’ve periodically announced gifts for important contributions to the project – like in [2018](https://urbit.org/posts/2018-2-17-update/) and [2019](https://urbit.org/posts/urbit-grants-and-mid-2019-gifts/) – but we wanted to make this more formal.
22+
23+Not everyone always works on structured projects, so the lack of formal criteria for receiving a gift is meant to reward contributors who work outside of the bounty and grant system.
24+
25+Going forward, gifts will be awarded semi-annually (every six months). They’ll retain the informal and arbitrary nature of the awards that came before: Tlon will determine who gets what. We’ll work hard to make sure these payouts are fair.
26+
27+To see the gifts that have been awarded so far, check out the [History section](https://grants.urbit.org/history) of the Grants website.
28+
29+### Bounties
30+
31+Bounties are discrete projects in search of a champion. Tlon will define a clear deliverable, and some number of stars as their reward. Larger bounties will often have their star reward spread across multiple milestones.
32+
33+Contributors can apply to claim a bounty by clicking the “Request to work on this” button. Once a contributor is selected to work on a bounty, nobody else will be able to apply.
34+
35+Bounties are listed in the [Bounties explorer](https://grants.urbit.org/rfws). Play around with the explorer by filtering bounties using the Tag and Category features.
36+
37+### Proposals
38+
39+Proposals are a way for contributors to pitch their own ideas, with a targeted number of stars. Proposals can be accepted, rejected, or accepted with changes. Unlike bounties, a proposal can only be completed by the individual or group who submitted it.
40+
41+Proposals don’t need to be fleshed out like a bounty does, at least not initially. Submit an idea and Tlon will work with you to refine it.
42+
43+You can see the list of accepted proposals in the [Proposals explorer](https://grants.urbit.org/proposals).
44+
45+### What can you do?
46+
47+[Sign up](https://grants.urbit.org/auth/sign-up) on our Grants website page, then set up your profile so we know who you are, linking your GitHub, Twitter, and your Azimuth point: reputation is a factor in determining eligibility for a grant.
48+
49+Also, check out the [Grants section](https://urbit.org/faq/#grants-1) of the new Urbit FAQ for more information.
content/blog/ares.mdnew file+51
@@ -0,0 +1,51 @@
1++++
2+title = "Ares"
3+date = "2023-06-26"
4+description = "A light technical description of Ares, the new Urbit runtime"
5+
6+[extra]
7+author = "Noah Kumin"
8+ship = "~librex-dozryc"
9+image = "https://storage.googleapis.com/media.urbit.org/blog/ares-header.png"
10++++
11+
12+![Image](https://storage.googleapis.com/media.urbit.org/blog/ares-header.png)
13+
14+## What is Ares?
15+
16+Ares is a new Urbit runtime that will be much faster and manage a much larger amount of data than previous versions of the runtime. Those new to Urbit commonly ask if they will be able to host photos and videos on their Urbit ships. Ares—a joint project from the Urbit Foundation, Tlon, and Zorp—sets the stage for us to be able to answer, simply, “Yes.” Ares is still a work in progress, but we expect to see the new binaries rolled out later this year. There are three components to the project. Let’s talk about them one by one.
17+
18+## 1. Code Generation
19+
20+Modern CPUs are extraordinarily fast. But until now your Urbit hasn’t been able to take full advantage of this fact. One way to conceptualize the problem is to imagine a train that is only able to go as fast as a track-worker can lay down track for it. In this analogy, your CPU is the train, and the track-worker is the Urbit runtime. The aim is to have large sections of track laid down ahead of time. Ares includes a codegen system that compiles Nock, Urbit’s assembly language, to machine code that the CPU can predict well.
21+
22+This system addresses what has until now been a problem: Nock is meant to invoke other code in a given Urbit computer’s “subject.” Or, in more common parlance, in the computer’s “state.” Your state changes with every new message your Urbit computer sends and receives, or with any new event in any app. That makes it hard to make the resulting machine code run fast, since the CPU needs to read from the subject while it’s running in order to figure out what machine code will be run next.
23+
24+The new code generation process in Ares solves this problem by using a system which the developers have called “subject knowledge analysis.” What does this mean? By analyzing how an Urbit subject might change over the course of a Nock computation, Ares will learn about the subject's tree shape and about its data dependencies (*i.e.*, the way that later parts of the computation depend on earlier parts of the computation). This allows those parts of the subject which are known at the time of compiling Nock to machine code to remain known at later points in the computation.
25+
26+To go back to our metaphor of train tracks, this is what allows the “track” to be laid down ahead of time. This set of known parts of the subject typically includes Nock formulas stored in [cores](https://developers.urbit.org/guides/core/hoon-school/F-cores#cores). This allows the resulting machine code to use direct jumps to perform Nock function calls. Without this “subject knowledge analysis,” the CPU would have had to perform an “indirect jump” by calculating the location to which a later instruction would jump. Now your computer’s CPU can jump directly to where it’s supposed to go.
27+
28+## 2. 2stackz Noun Allocator
29+
30+Ares will make use of what we’re calling the *2stackz noun allocator*. With the advent of Ares, your Urbit will be a virtual machine with two stacks and no heap. What does this mean? Traditionally, a program has a *stack* and a *heap*. The stack is a linear data structure within a program used for the program’s execution. The heap is a less structured region of memory that is used for storing large pieces of data or data that you want to keep around for a while without taking up space in the stack. However, the heap is slower, because its system for allocating memory is less orderly. (Imagine, say, trying to find a specific pair of socks in a heap of clothing.)
31+
32+Ares recognizes that because Nock is much more constrained than most languages, the Urbit runtime doesn’t actually need a heap. Instead you can take the function call stack and split it in two. The top of either stack can then be used as a little temporary heap. Whenever a function executes, you copy the data that gets returned from one stack to the other. And all the intermediate products that get created when running that function (*i.e.*, other functions that got called by the initial function) sit there as *garbage* (unwanted or unused data) in between the two stacks. But you don’t have to do the same sort of bookkeeping—tracking and updating these values—that you would have to do with a heap.
33+
34+Every piece of data in your Urbit computer is a noun. A noun is an atom (a positive integer or zero) or a cell (a pair of nouns). Before Ares, both allocating and freeing a noun in the Urbit runtime were processes that took a lot of time. (To *allocate* a noun is to put that noun in memory and to *free* it is to tell your urbit that you don’t need it any more.) Ares should make both of these processes much faster. This is good news because the Urbit runtime allocates nouns (particularly pairs of nouns, known as cells) like nobody’s business.
35+
36+## 3. Persistent Memory Arena
37+
38+Ares’s Persistent Memory Arena is for managing large amounts of data within your urbit in such a way that your urbit does not get slow. If you have terabytes of data within your Urbit, you can only have a very small subset of that within your hardware’s RAM at a given time. The rest of that data is going to have to live on disk—the section of your hardware that is more capacious but takes more time to access.
39+
40+To deal with this fact, your motherboard moves data back and forth between RAM and disk depending on what data needs to be accessed at a given time. This is known as *paging*, because it does so one *page* (usually four kilobytes) at a time. Traditionally operating systems will handle paging for you, but they do it in a generic way. The Persistent Memory Arena is designed specifically for managing Urbit's single-level store.
41+
42+A *single-level store* means that there’s no distinction in the operating system between data that lives in RAM and data that lives on disk. Instead of having two levels from which you can access data, you only have one, and the system itself manages which parts of the data are in RAM and which are in disk. The Persistent Memory Arena is an optimization for handling a large amount of data in a single level store. It is for nouns that persist between computations. Using the PMA, your urbit’s state can grow large without being hemmed in by the limitations of your hardware’s RAM.
43+
44+
45+## Updates and Links
46+
47+You can find the Ares GitHub repository [here](https://github.com/urbit/ares). The technical proposal is [here](https://github.com/urbit/ares/blob/status/docs/proposal/proposal-nock-performance.md). Check back at the Urbit Google Groups [listserv](https://groups.google.com/a/urbit.org/g/dev/), the [@zodisok](https://twitter.com/zodisok) Twitter account, and the Urbit Foundation [group](https://tlon.network/lure/~halbex-palheb/uf-public) for updates about the upcoming release.
48+
49+–
50+
51+*Noah Kumin is the founder and editor in chief of the [Mars Review of Books](https://marsreview.org/).*
content/blog/august-2022-grants-program.mdnew file+73
@@ -0,0 +1,73 @@
1++++
2+title = "August Grants Program Review"
3+date = "2022-08-30"
4+description = "The completion of the first cohort of Hoon School Live and the following App School Live program minted dozens of capable new Hoon developers. These developers are completing applications, closing out bounties, and putting together proposals at a rapid pace, with more to come as Assembly 2022 draws near."
5+[extra]
6+author = ""
7+ship = "~sarlev-sarsen"
8+image = "https://storage.googleapis.com/media.urbit.org/blog/b52.jpg"
9++++
10+
11+![Image](https://storage.googleapis.com/media.urbit.org/blog/b52.jpg)
12+
13+# Completed Grants
14+
15+Recently completed grant projects include Urbit micro-blogging, Hoon-native Discord bridging, Urbit’s first arcade-style game, Port application improvements, Ethereum bookkeeping and eth-provider infrastructure.
16+
17+* [Trill](https://urbit.org/applications/~sortug/trill) and sister application [Urbit Feed Aggregator](https://urbit.org/applications/~sortug/ufa) give you a way to escape from Twitter’s algorithms while still being able to share your shower thoughts with your followers.
18+* [Faux](https://urbit.org/applications/~midsum-salrux/faux) is a transformation of the python-based Urbit to Discord bridge, turning it into a Hoon native app and offering a front-end that takes you through the setup experience, letting you to bring your Discord friends a little taste of Urbit.
19+* [Slam](https://urbit.org/applications/~hanfel-dovned/slam), everyone’s favorite new arcade game, integrates with [Gora](https://urbit.org/applications/~dalten/gora) and [pals](https://urbit.org/applications/~paldev/pals), utilizing a mechanism whereby the number of gorae held by your pals will influence the way your game is played.
20+* The [Ethereum Provider](https://urbit.org/grants/eth-provider) grant gets the network a step closer to decentralized Ethereum access, particularly for those who don’t wish to rely on an infura node.
21+* A bounty for [Port Maintenance](https://urbit.org/grants/port-maintenance) delivered iterative improvements to the Port application for those who run their ships on a local machine.
22+* And Quartus delivered [Books](https://urbit.org/applications/~doller-doller-rabsef-bicrym/books), an Ethereum address and transaction manager for you to easily append notes and memos to your on chain transactions without having to rely on a third party (as a friendly reminder, [Urbit is not yet a secure environment so please be careful](https://twitter.com/pcmonk/status/1563634078779592709?s=20&t=FN7VVjMdjyIdukSvtg5_7g) what information you store on your ship).
23+
24+
25+# Proposals
26+
27+As the above grants wrap up, more grants are coming to life. Proposals are community generated and selected projects which offer contributors the space to build whatever tooling or applications they believe Urbit needs. Each of the following projects was funded in August:
28+
29+
30+
31+* [Herd](https://urbit.org/grants/herd) - Dependency management for Citadel
32+* [Full Stop](https://urbit.org/grants/full-stop) - A menstruation tracker for Urbit
33+* [Peat](https://urbit.org/grants/peat) - Urbit’s first backup utility
34+* [Quorum](https://urbit.org/grants/quorum) - A clone of stack exchange on Urbit
35+* [Gather](https://urbit.org/grants/gather) - an Urbit native meetup tool
36+* [Olif](https://urbit.org/grants/olif) - Olfactive rendering of Urbit address space
37+* [Urbit Interface Framework](https://urbit.org/grants/urbit-interface-framework) - Framework for alternative web browser interface
38+* [Whom](https://urbit.org/grants/whom) - A profile and contacts manager
39+
40+
41+# Apprenticeships
42+
43+Apprenticeships are also bringing opportunities for hands-on developer education and enabling seasoned contributors to share knowledge through real world projects. And contributors get to earn address space as they learn the stack and grow their network.
44+
45+Three new apprenticeships began in August:
46+
47+
48+
49+* [Loom Pointer Compression](https://urbit.org/grants/loom-pointer-compression) - Work to double the size of the loom
50+* [Build a UI for Volt](https://urbit.org/grants/volt-ui) - An interface for %volt, Urbit’s lightning wallet agent
51+* [Vere Profiling](https://urbit.org/grants/profiling) - Uncovering and visualized performance bottlenecks in the runtime
52+
53+
54+# Bounties
55+
56+August also brings with it the assignment of previously open bounties to developers looking to grow their portfolio of Urbit projects. Many of bounties that found contributors are a part of [Holium’s App Dev Summer](https://www.youtube.com/watch?v=dHyzH09QaZQ), and are slated to be completed by Assembly in Miami:
57+
58+* [Minesweeper](https://urbit.org/grants/minesweeper) - A classic desktop game, now natively in hoon
59+* [Abacus](https://urbit.org/grants/abacus) - A basic calculator app with the ability to convert units
60+* [Chronicle](https://urbit.org/grants/chronicle) - A news app that links articles from group channels
61+* [Lexicon](https://urbit.org/grants/lexicon) - A simple dictionary app with custom definitions for a group
62+* [Chess Improvements](https://urbit.org/grants/chess-bounty) - An enhanced chess experience with timing and ELO servers
63+
64+Even with all the claimed bounties, there remain a variety of projects which currently seek developers. Check out the following grants and apply to those that fit your skills and interests:
65+
66+
67+* [Trove](https://urbit.org/grants/trove) - A group file sharing tool
68+* [Urbit Native Ethereum wallet](https://urbit.org/grants/eth-wallet) - An ETH wallet for Urbit maxis
69+* [UrbitSwap](https://urbit.org/grants/urbitswap) - An Urbit-hosted Uniswap instance
70+* [Tune slaw/scot jets](https://urbit.org/grants/slaw-scot-jets) - Tuning jets for better performance
71+* [New Mars Persistent Memory](https://urbit.org/grants/persistent-memory) - Development of a persistent memory arena
72+
73+Have a project that you want to help fund and think would make a good bounty? Want to propose a project about which you are passionate? Looking for a mentor to better learn a part of the Urbit ecosystem? For more information on current projects and opportunities from the Urbit Foundation’s grant program, visit [urbit.org/grants](/grants) or reach out to ~sarlev-sarsen to get involved.
content/blog/azimuth-as-multipass.mdnew file+34
@@ -0,0 +1,34 @@
1++++
2+title = "Azimuth as Multipass"
3+date = "2019-05-15"
4+description = "What if everyone had a single 'civilizational key'?"
5+aliases = [
6+ "/posts/essays/azimuth-as-multipass/",
7+ "/posts/azimuth-as-multipass"
8+]
9+
10+[extra]
11+author = "Galen Wolfe-Pauly"
12+ship = "~ravmel-ropdyl"
13+image = "https://media.urbit.org/site/posts/essays/azimuth-as-multipass-1.png"
14++++
15+
16+![](https://media.urbit.org/site/posts/essays/azimuth-as-multipass-1.png)
17+
18+Why can’t I just walk up to a door and have it open for me? Why can’t I simply arrive at a restaurant and have them know I’m there? Shouldn’t I be able to buy a ticket to a show with my Multipass then scan it at the entrance and use it to buy drinks?
19+
20+Why should I have to log in with MEGACORP? Today, in most cases, it’s a different MEGACORP for every single context. It’s a MEGAMESS.
21+
22+Why not just use one? Forget about how we get there for a moment: just imagine how simple it could be.
23+
24+An Azimuth point is an identity and a wallet. Both a driver’s license and a credit card. Identity and money. Think about it as a ‘civilizational key’ for a new society. Concretely, it’s nice to imagine it as a physical object. A slick, card sized object with an e-ink screen. You can tap it to pay, tap it to enter, and plug it into a computer to boot your Arvo OS.
25+
26+Worried about losing it? Just remember your ticket. If you use our wallet system, all you need to remember is something like `~ravmel-ropdyl` and `~habpem-sondem-pidbyt-solbyn`. A point and a ticket. That’s it.
27+
28+Woke up in the desert, no idea how you got there, but can still remember your point and ticket? Great! Just get to an internet connection and re-ticket – you’ll be fine. Although probably dehydrated.
29+
30+If you’re someone who’s worried about getting kidnapped, just use a child identity. Your Azimuth planet has ~4B of them, so you can always invalidate one if you lose it.
31+
32+Perhaps part of how we ended up in the world we’re in is that we didn’t have something like Azimuth to begin with. Today, it’s backwards: everyone has an address on the network, but no one has an identity.
33+
34+We think everyone needs an identity that can hold money and have packets routed to it. Start there, and it’s quite fun to imagine where you end up. A civilized digital society might even be possible after all.
content/blog/azimuth-is-on-chain.mdnew file+107
@@ -0,0 +1,107 @@
1++++
2+title = "Azimuth is On-Chain"
3+date = "2019-01-13"
4+description = "The Urbit address space, now called Azimuth, is on the blockchain. And too many other things to fit into a single post."
5+aliases = [
6+ "/posts/essays/azimuth-is-on-chain",
7+ "/posts/azimuth-is-on-chain"
8+]
9+
10+[extra]
11+author = "Galen Wolfe-Pauly"
12+ship = "~ravmel-ropdyl"
13++++
14+
15+![](https://media.urbit.org/site/arvo-4.svg)
16+
17+The Urbit address space is now live on the Ethereum blockchain. We’re calling the PKI ‘Azimuth’ and you can find it at [`0x223c067f8cf28ae173ee5cafea60ca44c335fecb`](https://etherscan.io/address/0x223c067f8cf28ae173ee5cafea60ca44c335fecb) or [`azimuth.eth`](https://etherscan.io/address/azimuth.eth). Owners of Azimuth ‘points’ (galaxies, stars or planets) can use [Bridge](https://github.com/urbit/bridge/releases) to manage them and view their balance now.
18+
19+Sometime in the next few days, owners of Azimuth points will be able to boot Arvo, the Urbit OS, from their Azimuth point and request access to one of our 'cities': private communities for chat and discussion. These new cities use Landscape, a brand new UI for using Urbit in the browser.
20+
21+This means you can boot a deterministic OS from an identity you own, join a totally independent, decentralized and self-governing network and run a clean, simple UI. Pretty exciting. Is it ready for ordinary users? Definitely not.
22+
23+Since 2013, you've been able to boot an Urbit and join our test network. And, since 2013, we've always had our sights set on building a personal server that can both last 100 years and be delightful to use. Urbit isn't meant just to be as good as the MEGACORP software we use today. It's meant to be much, much better.
24+
25+But Urbit is not a 'product' in the conventional sense. Urbit is a public thing. It's meant to belong to everyone. For the past six years, much of our work was research and design work. Which means lots of weird ideas thrown away, and others rewritten or redesigned many times over. Our work has always been open source, but we tend to be pretty quiet about it.
26+
27+With Azimuth on the blockchain, it's time for us to start engaging with the world more directly.
28+
29+We aren't calling this a launch. There's no keynote. There's no dancing on stage. I mean, it's 2019. You must be pretty sick of being marketed to. We'll try to stick to the specifics here. What's new, what we've been up to and what works. There's too much to fit into a single post, so we'll keep it pretty light for now. Each of these sections will probably get its own post in the near future.
30+
31+> Note: As of `~2019.1.14` we're in the process of rebooting the Arvo network. We expect it to be back online before the end of the week. We'll update this post and [tweet](https://twitter.com/urbit) when the network is online and stable.
32+
33+## Rethinking the stack
34+
35+We've started to talk about Urbit as a stack of three parts: Azimuth, the address space and identity layer on Ethereum; Arvo, the OS and overlay network; and Aegean, a pattern for building decentralized communities on the Arvo network.
36+
37+We tried to capture this separation in [the primer](/primer), a new overview of Urbit. Explaining Urbit has always been challenging. A monolithic project that is OS, network, language, VM and UI barely makes sense. Separating the layers helps, we think.
38+
39+Let's step through them to see what's new.
40+
41+## Azimuth
42+
43+![](https://media.urbit.org/site/bridge-0.png)
44+
45+As a quick refresher: Urbit addresses, now called Azimuth 'points', are short names like `~diblun-tidduc`. You own your Azimuth point with a private key and can use it as a routable network address on the Arvo network. You can read more about Azimuth in [the primer](/primer#what-azimuth-is). If you're curious who owns all this address space, you can find that [in there too](/primer#azimuth-distribution).
46+
47+In late 2017 we decided to migrate the yet-to-be-named Azimuth to a system of Ethereum contracts. After a year of coding, testing, auditing and migrating — they're now fully deployed to the Ethereum mainnet.
48+
49+Azimuth is basically two parts, a database of who owns which points, and a set of rules about what points and their owners can do. That set of rules is called Ecliptic, and can be found at [`0x6ac07b7c4601b5ce11de8dfe6335b871c7c4dd4d`](https://etherscan.io/address/0x6ac07b7c4601b5ce11de8dfe6335b871c7c4dd4d) or [`ecliptic.eth`](https://etherscan.io/address/ecliptic.eth). The top-level Azimuth points, the galaxies, can vote on upgrades to the Ecliptic contract, but they can't edit the database of who owns what.
50+
51+The ownership database contract is called Azimuth, which you can find at [`0x223c067f8cf28ae173ee5cafea60ca44c335fecb`](https://etherscan.io/address/0x223c067f8cf28ae173ee5cafea60ca44c335fecb) or [`azimuth.eth`](https://etherscan.io/address/azimuth.eth). For those of you who own address space, you can use the `getOwnedPoints` function in the 'Read Contract' tab to check your balance. The function returns the number (not the phonemic string like `~ravmel-ropdyl`) of your points. Each Azimuth point is an ERC-721, non-fungible piece of digital property.
52+
53+To manage your points, we built [Bridge](https://github.com/urbit/bridge/releases), a completely custom interface for interacting with our Solidity contracts. Interface quality is really important to us, and we couldn't find anything in the 'crypto' world that met our standards. Bridge is good, but crypto UX is a hard problem. We've already got some ideas for improvements.
54+
55+If you're curious, you can find the source for the contracts in the [`urbit/azimuth`](https://github.com/urbit/azimuth) repo. The Bridge source is in the [`urbit/bridge`](https://github.com/urbit/bridge) repo.
56+
57+We had the source for our contracts audited by Open Zeppelin, Blockchain at Berkeley and Bloctrax. Did we miss something? We sure hope not — but we'd happily compensate anyone who can find bugs. Please reach out to security@urbit.org if you find something of concern. We'd be happy to hear from you.
58+
59+![](https://media.urbit.org/site/sigils.svg)
60+
61+Azimuth names have always had a pronunciation system. `~ronryd-nidseg` is 13,695,781, for example. Now, they also have a visual system. We call these strange crests from another planet 'sigils', and you'll notice them used throughout all our new interfaces. You can find the source in the [`urbit/sigil-js`](https://github.com/urbit/sigil-js) repository. Building these was a lot of fun — we'll save the details for a future post.
62+
63+So, how do you get an Azimuth point? We've left that question unanswered intentionally. Azimuth points are meant to be like digital land, not currency. They should change hands slowly. In order to get an Azimuth point, you'll need to find someone who already has one and is willing to part with it.
64+
65+## Arvo
66+
67+![](https://media.urbit.org/site/fast-lux-3.gif)
68+
69+Arvo boots from Ethereum, is no longer embarrassingly slow, and has a brand new build system. [Our documentation](https://urbit.org/docs/learn/arvo/hoon) has also improved quite a lot. Hoon, Arvo's programming language, has had a lot of work done to its type system and compiler. We built new tooling for generating static sites (you're probably reading this on one right now) that are much, much faster and easier to use.
70+
71+It's tough to talk about the progress we've made on Arvo without writing a long technical post. We'll save that for later. In a way, what's remarkable about Arvo is that it has become _less_ remarkable. It's more stable, faster, and the code quality has improved.
72+
73+There's plenty of work to do, though. Should you be building on top of Arvo? Probably not yet. The kernel and kernel modules are really where the work still lies. We build things on top of Arvo, and in doing so it's pretty clear that the system can be better. Clay (the filesystem) and Gall (the application model) are due for a rewrite. A complete rewrite of the web server, Eyre is almost finished.
74+
75+## Aegean
76+
77+![](https://media.urbit.org/site/landscape-inbox.png)
78+
79+Aegean is a pattern for building 'cities': groups of people running the same 'agent' on their Arvo servers. Agents aren't just 'apps' or programs. An agent rolls together the tools that a community needs. Today, our companies, communities, cults, cliques all have to duct tape together separate MEGACORP apps and services to compute together.
80+
81+Aegean reverses this pattern. A community on Arvo is a city: just a bunch of people running the same agent. Each city is in control of its own codebase: the interface, application code _and_ data storage. This means a community can have complete agency over how to compute together.
82+
83+Aegean cities can be completely different without impacting one another at all. Cities share the neutral infrastructure of Arvo and Azimuth — but they may never even know others exist. An archipelago of hypercultures.
84+
85+It's important to note: the pattern of these cities is _not_ the pattern of Azimuth. The network hierarchy should impact the society of Urbit as much as the electrical grid impacts the life of the street in Manhattan. It matters when the power goes out — but most of the time groups form and dissipate continuously.
86+
87+Before we can let the ocean of cities grow we have to homestead a few of our own.
88+
89+Our first agent is called [Landscape](https://github.com/urbit/urbit/tree/master/pkg/interface), an agent for chat and longform discussion. We are using Landscape to run a few experimental cities over the next month or so. If you have an Azimuth point, you'll need to [request access](mailto:support@urbit.org) to join.
90+
91+Anyone can create their own city, of course. The source is open. But we're not going to encourage you to just yet. Feel free to explore, but also be patient. We've got a lot planned around this. If Azimuth is done and Arvo is young, Aegean is just being born.
92+
93+## Tlon
94+
95+![](https://media.urbit.org/site/office-1.jpg)
96+
97+So who is behind all of this? A team of collaborators and contributors. Many of us work at [Tlon](https://tlon.io) — the company we started in 2013 to advance Urbit platform development. Tlon has attracted an incredible group of smart, talented people who want the world to be able to own and control their computers. I'm proud to work alongside them.
98+
99+One important omission on `tlon.io` is Curtis. As of today, he's no longer working on Urbit. [His own words](/posts/essays/a-founders-farewell) are the best way to understand his thinking. It's an achievement for the team, I think, that he can depart with confidence.
100+
101+One major reason for that confidence is that Erik and Anthony have now become COO and CPO respectively. Having thoughtful, organized people leading the project is a huge benefit to the whole team. I'm very glad to have them on board.
102+
103+## Looking ahead
104+
105+I certainly forgot at least a thing or two. We'll dive in to more detail in the coming weeks.
106+
107+There's a lot for you to explore. Have fun!
content/blog/azimuth-security-bounty-program.mdnew file+40
@@ -0,0 +1,40 @@
1++++
2+title = "Azimuth Security Bounty Program"
3+date = "2019-07-21"
4+description = "Inviting you (and your friends) to help us make Azimuth as secure as possible."
5+aliases = [
6+ "/posts/essays/azimuth-security-bounty-program",
7+ "/posts/azimuth-security-bounty-program"
8+]
9+
10+[extra]
11+author = "Anthony Arroyo"
12+ship = "~poldec-tonteg"
13+image = "https://media.urbit.org/site/posts/essays/azimuth-security-bounty-program-1.jpg"
14++++
15+
16+![](https://media.urbit.org/site/posts/essays/azimuth-security-bounty-program-1.jpg)
17+
18+Since launching [Azimuth](https://urbit.org/posts/azimuth-is-on-chain/), we’ve been running a private bounty program with [HackerOne](https://hackerone.com/). We’re now taking the program public and inviting you (and your friends) to help us make Azimuth as secure as possible.
19+
20+[Go here](https://hackerone.com/tlon) to see the live program on HackerOne.
21+
22+## What is Azimuth again?
23+
24+Azimuth is [the Urbit public key infrastructure](https://urbit.org/posts/azimuth-is-on-chain/). It’s a set of Ethereum smart contracts that allow for cryptographic ownership and management of Urbit identities. It also provides a governance mechanism whereby galaxy owners are able to propose and vote on improvements.
25+
26+People already [use Azimuth](https://github.com/urbit/bridge) to boot Arvo ships, spawn stars and planets for others and transfer points. But Azimuth is a general identity system, with great potential to be used beyond Arvo: there are primitives for reputation, payments and securing communication channels.
27+
28+## Security program details
29+
30+We had the Azimuth contracts audited by [Open Zeppelin](https://openzeppelin.org/), [Blockchain at Berkeley](https://blockchain.berkeley.edu/) and [Bloctrax](https://www.bloctrax.com/), but we don’t want to take any chances. We’re hoping that the HackerOne program will help us get more eyes on the contracts, identify vulnerabilities and get out in front of any problems. You can find more information about the program at [our page](https://hackerone.com/tlon) on HackerOne.
31+
32+We’re interested in any vulnerability in the Azimuth contracts that would allow an attacker to either seize other user’s points, impersonate points or that would result in the platform becoming unusable.
33+
34+The program page has links and instructions on how to set up a development version of Bridge and point it at either the Ropsten deployment of the contracts or at a local network to play with the contracts and look for vulnerabilities.
35+
36+## Arvo is out of scope for now
37+
38+We’re intentionally focusing our security efforts on Azimuth for now. Since Azimuth serves as our PKI layer, it’s the most crucial for the time being: it’s the source of truth for who owns what. We don’t want to have even a shred of a doubt that these cryptographic properties are secure.
39+
40+Of course, we’re working toward a future where you have a computer connected to this Azimuth point, and the computer has to be as secure as its identity. To achieve this, we have some more hard work to do on Arvo and our interpreter, Vere. When the time comes, we’ll also reach out for help testing vulnerabilities throughout the entire stack.
content/blog/beliefs-and-principles.mdnew file+134
@@ -0,0 +1,134 @@
1++++
2+title = "Beliefs and Principles Guiding the Urbit Project"
3+date = "2016-05-10"
4+description = "We believe."
5+aliases = [
6+ "/posts/essays/beliefs-and-principles",
7+ "/posts/beliefs-and-principles",
8+ "/posts/principles"
9+]
10+
11+[extra]
12+author = "Curtis Yarvin + Galen Wolfe-Pauly"
13+ship = "~sorreg-namtyv + ~ravmel-ropdyl"
14+image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/beliefs-and-principles.jpg"
15++++
16+
17+![](https://storage.googleapis.com/media.urbit.org/site/posts/essays/beliefs-and-principles.jpg)
18+
19+## Beliefs
20+
21+We believe that general-purpose computing is an essential tool to
22+unlock the power of individual creativity.
23+
24+We believe that ownership, privacy and control don't need to be
25+sacrificed in exchange for usability, accessibility and reliability.
26+
27+We believe in the power of the informed crowd to develop and maintain
28+software, through the IETF principles of sincerity and rough consensus.
29+The ability of the engineering community to govern itself through
30+republican forms is not an abstract theory; it's a proven fact.
31+
32+We believe in both free speech and individual accountability. We
33+believe that a healthy network is one with diverse and well-defined
34+communities, and clear, user-controlled, boundaries between public and
35+private space.
36+
37+We believe that no software system can replace human trust and
38+communication. Dialogue, judgment and governance are essential to
39+communities of all scales. Code and law can reduce conflict in the
40+common case; they can never handle all exceptions.
41+
42+## Principles
43+
44+Here are some principles of Urbit. Where principles conflict,
45+the first stated takes precedence.
46+
47+### Digital independence
48+
49+Digital independence is independent control of your own
50+general-purpose computer which holds your own primary data.
51+Urbit's ultimate purpose is to make practical digital
52+independence a useful and widely available product.
53+
54+### Code is law
55+
56+Wherever possible, the rules of Urbit must be executable as code.
57+Wherever possible, code must be self-enforcing. If not, it must
58+be perfectly defined. If not, it must not be stated.
59+
60+### Sovereignty is conserved
61+
62+Even where code is law, exceptional situations demanding
63+effective collective action will always arise. There must
64+always be a collective authority to solve these problems.
65+
66+Two known problems in Urbit that require central authority are
67+approval of software updates and activation of the network. But
68+there will certainly be others.
69+
70+### Purpose of collective authority
71+
72+Urbit, as opposed to the Tlon corporation, is a republic. Its
73+government has one task: promoting, preserving and protecting Urbit.
74+It may take any legal action which advances this goal. Any other
75+actions are _ultra vires_, out of scope. Urbit is not a
76+general-purpose charity.
77+
78+### Decentralized control
79+
80+Urbit should never fall under any kind of central control. All
81+transitions in galaxy ownership should divide positions, not
82+unite them.
83+
84+Galaxy and star ownership should also be separated. It is
85+harmful for a single entity to hold both galaxies and stars.
86+
87+### Property is contingent
88+
89+Property rights are contingent and accidental, not moral or
90+meritorious. A property register does not record why an owner
91+deserves some property. Ownership is neither a reward nor a
92+right; it is a fact.
93+
94+### Governance is by stake
95+
96+Ultimately, Urbit must be governed by those who own it. In each
97+tier, equal stakes must hold equal authority.
98+
99+### Content-neutral
100+
101+Urbit does not admit a tradeoff between anarchy and tyranny,
102+order and liberty. Urbit has zero tolerance for abuse, nor does
103+it facilitate censorship.
104+
105+Urbit will do everything possible to help you block content you
106+don't want to see. It does nothing to help you block content you
107+don't want others to see.
108+
109+### Trolling considered harmful
110+
111+If you post content on Urbit which may offend or disturb any
112+significant group of users, it is your responsibility to mark it
113+properly for automatic blocking.
114+
115+### Sockpuppets considered harmful
116+
117+The only legitimate reason for one individual to use multiple
118+identities is to maintain multiple active pseudonyms. But
119+multiple identities must never interact in the same context.
120+
121+### Not a darknet
122+
123+Urbit is not a darknet. It does not break real-world laws. It
124+is not designed to facilitate the breaking of real-world laws.
125+For any problem that lawbreakers have, there must always be a
126+better solution that is not Urbit.
127+
128+### Responsibility to route
129+
130+As long as they are not facilitating violations of any of these
131+principles, or laws in their own jurisdictions, stars and
132+galaxies are responsible for routing their children. They are
133+also collectively responsible for escape-routing the children of
134+stars and galaxies which fail in their responsibility.
content/blog/bootstrapping-urbit-from-ethereum.mdnew file+394
@@ -0,0 +1,394 @@
1++++
2+title = "Bootstrapping Urbit from Ethereum"
3+date = "2017-09-19"
4+description = "We've decided to launch Urbit's constitution as a system of Ethereum contracts."
5+aliases = [
6+ "/posts/essays/bootstrapping-urbit-from-ethereum",
7+ "/posts/bootstrapping-urbit-from-ethereum",
8+ "/blog/2017.9.20-bootstrapping-urbit-from-ethereum/",
9+ "/blog/2017.9-eth/"
10+]
11+
12+[extra]
13+author = "Curtis Yarvin + Galen Wolfe-Pauly"
14+ship = "~sorreg-namtyv + ~ravmel-ropdyl"
15++++
16+
17+_TL;DR:_
18+
19+We've decided to launch Urbit's constitution as a system of Ethereum contracts.
20+
21+We'll instantiate a land registry for Urbit address space; an ERC20 "spark"
22+token which is burned to create a generic star; and a voting system for
23+self-governance. We'll also create template contracts which galaxies can use to
24+auction stars, and stars to distribute planets.
25+
26+## A bit of background
27+
28+One thing we realized after the last sale was, 'oh hey, the network has been up
29+for about a year.' Not bad! It wasn't that long ago that we were rebooting the
30+universe every few weeks. We still have plenty of work to do — but Urbit has
31+matured to the point where public ownership of the network really should be
32+cryptographically real.
33+
34+But even when the servers stay up, Urbit is still a testnet and remains
35+centralized in practice. We (Tlon) retain the ability to reset the network keys
36+at any time. This just isn't very 2017.
37+
38+In theory, Urbit doesn't need a blockchain, because real estate moves slowly.
39+In digital real estate, as opposed to digital currency, a low-friction,
40+zero-trust solution to the double-spend problem isn't an economic necessity.
41+
42+In practice, though, we have a hard chicken-egg problem. In the current design,
43+the key you use to secure your urbit is the same key that you use to sign your
44+network packets. Abstractly, this is the right design -- you want one
45+definition of who owns an identity.
46+
47+But concretely, since Urbit keys are valuable, you don't want to put them in an
48+operating system that isn't generally recognized as systematically secure. It's
49+hard to achieve this status while you're a testnet. So the virtuous cycle never
50+gets started.
51+
52+Moving the Urbit land registry to Ethereum is an easy and obvious solution to
53+this problem. If your urbit is owned by an offline Ethereum key, there's now a
54+mature ecosystem for protecting this property. And its security doesn't depend
55+on the security of Urbit. So, we realized, maybe Urbit actually does need a
56+blockchain for its land registry. While the system matures, we can bootstrap
57+off of Ethereum, without changing the design of the Urbit cryptosystem.
58+
59+And best of all, you can get your Urbit star or planet entirely through the
60+blockchain, without interacting with any centralized database or payment
61+mechanism. So we're really living in 2017.
62+
63+Sounds good, right?
64+
65+It does sound good. Although, as usual, we care about making things that _work_
66+above all else. So, rather than a 'announcing the Urbit token sale' post, this
67+is going to get fairly technical. We want to start the discussion about how
68+this change is going to work, and how it's going to get implemented. We'll save
69+the hype for later.
70+
71+First, we'll walk through the costs and benefits of using Ethereum. Then,
72+we'll refresh our memories on how the Urbit address space works, and finally
73+we'll walk through some of the details of how we plan on implementing this.
74+We've thought quite thoroughly about these things, but public criticism is
75+really important.
76+
77+## Weighing the choice of Ethereum
78+
79+Our engineering style is to build the whole stack, from axioms to UI, from
80+custom, super-minimal parts. When these parts don't fit perfectly, we rewrite
81+them until they do. With a few exceptions, such as crypto algorithms, Urbit
82+doesn't reuse existing code or designs, depend on existing tools, or expect
83+outside contributors to solve problems essential to a complete experience.
84+
85+Instinctive minimalism is essential in a custom full stack. The best solution is
86+always to not solve the problem. The natural engineering response to the
87+pre-blockchain difficulty of solving Byzantine consensus agreement was: do we
88+really need it?
89+
90+### The case against Ethereum
91+
92+Since Urbit network address space is a land registry, not a currency,
93+transactions are low-frequency. A low-frequency transaction system can succeed
94+economically even if it has high friction. The double-spend problem, which
95+consensus computing solves, becomes easy or at least tractable given high
96+friction.
97+
98+We reinvent the wheel if we have to, throw it away if we can. So depending on
99+Ethereum goes against all Urbit's instincts.
100+
101+Let's enumerate the problems, as critically as we can:
102+
103+And Ethereum's user experience is notorious; its governance is suspect and
104+unstable; its dilution rate is unconscionable; its dev environment is full of
105+bugs and misfeatures; in short, it's a classic MVP. It has only one real goal:
106+success. It seems to be doing pretty well with that.
107+
108+We prefer [SLC](https://blog.asmartbear.com/slc.html) to MVP. Urbit under
109+construction is fun to play around in. But we certainly won't ask real users or
110+real developers to set foot in Urbit until their experience is truly simple,
111+lovable and complete. The original iPhone set the bar for this, and we'll get
112+as close as we can.
113+
114+### The case for Ethereum
115+
116+It's obvious that Urbit has a practical problem in deploying a self-hosted PKI.
117+When does the testnet become a realnet? You wouldn't put real, valuable keys in
118+your urbit, until you know the system is mature and secure.
119+
120+But how does anyone know that Urbit is mature until more daring users have used
121+it with real, valuable keys? But who wants to be the first person to hop into
122+the box?
123+
124+There is no clear way to bootstrap past the testnet phase. Except, well, reboot
125+Urbit onto an existing blockchain, with a tested and reasonably-secure
126+key-handling infrastructure, that can also validate the Urbit PKI rules. Then
127+each user can decide on their own whether sensitive data is safe in their own
128+urbit.
129+
130+## An Urbit refresher
131+
132+Maybe some people are here because they know what Ethereum is, but not so much
133+Urbit.
134+
135+For those of you not familiar, let's try to refresh your memories.
136+
137+### What Urbit is
138+
139+One simple way to think about Urbit is as a "personal blockchain." Like a
140+blockchain, Urbit is a deterministic virtual computer. Its semantics are defined
141+by a frozen lifecycle function, which maps its event history to its current
142+state. But, unlike a blockchain, an Urbit instance is a private computer for one
143+user, not a public record for everyone.
144+
145+Urbit's lifecycle function is a nano-interpreter called Nock. A typed functional
146+language, Hoon, compiles itself to Nock. An event-driven OS, Arvo, is written in
147+Hoon. Everything above Nock can upgrade itself over Urbit's own overlay packet
148+network, Ames. Ames is live and stable with test keys.
149+
150+Our Urbit interpreter runs on any Unix machine. The Urbit server is a
151+single-level store -- both database and application engine. Every Urbit event is
152+a transaction. Urbit is semantically frozen and cannot call out to Unix.
153+
154+Your Urbit instance is your personal server. Your urbit should eventually
155+contain and manage your whole digital life. You may compute at home or in the
156+cloud, based on your security/privacy tradeoff, but Urbit's formal semantics
157+makes ships trivial to migrate. You'll never be locked in to one computing
158+provider.
159+
160+### The Urbit address space
161+
162+An Urbit address is called a "ship." A ship is a network address, a
163+cryptographic identity, a pronounceable name, and a permanent memory. A ship's
164+name is just its numeric address, written in a syllabic base-256.
165+
166+Smaller addresses mean shorter, more memorable ships. Ships are classified in a
167+hierarchy: 8-bit "galaxies" (like `~dyl`), 16-bit "stars," (`~ropdyl`), and
168+32-bit "planets" (`~ravmel-ropdyl`). Galaxies and stars are network
169+infrastructure. Regular users have planets. The tight 32-bit address space makes
170+names short enough to remember, and costly enough to deter Sybil attacks.
171+
172+Planets are created by their prefix star; stars are created by their prefix
173+galaxy; galaxies were created by the founders. Parents assist their children,
174+providing essential services like peer-to-peer packet routing, but don't own or
175+control them. The prefix is just an initial default -- a ship can switch to any
176+parent that's willing to adopt it.
177+
178+## Summary of the integration model
179+
180+In the new integrated model, every planet, galaxy or star is owned by an
181+Ethereum address. The secret that controls this address is the ship's "master
182+key."
183+
184+The master key is not needed to operate the ship and should not be stored on it,
185+at least not until Urbit is more mature. Master keys should be kept as "cold" as
186+possible. They are only used to perform lifecycle operations on your ship, by
187+signing Ethereum transactions which are sent to the Urbit constitution.
188+
189+We'll fork an open-source Ethereum browser and add a custom UI for Urbit
190+transactions. New users will acquire their urbits entirely on the blockchain.
191+
192+The most basic Urbit transaction is starting a ship you own. To start your ship,
193+you use Urbit to generate an Urbit keypair, and use Ethereum to register the
194+Urbit public key (a 512-bit pair of Curve25519 for encryption and Ed25519 for
195+signature) on the Ethereum blockchain.
196+
197+For users who want to hold generic stars without starting or even selecting
198+specific ships, we'll create a divisible "spark" (USP) ERC20 token. A spark is
199+the right to create one star. Sparks are a convenience tool: they leverage the
200+mature ERC20 infrastructure for holding and trading token utility rights.
201+
202+Instead of launching stars directly, galaxies can cede their unlaunched stars to
203+the Urbit constitution. The issuing galaxy receives one spark in exchange for
204+this star. Any Ethereum address can redeem one spark in exchange for the right
205+to start one star from the constitution's pool.
206+
207+Once all the galaxies are created, Urbit is fully decentralized. We retain no
208+ownership powers over the Urbit constitution.
209+
210+The Urbit galaxies will mirror the state of the constitution, distribute its
211+state and events within Urbit, and post any transactions created within Urbit.
212+Generally an Urbit ship trusts its parent -- if not, it should find a new one
213+fast. But a deeply paranoid ship can still listen to Ethereum directly.
214+
215+## Contract designs
216+
217+The Urbit constitution is four contracts: certificate storage, spark storage,
218+election storage, and logic controller.
219+
220+Following Ethereum best practice, we'll use separate storage and logic
221+contracts. The logic contract is stateless, and can upgrade itself without
222+replacing the storage contracts.
223+
224+We'll walk through how we have designed these contracts in detail here. You can
225+also view our in-progress source at the
226+[`urbit/azimuth` GitHub repo](https://github.com/urbit/azimuth).
227+
228+### Certificate storage contract
229+
230+For every galaxy, star or planet, the certificate contract holds a current
231+state: `%latent`, `%locked`, `%liquid` or `%living`.
232+
233+The default/empty state is `%latent` (nothing has happened to this ship). The
234+contract stores no data for a latent ship.
235+
236+A `%locked` ship has an owner and an activation date. It cannot be activated
237+until the given date. Until activated, the locked ship can't be transferred,
238+vote, liquidate or launch children.
239+
240+A `%liquid` ship is held by the Urbit constitution to be redeemed for a spark.
241+It has no other state.
242+
243+A `%living` ship is active. Its state: an Ethereum address which owns it; an
244+Urbit public key; a revision number, which increments on any lifecycle
245+operation; and (for planets and stars) both current and requested (for escaping)
246+parent ships.
247+
248+The certificate contract throws an event on every state change.
249+
250+### Spark storage contract
251+
252+The spark contract is a divisible ERC20 token (you can't hold half a star, but
253+you can hold half a spark). Only the logic contract can create and destroy
254+tokens.
255+
256+### Governance storage contract
257+
258+The governance contract records galaxies' votes on governance proposals.
259+
260+There are two kinds of proposals: concrete and abstract. A concrete proposal is
261+the address of a new logic contract for the constitution. An abstract proposal
262+is the hash of a document.
263+
264+Voting is one-bit -- the default vote is "no" -- and irreversible. A 256-bit
265+bitfield records the set of galaxies that have voted for each proposal.
266+
267+Only active galaxies may vote. A counter records the number of active galaxies.
268+A proposal passes if more than 50% of active galaxies support it. If the
269+proposal is concrete, the old logic contract is terminated and the new one
270+receives storage control. Abstract proposals have no further effects on the
271+blockchain.
272+
273+### Logic contract
274+
275+The logic contract is stateless and supports the following ops:
276+
277+#### Create a galaxy
278+
279+What: move a galaxy from `%latent` to `%locked` state.
280+
281+Who: the founders only.
282+
283+Comments: this is the only founder-privileged operation.
284+
285+#### Liquidate a star
286+
287+What: move a specific star from `%latent` to `%liquid` state, granting one spark
288+to the galaxy owner.
289+
290+Who: owner of the active galaxy which is the star's prefix.
291+
292+#### Claim a star
293+
294+What: move a specific star from `%liquid` to `%locked` state, with the
295+activation date set to the present, and the owner as claimer; remove one spark
296+from the owner.
297+
298+Who: any Ethereum address which owns a spark.
299+
300+#### Launch a star or planet
301+
302+What: move a specific star or planet from `%latent` to `%locked` state, with the
303+activation date set to the present, and set the Ethereum address which owns the
304+ship.
305+
306+Who: owner of the parent of the launched ship.
307+
308+#### Start a ship
309+
310+What: move a specific ship from `%locked` to `%living` state, setting its Urbit
311+public key.
312+
313+Who: owner of the locked ship.
314+
315+#### Transfer a ship
316+
317+What: change the owner of a `%living` ship, also resetting the Urbit public key.
318+
319+Who: current owner of the ship.
320+
321+#### Rekey a ship
322+
323+What: in a living ship, change the Urbit public key, without changing the
324+Ethereum address that owns the ship.
325+
326+Who: owner of the ship.
327+
328+#### Request adoption
329+
330+What: in a living ship, set the requested-parent field.
331+
332+Who: owner of the ship.
333+
334+#### Accept adoption
335+
336+What: in a living ship, set the current parent to the requested parent, and
337+clear the requested parent.
338+
339+Who: owner of the requested parent.
340+
341+#### Create a proposal
342+
343+What: create a proposal, which is either the hash of a document (abstract) or
344+the address of a new logic contract (concrete).
345+
346+Who: owner of any living galaxy.
347+
348+#### Endorse a proposal
349+
350+What: register support for a proposal. If the proposal is concrete and this
351+vote takes it over 50%, upgrade the contract.
352+
353+Who: any galaxy who has not yet voted on this proposal.
354+
355+### Planet sales and spark auctions
356+
357+We'll also write contracts that help galaxies and stars distribute their stars
358+and planets.
359+
360+#### An auction contract for spark sales
361+
362+The ERC20 spark token creates a liquid market in stars, or rather star
363+precursors. But a galaxy liquidating sparks may not want to just sell a large
364+block into this market, which may have weak depth, especially when the token is
365+initially launched.
366+
367+So we'll validate and deploy the Nick Johnson design for an
368+[off-chain second-price auction](https://www.reddit.com/r/ethereum/comments/6igsdq/a_proofofconcept_of_a_better_crowdsale_contract/)
369+
370+To run an auction, the seller liquidates a block of stars, then transfers the
371+spark tokens to a seller-owned copy of the auction contract. The Urbit
372+constitution is not involved with the auction.
373+
374+#### A distribution contract for planet sales
375+
376+There is no generic token for planets. To start a planet, you need a star to
377+launch it with your Ethereum address as the owner.
378+
379+To distribute planets on the blockchain, a star instantiates a private copy of
380+the planet sale contract. Since the star is the contract's owner, the contract
381+can send launch operations to the Urbit constitution.
382+
383+The star owner configures the planet sale contract with two parameters: the
384+price in ether of a planet, and the number of planets available.
385+
386+## Okay, so
387+
388+That was quite a lot of information! There's also a blog post about the constitution
389+[here](https://urbit.org/blog/interim-constitution/), and GitHub issues on the
390+[urbit/azimuth repo](https://github.com/urbit/azimuth) are more
391+than welcome.
392+
393+There's a lot more to come on this front as our contracts get closer to getting
394+live, and we begin migrating toward an on-chain Urbit PKI.
content/blog/common-objections-to-urbit.mdnew file+725
@@ -0,0 +1,725 @@
1++++
2+title = "Common Objections to Urbit"
3+date = "2016-06-27"
4+description = "Some common objections to Urbit, discussed."
5+aliases = [
6+ "/posts/essays/common-objections-to-urbit",
7+ "/posts/common-objections-to-urbit",
8+ "/posts/objections/"
9+]
10+
11+[extra]
12+author = "Curtis Yarvin"
13+ship = "~sorreg-namtyv"
14+image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/common-objections-to-urbit-1.jpg"
15++++
16+
17+![](https://storage.googleapis.com/media.urbit.org/site/posts/essays/common-objections-to-urbit-1.jpg)
18+
19+We love crowdsourced criticism. We've heard a lot of great
20+objections to Urbit. Surely there's more out there! We'll
21+revise this document to include anything new and interesting.
22+
23+Here's our list right now:
24+
25+- [Urbit is not ready for prime time.](#prime)
26+- [Nock jets are a total hoax.](#jets)
27+- [Urbit needs an infinitely extending packet/event log.](#log)
28+- [Urbit is a total scamcoin. It's 100% premined.](#scam)
29+- [Urbit isn't even really decentralized! It has a government!](#gov)
30+- [Sandstorm/IPFS/Ethereum is way ahead of Urbit.](#sand)
31+- [Urbit doesn't have enough planets for every human being.](#planet)
32+- [Cloud computing is inherently non-private.](#pwned)
33+- [Urbit will never be able to call any existing code.](#code)
34+- [Hoon is too weird. No one will be able to program in it.](#program)
35+- [Urbit programmers are stuck with Hoon.](#stuck)
36+- [Ordinary users will never be able to manage an Urbit server.](#user)
37+- [Urbit has no killer app.](#killer)
38+- [Urbit is sniffed at by Houyhnhyms.](#horse)
39+
40+_"We choose to go to the moon, not because it is easy, but because it is hard."_
41+— [John F. Kennedy](https://www.youtube.com/watch?v=g25G1M4EXrQ)
42+
43+## Urbit is not ready for prime time. {% #prime %}
44+
45+_TLDR_: we agree.
46+
47+Urbit right now is a fun toy. It is fun to learn Hoon. It is
48+even fun and quite practical to make actual contributions.
49+(Hoon's IEEE floating-point was written by someone we've never
50+met: `~nym`, formerly `~nodpet-rinned`.) In fact, we have never
51+seen anyone _not_ have fun with Urbit.
52+
53+But there is all kinds of stuff wrong with the codebase. Urbit's
54+documentation is much improved, but remains incredibly weak --
55+Arvo is almost totally undocumented. Scaling is poor at best.
56+Urbit's reliability is dubious. Its security is nil.
57+
58+Urbit is feature-frozen. The only thing we're working on now,
59+and for the rest of 2016, is doc, debugging and and self-hosting.
60+In that order of importance -- teaching Urbit is more important
61+than fixing it, which is more important than making it useful.
62+But we're quite confident that these are all solvable problems.
63+
64+The most important milestone about Urbit today is that it's ready
65+for technical decisions to be made collectively. A system like
66+Urbit can only be invented by a mad auteur. It can't be
67+maintained or stabilized by a mad auteur. Our primary goal today
68+is expanding the number of people who understand Urbit, and we
69+expect these pioneers to participate in technical governance.
70+
71+## Nock jets are a total hoax. {% #jets %}
72+
73+_TLDR_: all of computing is a hoax. You can't compare a hoax
74+to nothing. You can only compare it to all the other hoaxes.
75+
76+A "jet" is a sort of software device driver in Urbit. Urbit is
77+precisely defined in terms of an interpreter that fits on a
78+T-shirt, Nock. But a naive implementation of Nock is nowhere
79+near practical, because Nock has only one integer operation:
80+increment. For example, to decrement a number in Nock, you
81+increment a counter up to the number under it.
82+
83+The only way an efficient Nock interpreter can work is to
84+recognize algorithms like decrement, and implement them
85+non-naively. By far the easiest way to do this is not to analyze
86+arbitrary code as it's being executed, but to register and match
87+well-known implementations in the standard library. No one
88+should be writing their own decrement.
89+
90+But the semantics of the interpreter, _so long as the jet and the
91+jet harness are defined correctly_, are exactly those of Nock.
92+We are not extending or changing Nock in any way. We are just
93+taking a shortcut in certain cases we understand perfectly.
94+
95+It's not at all unprecedented to have implementations much more
96+complex than the corresponding specification. The x86
97+instruction set is relatively simple; the complexity of its
98+decoding and execution path in a modern CPU is enormous. This
99+path may well have "peephole optimizations" that replace matched
100+algorithms, and if it doesn't the modern compiler does. People,
101+_bad_ people, use "jets" to cheat on benchmarks all the time.
102+
103+Nock is designed as a standard. It's built like a standard.
104+Typically what causes real problems in standards is ambiguity.
105+Two implementations are incompatible, but each swears it has the
106+right interpretation of the natural-language spec. This simply
107+cannot happen in the Nock world. If two implementations
108+disagree, at least one of them is incorrect. This puts us firmly
109+in "with enough eyeballs, all bugs are shallow" territory.
110+
111+The fact remains, however, that a Nock interpreter without jets
112+is completely useless. And there is not even an informal
113+document that tells you what jets you need for a reasonably
114+efficient Urbit. (There should be such a document.)
115+
116+The correct way to think about jets is not to compare them to a
117+perfect interpreter created by unicorns. Jets are a combined
118+replacement for two other techniques in language implementation:
119+intrinsics and a foreign-function interface.
120+
121+Compared to both intrinsics and an FFI, your jets have one key
122+disadvantage: they need to be specified in pure code. You may
123+not have this executable specification, which means you need to
124+write it. Is this really so bad for your development process?
125+An executable specification? Which can be trivially tested
126+against the efficient implementation?
127+
128+Compared to intrinsics, jets give you true separation between
129+mechanism and policy; only the interpreter, not the programmer
130+and not the compiler, needs to know what's accelerated.
131+
132+Compared to an FFI, jets preclude I/O, so can be trivially
133+sandboxed. Except that the programmer needs to mark routines
134+which may benefit from optimization with a hint, here too we
135+separate mechanism (efficient implementation) from policy.
136+
137+Yes, formal verification of jet equivalence is desirable.
138+However, in the real world, many specifications, including quite
139+complex ones, are tested into equivalence by brute force.
140+
141+Urbit has some jet abuses. The equivalence between our markdown
142+parser in Hoon and the CommonMark C library is super dubious. It
143+should be revisited.
144+
145+But the miscomputation resulting from a minor jet discrepancy is
146+not a security hole or even fatal. It effectively means the
147+event history, computed correctly, does not match the current
148+state. The way to resolve this conflict is for the current state
149+to win, and the event history to be discarded -- not abnormal
150+anyway. See the next question.
151+
152+## Urbit needs an infinitely extending packet/event. {% #log %}
153+
154+_TLDR_: no, it doesn't. Urbit can prune the log.
155+
156+We can prune the event log because the Urbit transition function
157+doesn't have any access to the event history -- just the current
158+state and the current event.
159+
160+Urbit defines the semantics of a complete event log. It doesn't
161+and can't require an implementation to maintain the whole log.
162+It can maintain a checkpoint and the log since that checkpoint.
163+
164+However, any practical urbit maintains a periodically updated
165+checkpoint. Our present implementation doesn't provide a way to
166+prune the event log. But that's just a missing feature. We have
167+one or two of those!
168+
169+## Urbit is a total scamcoin. It's 100% premined. {% #scam %}
170+
171+_TLDR_: yeah. But at least it's not the DAO.
172+
173+Like a cryptocurrency, Urbit is a digital title. But Urbit is
174+digital land, not digital money. If you assess it as a currency,
175+it's a lousy currency. If you assess a cat as a dog, it's a
176+lousy dog.
177+
178+In real-world economics, the crucial distinction between land and
179+money is that land (a) has intrinsic utility and (b) is
180+non-fungible.
181+
182+Because of (b) alone, frictionless transactions in land are
183+impossible. A blockchain is only needed to ensure zero-cost
184+high-frequency transactions. So digital land doesn't need a
185+blockchain. Which means it doesn't need mining.
186+
187+Of course, just because a digital title system doesn't need
188+mining, doesn't mean it can't distribute an initial allocation by
189+proof-of-work -- or by any other arbitrary method which is
190+careful not to benefit the system's own developers. Could we
191+give away the Urbit address space randomly? Sure. But why?
192+
193+Probably the purest design is the "proof-of-burn" initial
194+allocation used by some coins. By any standard, proof-of-burn is
195+technically beautiful and results in an extraordinary level of
196+ethical independence. We can't help but admire it.
197+
198+But any altcoin or metacoin is just way less work than Urbit. An
199+altcoin can afford to burn even its creation energy, capturing no
200+value at all from its seigniorage. Your altcoin doesn't have a
201+clean-slate system software stack to drive. If your rocket has
202+to go to the moon, it's going to leave a little bit of smoke in
203+the air.
204+
205+Ethically, what makes "premining" feel wrong is that the creators
206+of the currency are rewarded disproportionately for their effort.
207+The scamcoin is a get-rich-quick scheme, vaguely pyramid-shaped.
208+Nothing about Urbit matches this pattern at all.
209+
210+Curtis invented Urbit. So by the [homestead
211+principle](https://en.wikipedia.org/wiki/Homestead_principle), he
212+started out owning all of it. But by now, Urbit's 8-bit galaxies
213+have already been distributed among [57 separate individuals](https://github.com/urbit/arvo/blob/master/sys/vane/ames.hoon#L118-L373).
214+Curtis owns 20, or about 8%.
215+
216+Tlon, the corporation which still runs Urbit development, has 95.
217+(Without Tlon, there is basically no Arvo.) 50 are reserved for
218+a hypothetical Urbit Foundation. Tlon employees have another 16.
219+
220+The rest of the galaxies belong to donors, investors,
221+contributors, contest winners, and just random people who were in
222+the right place at the right time. One is a Silicon Valley
223+tycoon. Another is an Orthodox nun in a monastery in Greece. A
224+couple are ex-Tlon employees who might totally hate us. There is
225+nothing they all have in common, which is sort of the point.
226+
227+This property distribution looks a lot like land ownership in the
228+real world -- complex and asymmetrical. That's no accident. If
229+you have a problem living in New York because New York's real
230+estate is not distributed equally among its residents, you may
231+have a similar problem with Urbit. The reality is that Urbit,
232+like New York, wasn't born yesterday and comes with a complex
233+ownership history which we couldn't possibly change, even if we
234+wanted to.
235+
236+Decentralization is hard. The only real goal of a property
237+system in address space is to create and maintain
238+decentralization. The whole network has to exhibit centrifugal
239+force, not centripetal force. Proof-of-work systems certainly
240+seem to have unexpected centripetal qualities, producing
241+unanticipated concentrations of centralized hashpower. See the
242+next objection.
243+
244+## Urbit isn't even really decentralized! It has a government! {% #gov %}
245+
246+_TLDR_: it's technically impossible for Urbit to be
247+decentralized at this stage of its life. Urbit is designed to
248+achieve decentralization, not be born with it.
249+
250+A young network can't afford to be decentralized. It has to act
251+as a unit. Because it has no network effect, it needs every
252+scrap of efficiency it can get.
253+
254+A decentralized general-purpose computing network like Urbit can
255+_only_ be bootstrapped by a central government. For example, by
256+default your urbit upgrades its OS automatically (like an
257+"evergreen" browser) with signed network updates. Whoever signs
258+these updates is a government by definition.
259+
260+When it's impossible to eliminate centralized power, it becomes
261+necessary to tame, stabilize, and limit it. This should not be
262+surprising to anyone living under a constitutional government.
263+
264+As we found out with the DAO, if a network isn't ready to be
265+decentralized, its developers shouldn't even try. If Ethereum is
266+hard-forked to roll back the DAO (which looks like the most
267+probable result), it acknowledges that it both has a central
268+government, and needs a central government. Decentralization is
269+good. Pretend decentralization -- "decentralization theater" --
270+is harmful, and not a effective path to actual decentralization.
271+
272+A key test of a free software project's health is whether it can
273+fork. So long as the unity of the public-key hierarchy and the
274+network protocol is maintained, the Arvo kernel and Urbit system
275+can fork in all kinds of ways without disrupting the network.
276+Any stress will fragment the "government" that develops the
277+kernel, and as it fragments it grows more limited and stable.
278+
279+Urbit is designed to govern itself collectively by address space
280+ownership -- effectively, "proof of stake." Any arbitrary power,
281+will tend to fracture along these property lines. For instance,
282+our hot updates are sent through the galaxy hierarchy; in a
283+development fork, active galaxies would pick upstream sources.
284+Two implementations of a standard are better than one.
285+
286+And by fragmenting the galaxy space into 57 separate partitions,
287+we've created a global property map which is much more likely to
288+splinter further, than reunite.
289+
290+In the long run, every galaxy should have a separate owner, who
291+is a human being rather than a corporation. Combining galaxy
292+holdings will damage the reputation of both galaxies. The only
293+reason to merge ownership is to move toward incipient monopoly.
294+Whether a galaxy admits this openly or denies it dishonestly, its
295+reputation will suffer.
296+
297+The technical goal of Urbit is to create a network which, _if it
298+actually takes over the world_, inevitably becomes decentralized.
299+Even if Urbit takes over the world, no individual or coherent
300+organization takes over the world. There is nothing even close
301+to a single point of failure in a mature, successful Urbit.
302+
303+This is the goal of all the new "web3" decentralized systems. If
304+IPFS, Sandstorm or Ethereum takes over the world, nobody takes
305+over the world. (The same is almost true of the Internet --
306+though it wouldn't be that surprising if a time traveler from
307+2116 revealed that ICANN had become a planetary government.)
308+
309+Urbit, by starting out as a centralized network, just reduces the
310+technical problem to match the actual goal. Only long-term
311+decentralization matters.
312+
313+It's very important that Urbit in 2116 be fully decentralized.
314+For Urbit in 2016, pretending to be decentralized would be a joke
315+at best, and a hoax at worst. And of course, no one can DAO us
316+-- since the property system is still just a central registry.
317+Among other things, we check it into GitHub. GitHub is not a
318+blockchain -- but still, good luck with that.
319+
320+## Sandstorm/IPFS/Ethereum is way ahead of Urbit. {% #sand %}
321+
322+In general, web3 (next distributed web) solutions don't compete
323+with each other. They support each other. Concretely, they are
324+all part of each others' network effect.
325+
326+IPFS, Sandstorm, Ethereum, and Urbit can all take over the world
327+at the same time. None of them competes with the others. They
328+enable each other.
329+
330+For instance, IPFS and Urbit are both global immutable
331+namespaces. IPFS is a chord-routed, content-addressed namespace.
332+Urbit is a direct-routed, identity-addressed namespace. Urbit is
333+a typed revision-control system; IPFS is a blob store. IPFS
334+isn't a computer; the work hasn't been done, but Urbit can easily
335+mount the IPFS namespace and compute functionally against it.
336+
337+So the better IPFS does, the less Urbit needs to struggle against
338+its lack of network effect. The better Urbit does, the easier it
339+is for IPFS to point to a functional language that can actually
340+use its referential transparency directly. So their relationship
341+is symbiotic, not competitive at all.
342+
343+The closest thing to a general-purpose competitor that Urbit has
344+is Sandstorm. Sandstorm, which by the way rocks, is also a
345+personal server built around a network protocol.
346+
347+But Sandstorm and Urbit compete in the way that, on the PC, the
348+OS and the browser compete. In theory, the OS could solve the
349+problems that the browser solves; or the browser could be the OS.
350+In practice, Windows is a great OS to run a browser on.
351+
352+Similarly, a world in which Sandstorm takes off is an awesome
353+world for Urbit, because everyone who has a Sandstorm instance
354+has a great platform for running Urbit on. Urbit on Sandstorm
355+will be a sort of "double-hulled" personal server, safer and more
356+friendly than either system alone.
357+
358+Sandstorm and Urbit have very different approaches to network
359+identification; Sandstorm uses capabilities, Urbit identity.
360+Broadly speaking, we believe, capabilities are optimal for
361+expressive power; but identity is optimal for the UI of the
362+common case. We'd need to see the Powerbox, Sandstorm's UI, more
363+fully fleshed out to understand its UI approach better.
364+
365+## Urbit doesn't have enough planets for every human {% #planet %}
366+
367+A 32-bit planet is a tool, not a toy. Like a car, it's a device
368+for a responsible and independent adult. There aren't 4 billion
369+cars in the world, nor 4 billion independent adults.
370+
371+If you aren't an independent adult, and you don't need or even
372+shouldn't have unconditional digital freedom (no one's 8-year-old
373+daughter needs unconditional digital freedom), a moon from
374+someone else's planet is fine. (Even most of today's independent
375+adults don't complain enough about being Facebook's moons.)
376+
377+And limiting the supply of anything doesn't create a shortage.
378+It sets a price. Ideally, in the long run, we think a planet
379+should cost about $10. This could be off by an order of
380+magnitude either way, and it wouldn't be the end of the world.
381+
382+If a planet costs $10, that means you paid $10 to get a planet.
383+A planet with no reputation has a positive reputation, because
384+someone paid $10 for it and hasn't yet done anything wrong.
385+Positive default reputation is the single quality that makes a
386+social network social.
387+
388+There is always a tradeoff between free speech and free beer.
389+Urbit will always choose free speech.
390+
391+## Cloud computing is inherently non-private. {% #pwned %}
392+
393+_TLDR_: a general-purpose cloud computer is much, much more
394+private than a special-purpose cloud computer. In general, a
395+cloud VM is secure against corporations but not governments.
396+With a global adversary, compute in your closet -- or even on
397+your body.
398+
399+One reason we want the decentralized Internet is that we're tired
400+of giant corporations spying on us. Think about it this way:
401+Amazon is Netflix's main competitor. And yet, Netflix runs its
402+whole operation on AWS. Why is Netflix sure that Amazon won't
403+spy on it?
404+
405+A general-purpose virtual machine is special from a privacy
406+standpoint, just because it's commercially realistic to design
407+terms of service that prevent the host from peeking and poking at
408+the customer's machine. Crossing this moat is technically
409+nontrivial and can't possibly happen by any reasonable accident.
410+No hosting contract could contemplate it.
411+
412+Whereas when your cloud computer is a special-purpose machine --
413+just a database row on some corporation's mainframe -- there is
414+no way these services can promise not to handle your data.
415+Handling your data is _what they do_. On a special-purpose
416+server, the concept of privacy is not even defined.
417+
418+Where even a general-purpose server falls down is where the user
419+has a sovereign adversary, which can secretly violate explicit or
420+implicit hosting contracts. Users with a sovereign adversary
421+must rely only on their own physical security.
422+
423+However, most users don't have a sovereign adversary. And those
424+who do maximize their "herd immunity" if they can use the same
425+protocols as those who don't. Otherwise, the adversary could
426+simply focus on everyone who uses the secure protocols.
427+
428+Also, the portability of a cloud server image is critical. Of
429+course, since Urbit is formally specified, it's trivially
430+portable. In fact, one strategy against sovereign adversaries
431+may be continuous rotation between hosts, like an MX missile.
432+
433+## Urbit will never be able to call any existing code. {% #code %}
434+
435+_TLDR_: neither will Javascript. And dear Unix, the browser
436+does not miss interacting with your `$LD_LIBRARY_PATH` at all.
437+
438+You can't talk to the OS or use system libraries from Javascript.
439+Therefore, there is no point in having any kind of gateway,
440+compatibility bridge, native methods, or other interface between
441+Javascript and C.
442+
443+When in doubt, remember that Urbit is "the browser for the server
444+side." It plays by the same general rules. Isolation means
445+isolation.
446+
447+## There's no way Urbit will ever be adopted. It's too weird. {% #weird %}
448+
449+_TLDR_: Urbit adoption is designed to be driven by ordinary end
450+users. Urbit isn't ready for ordinary end users yet. We're
451+working on it -- come help.
452+
453+Right now, Urbit is a developer tool. Or rather, a developer toy
454+-- since the only thing it's useful for is developing Urbit. It
455+also could be a much better toy. We're working on that too.
456+
457+But it's absolutely wrong to think of Urbit being adopted as a
458+developer tool in the conventional sense. If you think this is
459+almost impossible, you're right.
460+
461+If we look at the way most successful platforms are adopted,
462+they're not adopted for their own virtues. They're adopted
463+because they're part of a larger solution. It's very hard to
464+displace a native component of an existing platform. Urbit is
465+not trying to do this.
466+
467+C is a better language than Pascal, but it didn't beat Pascal
468+because it's a better language. C beat Pascal because C was the
469+native language of Unix, and people wanted to program in Unix.
470+People don't use Javascript because Javascript is a great
471+language, but because it's the native language of the browser.
472+Replacing the native language of a platform may be doable -- but
473+it's incredibly hard.
474+
475+Hoon is not competing with C, or even Haskell, as a Unix
476+programming language. The only reason to program in Hoon is that
477+it's the native language of Urbit. Urbit is not competing with
478+node.js or Rails as a Web backend. The only reason to run Urbit
479+is to run a personal server.
480+
481+Nock is cool, but it only gets adopted if Hoon gets adopted.
482+Hoon is cool, but it only gets adopted if Urbit gets adopted.
483+Urbit only gets adopted if it's useful as a personal server for
484+human beings -- most of whom won't be Hoon programmers, or
485+programmers at all.
486+
487+## Hoon is too weird. No one will be able to program in it. {% #program %}
488+
489+_TLDR_: Hoon is ridiculously simple. Our documentation and
490+tooling are just immature.
491+
492+It's pretty fair to assume that (a) functional programming is
493+hard and weird, (b) Hoon is weird even for a functional language,
494+so (c) Hoon must be hard-squared.
495+
496+Actually, Hoon is weird even for a functional language because
497+it's an attempt to remove the hardest things about functional
498+programming: category theory, lazy evaluation, and gratuitous
499+abstraction. To know a language is to know what the compiler is
500+doing; all the semantics of the Hoon compiler fit in 2000 lines
501+of code.
502+
503+It's too easy for us to wind up living in Isaac Asimov's Trantor,
504+a world in which everything got invented thousands of years ago
505+and the idea of new technology is just weird and scary. History
506+isn't over yet, and nor is technical history.
507+
508+New things are harder to learn than old things. We ask smart
509+high-school students to learn calculus. Think about how much
510+harder it was for Newton and Leibniz to invent calculus, or for
511+their first students to pick it up. Hoon is nowhere near as hard
512+as calculus.
513+
514+Most of the difference is just the collective certainty that our
515+society conveys to a high-school student that calculus is
516+learnable. When you're learning Urbit, you don't have this
517+collective knowledge; so you don't have the confidence that the
518+problem is solvable. Confidence makes a huge difference.
519+Moreover, any bug or glitch in the developer experience destroys
520+this confidence and takes a long time to heal.
521+
522+Yes, we know: Hoon remains quite hard to learn. Again, we have
523+no reason to think this problem isn't solvable. Public
524+enlightenment remains our main priority.
525+
526+## Urbit programmers are stuck with Hoon. {% #stuck %}
527+
528+_TLDR_: patience, grasshopper.
529+
530+There's quite a straightforward way to implement any perfectly
531+specified language with a reliable interpreter in Hoon. First,
532+write an interpreter for that language in Hoon. Second, jet that intepreter function with the existing implementation.
533+
534+It is not clear that Javascript is _quite_ well-defined enough
535+for this treatment. But Lua probably is.
536+
537+## Ordinary users will never be able to manage an Urbit server. {% #user %}
538+
539+_TLDR_: Urbit's technical simplicity has always been designed
540+to drive human usability. But the polish is the last thing that
541+goes on. So we can't evaluate this claim right now.
542+
543+Right now, Urbit is only for geeks. You already need to be able
544+to wrangle a Unix machine to run it. What's the point?
545+
546+This Urbit isn't the real Urbit. It's an early milestone on the
547+way to the real Urbit.
548+
549+The real Urbit -- for normal human beings -- is a hosted service.
550+Getting a planet is as easy as signing up for Facebook. Probably
551+many users will think of it as another web account. They might
552+not even know it can run more apps than the ones they use.
553+
554+A deterministic, persistent cloud computer is something different
555+from a traditional server. Normally when we think of a server in
556+the cloud, we think of it like a live animal -- a creature that
557+needs to be cared for, fed, and herded. A file in the cloud is
558+more like a rock -- you can forget about it for ten years.
559+
560+An urbit is a general-purpose computer, but it doesn't even have
561+the concept of a reboot. It upgrades itself. If you don't feed
562+it any packets for ten years, then turn it back on, it will spend
563+a day or two upgrading itself, then be back to normal. Maybe
564+it's something in between a rock and an animal -- a cactus?
565+
566+Another huge difference versus an Internet server is that we're
567+confident that Urbit's limited supply of identities will make it
568+easy to keep abusers off the network. So far, so good -- but of
569+course, no one abuses a young network.
570+
571+The bottom line is that managing your urbit has to be as easy as
572+managing your iPhone. Normally, it consists of deciding what
573+apps you want to be running, and how much you trust them.
574+Resources can't be free, so sometimes you have to play memory
575+police. Humans have shown that they can handle these tasks.
576+
577+Our '70s OSes and networks, which were great designs in their day
578+and have matured into excellent industrial tools, give us a
579+totally misleading impression of how hard it should be to manage
580+a general-purpose computer. Computing isn't scary or dangerous.
581+Unix and the Internet are scary and dangerous. That's fine for
582+an industrial tool, but not a personal tool.
583+
584+## Urbit has no killer app. {% #killer %}
585+
586+_TLDR_: the killer app is personal API aggregation.
587+
588+It's a truism that any new platform has to be fundamentally much
589+better at solving some problem than the mature platform it seeks
590+to replace.
591+
592+We can look at Urbit's killer app from two perspectives: as a
593+developer, and as a user.
594+
595+From the developer's perspective, Urbit's advantage is that it's
596+a network stack which provides exactly-once delivery of typed,
597+validated, transactional, encrypted and authenticated messages.
598+The difference between an Urbit API and a REST API is like the
599+difference between a paved road and a dirt road. On the other
600+hand, you do need to learn a new functional language.
601+
602+From the user's perspective, there's one task that any personal
603+server can perform, that can't be performed by any Web service:
604+unrestricted API aggregation.
605+
606+Well before Urbit is ready to _replace_ any conventional web
607+services, it should be ready to _command_ them in place by API.
608+(Or if needed, by scraping.) If all you care about is being in
609+control of your own data, it's fine to leave it in the hands of
610+these services, as you have the API secrets to get it out.
611+
612+Managing a set of security connections to your existing services
613+is one of the first important tasks of a modern personal server.
614+This is a stateful task that typically requires both a durable
615+API key and a temporary OAuth token. APIs change all the time,
616+so connection maintenance also requires evergreen updates.
617+
618+The origin of this API key will vary, but usually the best way to
619+set it is BYOK: the user registers their own urbit as an "app."
620+And the neat thing about having your own API keys, for multiple
621+services, on a single general-purpose computer, is that none of
622+these services really has any practical way to control what you
623+do with your own data.
624+
625+Terms of service which constrain the use of data (as opposed to
626+the abuse of the service) simply aren't realistic and will no
627+longer apply. This enables a variety of novel user experiences
628+which aren't implementable as traditional web services, and also
629+aren't available via conventional third-party API aggregators.
630+
631+Also, since Urbit is after all quite immature, it doesn't make
632+much sense to restrict this security state to code within Urbit.
633+The Urbit interpreter `vere` runs as a Unix daemon that
634+implements the FUSE user-level filesystem protocol, and maps the
635+data on your services into the Unix filesystem. For example, one
636+of our demos lets you `ls` your GitHub issues.
637+
638+So it's straightforward to build, for instance, a Python app that
639+uses Urbit as a gateway to mash up a bunch of web services. As a
640+Unix programmer, you might even just regard Urbit as a generic
641+Web API gateway daemon, without worrying about its internals.
642+
643+We have other ideas for initial killer apps. But this, we feel,
644+is the best one. API libraries for `npm` et al abound.
645+Stateful, self-updating, generic API aggregators with FUSE
646+integration, also integrated with a reactive web server, are
647+rarer.
648+
649+## Urbit is sniffed at by Houyhnhyms. {% #horse %}
650+
651+It's difficult to categorize [this awesome
652+essay](http://ngnghm.github.io/blog/2016/06/11/chapter-10-houyhnhnms-vs-martians/)
653+in a single bullet point. So I've saved it for last.
654+
655+When reading this essay, it's important not to forget the amazing
656+absence of genuine, mutually critical discourse in computer
657+science (as in most sciences today). You never hear what Swift's
658+designers think of Go, or vice versa. And critical public
659+discourse decreases, not increases, with increasing academic
660+legitimacy.
661+
662+The basic test of any field purportedly scientific in nature is
663+whether its researchers are genuinely interested in each others'
664+work, and willing to share these genuine responses publicly. If
665+this practice does not exist, the field may still be useful
666+and/or interesting. But it is not science.
667+
668+What's awesome about Fare's essay is that he's _doing it right_.
669+All the actual details are irrelevant. And mostly wrong. But
670+that's of very little importance compared to _doing it right_.
671+
672+Anyway, we've already addressed the idea that jets are a sham.
673+Some other points:
674+
675+### Event-sourcing and/or caching is a pattern, not a layer
676+
677+Fare' is perfectly right that "one size does not fit all" in
678+persistence. Generally, Urbit uses event-sourced persistence.
679+
680+But it has multiple layers of event-sourcing: in the definition
681+of Urbit itself; in the application sandbox vane (Gall), and in
682+the application itself. Urbit also has a completely orthogonal
683+revision control system (Clay).
684+
685+And there is not a single cache across the whole system, though
686+arguably there should be; for instance, the functional build
687+system (Ford, which Fare' the master of build systems might
688+appreciate) has its own internal cache.
689+
690+It is a common mistake to confuse a design pattern with a layer
691+or feature, and equally fatal whichever direction you fail.
692+
693+### Let's be clear about why DSLs suck
694+
695+DSLs suck not because they are difficult to newbies in the base
696+language. DSLs suck because every time a programmer, even one
697+_experienced_ in the base language, comes into a new codebase or
698+project, she has to learn a new custom language.
699+
700+You need enormous wins to justify this cost. It's the goal of
701+the base language designer to preempt these wins, creating a
702+language which is almost never so tiresome and full of
703+boilerplate that it requires a DSL or template layer.
704+
705+Hoon is almost entirely made of macros -- but they are internal,
706+fixed, built-in macros (with no gensyms). This fixed set of
707+macros is essentially enough. Occasionally we want to add one or
708+two. But we never, ever pine for context-dependent macros.
709+
710+### Determinism is not consensus, and is not constraining
711+
712+Fare' is totally right that an urbit's data is meant for itself
713+alone. In fact, an urbit has the right to compute incorrectly if
714+it wants. We go to considerable lengths to ensure that you can't
715+gain any particular advantage by incorrect computing.
716+
717+The whole point of Nock is that it's so low-level that there is
718+no conceivable advantage in upgrading it. Divergence is just
719+pointless. This is not a question of network integrity, just of
720+practical standardization.
721+
722+This consistency stops at Nock. Without anyone violating the
723+correctness of their lifecycle functions, anyone or everyone in
724+Urbit could replace Hoon with Javascript. Determinism does not
725+cramp Urbit's semantic style in any way, shape or form.
content/blog/community-spotlight-the-portico.mdnew file+138
@@ -0,0 +1,138 @@
1++++
2+title = "Community Spotlight: The Portico"
3+date = "2021-05-03"
4+description = "Interview with The Portico founder Josh Reagan"
5+
6+[extra]
7+author = "Matt"
8+ship = "~tirwyd-sarmes"
9+image = "https://media.urbit.org/site/posts/essays/orthodoxchurch.jpg"
10++++
11+
12+![](https://media.urbit.org/site/posts/essays/orthodoxchurch.jpg)
13+
14+_One of the most striking things about Urbit is the ideological diversity between communities. The Community Spotlight blog series will focus on various Urbit communities via interviews with founding members._
15+
16+For the first week of the Community Spotlight series, I (~tirwyd-sarmes) will be speaking with Josh Reagan (~taglux-nidsep). Josh is the founder of The Portico, an Urbit community of Eastern Orthodox Christians.
17+
18+The Portico is a very active group with conversations taking place over multiple channels. There are channels for posting Orthodox iconography, discussing the broader Christian culture war, and just talking about Orthodoxy in general. Of particular interest is Josh’s “Euthyphro” blog series which investigates the relationship between logic and the Orthodox faith. This is a topic that Josh is well qualified to talk about: he has a PhD in Philosophy from Rice University. His dissertation on the epistemology of logic and truth-preservation was titled "Knowing Your Limits: Logic for Limited Beings”. Josh is also the co-author of a forthcoming textbook on formal logic.
19+
20+To read Josh’s blog is to be inducted into two esoteric traditions: theory of logic and Orthodox theology. With titles like “St. Gregory the Theologian and the Liar Paradox” and “The Existence of Abstract Objects”, Josh does not pull punches.
21+
22+Accordingly, our conversation focused on the idiosyncratic and niche community that The Portico is home to. There, you won’t find cussing or much talk about “life partners”, but you will find cutting critiques of liberalism and the best way to raise Orthodox children.
23+
24+As other users have pointed out, Urbit is pre-[Eternal September](https://en.wikipedia.org/wiki/Eternal_September). In fact, there’s some hope that the very nature of Urbit, how it tries to protect the sovereignty of niche communities via decentralization, might foil the Eternal September phenomenon. If Josh’s community persists, it will be a testament to both Josh and the decentralized Urbit network. As of now The Portico is a refreshing, perhaps jarring (as Josh might say), reminder of what the internet looked like back in the early days—a place for those who are different.
25+
26+I encourage you to take a look. Find The Portico at ~topnup-firber/the-portico.
27+
28+\-\-\-\-
29+
30+**Do you see any connection between Rod Dreher’s _The Benedict Option_ and your community on Urbit? Dreher sees a need for American Christians to create self-sustaining communities outside of the mainstream to protect the Christian religion and culture.**
31+
32+It’s tough to say with certainty—I’ve never read _The Benedict Option_.
33+
34+A few years ago, while he was writing the book, I was a regular reader of Dreher’s blog. From his descriptions there, I was never clear about what exactly he was proposing. Much of his “clarification” came by way of metaphor: don’t “run for the hills”, but stop “shoring up the American imperium”. I didn’t read his book because I didn’t have much confidence that he would be especially precise or insightful.
35+
36+[There is an interesting review I’d recommend](https://handleshaus.wordpress.com/2020/10/06/review-of-rod-drehers-live-not-by-lies/), however, of his later book, _Live Not By Lies_. I believe it accurately characterizes the scale of the threat Christians will soon face in this country.
37+
38+My upbringing was conservative Christian and self-consciously counter-cultural. I've inherited that understanding of what it means to be a Christian in an increasingly secular world. It comes naturally to me, so I find it obvious that Christians should form self-sustaining communities. But the details matter. What do such communities look like? How do we secure the freedom to pursue such communities? How do we sustain them, when myriad external forces seek to undermine them? How do we solve the long-term problem of the declining cultural importance of Christianity (which surely erodes the plausibility of our religion to many, even to some of those with sympathies toward it)?
39+
40+I don’t claim to know the answers to these questions.
41+
42+One kind of answer is that we should redouble our efforts to support and maintain a religiously and morally neutral liberal political order, which leaves room for subcultures to live and self-regulate as they wish. I disagree. Those who support a kind of “neutral” liberalism view it as an attempt to go “meta” and rise above various parochial metaphysical, moral, and religious disputes. I view this as a cop-out, a refusal to grapple with the most important questions.
43+
44+Does the liberal have metaphysically-rooted moral reasons for going “meta”? If so, then he’s just another sectarian and he should be honest about it. The only difference is that his team has had the whip hand for the last several generations. On the other hand, if the liberal claims no underlying metaphysical justification then his project can succeed only to the extent that he can arrange and adjudicate unprincipled (and therefore ad hoc) agreements between otherwise hostile moral communities. But how stable can such an arrangement really be?
45+
46+Orthodox Christians have theologically rich, metaphysical foundations for their social and moral teachings. With these we can form healthy, thriving, and growing communities. We can do so even under actively hostile political orders. If the early Church could make it under the Romans, so can we today. But it’s going to be difficult and sound judgment is necessary. Unfortunately, we lack strong leadership and that leaves us vulnerable. If we stay uncoordinated we dissipate our energies needlessly. If we latch onto the wrong leaders we can be led astray.
47+
48+The challenges are immense. There is no technological solution. Even so, I’m an Urbit early-adopter for a reason. Over the years I’ve come into contact with a number of Orthodox and Ortho-curious Urbit followers. Why not try to bring them together in an Urbit group?
49+
50+As far as I know, no one in the group is clergy. We’re all just a bunch of laymen with no authority to do much of anything. But I’d like to think we can still contribute in some way. I have an academic background in analytic philosophy so my inclination is to emphasize theory, but we have room for a bit of everything. Someone in the group wrote a script to take the texts of various Church Fathers and convert them to audio using AWS Polly. Those turned out pretty well!
51+
52+At times I entertain ambitions to do a bit more, but for now perhaps it’s better to keep expectations in check. If nothing else, we can read and discuss the Scriptures and Church Fathers together, and try to understand better how to apply and live out their teachings. As we continue to grow the community and develop a consistent internal dynamic perhaps opportunities will arise that aren’t yet on the horizon. One thing I can say is that I’m committed to keeping the group active and growing.
53+
54+**I’d like to talk about your blog on The Portico. It combines two of your main interests: logic and theology. In broad strokes, do you think theology and logic are compatible? What is the relevance of this intersection to both of these disciplines?**
55+
56+I feel obligated to answer this question in two ways.
57+
58+(1) If by “logic” you mean “first-order predicate calculus”, then I think there’s no special conflict between logic and theology. There are certain puzzles about their relationship, but similar puzzles exist between logic and other disciplines. Theology isn't especially endangered.
59+
60+For example, in the 1930s, Alfred Tarski proved his famous Undefinability Theorem. Crudely put, it says that a plausible truth predicate cannot consistently be contained in any formal system with axioms strong enough to model arithmetic. Superficially it seems like our options are (a) get rid of the concept of truth, (b) get rid of arithmetic, or (c) throw away parts of logic until all inconsistency disappears.
61+
62+None of these options is appealing. Tarski came up with a solution that mostly satisfies many logicians: reduce the concept of truth to “truth in a language” and forbid any language from containing its own truth predicate. If you want to talk about truth in a language L-1, you have to do it from a “metalanguage”, L-2.
63+
64+Is Tarski’s definition of truth in a language the definitive solution for preserving truth, math, and logic? Perhaps not many philosophers think so, and there’s a massive literature in which logicians have attempted to improve on or extend his results.
65+
66+Sometimes people seem to think formal logic is an infallible gift from heaven that must always be right. Kant said in the _Critique of Pure Reason_ that formal logic is essentially a completed field. In fact, [the logic of his day](https://en.wikipedia.org/wiki/Port-Royal_Logic) was an early-modern Cartesian variation of a medieval scholastic synthesis of ancient Stoic and Aristotelian logics. Roughly 100 years after Kant’s first critique was published, C. S. Peirce and Gottlob Frege independently discovered first-order mathematical logic as we know it today, inaugurating the greatest advance of logic since Aristotle. Kant was wrong.
67+
68+Mathematical logic is a convenient, generally reliable, man-made tool that, when used carelessly in certain untamed domains, can lead one astray. Probably most people reading this are familiar with such puzzles as the Liar paradox. When one understands that logic is not a completed science, and perhaps never will be, there is less reason to worry about whether it can be used to nuke entire disciplines, like theology.
69+
70+For more on this topic, see the blog post in my Urbit group: “St. Gregory the Theologian and the Liar Paradox”.
71+
72+(2) There is perhaps a deeper challenge than the one I’ve just sketched. The Stoics used the term “logic” to encompass what we might today call “epistemology”. If the word “logic” is meant in some such broad and normative sense, then we may restate the challenge as one about rationality and theology. Is it irrational to pursue theology in our modern age?
73+
74+As an undergraduate under the influence of Kierkegaard, I was attracted to a romantic, vaguely irrationalist notion of faith. Dawkins-mania was at its peak and I was disgusted by the pop-rationality (or was it empiricism?) of his annoying followers. Their view seemed to be that rationality just means “following the evidence”. The raw evidence is foundational, and theories are built atop by generalizing from the evidence. The ghost of logical positivism is with us even now.
75+
76+I was dimly aware that Quine and others had made it difficult to sustain epistemic foundationalism. However, being unable to supply a more clear and cogent notion of rationality, I became skeptical of the idea altogether. But I went too far.
77+
78+Instead, the proper response is to develop a superior account of rationality. Readers can probably guess where I went looking!
79+
80+The word “logic” comes from the Greek “λόγος”. This is also the word used to describe Jesus Christ in the Gospel of John: “In the beginning was the Logos, and the Logos was with God, and the Logos was God.” This connection is not merely etymological.
81+
82+For many ancients, the term “λόγος” meant something like “divine principle”. You might think of it as akin to a law of nature, but with stronger theological connotations. Christians appropriated this term and made it rather more exalted: the Logos is begotten of the Father, and yet somehow one with Him.
83+
84+We are told that all things come into being through the Logos (John 1:3), giving Him an intimate relationship to the whole of creation. He gives structure and order to all created things, and in His divinity He understands them as so structured and ordered. He is also sinless, perfectly holy, and good. In Christ we have a perfect unity of the knowledge of all truth and righteousness.
85+
86+Man was created in the image of God, which means that we bear a likeness to Christ. And we are commanded to realize that likeness with ever greater fidelity (Romans 8:29). The Church calls the pursuit of this likeness [“theosis”](<https://en.wikipedia.org/wiki/Theosis_(Eastern_Christian_theology)>).
87+
88+Thus we have the explanation of all normativity, according to Orthodox Christianity. In moral matters we must take on the holiness of Christ. In epistemic matters we aspire to the wisdom and knowledge of Christ, which includes an understanding of the whole created order. Socially we (the community of believers, i.e. the Church) are called to be in ever greater communion with God, cooperating with His work just as the Son cooperates with the Father.
89+
90+Sadly we are conceived in sin and ignorant; hence the need for redemption by Christ.
91+
92+Accordingly, my understanding of what it means to be rational is just to be Christ-like. The only perfect exemplar of reason, so construed, is Christ Himself. Any deviation from Him is irrational. What could be more logical than to be conformed to the Logos? But we cannot attain rationality without redemption. Hence we cannot become rational without first being saved from sin.
93+
94+Doubtlessly many will find all of this too much to take, just too implausible. What about the development of mathematics, or the advances of the sciences? These are canonically ennobling, intellectual achievements. Jesus wasn’t a mathematician or a scientist! Nowhere in the Scriptures is He recorded as having applied Bayes’ theorem.
95+
96+Undoubtedly my construal of rationality de-emphasizes the pursuit of knowledge by labeling it as merely one of several normative ends. To seek knowledge without seeking holiness is to be understood as dangerously unbalanced. To try to attain holiness and knowledge without communion with God is arrogant.
97+
98+On the other hand, we need not exaggerate matters. St. Paul affirms the need for specialization of labor within the Church (1 Cor. 12). There is room for some to specialize in intellectual endeavors, so long as they act in a cooperative setting in which the other virtues are pursued as well. (Nor should anyone neglect the development of such virtues in himself.) Mathematicians and physicists are more than welcome in the Church.
99+
100+According to this (all too briefly put) theory of rationality, there can be no conflict between ‘logic’ and theology. Theology is compatible with rationality because the account of rationality in question derives from a theological tradition. Naturally I’ve only given a sketch; much more could be said. But even if some readers are put off by the theory presented here, I hope it’s at least clear that there are conflicting notions of rationality. Anyone who wants to be rational confronts the task of figuring out which theory of rationality is correct.
101+
102+**In terms of community moderation, The Portico follows norms that are quite different than other online communities, often times quite drastically. For instance, living with women that you are not married to, is not something that should be talked about lightly. Can you talk about the importance of norms and how they relate to a healthy community?**
103+
104+Orthodox Christians are not commanded to “get along” with the rest of the world (John 15:18-25). We’re different, and our norms of interaction should likewise differ from those of outsiders. There is no one, monolithic “Orthodox culture”, but there are standards governing which local expressions of culture are legitimate and which are sinful. We should live in a way that enables and promotes holiness and discourages sin.
105+
106+We have rules that may seem unusual from the outside. I don’t permit profanity, lewd jokes, or irreverent comments about God. In your question you mention a living arrangement that is prevalent in the world. Another rule I have is that we shouldn’t talk causally about sinful practices or lifestyles as if they are unremarkable parts of ordinary life. If Orthodox Christianity is true then such things aren’t minor peccadilloes. They’re spiritually destructive. The marriage-bond sanctifies activities that would otherwise be sinful.
107+
108+If someone wants to analyze what is destructive about men and women living together before marriage, we’re open to that. But if you want to be affirmed in your sin, we’re not the place for you. Anyone of any religious creed is welcome to show up—but as a guest in an Orthodox Christian community. Hosts should be courteous to guests, but my first priority is not to make you feel good about your choices. We’re here to encourage each other, learn, and grow spiritually as Orthodox Christians. Naturally that means a little gate-keeping may sometimes be necessary if someone ever comes along who doesn’t share those goals. Being different is difficult and takes work.
109+
110+In a way the cultural contrast is meant to be jarring. It can force you to confront moral and cultural presuppositions that you didn’t even know you had. When you become aware of the wider choices of culture available to you, you become free to look with a critical eye on the culture you’ve hitherto taken for granted. I think anyone could see how that might be liberating, even before considering the particulars of the cultures in question. Of course, as an Orthodox Christian, I think we have a good case to make about the particulars of our subculture.
111+
112+I’ve never had to kick or ban anyone from the group. The group is relatively small (~180 people at the moment) so that probably helps. The vast majority of conversations are relaxed and friendly. Occasionally there are intense debates about one issue or another but I enjoy it, as long as it doesn’t become bitter or the primary mode of discourse. But everything ought to be done in a spirit of truth-seeking, not of one-upmanship.
113+
114+**The fact that The Portico can exist side-by-side with atheist communities on Urbit is pretty striking. On Urbit, a user is able to create niche communities and governance structures and yet still participate in a larger network. In other words, Urbit is trying to thread the needle between sameness and difference through federation at multiple levels. It seems to me that modern culture has become homogeneous due to an inability to maintain, or distinguish between, different communities. People who have nothing in common are forced to engage as if they were roommates, while those who are similar have trouble creating their own home. In other words, what is the role of community formation in the modern world and how does it connect to your critique of liberalism? Does Urbit have anything to say about this?**
115+
116+As I said in an earlier response, I see the liberal project as more or less an attempt to sidestep (not solve) difficult metaphysical and religious disputes between various distinct moral communities. Liberals have tried several methods of governance to achieve their ends. We can divide such attempts into two broad categories: centralized and decentralized.
117+
118+Social media companies in the US confront similar governance challenges, so we can analyze them in similar terms.
119+
120+A social network like Facebook takes a centralized approach. Zuckerberg spoke early and often of his desire to connect people and “bring the world closer together”. There was a sense that if people from various communities could get to know each other a little better, we would see how much we have in common and make progress toward some kind of universal cosmopolitan consensus.
121+
122+But that didn’t happen. With centralized social media you’re practically guaranteed to interact with people whose moral and metaphysical commitments are sharply at odds with your own. As a result, you face a persistent, nagging risk of conflict. Without warning, a friendly disagreement can explode into an all-out flame war. Most choose one of two basic approaches for dealing with this threat:
123+
124+(1) You live a compartmentalized life. You keep your moral and metaphysical commitments to yourself and cultivate a culturally homogenized persona for your social media activities. No one disagrees with you because there’s nothing to disagree with.
125+
126+(2) You can enlist to fight in the culture war and display your regimental colors with pride. And because you take your smartphone everywhere you’re always on the front line.
127+
128+These aren’t the only options, of course. With some combination of charisma, patience, and grace you can be relatively open about your beliefs without getting into too much trouble. But even if you have the talent to pull it off, it takes time and energy. Many of us aren’t willing to go to all that trouble. Social media is supposed to serve us, not the other way around.
129+
130+Urbit is decentralized which, in my opinion, means that it isn’t really a network in the way that Facebook is. I see Urbit as more of a network platform. The users create the networks, or migrate them in from elsewhere. We’re all using Landscape and running our VMs on Nock, so obviously there can be interaction between different communities. But anyone who doesn’t want that cross-community interaction doesn’t have to have it.
131+
132+I’ve followed Urbit’s progress since 2016, so I’m plugged into groups with other Urbit people I’ve come to know over the years. Other than that, however, I don’t know much about who’s out there. It’s not like The Portico is in one neighborhood and the atheists are in the next neighborhood over. There’s a real sense in which we’re not even on the same network—different Urbit communities share a common protocol, but a protocol isn’t a network.
133+
134+Some people may want to see a little of everything. If atheists want to join our group they’re welcome to do so! We’ll be friendly. I don’t seek out their groups, though.
135+
136+One virtue of decentralized social media is that it offers a totally different set of trade-offs with respect to how you share and act on your beliefs. What if you could talk earnestly about philosophy and religion without having to worry about alienating many of your friends and family? I guess that’s somewhat possible on Facebook—do they still have “groups”?—but Urbit was designed for it.
137+
138+Having said all that, I don’t think decentralization is a panacea. Even if Urbit takes off, it will likely face problems that are difficult to anticipate now. My hope is simply that Urbit’s trade-offs are healthier than the ones we’ve had before.
content/blog/convivial-networks.mdnew file+27
@@ -0,0 +1,27 @@
1++++
2+title = "Convivial Networks"
3+date = "2022-05-27"
4+description = "Like the relationships that we build within them, our platforms should yield satisfaction precisely because they’re non-trivial; they demand effort, which is another way of saying they require engagement with the world."
5+[extra]
6+author = ""
7+ship = "~witwyt-widlyr"
8+image = "https://media.urbit.org/blog/convivial-computers.jpg"
9++++
10+
11+![](https://media.urbit.org/blog/convivial-computers.jpg)
12+
13+In 1989, when the idea of forging a community online was still niche enough to feel like a radical dream, an essay in the inaugural issue of cyberpunk magazine Mondo2000 already had the audacity to ask: have we missed the revolution? Penned by Lee Felsenstein, the text takes stock of the potential, promised by the advent of the personal computer, for new technologies to contest control and engender greater forms of interpersonal connection. This opportunity, of course, was not a given. “If people can gain control over their own channels, and have the technological means available to do that directly”, he wrote, “then they can control their own communities.” If the revolution in question was not to be missed, then ownership and control over one’s own means of communication were central affordances of any technology that would lend itself to genuine community-building, or what Felsenstein called “convivial” interaction.
14+
15+His use of that term brings to mind Ivan Illich, whose “Tools for Conviviality” expressed the need for technology that can be grasped and reconstructed – tools of “high, independent efficiency” that a user could take responsibility for. Convivial tools are the opposite of industrial or institutional; Illich argued for making things usable and re-inserting the personal dimension into their construction. This was 1973, and he was talking about urban planning, but the resonance with Felsenstein’s point doesn’t seem so far a reach. If personal computing was indeed to offer any radical possibility, and especially any claim to agency over the ability to build and be in communities, it ought to be grounded in simple, accessible tools that we ourselves can operate.
16+
17+From a present standpoint, we could understand both Illich and Felsenstein’s texts as calls for human-scale technology. Simplicity is a central ingredient of this prescription; it’s hard to feel much ownership over something that one can’t use, manipulate, or maintain without deferring to an external expert every time something needs tinkering under the hood. In the decades since these treatises’ publication, personal computing has become totally commonplace, yet, with the elaboration of social networking and Cambrian Explosion of communication tools brought about by Web 2.0, it feels increasingly, and noticeably, less convivial.
18+
19+Why did this trajectory – and not one of “personal computing leagues” and ad-hoc hacking, of the nature Felsenstein and his _Mondo_ co-conspirators so passionately envisioned – take hold? My hypothesis is that, as [Rich Hickey](https://www.youtube.com/watch?v=SxdOUGdseq4&ab_channel=StrangeLoopConference) lays out, simplicity actually demands a lot of _work_. In a culture of convenience, the concerted and enthusiastic effort necessary to achieve real agency over our tools can, paradoxically, come across as prohibitively hard. Yet conflating accessibility with frictionlessness works to our collective detriment. The technologies capable of fostering conviviality _ask something of us_: engagement, patience, the will to understand. In our offline social lives, these are accepted as necessary labors of love: intimacy without investment is an impossible, irresponsible fantasy. To invoke the oft-quoted Simone Weil, “attention is the rarest and purest form of generosity.”
20+
21+And as we well know, in the present mediatic environment – tellingly termed the “attention economy” – the dynamics of directing our focus online are deeply broken. Is it any surprise that, on the platforms that have pioneered a business model out of stealing and selling that attention, community and conviviality feel so hard to come by? Effort, labor, and understanding are fundamental to relationships online and off. But the spaces where we’re meant to share these qualities online disingenuously sell us (or, rather, do they _buy us?_) with promises of ease that amount to empty calories, or worse.
22+
23+By removing friction from the equation (think: Log In With Facebook), they wall us in and transform our connections, conducted within their borders, into spaces of extraction. The mainstream communications platforms we have access to today are marketized to the hilt. Our interactions and the relational graphs they chart – in short, the tender data of our sociality – is made into fodder for surveillance capitalism. When nothing short of interpersonal intimacy is on the line, we ought to be very concerned with what is being occulted away in the name of convenience.
24+
25+If we want to create technologies that are conducive to meaningful community, where “engagement” is not just a quantitative metric or empty piece of advertising parlance, then, we need to re-orient our values beyond “ease of use”. Like the relationships that we build within them, our platforms should yield satisfaction precisely because they’re non-trivial; they command effort, which is another way of saying they require engagement with the world. Attention; generosity. In step with these values, I’m inspired to ask: what would a convivial social network look and feel like? Human-scale, peer-to-peer, open-source, and non-extractive are all descriptors that come to mind. You can probably anticipate where I’m going with this: a network with many of these merits exists today, ready to be used, tinkered with, and built on top of, and if you’re reading this, you’re probably familiar with it.
26+
27+Getting started on Urbit takes some work: investment in address space; effort to acquire a planet; possibly even bearing with some confusion during the booting process if you, like me, are an armchair network theorist who often shies away from the technical. But these costs are up-front, not black-boxed out of sight or hidden in an epic-length user agreement. Once it’s up and running, it even feels, dare I say, easy, though the healthy extension of my comfort zone that getting onto the network entailed – especially when I joined in November, a few months shy of the [L2 rollout](https://urbit.org/using/id/layer-2-for-planets) – sticks in my mind. It reminds me of the dynamics that have strengthened my closest relationships online and off: the ability to navigate challenges together and find a connection strengthened, not diminished, by our shared time spent swimming around in that vulnerable space of learning. By re-materializing a little bit of the friction of computing, not _gatekeeping_ but commanding effortful engagement, Urbit has created a platform that is purpose-built for conviviality.
content/blog/creating-sigils.mdnew file+172
@@ -0,0 +1,172 @@
1++++
2+title = "Creating Sigils"
3+date = "2020-02-03"
4+description = "The origin and design process informing Urbit's generative user avatar system, Sigils."
5+
6+[extra]
7+author = "Gavin Atkinson"
8+ship = "~ridlur-figbud"
9+image = "https://media.urbit.org/site/posts/essays/sigils3.png"
10++++
11+
12+<!-- ![](https://media.urbit.org/site/blog-9.jpg) -->
13+
14+![](https://media.urbit.org/site/posts/essays/sigils0-v3.png)
15+
16+One of the basic building blocks of Urbit is Urbit ID, our naming and identity system. Your Urbit ID is a short, recognizable name that’s also a network address for your Urbit OS instance. (You can find a complete, high level description of Urbit ID [here](https://urbit.org/understanding-urbit/urbit-id/).)
17+
18+Your Urbit ID is meant to feel a bit like a secret code name. It doesn’t leak any information about the real you — but it’s still memorable and recognizable. Getting an Urbit ID should feel exciting, like getting a brand new identity in a new world.
19+
20+From a design standpoint, some of this is accomplished simply by having a system for the names themselves. Under the hood, Urbit IDs are actually just numbers. There has always been an algorithm for turning these numbers into pronounceable names like `~tacryt-socryp` (13,304,832) or `~litzod` (1,280) or `~nes` (212).
21+
22+While the names are great, they’re not quite enough, especially in a rich interface. Each Urbit ID really needed some form of visual representation, image, or crest. A digital identity needs to be something you can really attach to, both yours and those that belong to your friends.
23+
24+There are 2^32^ or 4.2 billion unique Urbit IDs. Clearly there’s no way that we were going to do this by hand. And purely algorithmic solutions can often produce disappointing, undifferentiated output.
25+
26+Regardless, we set out to tackle this problem. By the end of this process, every Urbit ID got its very own ‘sigil.’
27+
28+In this post we’ll walk through how we thought about the problem, iterated through possible solutions, and the toolchain we used to arrive at the final result.
29+
30+## Background
31+
32+What are the basic primitives of a visual language? There aren’t any completely authoritative answers to this question, of course. But we knew that to produce such a large number of visually distinct items we’d need some way to reason about form that’s closer to letterforms.
33+
34+So we started by collecting influences.
35+
36+{% iframe src="https://www.are.na/tlon/seal-zp3irwad52y/embed" className="arena-iframe" width="100%" /%}
37+
38+The ‘chop’ or [seal](<https://en.wikipedia.org/wiki/Seal_(East_Asia)>) is conceptually pretty close to what we wanted to get to.
39+
40+<br /><br />
41+
42+{% iframe className="arena-iframe" src="https://www.are.na/tlon/kamon/embed" width="100%" /%}
43+
44+[Kamon](<https://en.wikipedia.org/wiki/Mon_(emblem)>) are even closer — especially since they have very little visual complexity.
45+
46+<br /><br />
47+
48+{% iframe className="arena-iframe" src="https://www.are.na/tlon/grids-jd_xbmspxkm/embed" width="100%" /%}
49+
50+We also spent a good amount of time with both Anni Albers and Agnes Martin. Both of these painters had an incredible mastery of the grid as a means of creating engaging visual work. These paintings all have a wonderful tension between an underlying system and their specific expression.
51+
52+<br /><br />
53+
54+{% iframe className="arena-iframe" src="https://www.are.na/tlon/stella-xfroicotm_4/embed" width="100%" /%}
55+
56+Frank Stella is a master at producing incredibly dynamic work from only a few elements. His ability to create a sense of depth from simple overlapping elements is fantastic.
57+
58+<br /><br />
59+
60+{% iframe className="arena-iframe" src="https://www.are.na/tlon/ledoux-palladio/embed" width="100%" /%}
61+
62+The plans of both Ledoux and Palladio are incredibly dynamic. They’re mostly gridded, use only a few elements, and use lots of symmetry — but they’re at once distinct, engaging, and fresh.
63+
64+<br /><br />
65+
66+{% iframe className="arena-iframe" src="https://www.are.na/tlon/flags-k9moxiayuvq/embed" width="100%" /%}
67+
68+Another influence: international maritime signal flags. We like these not only because of their striking visual qualities, but also because they correspond with a letter system, just like our sigils. Each one conveys useful information; for example, “Keep clear of me; I am maneuvering with difficulty,” a flag we all feel like raising from time to time. This influence was key to the idea that pairing symbol to phoneme was a possibility.
69+
70+You can see the whole collection of our visual research [here](https://www.are.na/tlon/2019-sigils-research).
71+
72+Ultimately, we didn’t specifically draw on any of these influences very consciously. The goal of visual research is to get a sense of the territory, what has been tried, and what works. We think these threads of prior work are evident in the final result — you can _feel_ them, but it’s tough to point to them individually.
73+
74+## What’s in a name?
75+
76+> _“Lev’s sigil appeared, strobing, as Netherton was getting out of the cab in Henrietta Street. “Yes?” Netherton asked.”_
77+>
78+> **— William Gibson, The Peripheral**
79+
80+Before we get to how we worked through the problem of actually designing these things, let’s talk about the problem of naming.
81+
82+We went through so many names for these things. Crest, symbol, seal, tag, pictograph, stamp, emblem, signet, icon, glyph, holomark, visage, radigy, pattern, the list goes on for an incredibly (embarrassingly) long time. We argued about this, we went back and forth about it.
83+
84+Sigil won, ultimately, because of the way that it’s personified in William Gibson’s _The Peripheral_. In the far future, characters talk to each other by some kind of telepresence. When a call comes in from someone else, they first appear as a ‘sigil.’ It’s a strange word, but we were imagining a similar use-case.
85+
86+While we can’t point to any specific parts of our visual research that reappear directly, sigil is lovingly borrowed.
87+
88+## Experiments + iterations
89+
90+So, how did we actually end up making these things?
91+
92+We iterated through plenty of possibilities before landing on our final approach. Let’s walk through the two we remember best.
93+
94+<br /><br />
95+
96+![](https://media.urbit.org/site/posts/essays/sigils1-v2.png)
97+
98+The first attempt was a series of images in the style of Karel Martens. Overall this technique was just too cluttered and sometimes difficult to parameterize in a predictable way. We kept iterating.
99+
100+<br /><br />
101+
102+![](https://media.urbit.org/site/posts/essays/sigils2-v2.png)
103+
104+Just like the previous example, the main idea was that we could take a set of geometric primitives, combine them, then alter their appearance along a set of parameters, like color, rotation, and size.
105+
106+But also just like the previous attempt, the technique of overlapping symbols made the images too difficult to read and differentiate. We wanted to create sigils that were not only great to look at, but visually ordered. Since overlapping elements didn’t seem to quite hit the mark, on we went.
107+
108+## Closing in
109+
110+Eventually, we realized: tiles! With tile designs there are no overlaps, which in early experiments immediately started to take on the consistent, legible appearance we were after. Each element is discrete and clearly visible. Tile designs were also easier to create and control from an implementation standpoint.
111+
112+Best of all, tiles made it clear that we should be thinking in terms of creating representations of individual syllables rather than entire names. Urbit IDs are constructed from two sets of 256 three-letter syllables. `~fallyn-balfus` is `fal` `lyn` `bal` `fus`, for example. (There are two syllable sets in order to prevent duplicates — we always alternate between the two when composing names.)
113+
114+Thinking in terms of syllables greatly reduced the complexity of the problem, but there was still some work to do.
115+
116+<br /><br />
117+
118+![](https://media.urbit.org/site/posts/essays/sigils3-v2.png)
119+
120+At first, we thought about using a 4 x 4 tile grid, as shown here. These designs were tricky to implement because of the detailed lines and arcs spanning across individual tiles. In order to generate a result that matched these mockups, a program would have to generate a data model that knew about which tiles touched which other tiles.
121+
122+We felt this was too complicated and had an unknown performance profile. Plus, they proposed a deterministic color scheme and we felt strongly that color is personal, not to mention hard to parameterize. In the end we thought it better to create something that had the potential for user customization.
123+
124+<br /><br />
125+
126+![](https://media.urbit.org/site/posts/essays/sigils4-v2.png)
127+
128+Around this stage, we were thinking a lot about how architectural plans aren’t unduly constrained by the fact that they’re only one color. We had a feeling we could make the grid smaller and assign details to the tiles individually.
129+
130+<br /><br />
131+
132+![](https://media.urbit.org/site/posts/essays/sigils10-v3.png)
133+
134+So, we scaled it down to a 2 x 2 grid and stuck with it. It’s simple to implement, visually unique, consistent, and the color scheme is black and white, leaving room for user customization. We felt we had reached a semblance of a final result. Now all we had to do was manually draw 512 unique but consistent individual ‘phonemes’.
135+
136+<br /><br />
137+
138+![](https://media.urbit.org/site/posts/essays/sigils5-v2.png)
139+
140+As it turns out, drawing 512 consistent, abstract elements by hand isn’t easy. We had to strike a balance between authorship and automation — we wanted each tile to look well-made, but not too authored. To do so, we took advantage of Figma’s web API which helped us design in SVG but iterate programmatically.
141+
142+## Final process
143+
144+![](https://media.urbit.org/site/posts/essays/sigils6-v4.png)
145+
146+We took a look at our hand drawn mockups and drew each individual visual building block of the tiles separately. Then we loaded the SVG elements into a script that programmatically combined them to create trillions of layered symbols. This way, we were able to easily select candidate phoneme symbols that worked visually.
147+
148+We eventually added a rule system to find higher quality phoneme symbols — but this combination of programmatic generation and hand selection was working pretty well.
149+
150+<br /><br />
151+
152+![](https://media.urbit.org/site/posts/essays/sigils7-v2.png)
153+
154+The final step, using the tool we built, was to hand select individual phoneme symbols and create a complete index.
155+
156+<br /><br />
157+
158+![](https://media.urbit.org/site/posts/essays/sigils8-square-v2.png)
159+
160+This allowed us to start looking at possible combinations and selecting phoneme symbols based on their interplay with others.
161+
162+Once we had selected the final set, we went about compiling the `sigil-js` library that’s now publicly available. This turned out to be fairly technically complex due to the different ways SVG is handled between browsers and Figma — but the end result is a single Javascript library you can use to embed an SVG in almost any context on a web page. See it in action and browse the available sigils [here](https://sigil.azimuth.network). If you're technically inclined, the [source](https://github.com/urbit/sigil-js) can be found on GitHub.
163+
164+<br /><br />
165+
166+![](https://media.urbit.org/site/posts/essays/sigils9.png)
167+
168+We think sigils are pretty successful. They look nice in our native Urbit interfaces, people have made them into shirts and posters and cards, even laser-cut them to make stamps.
169+
170+Urbit ID and the sigils are components of Urbit that are totally separate from the OS — you can use them on their own and potentially even extend their functionality. We’re happy with what we’ve done with them so far, and hope that people will experiment with what’s possible with this naming and identity system.
171+
172+![](https://media.urbit.org/site/posts/essays/sigils11-v2.png)
content/blog/desire-lines.mdnew file+35
@@ -0,0 +1,35 @@
1++++
2+title = "Desire Lines to a New Internet"
3+date = "2022-05-06"
4+description = "As more DAOs, NFT and digital communities find their way to Urbit, others are likely to follow their paths, making them their own, just like the network itself."
5+[extra]
6+author = ""
7+ship = "~dalwes-migdec"
8+image = "https://media.urbit.org/blog/desire-lines.jpg"
9++++
10+
11+![](https://media.urbit.org/blog/desire-lines.jpg)
12+
13+The beginning of a migration is usually imperceptible. First comes discontent, then comes the decision to either stick with inadequate, but familiar circumstances or to try something new and foreign. Eventually, someone makes the jump. A few others join. Then, seemingly all at once, a rush precipitates a trend, signaling the migration's final wave before broad and broader adoption.
14+
15+By now it's obvious that the tooling web3 communities and DAOs rely on day-to-day are, at best, deficient. Pointing this out verges on parody. Still, stuck between a disjointed terrain of engagement-oriented apps and data-harvesting services, where are these newly nomadic syndicates supposed to go? If you spend more than ten minutes on Twitter, reading the same canned takes on digital itinerancy, you will come across a variety of answers, and the figureheads of several recently incorporated Delaware LLCs claiming to be building the OS for web3. Some of these endeavors appear promising, to be sure, but none are more mature or as [well-positioned](https://datnut-pollen.discordja.net/discordja/giving-daos-a-brain) to satisfy this need than Urbit. A few communities are already on the network and [thriving](https://urbit.org/blog/urbit-for-creators), and another swell is approaching.
16+
17+To understand why Urbit is so appealing for web3 communities, start by examining the principles that motivate its development. Ownership of data, durability, and digital sovereignty underpin the entire project, from its earliest days to its present, evolved form. Without ownership, your tools control you more than you control them. Without built-in longevity, your tools can't be easily passed from one generation to the next, which is the premise of Urbit's technological page one rewrite. (For those interested in learning more about Urbit's clean slate stack, you can read documentation [here](https://urbit.org/docs).) Finally, without sovereignty, you're powerless to the whims of a centralized stronghold of corporate and bureaucratic control.
18+
19+As an open source peer-to-peer network, Urbit offers communities the reliability absent elsewhere in the ecosystem, and the assurance that there will never be surreptitious terms of service changes, nor shareholders to appease. By design and in spirit, Urbit is the only viable alternative to the hodgepodge of competing chat rooms, voting services, blogs, and wallets presently available. Building dapps that supplant these services ultimately leads to similar impractical quandaries. Every dapp requires that a server be online, in a friendly jurisdiction, for you to be able to access its interface and once you access its interface, a dapp can't store any data about you that isn't on a (slow) public blockchain. Why can't a dapp wallet show you all of your assets, your transaction history, and all the contacts you trade with? Because running and operating the necessary server is at odds with the premise of a dapp.
20+
21+An Urbit app retains its decentralized integrity while providing the ability to share data between apps, run regular computation, and call out to the blockchain as needed—all on a cohesive platform. Fundamentally, Urbit is yours: to own, to customize, to turn into a digital home. When more communities ditch the dance between MEGACORP-operated servers and create new homesteads on Urbit, it gets significantly easier for others to mirror their steps and relocate themselves.
22+
23+Communities that find their way to Urbit are essentially traversing desire lines, taking paths that "emerge gradually and organically, almost of their own accord" as [described](https://books.google.ca/books?id=mW7RCwAAQBAJ&pg=PA3&dq=%2522christopher+alexander%2522+organically+%2522paths%2522&hl=en&sa=X&ved=0ahUKEwjN7dqN6fbPAhUqr1QKHTB9BBsQ6AEIHjAA%23v=onepage&q=%2522christopher%2520alexander%2522%2520organically%2520%2522paths%2522&f=false#v=onepage&q=%2522christopher%2520alexander%2522%2520organically%2520%2522paths%2522&f=false) by the late architect Christopher Alexander. Before Urbit's [L2 launched](https://urbit.org/blog/layer-2-guides), distributing a tranche of planets to community members would have been cost prohibitive. Now that it can be done, and done simply, planet activations are rapidly increasing, [doubling](https://twitter.com/jmrphy/status/1517533689118306304) in the last two months. Desire lines to Urbit exist as invitations for the next community, to pass over, and to make their own, just like the network itself.
24+
25+The limitations of operating on the clearnet appear to be at long last irrevocable. Multiple desire lines to Urbit are materializing concurrently. Remilia Collective, aka Remco, aka the creators of Milady, has been [vocal](https://blog.remilia.org/urbit-with-port/) about the network for quite some time, but more community members than ever have onboarded as the result of a [headless](https://twitter.com/TheCombineDAO/status/1514000804235120644), [grassroots](https://twitter.com/hastuc_dibtux/status/1514031235135377421) collaboration between Urbit maximalists and miladies.
26+
27+DAO tooling is also proliferating on Landscape, Tlon's interface for navigation on Urbit and a platform from which developers can release apps directly to users with minimal effort. [Holium](https://www.holium.com), a team working specifically on unifying the DAO tech stack, released a ballot app last month that allows for flexible voting, delegating, and result-related actions. [PointDAO](https://pointdao.notion.site/pointdao/Point-DAO-bc8fc478b67a49ac92358a2a40d77d35), a collective of more than two hundred people that owns a galaxy, serves as a prototype for other communities to crowdfund purchases of Urbit address space—a procedure that they are aiming to make replicable and scalable.
28+
29+Growing your own society on Urbit can be as straightforward as using ownership of one token as the prerequisite for claiming another token (in other words: token gating a token). The Urbit Foundation just funded a [grant](https://urbit.org/grants) that simplifies the process of deploying Urbit IDs via another NFT's minting. Development is still ongoing, but [Dusko](https://dusko.world), the NFT project that received the grant, did a trial run last week to coincide with the release of a fresh batch of character pfps. For each mint, the collector could [custody](https://www.mintdusko.world) their very own planet—all authenticated via Metamask. (To track their progress, join [~panrut-ragbyl/dusko](https://urbit.org/groups/~panrut-ragbyl/dusko).) Dusko's approach represents the first desire line of its kind, and other communities are likely to take their path.
30+
31+The adage goes something like as soon as you notice a migration is underway, you've already missed the boat. But there's no boat to miss because an overabundance of communities could never exist on Urbit—it's as vast as it is cozy. Angling to get your community onboard? Share planets with a NFT-based community using Valve, the distribution mechanism Dusko is working on, or apply to build your own version. Crowdsource the funds for a star. Set up your group and send out a [flare](https://tirrel.io): everyone else will follow.
32+
33+
34+
35+
content/blog/eliza.mdnew file+46
@@ -0,0 +1,46 @@
1++++
2+title = "Eliza"
3+date = "2021-02-22"
4+description = "Building things, even Calm™ things, makes noise."
5+
6+[extra]
7+author = "Christian Langalis"
8+ship = "~pindet-timmut"
9+image = "https://media.urbit.org/site/posts/essays/valleys.jpg"
10++++
11+
12+![valleys](https://media.urbit.org/site/posts/essays/valleys.jpg)
13+
14+## The Storm before the Calm
15+
16+Building things, even Calm™ things, makes noise. George Nakashima’s wooden furniture evokes peace, but its construction still begins with a chainsaw. We mention this because we’re firing up our newest power tool.
17+
18+We call her Eliza. She is a data-collection robot.
19+
20+Hang on. An AI? Harvesting my data? Spying on me? Flooding me with spam? This is Urbit, right? Let us tell you about our new friend in basic terms, where MEGACORP might otherwise deploy legalese.
21+
22+## What Eliza is and isn’t
23+
24+> Replicants are like any other machine - they're either a benefit or a hazard. If they're a benefit, it's not my problem.
25+>
26+> **Rick Deckard**
27+
28+Let's start with the benefits. Eliza is a simple chatbot. She was made to collect feedback on Landscape. She asks direct questions about peoples' usage of Urbit, records any responses, and reports them to her managers at Tlon. She'll also provide timely advice and information to ships kind enough to chat with her. She'll begin reaching out to ships via DM in the coming month. If you don't want to, just say no, and you'll never hear from her again.
29+
30+Finding bugs is critical to Urbit's rapid development, especially in this period of nascency. Most Urbit-related frustrations go unreported; regular folks don't think to open up Github when they experience a minor issue. That's why it's incumbent upon us to design a lower-friction forum for feedback. People who aren't comfortable filing an issue might be willing to talk to a friendly chatbot.
31+
32+Now, about hazards. By design, there are few. Eliza runs on Tlon's comet, not on your planet. There will be no OTA to install `%eliza-bot-store` on everyone's ships. Eliza learns things through conversation, not hidden surveillance software. Data she requests, like the text output of our network analytic tool, `+tally`, must be sent manually. MEGACORP tends to cut this corner; to refine their products, they just track your reactions in real-time.
33+
34+Since she's [open-source](https://github.com/urbit/urbit/blob/b0c1f83287cbf4c85847a9238d9f4be17e1fcb33/pkg/arvo/app/eliza.hoon), anyone can creatively deploy Eliza. Just write her a dialogue tree. Of course, that also means we can't keep people from misusing Urbit bots. We think automated agents on the Urbit network are inevitable, so let's create a good baseline culture around them. (Much love to Tendiebot, who's serving up stock prices in `~tomdys/wall-star-bets`.) However, once Urbit is used world-wide, we can't rely on culture alone.
35+
36+## A New Internet Economics
37+
38+The sum of Urbit's architectural design is a new online economics: a way to finance and monetize access to internet infrastructure where people retain maximum equity. Explicitly acquire a low-maintenance, low-cost server. Use it to compute explicit things. Return to life.
39+
40+We all know the basic MEGACORP business model: offer a free service (to suckers who don't own a server), secretly mine the data they generate on the (addictive) platform, then sell targeted ads to advertisers. This model will not survive Urbit. The ubiquitous personal server changes the economic equation. You used to 'pay' for an experience with your time and data. On Urbit, once you purchase core internet infrastructure, it's yours.
41+
42+So, can Urbit meaningfully curtail our world's appetite for data? We'll see. Post-enlightenment society runs on instrumental reason, right down to the last byte. Marketers will always want a fresh dataset. However, when the goods are on your Urbit, you can at least demand the respect you deserve. Long term, we expect a transparent market for data, not an opaque "agreement". An analytics company wants to track everything you see and do on Urbit? They better be paying well.
43+
44+Eliza doesn't pay respondents. Her collection is a charity to Urbit's developers. (We're also still busy enabling payments on Urbit with the Bitcoin wallet.) However, her presence is not a term of service either. In a few years, by the nth time some smart aleck uses Eliza's chatbot code and conjures 'Zalexa' to attempt an intrusion upon your Calm™, we will see the economics of Urbit's architecture suddenly vivify. Blacklists, reputation systems, and, eventually, even data markets, all Urbit primitives envisioned long ago, will become real. We won't need Zoogle to underwrite a spam filter for the entire internet; the scarcity of Urbit address space, in tandem with a true web-of-trust, handles that.
45+
46+If Urbit is to be used worldwide, the old system will not go down without a fight. Spammers, spies, and digital robber-barons will hunt for ways to game Urbit. Our passage out of the digital gutter is beginning in earnest, and we are thrilled to put our new architectures to the test.
content/blog/events-series.mdnew file+53
@@ -0,0 +1,53 @@
1++++
2+title = "Urbit Events Series"
3+description = "These events are an opportunity for Urbit contributors to share real-time updates that don’t make it into this blog, and for the community to get to know the contributors (and one another)."
4+date = "2020-10-29"
5+
6+[extra]
7+description = "These events are an opportunity for Urbit contributors to share real-time updates that don’t make it into this blog, and for the community to get to know the contributors (and one another)."
8+author = "Lane Rettig"
9+ship = "~naplet-hildec"
10+image = "https://media.urbit.org/site/posts/essays/bau.jpg"
11++++
12+
13+![people gathered](https://media.urbit.org/site/posts/essays/bau.jpg)
14+
15+_TL;DR: Urbit is launching a series of community events, the first of which is a developer call taking place on Thursday, November 5 at 9am PT. [Sign up here](https://www.meetup.com/urbit-sf/events/274279522/), and read on for all of the details._
16+
17+--
18+
19+If you’re familiar with the project, you’ve probably noticed that Urbit folks talk a lot about the fact that [Urbit is for communities](https://urbit.org/blog/urbit-is-for-communities/). This is central to what Urbiteers believe: Urbit is a platform that any group of people should be able to use to build, communicate, and transact in precisely the way that makes sense to them. Today, Urbit is already capable of facilitating many of these activities, and it’s already a big part of the daily workflow for many people. I think we’re off to a pretty good start, and over time Urbit will become accessible to more communities.
20+
21+Something we tend to talk less about is the fact that Urbit itself is also a community. If you’ve spent any amount of time hanging out in Landscape in the Urbit Community group, you already know this—but getting to know the community takes time and effort.
22+
23+One of the reasons you don’t hear about the Urbit community as much is that community is difficult to pin down: you'd be hard-pressed to put "the community" into a room together. It's a weird, fuzzy notion and doesn't have clear boundaries.
24+
25+Other parts of Urbit do have clear boundaries. If you decided to learn more about Urbit, chances are you started by reading the docs. You might learn about [Nock](https://urbit.org/docs/tutorials/nock/), [Hoon](https://urbit.org/docs/glossary/hoon/), and [Arvo](https://urbit.org/docs/glossary/arvo/). You might get an [Urbit ID](https://urbit.org/understanding-urbit/urbit-id/) and [launch your own ship](https://urbit.org/getting-started/). These things are all pretty well documented and, while not necessarily easy, their respective processes are relatively straightforward and [getting easier](https://urbit.org/blog/hosting-the-future/) every day. Community is less well documented. It’s more difficult to document—it’s something you just have to experience.
26+
27+We lead with technology because it’s what we’re good at and because it’s easier to write about. But the social side of Urbit is no less important. Since so many of us are working on and contributing to Urbit in order to solve our own problems, and since we’re dogfooding as we go, you could define Urbit as the minimal technological infrastructure needed to sustain the Urbit community. It’s circular, but it’s as good a definition of Urbit as you’re likely to find. For this reason, you can’t really understand Urbit without some degree of exposure to the cultural knowledge of its community. When the Urbit community did fit in a single room together, transmitting cultural knowledge was easy and happened over pizza and beer. As the number and diversity of Urbit stakeholders continue to grow, we need to find ways to scale the transmission of this cultural knowledge.
28+
29+One way that seems to work well is getting everyone together once in a while for events. Over the last few years, I and others in the community have collectively attended hundreds of community events, virtually and in person around the world, from small developer chats to massive, global developer conferences with thousands of attendees. Urbit has even hosted [a few of our own](https://www.meetup.com/urbit-sf/).
30+
31+As a newcomer to the Urbit community I recently found myself seeking exposure to cultural knowledge. I know from experience attending and organizing events in other communities that regular events are a good way of making this knowledge more accessible, and of helping newcomers like myself onboard. I applied for [a grant](https://grants.urbit.org/proposals/1751024973) to bootstrap a new event series, and I’m excited to announce that this series is launching next week with the support of [urbit.org and the grants program](https://urbit.org/blog/first-steps-towards-urbit-org/).
32+
33+The event series has three components. The first is a series of developer calls. These will be shorter and more narrowly focused on the technologies that underpin Urbit, from the top of the stack to the very bottom. They’re an opportunity for the people developing and contributing to Urbit to share their knowledge and expertise, including things that typically don’t make it into the docs, such as how and why Urbit works the way it does. It’s recently become much easier to build applications on top of Urbit, so I hope these events will help developers see what sort of things they can already use Urbit to build, and how to get started. These events are also an opportunity for Urbit contributors to share real-time updates that don’t make it into this blog, and for the community to get to know the contributors (and one another!).
34+
35+The first developer call will take place on Thursday, November 5 at 9am PT, and you can [sign up to attend here](https://www.meetup.com/urbit-sf/events/274279522/). The second call will take place two weeks later on Thursday, November 19, and we’ll continue holding these calls about every two weeks.
36+
37+The second component is a larger Town Hall event to take place on Thursday, December 17. The Town Hall will feature multiple speakers and will cover topics including technology but also design, community, and our overall progress towards our vision for Urbit. You can think of it as part show and tell, part “State of the Network,” part meet-and-greet.
38+
39+The third component is a larger conference, tentatively called UrbitCon, to take place early next year. This event is still in a conceptual phase. It’ll be an opportunity for the global Urbit community to celebrate how far the project has come, to share technical as well as cultural knowledge, and, maybe most importantly, to hang out together and have some fun as well. Watch this space for more information on the Town Hall and UrbitCon.
40+
41+Collectively, these events allow the community to achieve several goals. Firstly, they’re a great way for community members to meet one another, exchange cultural knowledge, and share what they’re working on. Events provide excellent motivation to get something that’s a work-in-progress to a state where you can share it with others!
42+
43+Secondly, the content from these events will be recorded and published, and will form the cornerstone of a new knowledge base on urbit.org that will augment existing documentation. This will make it much easier for newcomers, even those that can’t attend the events live, to benefit from the wealth of knowledge and expertise of the Urbit community.
44+
45+Finally, these events are a great opportunity for community members to contribute things other than code. While Tlon will provide speakers for the first few events of the series, it’s important to emphasize that the initiative is entirely community-led and that we’ll need lots of help to organize and host events. If you’re interested in helping out with any of the events in the series, please find me and others helping out with events on Landscape in the Urbit Community group (the channels called “Events Series”).
46+
47+They say that a project’s community has reached critical mass when new things are happening that even the project’s earliest and most active contributors aren’t aware of. By this standard, the Urbit community reached critical mass sometime in the past few months, as even core team members tell me they’re regularly surprised to learn of another new project or initiative launched by a community member.
48+
49+Tlon could no longer catalog the Urbit community even if it wanted to. This is a good thing. As Tlon [has also said](https://urbit.org/blog/hosting-the-future/), it’s natural that Tlon and Urbit drift apart a bit over time. Just as Urbit itself is self-hosted, so the community, over time, should become self-hosting: it should play a more active role in shaping the future of the project. A community-run event series can be an important catalyst for this trend. I’m looking forward to the first event, and I hope to see you there, and at many events to come.
50+
51+--
52+
53+_Sign up to attend [the first event](https://www.meetup.com/urbit-sf/), and join the channels called “Events Series” on Landscape in the Urbit Community group to get involved._
content/blog/first-contract.mdnew file+289
@@ -0,0 +1,289 @@
1++++
2+title = "Azimuth’s First Contract Upgrade"
3+date = "2021-06-04"
4+description = "Galactic Senate makes first concrete action"
5+
6+[extra]
7+author = "Jonathan Paprocki and Mark"
8+ship = "~datnut-pollen and ~palfun-foslup"
9+image = "https://media.urbit.org/site/posts/essays/land3.jpg"
10++++
11+
12+![milestone](https://media.urbit.org/site/posts/essays/land3.jpg)
13+
14+Recently, the [first upgrade](https://github.com/urbit/azimuth/pull/35) to the
15+[Azimuth](/docs/glossary/azimuth) smart contracts which make up Urbit ID was
16+put up to an [upgrade proposal vote](/docs/glossary/upgrade) by the
17+[Galactic Senate](/docs/glossary/senate). This vote is still open and will
18+last for 30 days (June 20th) or until an absolute majority is reached. We’d like
19+to take this opportunity to discuss two things. [First](#changelist), what the
20+proposed changes are, and [second](#senate), a review of how Urbit governance
21+works and where we’re at in the decentralization process.
22+
23+Before we dive into what the proposed changes are, let’s review what the Senate
24+is actually capable of changing. Urbit ID is really two sets of smart contracts:
25+Azimuth and [Ecliptic](/docs/glossary/ecliptic). Azimuth is the data of the
26+public key infrastructure - roughly, this is the list of
27+[ships](/docs/glossary/ship) and which Ethereum addresses own them, along
28+with other data such as networking keys and sponsorship status. The Senate has
29+no ability to touch this data directly. This is in direct contrast to all
30+existing centralized services, where your account is always at risk of being
31+taken away from you. What the Senate can change is Ecliptic, which is the
32+“business logic” that decides how you can interact with the data in Azimuth.
33+These are mechanisms such as what powers various
34+[proxies](/docs/glossary/proxies) have, how stars/planets are released over
35+time, and how sponsorship works. Put another way, the data and database format
36+must remain the same, but the rules by which we interact with it may change
37+according to the governance rules we [detail below](#senate).
38+
39+## Changelist {% #changelist %}
40+
41+The Galactic Senate is voting on the following changes to Ecliptic:
42+
43+- Fixed ERC721 compatibility
44+- Self-modifying proxies
45+- Upgraded Claims contract
46+
47+### Fixed ERC721 compatibility
48+
49+In Ecliptic, the contract includes various functions and events
50+that make it conform to the ERC721 (non-fungible token) standard. However, two
51+events have [ever so slightly
52+non-confirming](https://github.com/urbit/azimuth/issues/8) descriptions. This
53+causes Ethereum explorers like Etherscan to incorrectly recognize Azimuth as
54+ERC20 (fungible token), rather than ERC721.
55+
56+The proposed change simply modifies the event descriptions to accurately match
57+the ERC721 definition. This does not affect any functionality within the
58+contract itself.
59+
60+### Self-modifying proxies
61+
62+Owners of Azimuth assets are allowed to configure "proxy addresses" for those
63+assets: Ethereum addresses allowed to act "as" the owner, but only for a subset
64+of operations. For example, setting the management proxy will let you change
65+your networking keys and sponsor using that address, just like your ownership
66+address can. This is useful for keeping the ownership keys in very cold storage
67+while still letting you perform lower-value operations.
68+
69+Currently, only the ownership address is allowed to change proxy addresses.
70+Fairly early on after Azimuth's deployment, we realized it might be nice for
71+proxies to be able to change themselves.
72+
73+This means that, in addition to being able to configure networking keys and
74+sponsorship, your management proxy would be able to assign a new management
75+proxy. This would allow you, or a trusted third party holding your management proxy,
76+to rotate your proxy keys without needing to take your ownership keys out of cold
77+storage.
78+
79+### Upgraded Claims contract
80+
81+[The Claims
82+contract](https://github.com/urbit/azimuth/blob/master/contracts/Claims.sol)
83+lets asset managers associate various "claims" with their identity. For
84+example, an Ethereum address to send donations to, or proving ownership of a
85+Twitter account.
86+
87+For ease of use by off-chain tools and services, the contract emits events
88+(notifications) whenever any claims are updated. However, the current version of
89+the contract has a bug where it does not emit events when all claims are removed
90+at once (clearClaims()). This "gap" in the event stream makes it much more
91+difficult to write off-chain tools around this contract. Considering Claims has
92+seen [practically no
93+use](https://etherscan.io/address/0xe7e7f69b34d7d9bd8d61fb22c33b22708947971a#events)
94+since it was first deployed, it should not be a problem to simply start over
95+fresh with a new contract that contains [the
96+fix](https://github.com/urbit/azimuth/pull/32) for the described bug.
97+
98+The reason we must do an Ecliptic upgrade to switch to a new Claims contract, is
99+that it is tied in with the logic for transferring an asset. If an asset is
100+flagged for "reset" (common when transferring to/from someone other than
101+yourself), its configured proxies, networking keys and claims are cleared during
102+transfer. As such, Ecliptic will need to know about the address of the new
103+Claims contract.
104+
105+## Urbit Governance {% #senate %}
106+
107+![geology](https://media.urbit.org/site/posts/essays/b1.jpg)
108+
109+The ultimate goal of Urbit is to become a digital republic manifested as a peer
110+to peer network owned and controlled by its users. The goal of Tlon, then, is to
111+become one of many companies who build products for Urbit rather than being the primary
112+driving force behind its development. We’d like to take this opportunity to
113+spell out our perspective on where we’re at in that process. Here are some previous posts that are relevant, but please note that
114+some of them are several years old and as such may not accurately reflect our
115+current position, but still serve as useful historical markers. We hope to
116+revisit and refresh these documents soon.
117+
118+- [2016.5.16 - Interim
119+ Constitution](/blog/interim-constitution)
120+- [2016.5.16 - The
121+ Urbit Address Space](/blog/the-urbit-address-space)
122+- [2016.6.24 - The DAO as a Lesson in Decentralized
123+ Governance](/blog/the-dao-as-a-lesson-in-decentralized-governance)
124+- [2019.1.11 - Governance of
125+ urbit.org](/blog/governance-of-urbit)
126+
127+### Galactic Senate
128+
129+The Galactic Senate is composed of all [galaxy](/docs/glossary/galaxy)
130+holders, which at present consists of more than 100 individuals and a few
131+organizations, including Tlon and the Urbit Foundation. Using the Azimuth
132+voting contract, the Senate can present and vote on two kinds of proposals:
133+[document proposals](/docs/glossary/docvote) and [upgrade
134+proposals](/docs/glossary/upgrade). Thus far, all matters which the Senate
135+has voted on have been document proposals. The [most recent
136+vote](https://github.com/urbit/azimuth/pull/34) declared the Urbit network as
137+(i) being secure (as confirmed by a [third party
138+audit](/blog/security-audit)) and (ii) having reached continuity (as in, no
139+further [network breaches](/docs/glossary/breach) are expected). Previous votes
140+were to declare that [Azimuth is live](https://github.com/urbit/azimuth/pull/25)
141+and that [Arvo is stable](https://github.com/urbit/azimuth/pull/24).
142+
143+### Address space distribution
144+
145+Perhaps the most informative measure of how decentralized Urbit is in terms of
146+how many independent parties hold address space. By the very nature of Urbit, it
147+is impossible to know this with great accuracy (a common feature of
148+decentralized projects). However, the movement of galaxies is closely watched
149+and thus we have a fairly good idea of how distributed they are.
150+
151+In the beginning, Urbit’s creator Curtis Yarvin was in possession of the entire
152+address space - all 256 galaxies, and everything underneath it. A network of one
153+is no network at all, and so over the last decade Urbit’s development has been
154+primarily driven by selling or giving away these galaxies. On [June 1,
155+2016](/blog/the-urbit-address-space), the allocation was:
156+
157+> 95, to the Tlon Corporation. 50, to urbit.org, the future community
158+> foundation. 40, to Tlon employees and their family members (24 to Curtis, who
159+> started in 2002; 16 to everyone else, who started in 2014). 34, to outside
160+> investors in Tlon. 37, to 33 other individuals, who donated to the project,
161+> contributed code or services, won a contest, or were just in the right place
162+> at the right time.
163+
164+Since then, Tlon has sold a number of
165+its galaxies to fund development and others have changed hands to the point
166+that Tlon and urbit.org no longer possess a majority share of galaxies. In
167+January 2019, [Curtis gave all of his galaxies](/blog/a-founders-farewell) to
168+Tlon when he left the project. In August 2020 we shared an update on the [known
169+distribution of address space](/blog/value-of-address-space-pt3), where
170+Curtis’ galaxies are marked as Tlon’s “naked galaxies”. Shortly thereafter, Tlon
171+disbursed its naked galaxies among the employees that wanted one who did not
172+already possess one, thus removing Tlon and urbit.org’s controlling share of the
173+Senate. Galaxies held by current and former Tlon employees are entirely
174+independent of Tlon Corporation—they may do with them, and vote with them, as
175+they please. `~ravmel-ropdyl` plans to give more color to this decision in the
176+near future.
177+
178+Distribution of stars is much more difficult to know. There is an active market
179+for stars on [OpenSea](https://opensea.io/collection/urbit-id), so we know that
180+they are changing hands frequently, but checking the number of distinct Ethereum
181+addresses that hold stars does not tell you very much information since a single person can control multiple adresses.
182+
183+### Software and smart contracts
184+
185+As was written in [The DAO as a Lesson in Decentralized
186+Governance](https://urbit.org/blog/the-dao-as-a-lesson-in-decentralized-governance/),
187+we are keenly aware of the threat of _decentralization theater_. Urbit has
188+undergone steady progress towards decentralization, and with the developments we
189+outline below, it’s never been more clear that the project is beginning to leave
190+the cradle of Tlon. It’s also important to note that the decentralization of a
191+project is always a movement away from an initial centralized state⁠—you cannot
192+go from A to Z without first traversing every letter in between. While Urbit was
193+centralized at the beginning, the journey towards a network owned and
194+controlled by the users is now well underway.
195+
196+In the past, nearly all Urbit software was written by Tlon. While Tlon is still
197+the only corporation actively updating Urbit’s MIT-licensed open source
198+software, namely [Vere](/docs/glossary/vere) (the runtime),
199+[Arvo](/docs/glossary/arvo) (the kernel),
200+[Landscape](/docs/glossary/landscape) (the client), and
201+[Bridge](/docs/glossary/bridge) (the ID manager), unaffiliated individuals have been making enormous contributions to Urbit over the past couple of years via the [grants program](https://grants.urbit.org/history). Recent examples include the [Bitcoin node and wallet integration](https://github.com/urbit/urbit/pull/4940), [WebRTC integration](https://grants.urbit.org/proposals/21131866-webrtc-gall-agent-and-external-app), [Port, an Urbit installer and ship manager](https://github.com/arthyn/port), and [`|fuse`, an important primitive for 3rd party software distribution](https://github.com/urbit/urbit/pull/4820).
202+
203+The only real power Tlon holds over Urbit is the ability to push [OTA
204+updates](/docs/glossary/ota-updates) via `~zod`, and suggest that people
205+download our binaries. To the best of our knowledge, all extant galaxies
206+retrieve their OTA updates from `~zod`, who forward it to their stars, who
207+forward it to their planets. This software distribution route is merely a
208+convenient default setting. Ships initially retrieve OTA updates from their
209+sponsor, but they have full authority to retrieve updates from whoever they want
210+with the `|ota` command, or even to only install software updates by hand if
211+they so choose.
212+
213+In the future, one can easily imagine many organizations shipping their own
214+distributions of Urbit from their own urbit nodes, somewhat analogously to the
215+large number of Linux distributions which exist today. There is nothing we can
216+do to stop a group from forking Urbit, declaring `~sampel-palnet` the new `~zod`
217+(both for updates and for sponsorship purposes), and retrieving all OTA updates
218+via that route and building their own binaries. This is all by design, and we
219+wouldn’t want it any other way.
220+
221+The use of the Azimuth smart contracts is also somewhat optional. By changing a
222+few lines of code to point their ships at another set of PKI smart contracts,
223+they could rid themselves of hierarchical peer discovery entirely and make use
224+of some other routing strategy such as [Kademlia based DHT
225+routing](https://en.wikipedia.org/wiki/Kademlia). This would likely give rise to
226+an entirely separate network. The fact that the network is fully capable of such
227+a schism helps keep the Senate honest and accountable to the users. If they ever
228+were to vote on a contract modification that greatly angered or upset a portion
229+of the user base, they would be inviting such a schism and be entirely deserving
230+of it. In that sense, the power to control the network is already held by the
231+users, they just have not yet had a reason to make use of it.
232+
233+### Legitimacy
234+
235+The only way by which Tlon and the Senate hold any power is via legitimacy.
236+Vitalik Buterin recently wrote a [very informative
237+article](https://vitalik.ca/general/2021/03/23/legitimacy.html) on the role of
238+legitimacy in decentralized governance, and I do not know of a better source to
239+understand how Tlon and the Senate are kept in check by the users. Besides the
240+DAO split resulting in Ethereum and Ethereum Classic mentioned in the article,
241+perhaps the most prominent example of the power users have over a decentralized
242+network is the saga of [Steem and Justin
243+Sun](https://www.coindesk.com/justin-sun-bought-steemit-steem-moved-to-limit-his-power).
244+The short version of the story is that Justin Sun bought a controlling share of
245+the Steem blockchain and attempted to exert control over it, and the users
246+banded together to fork the blockchain into one called Hive, which was identical
247+to Steem except with Sun’s token balance set to zero. An analogous outcome for
248+Urbit would be that the Senate makes sweeping changes to the PKI and invites a
249+schism like that outlined above.
250+
251+For these reasons, there are strong disincentives for any one organization or
252+individual to acquire too many galaxies. If galaxy ownership becomes more centralized, individuals will be less incentivized to build on the network which will reduce the value of address space. Furthermore, such centralization might provoke a fork if such centralized powers are perceived as malicious by the users. This is in contrast to real-life republics, where there is little risk
253+for one party to accumulate as much power as they can manage since the cost to
254+the citizens to overthrow that power is enormous. Thus, only especially
255+egregious displays of power ever result in rebellion. Within the Urbit republic,
256+users need only to change the code they run to leave the Senate powerless, and
257+so the threat of rebellion is much more real. We estimate that within a digital
258+republic like Urbit, the centrifugal forces outweigh the centripetal forces, and
259+that the outcome of this is more stable than the reverse.
260+
261+### Why have governance at all?
262+
263+An important question the reader may still have lingering is: why does Urbit
264+need governance at all? The short answer is: (i) there will always be necessary
265+protocol upgrades that cannot be foreseen, and (ii) a total lack of governance
266+inevitably gives rise to a shadow government with undefined powers that is
267+almost impossible to hold accountable.
268+
269+With (ii), we see this to be the case on many early blockchain projects where
270+power is shared by the developers and the miners, but what each is capable of
271+doing has never been codified, and thus users of the blockchain can never have a
272+great deal of certainty of what changes might occur in the future. This doesn’t
273+guarantee a bad outcome, but it does create more wariness among developers when they cannot know whether they really have a say in
274+the project's direction. Recognizing this issue, many newer blockchain and
275+blockchain-adjacent projects have built-in governance mechanisms that lay out
276+exactly what an individual can expect should they join and contribute to that
277+network.
278+
279+As for (i), with Urbit being a wholly new kind of network, it would take
280+incredible luck to get the PKI exactly right on the very
281+first try without ever needing another modification. Thus, some mechanism was
282+needed to guarantee that the PKI’s logic could be altered. Leaving control of
283+Azimuth in the hands of Tlon would have just granted Tlon dictatorial power, which Tlon nor Urbit users desired. There’s certainly
284+room to argue that the Galactic Senate is not a perfect system: our interim
285+constitution did outline potential roles for stars and planets to play in
286+governance in the future, so there is ample opportunity for the system to evolve
287+in response to the will of the users. As always, it is important to keep in mind
288+the unfinished nature of the Urbit of today and the still moldable clay of the
289+Urbit of tomorrow⁠—nothing yet is set in stone.
content/blog/first-steps-towards-urbit-org.mdnew file+52
@@ -0,0 +1,52 @@
1++++
2+title = "First Steps Towards urbit.org"
3+date = "2020-08-11"
4+description = "With a stable platform taking shape and a strong community forming that wants to help build Urbit, it’s time to make urbit.org real."
5+
6+[extra]
7+author = "Josh Lehman"
8+ship = "~wolref-podlex"
9+image = "https://media.urbit.org/site/posts/essays/first-steps.png"
10++++
11+
12+![](https://media.urbit.org/site/posts/essays/first-steps.png)
13+
14+## Summary
15+
16+It’s been a long time since we last discussed separating the [governance of urbit.org](https://urbit.org/blog/governance-of-urbit/) from Tlon. In the last few weeks, we’ve taken steps to make such a separation real. In this update we’ll discuss the background that led us here, why we’re doing this now, and what this means for Urbit.
17+
18+## Background
19+
20+At present Urbit is an open-source project developed primarily by the company Tlon. Urbit is an ambitious project with a long roadmap, which has required both careful guidance and resources to sustain its development. These resources have been Urbit’s address space, which have value in direct proportion to the value of Urbit as a platform. Naturally, Tlon has been focused thus far on making Urbit into a platform that people want to use.
21+
22+Ultimately, Urbit presents more possibilities than any one organization can manage. We anticipated this, and set aside address space for urbit.org, which we’ve often thought of as some type of software foundation. As Urbit matures to the point where Tlon can shift from developing the platform to developing products _on_ the platform, urbit.org is meant to continue to improve and maintain the parts of Urbit that many will come to rely upon.
23+
24+When we last discussed this, in early 2019, we weren’t quite ready to pull the trigger on setting up urbit.org. We weren’t sure if a software foundation would be the right structure, didn’t have the resources to tackle the overhead, and Urbit wasn’t yet stable enough for Tlon to focus on anything _but_ platform development.
25+
26+## The Present
27+
28+Urbit is really starting to look like a platform. Tlon has put tons of work into making Urbit stable and performant, we’ve launched OS1, and hosting services are on the horizon. Meanwhile, the grants program and Hoon School were initiated, and community members have been [contributing](https://github.com/natareo/hooncard/blob/master/hooncard.pdf) [learning](https://github.com/timlucmiptev/gall-guide/blob/master/guide-docs/overview.md) [materials](https://github.com/lukechampine/rote/blob/master/urbit/app/rote.hoon), [issuing](https://github.com/urbit/urbit/pull/2885) [patches](https://github.com/urbit/urbit/pull/3202) [to](https://github.com/urbit/urbit/pull/3238) [Urbit](https://github.com/urbit/urbit/pull/2867), and [building](https://github.com/ryjm/srrs) [new](https://github.com/dclelland/UrsusChat) [applications](https://github.com/yosoyubik/canvas) [in](https://github.com/yosoyubik/urbitcoin) [userspace](https://github.com/taalhavras/ucal).
29+
30+With a stable platform taking shape and a strong community forming that wants to help build Urbit, it’s time to make urbit.org real. We’ve had plenty of time to think about what it should look like, how it should work, and who should lead it.
31+
32+Our plan is to run urbit.org as a protocol—we’ll treat it like a real entity, but instead of dealing with the administrative details of setting up such an organization, we’ll incubate it within Tlon and give it a mandate: To competently distribute address space as a means of improving Urbit.
33+
34+## Moving Forward
35+
36+On that note, allow me to introduce myself: I’m Josh[^1], the new Interim Director of urbit.org. I’ve been a follower of this project for several years now and more recently a fairly active community member. I first became fascinated by Urbit as a programmer that saw the potential in a clean-slate OS; I later became compelled by a future in which social computing becomes small, friendly, and human-scale again.
37+
38+My background is predominantly in building software, companies, and teams—most notably [Starcity](https://starcity.com), where I am a co-founder and CTO. Starcity[^2], like Tlon, is focused on enabling communities to flourish. While the approaches couldn’t be more different, the goal of bringing people together in fundamentally human ways is shared.
39+
40+My goal is to leverage urbit.org to ensure Urbit’s success. I want to see a world in which Urbit is used by my friends, family, colleagues, everyone I know. To get there, much is left to build.
41+
42+To that end, the first objective of urbit.org is to recruit builders and give them the tools to succeed. I’ll be focusing heavily on providing technical support to developers that engage with us via Grants, outreach to the wider developer community, supporting the efforts of those that are creating educational courses and documentation, and enlarging the contribution surface by exposing it to other programming languages[^3].
43+
44+The product work that Tlon is doing is crucial to Urbit’s long-term success, so I’ll also be leveraging bounties to more directly accelerate their development efforts. Landscape represents the clearest example of a cohesive vision for Urbit’s use. The existence of a polished product built on Urbit demonstrates to the world that the platform is robust and capable, and the growing community seems eager to help. You can expect more bounties very soon that provide a direct connection to the Landscape roadmap.
45+
46+As I’m only just getting started, I’d love to hear your thoughts. If you’re working on any grants you’ll hear from me soon, and if you have an idea that you want to pursue, I’m here to help you make it happen. You can reach me directly via Urbit as `~wolref-podlex` or by email at josh@urbit.org.
47+
48+I look forward to working with you.
49+
50+[^1]: But my friends call me ~wolref-podlex.
51+[^2]: We’re also really into the idea of being the first builder of housing on Mars. Just saying...
52+[^3]: We call this project Airlock. You’ll hear more about it soon.
content/blog/ford-fusion.mdnew file+222
@@ -0,0 +1,222 @@
1++++
2+title = "Ford Fusion"
3+date = "2020-07-14"
4+description = "Ford Fusion was an overhaul of Urbit's over-the-air upgrade process and a rewrite of its build system. The new update system corrects a few long-standing bugs with the previous one, and the new build system is simpler, smaller (by around 5,000 lines), and easier to manage."
5+
6+[extra]
7+author = "Ted Blackman"
8+ship = "~rovnys-ricfer"
9+image = "https://media.urbit.org/site/posts/essays/ford-fusion.png"
10++++
11+
12+![](https://media.urbit.org/site/posts/essays/ford-fusion.png)
13+
14+## Overview and Rationale
15+
16+Ford Fusion was an overhaul of Urbit's over-the-air upgrade process and a rewrite of its build system. The new update system corrects a few long-standing bugs with the previous one, and the new build system is simpler, smaller (by around 5,000 lines), and easier to manage.
17+
18+Since deployment of Ford Fusion to the livenet in late June, over-the-air updates (OTAs) have been much smoother. Before Ford Fusion, it was common for an OTA to take several hours, use too much memory, and leave ships in inconsistent states. After Ford Fusion, multiple OTAs have been pushed out, including kernelspace changes, and most users didn't even notice.
19+
20+Urbit has always been able to update itself OTA, but this process has often been rocky. Updating an operating system kernel on-the-fly is a difficult problem in general, like performing heart replacement surgery on yourself while running a marathon. Code that allows Linux to update its kernel in this way became a startup called Ksplice, won multiple awards, and sold to Oracle. Even that, as impressive as it is, and as brilliant as its [programmers](https://nelhage.com) are, can only perform certain limited kinds of patches to the kernel.
21+
22+Urbit isn't exactly a traditional operating system, so the comparison is somewhat unfair, but the purpose of better architecture is to create unfair comparisons. In this case, because the Nock layer is frozen, upgrading everything above that layer is easier. Upgrades are also facilitated by pure-functional semantics, transactional event processing, a type system oriented toward concrete data, and orthogonal persistence. These features make it feasible for Urbit to upgrade
23+itself in the general case, not just some special cases.
24+
25+Ford Fusion has fixed the major upgrade issues of the past by guaranteeing three properties that in retrospect are obvious requirements, but, like much of Urbit, took many years and rewrites to identify as such:
26+
27+- Atomic: the update should complete or fail in one transaction. If it
28+ fails, the system shouldn't get stuck.
29+- Self-contained: there must be no implicit dependencies or hysteresis
30+ (dependence on previous system states) when building the new software
31+ from source.
32+- Ordered: updates must be monotonically sequenced from the system's
33+ lowest layer to highest.
34+
35+Let’s walk through them one by one.
36+
37+### Atomic
38+
39+In previous versions of Urbit, updates failed atomicity by deferring parts of the update to later events, which are separate transactions that can fail independently. Generally, each deferral causes an exponential increase in the number of failure states that needed to be handled.
40+
41+We've learned that asynchronicity is an entropic state. A system will tend toward more asynchronicity over time unless effort is put into keeping it synchronous. [As Jonathan Blow has noted](https://youtu.be/pW-SOdj4Kkk?t=2547), the language server protocol has turned every editor plugin into a distributed system, since now it has to communicate asynchronously with the main editor process.
42+
43+Consider an update system that took multiple Arvo events to complete. An ad-hoc higher-level transaction system would need to be built to roll back the effects of the first few events in case of failure. It’s important for various parts of the system to be able to emit effects on upgrade; since those effects would need to be rolled back if a later event in this upgrade fails, the system would need to maintain a queue of those events and only apply them once all the other upgrade events have completed.
44+
45+Note that the asynchronicity has now spread. Some effects that would normally be guaranteed to be processed synchronously might now be asynchronous. Entropy has begun to take hold, chipping away at the set of invariants the system is capable of guaranteeing.
46+
47+This observation is not purely theoretical. False modularity was the cause of internal asynchronicity in Clay where it had to wait for responses in a complex dance with Ford, which was another vane (Arvo kernel module); moving Ford into Clay allowed function calls that were synchronous from Clay’s perspective, which allowed further simplifications, culminating in about a twenty percent reduction of source code size of the Arvo kernelspace.
48+
49+[Steve Yegge's "platform
50+rant"](https://gist.github.com/chitchcock/1281611) describes a Bezosian
51+edict prohibiting synchronous communication among modules through direct
52+linking. This can be seen as an acknowledgment of the difficulty Amazon
53+was going to have when it needed to turn internal services external. If
54+your software needs to run in hell, build it that way from the start.
55+
56+An Urbit ship is not an enterprise SaaS product and does not need to run in this hell; it exists for just one person, with natural pressure pushing it in the opposite direction from Amazon’s web services. Instead of needing a ship’s state and functionality sharded into microservices strewn across multiple clusters, an Urbit instance is easiest to manage as a single server with all its state unified into one data structure and its event log stored as one totally ordered sequence of state updates -- the antithesis of a distributed system.
57+
58+### Self-Contained
59+
60+Before Ford Fusion, each commit to the Clay filesystem validated its files using filetypes (called “marks”) defined by files in the previous commit. This could cause bugs if the filetype definitions had changed in a backward-incompatible manner. It also meant a commit could not add both a new filetype and new files of that type; instead, you needed two commits: one to define the filetypes, and a second to add files of that new type. More theoretically, it caused history-dependence. The validated contents of files in a commit could vary based on the history of commits that led to this one.
61+
62+Another way source code failed to be self-contained was that it had access to symmetry-breaking information at build-time, namely ship, desk (Urbit's answer to a git branch), and (faked) date. A build recipe should be able to shared, cached, and rerun without dependence on local conditions, so user code now no longer learns its ship, desk, or date until runtime.
63+
64+Source code also had build-time access to Urbit's immutable global namespace, called the “scry namespace”, which the kernel makes available as an implicit argument to userspace Hoon code. The scry namespace is immutable and referentially transparent, i.e. a request must always yield the same result for all time, but if an agent asks the kernel for a resource that’s from the future, hosted on another ship, or to which that agent doesn’t have permission, the kernel will deny the request.
65+
66+If the kernel denies a scry request that user code made during the build process, the build system has no choice but to treat it as a nondeterministic error. Nondeterministic errors can never be fully eradicated, if for no other reason than that the user always has the option to defenestrate the machine—there's nothing deterministic about that. But we try to minimize them, and especially to minimize uncertainty as to under what conditions they might occur.
67+
68+No build should be killed by the absence of files outside the desk, so as of this update, user code can no longer scry at build time. Once built, userspace programs can scry if run in a context with a scry handler; a Gall agent's runtime scry requests still work just fine.
69+
70+### Ordered
71+
72+The final kind of failure fixed by Ford Fusion was the lack of ordered layering during a software update. The most common form of this failure was that old Ford had a tendency to try to build userspace code using the previous version's standard library. This didn't work too well, unsurprisingly.
73+
74+Emerging from this underworld required making a number of changes to the Arvo kernel, Clay, Gall, and the procedure for kernel updates. To avoid turning into a pillar of salt, I'll skip the details of how the old system worked and instead describe the new update procedure.
75+
76+## How Updates Work Now
77+
78+These are the layers of the stack that update themselves on the fly, from lowest to highest:
79+
80+- hoon: the hoon language definition and compiler, defined in `/sys/hoon/hoon`
81+- arvo: the arvo kernel proper and related type definitions, in `/sys/arvo/hoon`
82+- zuse: the standard library, in `/sys/zuse/hoon`
83+- vanes: arvo kernel modules, including clay itself, in folder `/sys/vane`
84+- userspace: apps, marks, ancillary source code like libraries, and user data
85+
86+An update to one layer necessitates a reload of all layers above it; e.g. a change to Zuse should trigger updates to the vanes and userspace. Conversely, an update to a higher layer should not cause a spurious reload of lower layers, which should not be affected by the change; for example, an update to just userspace should not cause any reloads of system code.
87+
88+Clay is responsible for enforcing the layering of updates. An update to a module is triggered when an attempt is made to commit a change to Clay that affects one or more files needed to build the module. For example, if the 'foo' agent's source, defined in `/app/foo/hoon`, imports the 'bar' library from `/lib/bar/hoon`, then a modification to `/lib/bar/hoon` triggers an update to the 'foo' agent. All vanes and userspace files depend on Zuse, which depends on the Arvo and Hoon sources, so a change to the Hoon, Arvo, or Zuse sources will trigger updates to all vanes and userspace files.
89+
90+When asked to perform a commit, Clay determines which layers need to be updated based on which files have changed and which modules depend on those files. For now, all running programs load their source from the `%home` desk, so only changes to `%home` trigger stateful updates. Files in other desks can be built, but not installed into the system. This might be relaxed in the future.
91+
92+The process of updating varies by layer. The Hoon and Zuse layers are stateless, so their newly rebuilt cores (Nock executables) must be stored (somewhere in the system’s Nock tree, in memory; remember, Urbit is a single-level store), but they have no state that would need to be migrated. The Arvo kernel, vanes, and userspace agents are all live, stateful programs, so in order to update one of those, the system must extract the state from the old program, pass that data into the newly built program, then discard the old program and store the new one. Arvo and agent state injection routines can emit effects, but vane updates cannot.
93+
94+To work around this limitation, Gall has a two-phase update process. First it enters a dormant “pupal” phase that stores not running agent cores, but only the agent states that the old Gall had extracted from its agents. When Clay notifies Gall that its agents have been rebuilt, Gall “molts” back into normal functionality by loading the agent cores from Clay and then running their `+on-load` routines to inject the old state.
95+
96+If there's a change to files in `/sys` on the `%home` desk, Clay asks Arvo to update kernelspace. Clay sends a sequence of moves (effects) to Arvo to ask Arvo to perform any necessary updates to hoon, the kernel, Zuse, and vanes. This sequence is terminated by an extra move back to Clay itself, which will be received by the updated version of Clay after migrating its state. The rebuilt Clay can then use the newly rebuilt version of Zuse to rebuild userspace and notify clients of the update. One client is Gall, which molts when Clay notifies it.
97+
98+Clay triggers updates, but the Arvo kernel is responsible for performing updates to all kernelspace layers, and Gall is responsible for updating userspace agents. Agents are stored in Gall's state, but all other layers are stored directly in the Arvo core's state, so the Arvo kernel contains the routines that reload Hoon, the kernel itself, Zuse, and the vanes.
99+
100+The Arvo kernel reloads itself by receiving its new source code as a `%lyra` move from Clay, compiling this source into a core with empty state, then calling the new core's `+load` routine with the relevant parts of the old state. The state passed to the new Arvo now includes not just the vane cores and their states, but also the Arvo "duct" call `stack`, which maintains a stack of queues of moves to be passed from one vane to another, and a list of effects to emit to Unix at the end of the current Arvo event. If needed, Arvo could migrate the outstanding moves themselves -- if, say, the duct datatype changes.
101+
102+Passing the Arvo call stack state to new Arvo allows a kernel update to happen in the middle of a more complex event without disturbing other sequences of processing steps happening concurrently in the vanes.
103+
104+This entire update process happens in one Arvo event and doesn’t break event-dispatching semantics. This not only provides atomic rollback, but allows the update to be combined with other actions into a larger transaction -- for example, to stage complex changes, user code could trigger two kernel updates in a row, both in the same event.
105+
106+Note that this is the opposite situation from the entropically leaking asynchronicity described earlier. Now the guarantees don’t deteriorate; they can be composed into stronger guarantees.
107+
108+## How Clay Validates a Desk
109+
110+A desk is Urbit's answer to a git branch. It's almost identical, except all files are typed and validated, and whenever a commit becomes the equivalent of git’s ‘HEAD’, it’s assigned a semantically meaningful revision number, and all files are typed and validated.
111+
112+If Clay has been asked to perform a commit, it needs to validate all the files in this desk and notify all subscribers to live queries of this desk's data. Gall, for example, maintains live queries on builds of its live agents. Validation uses the Ford build system, which as of this update is no longer a standalone vane but a core within Clay.
113+
114+A Clay commit, like a git commit, is specified as the current value of all its changed files (and, separately, references its parent commits by hash), not as the diff from a parent commit. Unlike git, Clay is typed, and every file must be validated according to its "mark". A mark is named like a file extension, e.g. `%txt`, `%png`, or `%noun`, and Clay maintains a mapping from that name to behaviors of values of that type under various operations. The last segment of any Clay path specifies the mark to use for operations on that file, including validation.
115+
116+Mark operations include conversion to and from other marks (such as converting `%json` to `%txt`), revision control operations (diff, patch, and merge), and validating an untyped noun. Operations for mark `%foo-bar` are defined by a core built using the source code at `/mar/foo-bar/hoon`, or if that doesn't exist, at `/mar/foo/bar/hoon`.
117+
118+Consider a file at `/web/foo/json`. In order to validate this file, Clay must load the mark definition core and use its validation routine to ensure the untyped value of `/web/foo/json` is in fact valid JSON. To obtain this core, Clay must build the file at `/mar/json/hoon` from source and then process the resulting raw mark core using some mild metaprogramming to get a standard interface core for dealing with marks, called a `$dais`, whose type is defined in Zuse.
119+
120+Since building a source file only makes sense if the file has been validated as a `%hoon` file, but mark definitions themselves must be built from source, there's a logical dependency cycle -- who validates the validators? To break this cycle, Clay hard-codes the validation of `%hoon` files. This allows mark definitions to be built from source, and in fact any file can depend on any other file of any mark as long as there are no cycles. As of Ford Fusion, Ford performs a cycle check to ensure acyclicity.
121+
122+Since building a file is a pure function, Clay memoizes the results of all builds, including builds of marks, mark conversions, and hoon source files. These memoization results are stored along with the desk and are used by later revisions of that desk. Future work should allow merge commits to pull memoized builds from all parents, but for now only the previous revision of the current desk is used. This is a major simplification of previous Ford architectures, which maintained much more complex caches with less clear eviction semantics. Now on every commit, we just throw away any unused memoized builds from the previous revision's Ford cache.
123+
124+Once Clay has validated every file in this new revision of a desk, it constructs and sends updates to any subscriptions that other vanes or agents have requested. More Ford builds may be run to fulfill these requests, including builds for any running agents whose dependencies changed in this commit.
125+
126+When Gall receives a newly rebuilt agent from Clay, it calls the gate produced by the `+on-load` arm of the new agent with the state extracted from the old agent. If there is a crash in any `+on-load` calls or in the handling of any effects they emit (which can include more agent activations), then the whole event crashes, canceling the commit. This effectively gives any agent the ability to abort a commit by crashing.
127+
128+It is a bit counterintuitive that an app reload failure could prevent a kernel update. The reason is that we don't want the system to update itself into a broken state. An Urbit can be rendered practically unusable by the presence of broken agents, even if the kernel hasn't lost integrity,
129+so it's kinder to the user not to break their agents by installing an incompatible kernel update. This also puts virtuous pressure on kernel developers not to "break userspace", the importance of which has been insisted on for decades by Linus Torvalds, among others.
130+
131+If an agent does crash a commit event that included a kernel update, the attempted commit is now trivially rolled back, and the system can deliver an error message to the user. This does not leave the system in an inconsistent or stuck state, so the user could modify the failing agent and try the kernel update again later. Supporting better workflows for keeping third-party agents up-to-date will be an important aspect of Urbit’s upcoming software distribution work.
132+
133+## Ford Build Semantics
134+
135+### The Three Types of Ford Builds: Files, Marks, and Casts
136+
137+The Ford build semantics have been simplified. There are now three kinds of builds that Ford can perform: files, marks, and casts, all of which happen synchronously as function calls inside Clay and are available (without memoization) as scry interfaces.
138+
139+#### File Builds
140+
141+A file build takes in a filepath containing Ford runes and Hoon source, runs the Ford runes to perform imports, and then compiles the source, producing a `$vase`, a noun tagged with its Hoon type.
142+
143+Clay exposes file builds into the scry namespace with `%ca`: as an example, `.^(vase %ca /~zod/home/3/lib/sole/hoon)` will build the `sole` library.
144+
145+#### Mark Builds
146+
147+A mark build produces a `$dais` mark-interface core. It first performs a file build on the Hoon file in `/mar` that defines the mark core, then it does some metaprogramming to make the operations more convenient to use. If the raw mark core delegated revision control operations to another mark core, the mark build will also load the delegate mark core and resolve the result into the `$dais`.
148+
149+Clay exposes mark builds into the scry namespace with `%cb`: as an example, `.^(dais:clay %cb /~zod/home/3/mar/foo/hoon)` builds a `$dais` for the `%foo` mark.
150+
151+#### Cast Builds
152+
153+A cast build produces a `$tube`: a gate that takes a value of one mark as input and converts it to a valid value of another mark or crashes. To convert from mark `%foo` to mark `%bar`, Clay tries the following operations, in order:
154+
155+- direct grow from `%foo`
156+- direct grab from `%bar`
157+- indirect jump from `%foo` through `%qux`
158+- indirect grab from `%bar` through `%qux`
159+
160+The `%foo` mark can “grow to” `%bar` by providing an arm in its `+grow` core named `+bar`. `%bar` can convert from `%foo` using a `+foo` arm in its `+grab` core. `%foo` can also chain a conversion through an intermediary using an arm in its `+jump` core, and `%bar` can specify an “indirect grab” by having a `+grab` arm produce a delegate mark instead of directly defining a conversion gate.
161+
162+Clay exposes cast builds into the scry namespace with `%cc`: as an example, `.^(tube:clay %cc /~zod/home/3/foo/bar)` builds a `$tube` conversion gate from `%foo` to `%bar`.
163+
164+### Ford Runes
165+
166+There are now only four Ford runes. A file can contain zero, one, or many of each, but each Ford expression can only be one line, and they must be in the standard order of `/-`s, `/+`s, `/=`s, and then `/*`s.
167+
168+```
169+/- foo, *bar, baz=qux
170+```
171+
172+The `/-` rune imports a structures file from `/sur`. You can import it as just `foo`, in which case the build result of that file (usually a core with mold definitions) will be pinned into the compilation subject with the face `foo`. If you prefix it with a `*` as in `*bar`, the result will be pinned into the subject with no face; if the structures file compiled to a core, this exposes all the arms into the namespace of the compilation subject. Finally, if you import it as `baz=qux`, the `baz` face will be applied instead of `qux`. This is similar to "import as" in other languages.
173+
174+```
175+/+ foo, *bar, baz=qux
176+```
177+
178+The `/+` rune imports a library file from `/lib`. Aside from the different source folder, the syntax and semantics are the same as for `/-`.
179+
180+```
181+/= clay-raw /sys/vane/clay
182+```
183+
184+The `/=` rune imports the result of building a hoon file from a user-specified path (the second argument), wrapping it in a face specified by the first argument. The final `/hoon` at the end of the path must be omitted. This is mostly useful for importing a file for testing. The file at the specified path will be built as a normal userspace hoon file; i.e. its compilation subject will be Zuse augmented with the results of any Ford runes it has at the top of the file.
185+
186+```
187+/* hello-gen %hoon /gen/hello/hoon
188+```
189+
190+The `/*` rune imports the contents of a file in the desk, specified as the third argument with the full path including the trailing mark, converted to the mark specified by the second argument, and pinned into the compilation subject wrapped in the face specified by the first argument. This can be used to import static data at build-time, such as a data file, a media file, or, in the case of this example, a hoon file as source text rather than already built.
191+
192+A valid userspace hoon file must contain a nonempty list of hoons (hoon source expressions) below the Ford runes, separated by gap (more than one space, or at least one newline). The system wraps this list of hoons in a `=~` expression so that the result of the previous hoon is used as the subject of the next hoon. The result of the Ford runes is used as the compilation subject for this `=~` hoon; informally, the shape of the compilation subject can be thought of as:
193+
194+```
195+:* fastar-2 fastar-1
196+ fastis-2 fastis-1
197+ faslus-2 faslus-1
198+ fashep-2 fashep-1
199+ <zuse>
200+==
201+```
202+
203+## Future Work
204+
205+Urbit still needs to make better use of desks other than `%home` and the development process should be adjusted given the tighter coupling between source code and kernel and tighter criteria for accepting an update.
206+
207+This work also hopefully provides a good foundation of a package management and software distribution system for Urbit. As `~wicdev-wisryt` has said, a user should be able to run `|install ~norsyr-torryn/canvas` to load and build remote source. No one should experience dependency hell on Urbit, but we're not there yet.
208+
209+At least now, building a desk has no dependencies, other than a Ford with a compatible Hoon compiler. No decisions have been made on this yet, but
210+Ford might get moved to inside the desk, possibly by making Zuse callable. This could allow a desk to expose a Nock interface in addition to a typed Hoon interface, which could even let a desk be used as a "pill" bootloader.
211+
212+## Conclusion
213+
214+`~littel-ponnys` and I spent most of 2018 rewriting Ford with the intent of improving its performance. Compared to its predecessor, its result was better in some ways but worse in others. The caching system was labyrinthine and poorly factored, making the system difficult to debug or prove correct, even informally. Some things were faster, but the caching and dependency tracking were actually complex enough that a number of common operations, like mark conversion, were too slow.
215+
216+In early 2020, `~master-morzod` suggested moving Ford into Clay to reduce asynchronicity. It seemed absurd at first, but at some point I realized I could combine that idea with a simpler build-caching scheme and self-contained desk builds, and `~wicdev-wisryt` realized he could use that to further simplify Clay’s commit and merge code, which he did as part of this project.
217+
218+The first time I rewrote Ford, it took me six months, with help from `~littel-ponnys`, and it weighed in at 6,000 lines of code. The second time, in late 2018, took a few weeks. The third time, in January 2020, took a week. I wrote `+ford` in Ford Fusion in one long day, and it’s about 500 lines of synchronous, functional code.
219+
220+It has taken me two or three years to understand this problem as well as I do, and I expect there are parts of it I still don’t understand. The code itself isn’t the issue; it’s finding the right answer to ontological and teleological questions. What _is_ Ford? What will it be in a hundred years? I’m confident Ford Fusion is more similar than its predecessor to the Ford of 2120, because it’s smaller, more functional, and easier to understand and administer.
221+
222+As an engineering discipline and organizational practice, working on a system intended to be frozen yields surprising simplifications like this every so often. Urbit is now reaching the point where we’re starting to see more of the obsidian edges of the frozen future system emerge from the lava.
content/blog/foss-1.mdnew file+64
@@ -0,0 +1,64 @@
1++++
2+title = "Urbit's Open Source Culture, Part I"
3+date = "2023-05-31"
4+description = "How did Urbit cultivate a unique open source software culture? Let's take a look at how we got to where we are today."
5+
6+[extra]
7+author = "N E Davis"
8+ship = "~lagrev-nocfep"
9+image = "https://upload.wikimedia.org/wikipedia/commons/a/a9/SR71_factoryfloor_SkunkWorks.jpg"
10++++
11+
12+![](https://upload.wikimedia.org/wikipedia/commons/a/a9/SR71_factoryfloor_SkunkWorks.jpg)
13+
14+> “Open source is an intellectual property destroyer. I can't imagine something that could be worse than this for the software business and the intellectual-property business.” (Jim Allchin, Microsoft executive)
15+
16+A founder's personal enquiry into the foundations of practical computing grew into a skunkworks startup to build an alternative basis for principled computing, and has now evolved into a burgeoning open source platform and community.
17+
18+- [Moron Lab, “Maxwell's equations of software (Nock)” (~2010.1.9)](https://moronlab.blogspot.com/2010/01/nock-maxwells-equations-of-software.html)
19+- [Moron Lab, “Urbit: functional programming from scratch” (~2010.1.13)](https://moronlab.blogspot.com/2010/01/urbit-functional-programming-from.html)
20+
21+How did Urbit cultivate a unique open source software culture? Let's take a look at how we got to where we are today.
22+
23+Open source culture really got going in the 1980s with the restrictive Unix licensing scheme and the consequent publication of the GNU software tools. With the marriage of GNU to Linux ([“I'd like to interject for a moment”](https://copypastatext.com/id-just-like-to-interject-for-a-moment/)), a full stack, from the bare metal to the end user, was possible. Usenet and early Internet forums furthermore encouraged interested developers to start contributing actively.
24+
25+The ethos of open source software drew on a number of sources, from William Gibson's _Neuromancer_ trilogy to “A Cypherpunk's Manifesto.” Those involved were often motivated by a healthy distrust of proprietary software. The big break for open source software (OSS) came with the [Unix ownership lawsuits](https://en.wikipedia.org/wiki/Unix_wars), which gave GNU/Linux a chance to break into the bigtime for systems software. The [2001 case against Microsoft](https://en.wikipedia.org/wiki/United_States_v._Microsoft_Corp.) as a monopoly lent further credence to the open source mandate.
26+
27+During this time, Urbit began life as a personal dissertation, in a sense, to derive a minimalist practical set of computing expressions as a combinator calculus. The early concepts that became part of Urbit, such as kelvin versioning and Maxwellian code, show up during its first decade. Nock was not open source for two reasons: the founder's conviction that as software it was already public domain, and the fact that there was no one yet to collaborate with.
28+
29+It was about a decade before Tlon was started as a small bespoke programming house to work on the esoteric project of defining something usable on top of the minimalist Nock specification. No one knew about Urbit besides some blog readers, and unless you worked in or next to Tlon you had basically zero chance of following the project via software alone.
30+
31+Early Tlon did a fairly good job of putting their software out there, but the documentation and nomenclature were considered obscurantist and the project was described as performance art or a deliberate wild goose chase. These combined to make Urbit appear fairly opaque, despite open development using GitHub and the liberal MIT license. System components like Nock and Arvo were declared public domain or liberally licensed.
32+
33+To this point (let's say 2019), Urbit was by license and by code an open source project, but had a reputation for being basically impossible for an outsider, even one with a fair amount of coding experience, to really figure out what's going on without serious handholding from the core devs. (Nor is this inappropriate for a small startup at this stage—it simply is the way most nominally OSS projects function.) However, the mystery engaged others beyond Tlon to brave the wilds and figure out what this Urbit project was all about.
34+
35+Urbit’s goal has always been to produce a stable kernel for all time, referred to by a metaphor of losing heat energy and entropy. As Urbit gradually cooled from red hot slag to what we'll call a developer alpha, Tlon began a project of greater outreach to the developer community. In particular, crypto software developers saw attractive aspects in Nock's concision and apparent provability and in Urbit's functional-as-in-math approach to operating system and application state. Tlon started a Discord for onboarding and troubleshooting, including community concierges who were tasked with engaging anyone with ship troubles. This tapped into and fostered a culture of Urbiters aggressively helping others debug and troubleshoot their ships, which continues to this day. Tlon also began Hoon 101 to teach outsiders how to actually build things on Urbit.
36+
37+As Urbit slowly grew into a larger developer community, some hard strategic questions about project scope and direction came into focus. There had always been a provision for Urbit to have some sort of foundation with stewardship over the project—either the Urbit Educational Foundation or something similar. Like the Linux Foundation, this organization would serve to coordinate activity between various companies and individuals contributing to the Urbit project. The foundation would receive an endowment of galaxies earmarked to fund Urbit's development.
38+
39+Urbit's use of address space to fund development means that the builders, even those who have discovered Urbit relatively recently, are able to acquire a significant stake in the project and its success.
40+
41+In practical terms, Tlon started the Urbit Foundation internally first as `urbit.org`, then rolled it out as a standalone company with a mandate to first build itself into a viable cultivator of Urbit, then to take over Urbit core development. By early 2023, the Urbit Foundation was in a position to take over core development for the platform.
42+
43+There have been several aspects of this journey that have led Urbit to have a thriving and promising open source software culture:
44+
45+1. Urbit's nature as a functional operating system has a deep appeal to software developers and others who find appeal in a mathematically elegant system, including the guarantees made by innovations such as the scry namespace bindings and the public key infrastructure.
46+2. Hoon is a mood. What I mean by that is that Hoon's unique aesthetics, subject-oriented paradigm, and the utility of cores give coders a unique experience, like systems programming in APL would feel like.
47+3. The developer docs are finally prioritized and made publicly legible. Large swaths of the operating system and standard library are finally documented.
48+4. Third-party software distribution is made trivial. Decentralized peer-to-peer open source software distribution without having to go through a GitHub intermediary changes the game.
49+5. Urbit's educational program expands from Tlon's initial offerings to a community program (Hooniverse/Hooniversity), then to a dedicated program with specific course milestones under the auspices of the Urbit Foundation.
50+6. Urbiters start meeting in person at Assembly and other events. After the 2020 efflorescence of the Urbit community, this is the first time most of the newer people were able to meet in real life. (This is a substantially different situation than the pre-2019 Urbit environment—most people didn't know Tlonners first, they knew Urbit first and mainly online.)
51+7. Three major active groups form dedicated to all-purpose coding on Urbit:
52+ A. Hooniverse, ~hiddev-dannut/new-hooniverse, originally strictly for the community Hoon School but now for all of the UF's educational efforts.
53+ B. The Forge, ~middev/the-forge, for advanced technical discussion.
54+ C. `[battery payload]`, ~dister-dozzod-lapdeg/battery-payload, the UF's developer community group.
55+8. The Urbit Foundation begins an active grants program. At first focusing on userspace and cultural grants, this eventually leans back into kernel work.
56+9. As the Urbit Foundation takes over core development, this necessitates changing that process from being a one-company project to requiring coordination, said coordination being much easier in the open than in closed meetings. (This also enables Tlon to focus on product delivery over core development.)
57+10. The Urbit Foundation begins using a `gather.town` “Urbit Hacker House,” which puts people together for synchronous interrupts. Any community member can wander in and be a fly on the wall or an active interlocutor.
58+ A. This enables the UF to start hosting daily pull request triage and a rapid assignment of tasks in the open.
59+ B. Communications strategy meetings are also public.
60+ C. Build parties (originally conceived as app-in-a-day) demonstrate pair programming, achieve inter-programmer communication of information akin to IRL programming, and allow anyone to participate.
61+
62+We find ourselves, as Urbit developers, having grown together a strong and unique culture of open source software development verging on radical transparency. It's not just code and license being open—it's the entire ensemble of programmer culture and on-platform dogfooding (to the extent possible). The greybeards and the noobs encounter each other directly and openly all the time, in `gather.town` and in Urbit groups.
63+
64+From modest beginnings, Urbit has achieved some small traction in the world and grown an exemplary open source culture. What will it take for Urbit to succeed in the future? That's the next entry.
content/blog/foss-2.mdnew file+59
@@ -0,0 +1,59 @@
1++++
2+title = "Urbit's Open Source Culture, Part II"
3+date = "2023-06-13"
4+description = "How will Urbit continue to foster its innovative open source software culture?"
5+
6+[extra]
7+author = "N E Davis"
8+ship = "~lagrev-nocfep"
9+image = "https://spacecenter.org/wp-content/uploads/2023/02/img-apollo-mission-control-3.jpg"
10++++
11+
12+![](https://spacecenter.org/wp-content/uploads/2023/02/img-apollo-mission-control-3.jpg)
13+
14+> God watches over fools, drunks, and the United States of America. (Otto von Bismarck, apocryphal)
15+
16+In our last installment, we considered how Urbit has grown its own robust open source culture. Now we look to the future: what will it take for Urbit to succeed, not only as an exemplary open source project but as a computing platform that delivers on its promise?
17+
18+Part of what makes an open source culture vibe is remix culture, the ability to rework the source material to produce novel components or manifestations. Urbit has the raw materials for this in spades, memetically and technically. It is up to us to keep these tools in our developers’ and enthusiasts’ hands.
19+
20+The default answer, which isn't terrible, is that Urbit should keep doing what it's done to get this far:
21+
22+1. Urbit should continue to prioritize decentralized development.
23+2. Urbit should lean into ownership-based incentives. Indeed, this is the most effective lever that the Urbit Foundation has.
24+3. Urbit should maintain the developer's republic. Core developers should rub shoulders with first-time Hooners.
25+4. Urbit should continue to ship source with code, since that is how code is actually distributed. The means of open source software are _necessarily in the user's hands_ with Martian software.
26+
27+There are some areas in which we hope to improve. Our documentation continues to expand, as do our educational offerings. We have a mandate to use the Urbit Foundation’s endowment of stars to produce the mature Urbit.
28+
29+What else should we have an eye to in the near future? There’s always more to do, but by prioritizing the items on this short list we would continue to elaborate our open source bona fides as a community and a steering foundation.
30+
31+1. **Code accessibility should be a priority.** Any computer language falls on the spectrum between machine legibility (the pole of machine code and assembly language) and human legibility (the pole of [Scratch](https://scratch.mit.edu/). All code must walk this line.
32+
33+ Hoon has had a reputation for being a language of dense expressions, which we believe is now being cleared by sunshine. However, Hoon's extensive sugar syntax and irregular expressiveness can make it challenging for those relatively new to Hoon to decipher programs. We can support their learning and entry into the ecosystem by defining a subset of Hoon syntax that we adhere to in all of the docs and some of the userspace code. Even if there is a "better" way to write it, we should prefer this restricted discipline in those cases. Let's call this subset "Hoon Prime." Hoon Prime will not always be the most concise Hoon code, and it will likely fail to maintain certain well-established preferences, like heavier expressions going to the bottom, but it should encourage developers to produce generators and agents from `%base`-distributed models as quickly as possible.
34+
35+ Hoon Prime should also adopt a standard of literate programming. Several example files already display such a self-documenting nature:
36+
37+ - [`simple.hoon` for solid-state subscriptions](https://github.com/wicrum-wicrun/sss/blob/master/urbit/app/simple.hoon)
38+ - [`deco.hoon` for doccords](https://github.com/urbit/urbit/blob/develop/pkg/arvo/lib/deco.hoon)
39+ - [`pals.hoon`](https://github.com/Fang-/suite/blob/master/app/pals.hoon)
40+ - [`rudder.hoon` for serving websites](https://github.com/Fang-/suite/blob/master/lib/rudder.hoon)
41+
42+ Our userspace code accessibility model should allow contributors from widely different skill levels to interact. We need to surface and document code patterns as cleanly as possible in the code we distribute. We need to include comments and unit tests so people can see how and why code works like it does.
43+
44+ Code accessibility cannot be an afterthought. We need to upgrade as much code as possible to A standards [per the style guide](https://developers.urbit.org/reference/hoon/style#grading).
45+
46+2. We need to improve the developer experience. Part of this involves better coding support, and part of this involves better debugging support.
47+
48+ To promote better coding, we should continue to develop IDE integrations like the Hoon Language Server. We've had some significant wins here, but rust never sleeps. We should also continue to produce userspace and middleware support libraries. We need to pay attention to how developer preferences are manifesting in their workflows and tooling.
49+
50+ Better error messaging and debugging support, perhaps even a framework for line-by-line code execution, would be invaluable. Upgrading Dojo and generator support is an easy win. Any tool friction is a sin and we need to track this and think about how to improve use.
51+
52+3. We need our open source culture to continue to develop in the sunlight. We need to highlight and communicate user stories for developer tools, new and old. We need to share these from inside of companies in the ecosystem. I'm not going to call for “best practices”—it's too early and that's too corporate—but tacit knowledge and horizontal skill transfer need to be encouraged through active pair programming and utilization of build parties and the like.
53+
54+ We need to expose how bugs occur, propagate, and are corrected. The core development team has committed to public [postmortems](https://github.com/urbit/urbit/issues/6583) when things go wrong.
55+
56+4. Ultimately, Urbit has to stay playful. Urbit makes programming, even systems programming, a lot of fun. Fun is open-ended and surprising. It allows for whimsy in code and product.
57+
58+Our developer onboarding and open source culture should be a model for the entire open source world. This is neither impossible nor impractical—we've made huge strides in legibility, and we're sailing with the wind.
59+
content/blog/gifts-q3-2020.mdnew file+72
@@ -0,0 +1,72 @@
1++++
2+title = "Gifts Q3 2020"
3+date = "2020-09-22"
4+description = "Twice a year we distribute address space to those that have made valuable contributions to Urbit. Now called our Gifts program, the gifting of address space has been part of Urbit long before we had a grants program."
5+
6+[taxonomies]
7+grant_type = [ "Gift" ]
8+grant_category = [ ]
9+
10+[extra]
11+author = "Josh Lehman"
12+ship = "~wolref-podlex"
13+image = "https://media.urbit.org/site/posts/essays/gifts.png"
14++++
15+
16+![](https://media.urbit.org/site/posts/essays/gifts.png)
17+
18+Twice a year we distribute address space to those that have made valuable contributions to Urbit. Now called our _Gifts_ program, the gifting of address space has been part of Urbit long before we had a grants program.
19+
20+I'm happy to announce that urbit.org has a record number of gifts to distribute to community contributors for the period from February to August of 2020. Because the gifting of address space is an old tradition, and the last several months have seen an unprecedented amount of user growth, let’s talk about why we do this.
21+
22+## Why gifts?
23+
24+One way to think about Urbit is as _infrastructure for powering digital communities._ We’ve talked about this before in [some detail](https://urbit.org/blog/urbit-is-for-communities/), so while I won’t rehash the “why” of that here, I’ll reiterate that what we really want is a digital world that's generated by the communities that inhabit it.
25+
26+We know that digital communities need better technology with which to generate their world; just as importantly though, they need _people_ to inhabit and develop them.
27+
28+Tlon and urbit.org can’t bring the world into Urbit alone—we need community members to help us. By distributing address space to a variety of people that can invite their friends and families, the network can grow faster, more organically, and with a wider range of diversity.
29+
30+Currently, the majority of available address space is owned by Tlon and urbit.org, but it won’t stay that way. Instead, we want to give address space to folks that want Urbit to succeed. Because we’re custodians of something valuable it’s important that we are intentional about how we handle it. We treat that responsibility seriously.
31+
32+Gifts are one of the ways we invest in the future of the network. We look for others that see Urbit’s value and engage in building the digital home that they want to live in. They ease the learning curve for people new to Urbit, contribute to the technology, and create thriving communities.
33+
34+## Recipients
35+
36+Gifts are being awarded for a variety of reasons this quarter. As usual, there have been plenty of code and documentation contributions, but this time around we’re also recognizing those who have evangelized Urbit, been active in guiding newcomers to the system, and developed thriving communities within Landscape.
37+
38+Gifts are being awarded using the following criteria:
39+
40+**Bronze**: one star for continuous contributions over the last six months in at least one of the above areas.
41+
42+**Silver**: two stars for creation of something exceptional and/or contributing across many categories.
43+
44+**Gold**: three stars awarded to one contributor who has contributed at a volume that indicates a high degree of care and ownership.
45+
46+Without further ado, here are the recipients:
47+
48+### Gold
49+
50+[`~radbur-sivmus`](https://github.com/tylershuster) has more or less become an unofficial member of the interface team by tackling an absolutely [immense](https://github.com/urbit/urbit/pulls?q=is%3Apr+author%3Atylershuster+) amount of Landscape-related work.
51+
52+### Silver
53+
54+- [`~littel-wolfur`](https://github.com/ryjm): Jake maintains the premier development group in Urbit, The Forge, and has led the way for other developers by authoring [srrs](https://github.com/ryjm/srrs), one of the more popular community-developed applications on Urbit.
55+- [`~botter-nidnul`](https://github.com/botter-nidnul): `~botter` has been instrumental in furthering [Urbit on ARM](https://botter-nidnul.github.io/), has made contributions across Vere and our documentation, and been highly active in onboarding newcomers on our Discord server.
56+- [`~timluc-miptev`](https://github.com/timlucmiptev): `~timluc` is highly engaged in many groups and the maintainer of some, wrote the [Nock for Everyday Coders](https://blog.timlucmiptev.space/part1.html) guide, and has gone far above and beyond in teaching the community about developing Landscape applications.
57+- [`~lanrus-rinfep`](https://github.com/dclelland): Daniel has done extensive development on iOS by writing Swift libraries for interacting with Urbit, and employed all of these towards the development of an [iOS client for chat](https://github.com/dclelland/UrsusChat).
58+- [`~minder-folden`](https://twitter.com/the_pritchard): Jonathan is a prolific member of the community. His group _The Sanctorium_ is always active, he's always around to help newcomers to the system, is an active evangelist on Twitter, and a creator of much excellent content.
59+
60+### Bronze
61+
62+- [`~watter-parter`](https://github.com/lukechampine): Luke has made a number of [contributions](https://github.com/urbit/urbit/pulls?q=is%3Apr+is%3Aclosed+author%3Alukechampine) to Arvo, and wrote a great [introductory guide](https://github.com/lukechampine/rote) to developing Gall agents.
63+- [`~naltyc-wornes`](https://github.com/JohnELester): `~naltyc` runs the popular group “Smol Computers” both inside and outside of Urbit where discussions ensue about various forms of computing on small devices like Android and ARM, and actively evangelizes the project.
64+- [`~nartes-fasrum`](https://twitter.com/nartesfasrum): `~nartes` evangelizes Urbit on Twitter by creating artwork, and maintains the popular food-centric group “Urbytes.”
65+- [`~fonnyx-nopmer`](https://twitter.com/fonnyx_nopmer): `~fonnyx` maintains an active presence throughout many groups on Urbit and runs the first Urbit-centric podcast, [Hooked on fonnyx](https://www.twitch.tv/fonnyx).
66+- `~libhut-samwes`: `~libhut` started and maintains one of the most popular groups on Urbit centered on crypto and investing, and contributes to conversations throughout Urbit.
67+- `~salmus-master`: In addition to embodying the quality of high-level, respectful debate we like to see, `~salmus` created the group: “The Tribal Network,” where he maintains one of the most active long-form notebooks on Urbit.
68+- [`~fostyr-solfyr`](https://github.com/cmarcelo): `~fostyr` has submitted a number of PRs against Arvo, including a much-requested feature to reset the web login code.
69+- [`~sarpen-laplux`](https://github.com/xiphiness): `~sarpen` has done a significant amount of research and work on Ethereum ABI parsing and other Ethereum-related topics in addition to being an active participant in dialogues throughout Urbit.
70+- `~mister-todteg`: `~mister` is a top evangelist of Urbit on Twitter, has brought many newcomers onto the network, and has even made several hires for his company from within the network.
71+
72+Thank you to all who contributed to making Urbit what it is today!
content/blog/governance-of-urbit.mdnew file+43
@@ -0,0 +1,43 @@
1++++
2+title = "Governance of urbit.org"
3+date = "2019-01-10"
4+description = "Stewardship of the Urbit Project."
5+aliases = [
6+ "/posts/essays/governance-of-urbit",
7+ "/posts/governance-of-urbit"
8+]
9+
10+[extra]
11+author = "Erik Newton"
12+ship = "~patnes-rigtyn"
13++++
14+
15+![](https://storage.googleapis.com/media.urbit.org/site/governance-1.svg)
16+
17+## Summary
18+
19+Long before Urbit first appeared as a prototype in 2013, we considered Urbit address space to be property. Granted, Urbit property ownership was only reflected as a text file in a github repository – but it was always designed to be cryptographically owned, and we've always taken that file seriously.
20+
21+If you've ever looked at that text file, you've probably noticed that there has been a pool of Urbit assets there marked "urbit.org" since the beginning. Now that we're moving our property registry out of that repository and onto the Ethereum blockchain, we wanted to be as clear as we can be about what the plan is for those urbit.org addresses.
22+
23+The TL;DR is that "urbit.org" will likely split into a separate entity from Tlon in the future. For now though, Tlon and urbit.org have the same mandate, so separating them doesn't make sense. For the time being, Tlon will continue to manage and use urbit.org assets directly for platform development. As a first step toward making urbit.org independent we've started to develop a board of advisors who we hope will one day manage those assets independently.
24+
25+## Background
26+
27+The history of a few lines in a text file doesn't give a whole lot of context. So, first, let's fill in a few more of the details.
28+
29+In 2013 Curtis and Tlon each contributed 32 galaxies to a pool newly called "urbit.org." The idea at the time was to set aside address space to fund "platform development" – in the spirit of the IETF or the Mozilla foundation. This was long before anyone had heard of a Swiss blockchain foundation or anything of the sort. Our view was that it was going to take a lot of resources to build a system as robust and far reaching as Urbit intends to be, and 64 galaxies (25% of the total network) seemed sufficient. It was thought at the time that urbit.org might eventually take the form of a separate foundation, but we were simply too small and under-resourced a team to figure out the right legal structure at the time.
30+
31+Tlon – as distinct from urbit.org – has always been imagined as a future service provider in the urbit ecosystem. But Urbit is still young, so those services aren't really needed yet.
32+
33+Instead, what is needed is platform development. So Tlon has acted, in a way, as urbit.org was supposed to, by taking on the bulk of platform development efforts. This work consists of everything from kernel development to interface design and documentation. Tlon has sold (and granted) both its own galaxies, and some of those originally designated as urbit.org galaxies towards this end. We'll continue to do this for the foreseeable future, since Urbit's development needs (though finite) remain ongoing. We can't predict exactly how long this will continue, although we wish we could!
34+
35+## Future plans
36+
37+As Urbit becomes more widely used, we expect to make the Tlon/urbit.org separation real.
38+
39+We've considered the foundation model, but have come to the conclusion that it doesn't really make sense. For one, it's quite expensive in terms both of administrative overhead, and the associated legal costs. For another, there just isn't anyone we trust enough to take over high level management of such an organization (see Tezos). Finally, our view is that foundations are not entirely effective in their mandates (see [this article](https://nadiaeghbal.com/foundations) from our friend Nadia).
40+
41+One step we're pursuing is the creation of a board of advisors to guide our use of the urbit.org assets at Tlon. We're in discussions with several potential board members now. Our goal with this structure is to include more voices outside of Tlon in the process of governing the urbit.org assets, and to make their advice transparent to the public.
42+
43+As with all of our projects, we think it's better to walk before we run. For now, Tlon will continue to act as urbit.org and use both pools of resources for ongoing platform development. Next, we'll create a board to advise on the use of those resources. Eventually, Tlon and urbit.org will likely become separate entities. We'll get there – one step at a time.
content/blog/hackathon-results.mdnew file+59

This diff is too big to show here.

content/blog/haleek-maul-interview.mdnew file+71

This diff is too big to show here.

content/blog/hoon-4-lispers.mdnew file+764

This diff is too big to show here.

content/blog/hosting-the-future.mdnew file+30

This diff is too big to show here.

content/blog/immunology-for-the-internet-age.mdnew file+118

This diff is too big to show here.

content/blog/infrastructural.mdnew file+73

This diff is too big to show here.

content/blog/interim-constitution.mdnew file+145

This diff is too big to show here.

content/blog/interplanetary_commerce.mdnew file+37

This diff is too big to show here.

content/blog/introducing-os1.mdnew file+140

This diff is too big to show here.

content/blog/introduction-to-the-combine-dao.mdnew file+46

This diff is too big to show here.

content/blog/io-in-hoon.mdnew file+342

This diff is too big to show here.

content/blog/iot.mdnew file+445

This diff is too big to show here.

content/blog/landscape-a-portrait.mdnew file+89

This diff is too big to show here.

content/blog/layer-2-faq.mdnew file+155

This diff is too big to show here.

content/blog/magic.mdnew file+205

This diff is too big to show here.

content/blog/metaphase.mdnew file+79

This diff is too big to show here.

content/blog/on-christopher-alexander.mdnew file+70

This diff is too big to show here.

content/blog/pin-the-face-that-launches-a-thousand-ships.mdnew file+146

This diff is too big to show here.

content/blog/pki-maze.mdnew file+70

This diff is too big to show here.

content/blog/platform-decay.mdnew file+50

This diff is too big to show here.

content/blog/precepts-discussion.mdnew file+756

This diff is too big to show here.

content/blog/precepts.mdnew file+341

This diff is too big to show here.

content/blog/providers.mdnew file+82

This diff is too big to show here.

content/blog/pseudonymous-reputation.mdnew file+64

This diff is too big to show here.

content/blog/rollups.mdnew file+222

This diff is too big to show here.

content/blog/security-and-continuity.mdnew file+60

This diff is too big to show here.

content/blog/security-audit.mdnew file+153

This diff is too big to show here.

content/blog/simple-durable-yours.mdnew file+48

This diff is too big to show here.

content/blog/smart-home-of-the-future.mdnew file+60

This diff is too big to show here.

content/blog/stable-arvo.mdnew file+93

This diff is too big to show here.

content/blog/state-of-urbit.mdnew file+95

This diff is too big to show here.

content/blog/the-100-year-computer.mdnew file+30

This diff is too big to show here.

content/blog/the-dao-as-a-lesson-in-decentralized-governance.mdnew file+327

This diff is too big to show here.

content/blog/the-missing-middle.mdnew file+50

This diff is too big to show here.

content/blog/the-shape-of-dao-governance-to-come.mdnew file+103

This diff is too big to show here.

content/blog/the-state-of-landscape.mdnew file+78

This diff is too big to show here.

content/blog/the-understanding-urbit-podcast.mdnew file+22

This diff is too big to show here.

content/blog/the-urbit-address-space.mdnew file+299

This diff is too big to show here.

content/blog/tools-of-our-own.mdnew file+66

This diff is too big to show here.

content/blog/toward-a-frozen-operating-system.mdnew file+260

This diff is too big to show here.

content/blog/toward-a-new-clay.mdnew file+1012

This diff is too big to show here.

content/blog/urbit-and-bitcoin.mdnew file+21

This diff is too big to show here.

content/blog/urbit-and-the-blockchain.mdnew file+272

This diff is too big to show here.

content/blog/urbit-creator-daos.mdnew file+74

This diff is too big to show here.

content/blog/urbit-for-creators.mdnew file+47

This diff is too big to show here.

content/blog/urbit-for-normies.mdnew file+175

This diff is too big to show here.

content/blog/urbit-grants-and-mid-2019-gifts.mdnew file+49

This diff is too big to show here.

content/blog/urbit-is-for-communities.mdnew file+92

This diff is too big to show here.

content/blog/urbithost-interview.mdnew file+116

This diff is too big to show here.

content/blog/using-urbit-in-2023.mdnew file+55

This diff is too big to show here.

content/blog/value-of-address-space-pt1.mdnew file+144

This diff is too big to show here.

content/blog/value-of-address-space-pt2.mdnew file+141

This diff is too big to show here.

content/blog/value-of-address-space-pt3.mdnew file+117

This diff is too big to show here.

content/blog/what-is-urbit-for.mdnew file+196

This diff is too big to show here.

content/blog/why-hoon.mdnew file+274

This diff is too big to show here.

content/blog/why-urbit-probably-does-not-need-a-blockchain.mdnew file+623

This diff is too big to show here.

content/blog/your-last-computer.mdnew file+36

This diff is too big to show here.

content/bounties.mdnew file+54

This diff is too big to show here.

content/campus/_index.mdnew file+37

This diff is too big to show here.

content/campus/blockchain-enthusiasts.mdnew file+35

This diff is too big to show here.

content/campus/creatives.mdnew file+21

This diff is too big to show here.

content/coinmarketcap.mdnew file+8

This diff is too big to show here.

content/communities/urbit-austin.mdnew file+11

This diff is too big to show here.

content/communities/urbit-berlin.mdnew file+16

This diff is too big to show here.

content/communities/urbit-christchurch.mdnew file+13

This diff is too big to show here.

content/communities/urbit-cph.mdnew file+11

This diff is too big to show here.

content/communities/urbit-dc.mdnew file+19

This diff is too big to show here.

content/communities/urbit-denver.mdnew file+19

This diff is too big to show here.

content/communities/urbit-london.mdnew file+15

This diff is too big to show here.

content/communities/urbit-mst.mdnew file+13

This diff is too big to show here.

content/communities/urbit-ny.mdnew file+11

This diff is too big to show here.

content/communities/urbit-paris.mdnew file+23

This diff is too big to show here.

content/communities/urbit-seattle.mdnew file+14

This diff is too big to show here.

content/communities/urbit-sf.mdnew file+15

This diff is too big to show here.

content/ecosystem/spotlight/2022-august.mdnew file+44

This diff is too big to show here.

content/ecosystem/spotlight/2022-december.mdnew file+40

This diff is too big to show here.

content/ecosystem/spotlight/2022-november.mdnew file+42

This diff is too big to show here.

content/ecosystem/spotlight/2022-october.mdnew file+41

This diff is too big to show here.

content/ecosystem/spotlight/2022-september.mdnew file+45

This diff is too big to show here.

content/ecosystem/spotlight/2023-february.mdnew file+48

This diff is too big to show here.

content/ecosystem/spotlight/2023-june.mdnew file+40

This diff is too big to show here.

content/ecosystem/spotlight/2023-may.mdnew file+50

This diff is too big to show here.

content/events/2017-08-11-after-hours-bootstrapping-urbit-from-the-ethereum-blockchain.mdnew file+21

This diff is too big to show here.

content/events/2017-09-22-after-hours-fun-with-arvo-the-urbit-os.mdnew file+20

This diff is too big to show here.

content/events/2017-10-26-after-hours-designing-robust-human-systems.mdnew file+20

This diff is too big to show here.

content/events/2017-11-16-after-hours-visiting-contributors.mdnew file+17

This diff is too big to show here.

content/events/2018-01-26-urbit-irl-20181.mdnew file+18

This diff is too big to show here.

content/events/2018-02-23-urbit-irl-20182.mdnew file+18

This diff is too big to show here.

content/events/2018-03-11-20183-hoon-school.mdnew file+16

This diff is too big to show here.

content/events/2018-03-23-urbit-irl-20183.mdnew file+18

This diff is too big to show here.

content/events/2018-04-08-20184-hoon-school.mdnew file+16

This diff is too big to show here.

content/events/2018-05-25-urbit-irl-20185.mdnew file+18

This diff is too big to show here.

content/events/2018-08-03-after-hours-decentralized-web-summit.mdnew file+14

This diff is too big to show here.

content/events/2018-08-17-urbit-irl-20188.mdnew file+20

This diff is too big to show here.

content/events/2018-09-21-urbit-irl-20189.mdnew file+18

This diff is too big to show here.

content/events/2018-10-10-urbit-zcash-blockchain-week.mdnew file+24

This diff is too big to show here.

content/events/2018-12-20-after-hours-its-just-a-party-man.mdnew file+18

This diff is too big to show here.

content/events/2019-03-01-after-hours-ask-galen-anything.mdnew file+20

This diff is too big to show here.

content/events/2019-03-08-urbit-irl-austin-tx.mdnew file+16

This diff is too big to show here.

content/events/2019-04-19-urbit-irl-20194.mdnew file+20

This diff is too big to show here.

content/events/2019-05-17-urbit-irl-20195.mdnew file+18

This diff is too big to show here.

content/events/2019-06-21-urbit-irl-20196.mdnew file+18

This diff is too big to show here.

content/events/2019-07-19-urbit-irl-20197.mdnew file+20

This diff is too big to show here.

content/events/2019-08-29-urbit-austin-20198.mdnew file+18

This diff is too big to show here.

content/events/2019-10-04-urbit-irl-201910.mdnew file+20

This diff is too big to show here.

content/events/2019-11-15-urbit-irl-201911.mdnew file+20

This diff is too big to show here.

content/events/2019-12-13-urbit-irl-201912.mdnew file+28

This diff is too big to show here.

content/events/2020-01-24-urbit-irl-20201.mdnew file+24

This diff is too big to show here.

content/events/2020-02-28-urbit-irl-20202.mdnew file+22

This diff is too big to show here.

content/events/2020-04-03-urbit-os1-launch-party.mdnew file+49

This diff is too big to show here.

content/events/2020-10-09-urbit-hosting-launch-event.mdnew file+38

This diff is too big to show here.

content/events/2020-11-05-developer-call-graph-store.mdnew file+24

This diff is too big to show here.

content/events/2020-11-19-developer-call-bittorrent-tracking-on-urbit.mdnew file+22

This diff is too big to show here.

content/events/2020-12-10-developer-call-injecting-external-services-into-urbit.mdnew file+24

This diff is too big to show here.

content/events/2021-02-04-developer-call-architectural-idea-maze.mdnew file+23

This diff is too big to show here.

content/events/2021-03-04-developer-call-scaling-azimuth.mdnew file+25

This diff is too big to show here.

content/events/2021-03-18-developer-call-pressure-and-protolith.mdnew file+25

This diff is too big to show here.

content/events/2021-04-01-developer-call-javascript-apps-on-urbit.mdnew file+25

This diff is too big to show here.

content/events/2021-04-15-developer-call-software-distribution.mdnew file+34

This diff is too big to show here.

content/events/2021-04-27-bitcoin-launch.mdnew file+27

This diff is too big to show here.

content/events/2021-04-29-developer-call-real-time-communications-on-urbit.mdnew file+30

This diff is too big to show here.

content/events/2021-05-13-developer-call-versioned-networking.mdnew file+26

This diff is too big to show here.

content/events/2021-05-27-town-hall.mdnew file+54

This diff is too big to show here.

content/events/2021-07-01-developer-call-runtime-future.mdnew file+25

This diff is too big to show here.

content/events/2021-07-15-developer-call-yakshaving.mdnew file+25

This diff is too big to show here.

content/events/2021-09-02-21q3-dc-meetup.mdnew file+22

This diff is too big to show here.

content/events/2021-09-16-developer-call-azimuth-scaled.mdnew file+46

This diff is too big to show here.

content/events/2021-09-24-urbit-outside.mdnew file+23

This diff is too big to show here.

content/events/2021-10-07-developer-call-visor.mdnew file+38

This diff is too big to show here.

content/events/2021-10-15-assembly.mdnew file+26

This diff is too big to show here.

content/events/2021-10-16-assembly-keynote.mdnew file+14

This diff is too big to show here.

content/events/2021-10-16-assembly-sw-dist-qa.mdnew file+14

This diff is too big to show here.

content/events/2021-10-28-developer-call-hosting.mdnew file+33

This diff is too big to show here.

content/events/2021-11-26-meetup-brisbane.mdnew file+30

This diff is too big to show here.

content/events/2022-01-21-meetup-austin.mdnew file+16

This diff is too big to show here.

content/events/2022-02-17-developer-call-building-developers.mdnew file+27

This diff is too big to show here.

content/events/2022-03-24-developer-call-urbit-three-ways-with-quartus.mdnew file+26

This diff is too big to show here.

content/events/2022-04-05-urbit-meetup-stockholm.mdnew file+30

This diff is too big to show here.

content/events/2022-04-21-developer-call-uqbar-and-urbits-first-blockchain.mdnew file+24

This diff is too big to show here.

content/events/2022-04-26-urbit-foundation-meetup-kingsnight-amsterdam.mdnew file+23

This diff is too big to show here.

content/events/2022-05-06-urbit-weekend-kansas.mdnew file+20

This diff is too big to show here.

content/events/2022-06-16-developer-call-urbits-new-terminal-stack-tlon copy.mdnew file+23

This diff is too big to show here.

content/events/2022-06-16-developer-call-urbits-new-terminal-stack-tlon.mdnew file+24

This diff is too big to show here.

content/events/2022-07-07-hackathon-hackfs.mdnew file+18

This diff is too big to show here.

content/events/2022-07-08-urbit-fireside-chat-1.mdnew file+19

This diff is too big to show here.

content/events/2022-07-21-developer-holium-community-os.mdnew file+25

This diff is too big to show here.

content/events/2022-07-21-ethcc-paris-22-meetup.mdnew file+21

This diff is too big to show here.

content/events/2022-07-22-urbit-outside-alta-plaza.mdnew file+22

This diff is too big to show here.

content/events/2022-07-28-urbit-meetup-milano-22.mdnew file+22

This diff is too big to show here.

content/events/2022-08-04-reassembly.mdnew file+31

This diff is too big to show here.

content/events/2022-08-12-urbit-fireside-chat-2.mdnew file+20

This diff is too big to show here.

content/events/2022-08-27-urbit-outside-alta-plaza.mdnew file+17

This diff is too big to show here.

content/events/2022-09-08-developer-call-future-of-khan.mdnew file+25

This diff is too big to show here.

content/events/2022-09-15-developer-call-IoT.mdnew file+27

This diff is too big to show here.

content/events/2022-09-19-rabbit-hole-talk.mdnew file+19

This diff is too big to show here.

content/events/2022-09-22-assembly.mdnew file+14

This diff is too big to show here.

content/events/2022-10-13-devcon-bogotá-urbit-meetup-22.mdnew file+36

This diff is too big to show here.

content/events/2022-11-01-developer-week.mdnew file+75

This diff is too big to show here.

content/events/2022-11-19-urbit-irl.mdnew file+18

This diff is too big to show here.

content/events/2022-19-10-developer-call-herd-dependency.mdnew file+25

This diff is too big to show here.

content/events/2023-01-28-urbit-meetup-christchurch.mdnew file+21

This diff is too big to show here.

content/events/2023-01-31-urbit-meetup-krakow.mdnew file+26

This diff is too big to show here.

content/events/2023-02-23-urbit-meetup-berlin.mdnew file+27

This diff is too big to show here.

content/events/2023-03-05-meetup-el-salvador.mdnew file+24

This diff is too big to show here.

content/events/2023-03-25-urbit-meetup-christchurch.mdnew file+21

This diff is too big to show here.

content/events/2023-04-18-urbit-lisbon.mdnew file+19

This diff is too big to show here.

content/events/2023-04-27-urbit-meetup-berlin.mdnew file+27

This diff is too big to show here.

content/events/2023-04-27_urbit-austin-meetup-consensus.mdnew file+16

This diff is too big to show here.

content/events/2023-05-10_urbit-meetup-berlin.mdnew file+25

This diff is too big to show here.

content/events/2023-05-14_urbit-meetup-london.mdnew file+23

This diff is too big to show here.

content/events/2023-05-18_urbit-denver-meetup.mdnew file+19

This diff is too big to show here.

content/events/2023-05-18_urbit-miami-meetup.mdnew file+20

This diff is too big to show here.

content/events/2023-05-27_urbit-meetup-london.mdnew file+21

This diff is too big to show here.

content/events/2023-05-27_urbit-meetup-mst.mdnew file+20

This diff is too big to show here.

content/events/2023-06-03-urbit-meetup-christchurch.mdnew file+24

This diff is too big to show here.

content/events/2023-06-08_urbit-meetup-berlin.mdnew file+25

This diff is too big to show here.

content/events/2023-06-08_urbit-meetup-prague.mdnew file+39

This diff is too big to show here.

content/events/2023-06-12-developer-week.mdnew file+95

This diff is too big to show here.

content/events/2023-06-15_urbit-denver-meetup.mdnew file+19

This diff is too big to show here.

content/events/2023-06-24-urbit-meetup-christchurch.mdnew file+24

This diff is too big to show here.

content/events/2023-06-29-Urbit-Paris-Meetup-1.mdnew file+30

This diff is too big to show here.

content/events/2023-07-01_urbit-meetup-mst.mdnew file+23

This diff is too big to show here.

content/events/2023-07-20-Urbit-Paris-Meetup-ethcc.mdnew file+53

This diff is too big to show here.

content/events/2023-08-16_reassembly.mdnew file+22

This diff is too big to show here.

content/events/2023-10-28_urbit-assembly-lisboa.mdnew file+24

This diff is too big to show here.

content/faq.mdnew file+267

This diff is too big to show here.

content/fora.mdnew file+11

This diff is too big to show here.

content/getting-started/_index.mdnew file+28

This diff is too big to show here.

content/getting-started/cli.mdnew file+290

This diff is too big to show here.

content/getting-started/cloud-hosting.mdnew file+468

This diff is too big to show here.

content/getting-started/desktop.mdnew file+11

This diff is too big to show here.

content/getting-started/get-id.mdnew file+113

This diff is too big to show here.

content/getting-started/getting-around.mdnew file+55

This diff is too big to show here.

content/getting-started/home-servers.mdnew file+27

This diff is too big to show here.

content/getting-started/hosted.mdnew file+30

This diff is too big to show here.

content/getting-started/hosting-providers.mdnew file+24

This diff is too big to show here.

content/getting-started/installing-applications.mdnew file+39

This diff is too big to show here.

content/getting-started/interfaces.mdnew file+10

This diff is too big to show here.

content/getting-started/joining-groups.mdnew file+54

This diff is too big to show here.

content/getting-started/self-host.mdnew file+33

This diff is too big to show here.

content/gifts/sample.mdnew file+6

This diff is too big to show here.

content/grants/2019/bitcoin-node-json-rpc-api-part-1.mdnew file+54

This diff is too big to show here.

content/grants/2019/bitcoin-node-json-rpc-api-part-2.mdnew file+54

This diff is too big to show here.

content/grants/2019/bitcoin-node-json-rpc-api-part-3.mdnew file+54

This diff is too big to show here.

content/grants/2019/bitcoin-node-json-rpc-api-part-4.mdnew file+54

This diff is too big to show here.

content/grants/2019/bitcoin-wallet-on-bridge.mdnew file+62

This diff is too big to show here.

content/grants/2019/escape.mdnew file+46

This diff is too big to show here.

content/grants/2019/gall-api-documentation.mdnew file+53

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-1.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-10.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-2.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-3.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-4.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-5.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-6.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-7.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-8.mdnew file+62

This diff is too big to show here.

content/grants/2019/host-two-urbit-meetups-9.mdnew file+62

This diff is too big to show here.

content/grants/2019/ragnarok-online-on-urbit.mdnew file+53

This diff is too big to show here.

content/grants/2019/udon-syntax-highlighter.mdnew file+43

This diff is too big to show here.

content/grants/2019/unit-tests-for-json-parsing.mdnew file+49

This diff is too big to show here.

content/grants/2019/unit-tests-for-pure-algorithms.mdnew file+60

This diff is too big to show here.

content/grants/2019/unit-tests-for-sha-functions.mdnew file+50

This diff is too big to show here.

content/grants/2019/unit-tests-for-zuse-cryptographic-functions.mdnew file+52

This diff is too big to show here.

content/grants/2020/a-book-about-urbit.mdnew file+84

This diff is too big to show here.

content/grants/2020/a-network-enabled-spatial-database-and-demonstration-app.mdnew file+94

This diff is too big to show here.

content/grants/2020/antechamber.mdnew file+106

This diff is too big to show here.

content/grants/2020/art-by-urbit.mdnew file+31

This diff is too big to show here.

content/grants/2020/bart-train-tracker-landscape-tile.mdnew file+50

This diff is too big to show here.

content/grants/2020/bitcoin-full-node-provider-and-wallet.mdnew file+102

This diff is too big to show here.

content/grants/2020/bitcoin-key-derivation.mdnew file+66

This diff is too big to show here.

content/grants/2020/boston-t-train-tracker-landscape-tile.mdnew file+53

This diff is too big to show here.

content/grants/2020/calendar-ui.mdnew file+55

This diff is too big to show here.

content/grants/2020/calendar.mdnew file+115

This diff is too big to show here.

content/grants/2020/content-saver.mdnew file+44

This diff is too big to show here.

content/grants/2020/cta-train-tracker-landscape-tile.mdnew file+52

This diff is too big to show here.

content/grants/2020/display-eth-data.mdnew file+55

This diff is too big to show here.

content/grants/2020/docker-image-for-cloud-container-orchestration.mdnew file+49

This diff is too big to show here.

content/grants/2020/ethereum-abi-parser.mdnew file+56

This diff is too big to show here.

content/grants/2020/go-airlock-library.mdnew file+44

This diff is too big to show here.

content/grants/2020/haskell-airlock-library.mdnew file+43

This diff is too big to show here.

content/grants/2020/hoon-001-learner-efficiency-and-early-learner-resources.mdnew file+78

This diff is too big to show here.

content/grants/2020/host-three-college-university-urbit-meetups-1.mdnew file+67

This diff is too big to show here.

content/grants/2020/host-three-college-university-urbit-meetups-2.mdnew file+67

This diff is too big to show here.

content/grants/2020/host-three-college-university-urbit-meetups-3.mdnew file+67

This diff is too big to show here.

content/grants/2020/host-three-virtual-urbit-meetups.mdnew file+52

This diff is too big to show here.

content/grants/2020/links-in-urbit-reference-docs.mdnew file+31

This diff is too big to show here.

content/grants/2020/llelogram.mdnew file+55

This diff is too big to show here.

content/grants/2020/matrices-in-hoon.mdnew file+58

This diff is too big to show here.

content/grants/2020/matrixriotim-bridge-bot.mdnew file+42

This diff is too big to show here.

content/grants/2020/open-street-maps-data-importation.mdnew file+52

This diff is too big to show here.

content/grants/2020/staff-the-urbit-help-desk-1.mdnew file+64

This diff is too big to show here.

content/grants/2020/staff-the-urbit-help-desk-2.mdnew file+64

This diff is too big to show here.

content/grants/2020/staff-the-urbit-helpdesk-west.mdnew file+58

This diff is too big to show here.

content/grants/2020/the-complete-guide-to-gall-and-landscape.mdnew file+85

This diff is too big to show here.

content/grants/2020/tor-nodes-relay-search-tile.mdnew file+45

This diff is too big to show here.

content/grants/2020/typescript-airlock-library.mdnew file+43

This diff is too big to show here.

content/grants/2020/up-to-date-hoon-reference-card.mdnew file+30

This diff is too big to show here.

content/grants/2020/urbian-a-customized-linux-distribution-for-urbit-appliances.mdnew file+88

This diff is too big to show here.

content/grants/2020/urbit-event-series.mdnew file+92

This diff is too big to show here.

content/grants/2020/urbit-explainer-video.mdnew file+35

This diff is too big to show here.

content/grants/2020/urbit-http-api-for-kotlin.mdnew file+37

This diff is too big to show here.

content/grants/2020/urbit-http-api-for-rust.mdnew file+55

This diff is too big to show here.

content/grants/2020/urbit-http-interface-java-edition.mdnew file+66

This diff is too big to show here.

content/grants/2020/urbit-http-library-for-ruby.mdnew file+42

This diff is too big to show here.

content/grants/2020/urbit-online-meetup.mdnew file+30

This diff is too big to show here.

content/grants/2020/urbit-ship-and-star-hosting-and-troubleshooting-docs.mdnew file+38

This diff is too big to show here.

content/grants/2020/verifying-urbit-id-on-keybase.mdnew file+76

This diff is too big to show here.

content/grants/2020/web-scraper.mdnew file+45

This diff is too big to show here.

content/grants/2021/analytics-script.mdnew file+54

This diff is too big to show here.

content/grants/2021/authenticate-with-urbit.mdnew file+36

This diff is too big to show here.

content/grants/2021/azimuth-cli.mdnew file+164

This diff is too big to show here.

content/grants/2021/bitcoin-wallet-maintenance.mdnew file+65

This diff is too big to show here.

content/grants/2021/bridge-l2-revamp.mdnew file+57

This diff is too big to show here.

content/grants/2021/clojure-urbit-client.mdnew file+113

This diff is too big to show here.

content/grants/2021/comprehensive-local-server-and-mum-explanation-video.mdnew file+45

This diff is too big to show here.

content/grants/2021/contacts.mdnew file+37

This diff is too big to show here.

content/grants/2021/content-producer.mdnew file+40

This diff is too big to show here.

content/grants/2021/cross-platform-desktop-urbit-app.mdnew file+96

This diff is too big to show here.

content/grants/2021/cypherscope-bot.mdnew file+80

This diff is too big to show here.

content/grants/2021/educational-guide-todomvc-urbit-edition.mdnew file+332

This diff is too big to show here.

content/grants/2021/feed-aggregator.mdnew file+103

This diff is too big to show here.

content/grants/2021/graph-store-documentation-guide.mdnew file+115

This diff is too big to show here.

content/grants/2021/guide-to-s3.mdnew file+35

This diff is too big to show here.

content/grants/2021/host-two-urbit-meetups-11.mdnew file+62

This diff is too big to show here.

content/grants/2021/host-two-urbit-meetups-12.mdnew file+58

This diff is too big to show here.

content/grants/2021/host-two-urbit-meetups-13.mdnew file+59

This diff is too big to show here.

content/grants/2021/host-two-urbit-meetups-14.mdnew file+59

This diff is too big to show here.

content/grants/2021/host-two-urbit-meetups-15.mdnew file+59

This diff is too big to show here.

content/grants/2021/host-two-urbit-meetups-16.mdnew file+59

This diff is too big to show here.

content/grants/2021/json-jet.mdnew file+51

This diff is too big to show here.

content/grants/2021/login-with-urbit.mdnew file+84

This diff is too big to show here.

content/grants/2021/machine-learning.mdnew file+122

This diff is too big to show here.

content/grants/2021/market-interface.mdnew file+62

This diff is too big to show here.

content/grants/2021/meetup-bom.mdnew file+118

This diff is too big to show here.

content/grants/2021/minimal-urbit-os.mdnew file+58

This diff is too big to show here.

content/grants/2021/native-urbit.mdnew file+30

This diff is too big to show here.

content/grants/2021/network-explorer-data-pipeline-http-api.mdnew file+234

This diff is too big to show here.

content/grants/2021/nuck-jet.mdnew file+59

This diff is too big to show here.

content/grants/2021/overhaul-the-urbitorg-website.mdnew file+74

This diff is too big to show here.

content/grants/2021/planet-sales.mdnew file+66

This diff is too big to show here.

content/grants/2021/pokur.mdnew file+90

This diff is too big to show here.

content/grants/2021/ra-debugging-tools.mdnew file+26

This diff is too big to show here.

content/grants/2021/ra-page-tracking.mdnew file+34

This diff is too big to show here.

content/grants/2021/ra-segfaults.mdnew file+32

This diff is too big to show here.

content/grants/2021/ra-stack-overflow.mdnew file+32

This diff is too big to show here.

content/grants/2021/search-in-groups.mdnew file+42

This diff is too big to show here.

content/grants/2021/send-emails-to-a-mailing-list.mdnew file+78

This diff is too big to show here.

content/grants/2021/smol-future-sustained-knowledge-sharing-and-marketing.mdnew file+97

This diff is too big to show here.

content/grants/2021/speech-recognition.mdnew file+78

This diff is too big to show here.

content/grants/2021/staff-the-urbit-helpdesk-east.mdnew file+58

This diff is too big to show here.

content/grants/2021/static-site-generation.mdnew file+80

This diff is too big to show here.

content/grants/2021/thread-documentation.mdnew file+85

This diff is too big to show here.

content/grants/2021/translate-key-parts-of-urbitorg-into-german.mdnew file+31

This diff is too big to show here.

content/grants/2021/translate-key-parts-of-urbitorg-into-korean.mdnew file+31

This diff is too big to show here.

content/grants/2021/translate-key-parts-of-urbitorg-into-norwegian.mdnew file+32

This diff is too big to show here.

content/grants/2021/translate-key-parts-of-urbitorg-into-spanish.mdnew file+31

This diff is too big to show here.

content/grants/2021/try-urbit-website.mdnew file+33

This diff is too big to show here.

content/grants/2021/twitter-uv-extension.mdnew file+67

This diff is too big to show here.

content/grants/2021/ua-collaborative-text-editor.mdnew file+31

This diff is too big to show here.

content/grants/2021/ua-filesharer.mdnew file+30

This diff is too big to show here.

content/grants/2021/ua-heads-up-poker.mdnew file+35

This diff is too big to show here.

content/grants/2021/ua-invoice-system.mdnew file+35

This diff is too big to show here.

content/grants/2021/ua-marketplace.mdnew file+36

This diff is too big to show here.

content/grants/2021/ucal-google-and-outlook-integration.mdnew file+85

This diff is too big to show here.

content/grants/2021/urbit-api-for-elixir.mdnew file+38

This diff is too big to show here.

content/grants/2021/urbit-community-concierge-east-coast-2q2021.mdnew file+36

This diff is too big to show here.

content/grants/2021/urbit-community-concierge-east-coast.mdnew file+36

This diff is too big to show here.

content/grants/2021/urbit-community-concierge-west-coast-2q2021.mdnew file+36

This diff is too big to show here.

content/grants/2021/urbit-community-concierge-west-coast.mdnew file+36

This diff is too big to show here.

content/grants/2021/urbit-http-api-for-emacs-elisp.mdnew file+39

This diff is too big to show here.

content/grants/2021/urbit-http-api-for-python.mdnew file+46

This diff is too big to show here.

content/grants/2021/urbit-irc-bridge.mdnew file+49

This diff is too big to show here.

content/grants/2021/urbit-lfs-filehosting.mdnew file+68

This diff is too big to show here.

content/grants/2021/urbit-notes.mdnew file+102

This diff is too big to show here.

content/grants/2021/urbit-react-cookbook.mdnew file+47

This diff is too big to show here.

content/grants/2021/uturn.mdnew file+38

This diff is too big to show here.

content/grants/2021/uv-extension-library.mdnew file+44

This diff is too big to show here.

content/grants/2021/video-content-manager.mdnew file+61

This diff is too big to show here.

content/grants/2021/volt-lightning-on-urbit.mdnew file+313

This diff is too big to show here.

content/grants/2021/webrtc-gall-agent-and-external-app.mdnew file+81

This diff is too big to show here.

content/grants/2021/~home-urbit.mdnew file+119

This diff is too big to show here.

content/grants/2022/abacus.mdnew file+56

This diff is too big to show here.

content/grants/2022/app-engram.mdnew file+117

This diff is too big to show here.

content/grants/2022/app-openbsd.mdnew file+53

This diff is too big to show here.

content/grants/2022/app-store.mdnew file+159

This diff is too big to show here.

content/grants/2022/app-urvault.mdnew file+41

This diff is too big to show here.

content/grants/2022/app-uv-native-notificatons.mdnew file+42

This diff is too big to show here.

content/grants/2022/apprenticeship-extending-bitcoin.mdnew file+76

This diff is too big to show here.

content/grants/2022/apprenticeship-studio-collections.mdnew file+55

This diff is too big to show here.

content/grants/2022/apprenticeship-studio-email.mdnew file+40

This diff is too big to show here.

content/grants/2022/astrolabe.mdnew file+165

This diff is too big to show here.

content/grants/2022/books-development.mdnew file+44

This diff is too big to show here.

content/grants/2022/books.mdnew file+116

This diff is too big to show here.

content/grants/2022/calendar-holium.mdnew file+53

This diff is too big to show here.

content/grants/2022/chess-bounty.mdnew file+54

This diff is too big to show here.

content/grants/2022/chronicle.mdnew file+63

This diff is too big to show here.

content/grants/2022/communal-computing.mdnew file+130

This diff is too big to show here.

content/grants/2022/cue.mdnew file+60

This diff is too big to show here.

content/grants/2022/desk-import-export.mdnew file+102

This diff is too big to show here.

content/grants/2022/digital-editor-MROB.mdnew file+50

This diff is too big to show here.

content/grants/2022/digital-storefront.mdnew file+73

This diff is too big to show here.

content/grants/2022/dusko-valve.mdnew file+81

This diff is too big to show here.

content/grants/2022/eth-provider.mdnew file+65

This diff is too big to show here.

content/grants/2022/eth-wallet.mdnew file+49

This diff is too big to show here.

content/grants/2022/eyre-scry.mdnew file+72

This diff is too big to show here.

content/grants/2022/faux.mdnew file+58

This diff is too big to show here.

content/grants/2022/filesharer.mdnew file+100

This diff is too big to show here.

content/grants/2022/full-stop.mdnew file+131

This diff is too big to show here.

content/grants/2022/gather.mdnew file+87

This diff is too big to show here.

content/grants/2022/general-web-permissions.mdnew file+36

This diff is too big to show here.

content/grants/2022/gnosis-safe.mdnew file+56

This diff is too big to show here.

content/grants/2022/go-urbit.mdnew file+64

This diff is too big to show here.

content/grants/2022/gora-apprentice.mdnew file+61

This diff is too big to show here.

content/grants/2022/herd.mdnew file+58

This diff is too big to show here.

content/grants/2022/hoon-eval.mdnew file+56

This diff is too big to show here.

content/grants/2022/hoon-markdown-library.mdnew file+52

This diff is too big to show here.

content/grants/2022/http-server-driver.mdnew file+98

This diff is too big to show here.

content/grants/2022/keep.mdnew file+119

This diff is too big to show here.

content/grants/2022/knox.mdnew file+81

This diff is too big to show here.

content/grants/2022/lexicon.mdnew file+69

This diff is too big to show here.

content/grants/2022/lightning-development.mdnew file+201

This diff is too big to show here.

content/grants/2022/loom-pointer-compression.mdnew file+62

This diff is too big to show here.

content/grants/2022/meld-memory.mdnew file+55

This diff is too big to show here.

content/grants/2022/membrane.mdnew file+98

This diff is too big to show here.

content/grants/2022/middleware-apprentice.mdnew file+55

This diff is too big to show here.

content/grants/2022/minesweeper.mdnew file+48

This diff is too big to show here.

content/grants/2022/native-planet-2.mdnew file+90

This diff is too big to show here.

content/grants/2022/nested-goals.mdnew file+162

This diff is too big to show here.

content/grants/2022/notifications-protocol.mdnew file+64

This diff is too big to show here.

content/grants/2022/olif.mdnew file+97

This diff is too big to show here.

content/grants/2022/peat.mdnew file+66

This diff is too big to show here.

content/grants/2022/persistent-memory.mdnew file+157

This diff is too big to show here.

content/grants/2022/plug.mdnew file+165

This diff is too big to show here.

content/grants/2022/pony-bounty.mdnew file+72

This diff is too big to show here.

content/grants/2022/port-maintenance.mdnew file+72

This diff is too big to show here.

content/grants/2022/port-to-hosting.mdnew file+56

This diff is too big to show here.

content/grants/2022/profiling.mdnew file+74

This diff is too big to show here.

content/grants/2022/qr-login.mdnew file+48

This diff is too big to show here.

content/grants/2022/quorum.mdnew file+106

This diff is too big to show here.

content/grants/2022/regex-library.mdnew file+114

This diff is too big to show here.

content/grants/2022/seguro-phase-2.mdnew file+190

This diff is too big to show here.

content/grants/2022/seguro-prototype.mdnew file+66

This diff is too big to show here.

content/grants/2022/serving-the-people.mdnew file+101

This diff is too big to show here.

content/grants/2022/slam.mdnew file+113

This diff is too big to show here.

content/grants/2022/slaw-scot-jets.mdnew file+72

This diff is too big to show here.

content/grants/2022/smart-lightbulb-controller.mdnew file+104

This diff is too big to show here.

content/grants/2022/symmetric-routing.mdnew file+69

This diff is too big to show here.

content/grants/2022/trail.mdnew file+168

This diff is too big to show here.

content/grants/2022/trill-ufa.mdnew file+67

This diff is too big to show here.

content/grants/2022/trove.mdnew file+94

This diff is too big to show here.

content/grants/2022/urbit-forms.mdnew file+250

This diff is too big to show here.

content/grants/2022/urbit-interface-framework.mdnew file+88

This diff is too big to show here.

content/grants/2022/urbitswap.mdnew file+59

This diff is too big to show here.

content/grants/2022/value-articles.mdnew file+54

This diff is too big to show here.

content/grants/2022/volt-ui.mdnew file+54

This diff is too big to show here.

content/grants/2022/whom.mdnew file+70

This diff is too big to show here.

content/grants/2023/aera.mdnew file+50

This diff is too big to show here.

content/grants/2023/app-metrics.mdnew file+74

This diff is too big to show here.

content/grants/2023/blog-updates.mdnew file+64

This diff is too big to show here.

content/grants/2023/bridge-grab-bag.mdnew file+35

This diff is too big to show here.

content/grants/2023/community-meetups.mdnew file+37

This diff is too big to show here.

content/grants/2023/did-rfp.mdnew file+26

This diff is too big to show here.

content/grants/2023/elm.mdnew file+68

This diff is too big to show here.

content/grants/2023/email-stella-fixa-rfp.mdnew file+29

This diff is too big to show here.

content/grants/2023/eyre-noun-channels.mdnew file+42

This diff is too big to show here.

content/grants/2023/generator-doccords.mdnew file+46

This diff is too big to show here.

content/grants/2023/gh-concierge.mdnew file+42

This diff is too big to show here.

content/grants/2023/git-on-clay.mdnew file+42

This diff is too big to show here.

content/grants/2023/goals-2.mdnew file+64

This diff is too big to show here.

content/grants/2023/hoon-linter.mdnew file+30

This diff is too big to show here.

content/grants/2023/hoon-replit.mdnew file+45

This diff is too big to show here.

content/grants/2023/issue-grab-bag.mdnew file+36

This diff is too big to show here.

content/grants/2023/json-parser-suite.mdnew file+170

This diff is too big to show here.

content/grants/2023/kNock-property-testing.mdnew file+71

This diff is too big to show here.

content/grants/2023/lick.mdnew file+82

This diff is too big to show here.

content/grants/2023/mapping-ids.mdnew file+106

This diff is too big to show here.

content/grants/2023/network-weather.mdnew file+24

This diff is too big to show here.

content/grants/2023/oauth2-stella-fixa-rfp.mdnew file+31

This diff is too big to show here.

content/grants/2023/osmosis-client.mdnew file+48

This diff is too big to show here.

content/grants/2023/pastebin-RFP.mdnew file+28

This diff is too big to show here.

content/grants/2023/pastebin-proposal.mdnew file+33

This diff is too big to show here.

content/grants/2023/portal-features-1.mdnew file+82

This diff is too big to show here.

content/grants/2023/privacy-msg.mdnew file+89

This diff is too big to show here.

content/grants/2023/quorum-2.mdnew file+84

This diff is too big to show here.

content/grants/2023/replit.mdnew file+52

This diff is too big to show here.

content/grants/2023/school-support-23q1.mdnew file+43

This diff is too big to show here.

content/grants/2023/splitwise-rfp.mdnew file+26

This diff is too big to show here.

content/grants/2023/splitwise.mdnew file+129

This diff is too big to show here.

content/grants/2023/text-search.mdnew file+24

This diff is too big to show here.

content/grants/2023/tinygrad.mdnew file+24

This diff is too big to show here.

content/grants/2023/treesitter.mdnew file+71

This diff is too big to show here.

content/grants/2023/turf.mdnew file+205

This diff is too big to show here.

content/grants/2023/uc-concierge.mdnew file+42

This diff is too big to show here.

content/grants/2023/update-mass.mdnew file+26

This diff is too big to show here.

content/grants/2023/urbit-ninja-strike-team.mdnew file+38

This diff is too big to show here.

content/grants/2023/urbit-react-docs.mdnew file+124

This diff is too big to show here.

content/grants/2023/vere-eyre-cache.mdnew file+38

This diff is too big to show here.

content/grants/2023/wiki-stella-fixa-rfp.mdnew file+26

This diff is too big to show here.

content/groups/_index.mdnew file+3

This diff is too big to show here.

content/groups/~bitbet-bolbel/urbit-community.mdnew file+14

This diff is too big to show here.

content/groups/~bitdeg/assembly22.mdnew file+10

This diff is too big to show here.

content/groups/~dalten/aera.mdnew file+10

This diff is too big to show here.

content/groups/~dibref-labter/arbit.mdnew file+9

This diff is too big to show here.

content/groups/~dister-dozzod-lapdeg/battery-payload.mdnew file+9

This diff is too big to show here.

content/groups/~fabled-faster/new-york.mdnew file+10

This diff is too big to show here.

content/groups/~fabled-faster/structure.mdnew file+10

This diff is too big to show here.

content/groups/~fabled-faster/wind.mdnew file+10

This diff is too big to show here.

content/groups/~famreb-todmec/the-combine-public.mdnew file+13

This diff is too big to show here.

content/groups/~halbex-palheb/uf-public.mdnew file+10

This diff is too big to show here.

content/groups/~hatryx-lastud/other-life.mdnew file+10

This diff is too big to show here.

content/groups/~hiddev-dannut/new-hooniverse.mdnew file+11

This diff is too big to show here.

content/groups/~hocwyn-tipwex/uqbar-event-horizon-forever.mdnew file+11

This diff is too big to show here.

content/groups/~ladtem-filmyr/urbit-ny-week.mdnew file+193

This diff is too big to show here.

content/groups/~lanlyd/terminal.mdnew file+8

This diff is too big to show here.

content/groups/~lodsum-rilner/emil-graphics.mdnew file+10

This diff is too big to show here.

content/groups/~martyr-sarlev-sarsen/assembly-hackers.mdnew file+10

This diff is too big to show here.

content/groups/~matwet/networked-subject.mdnew file+11

This diff is too big to show here.

content/groups/~middev/the-forge.mdnew file+10

This diff is too big to show here.

content/groups/~mister-hilper-dozzod-dalten/quartus.mdnew file+10

This diff is too big to show here.

content/groups/~napmer-rilnut/wet-brain.mdnew file+10

This diff is too big to show here.

content/groups/~natnex-ronret/door-link.mdnew file+10

This diff is too big to show here.

content/groups/~nibset-napwyn/tlon-public.mdnew file+10

This diff is too big to show here.

content/groups/~poldec-tonteg/the-phantom-tollbooth.mdnew file+12

This diff is too big to show here.

content/groups/~sillus-mallus/toki-pona.mdnew file+12

This diff is too big to show here.

content/groups/~sitbus-dapsup/urstralia.mdnew file+9

This diff is too big to show here.

content/groups/~tirrel/the-marketplace.mdnew file+14

This diff is too big to show here.

content/groups/~todset-partug/urmetica.mdnew file+9

This diff is too big to show here.

content/groups/~wacrep-lossul/encyclosphere.mdnew file+9

This diff is too big to show here.

content/groups/~widbep-faltev/asheville.mdnew file+9

This diff is too big to show here.

content/groups/~winder-dapsym/urchan.mdnew file+29

This diff is too big to show here.

content/groups/~witbep-witbep/embark.mdnew file+11

This diff is too big to show here.

content/highlights/highlight-1.mdnew file+6

This diff is too big to show here.

content/highlights/highlight-2.mdnew file+6

This diff is too big to show here.

content/highlights/highlight-3.mdnew file+6

This diff is too big to show here.

content/ids/ballun-dilsup.mdnew file+7

This diff is too big to show here.

content/ids/battus-datsun.mdnew file+10

This diff is too big to show here.

content/ids/binnus.mdnew file+10

This diff is too big to show here.

content/ids/bintud-bitnev.mdnew file+8

This diff is too big to show here.

content/ids/bitbet-bolbel.mdnew file+4

This diff is too big to show here.

content/ids/botbyn-dolrum.mdnew file+7

This diff is too big to show here.

content/ids/datder-sonnet.mdnew file+13

This diff is too big to show here.

content/ids/datnut-pollen.mdnew file+15

This diff is too big to show here.

content/ids/datryn-ribdun.mdnew file+12

This diff is too big to show here.

content/ids/datsyr-radser.mdnew file+12

This diff is too big to show here.

content/ids/dopbet-larped.mdnew file+7

This diff is too big to show here.

content/ids/fallyn-balfus.mdnew file+8

This diff is too big to show here.

content/ids/finmep-lanteb.mdnew file+29

This diff is too big to show here.

content/ids/forryd-ravtyn.mdnew file+6

This diff is too big to show here.

content/ids/haddef-sigwen.mdnew file+12

This diff is too big to show here.

content/ids/haldul-navsyr.mdnew file+7

This diff is too big to show here.

content/ids/hocmed-lidrev.mdnew file+8

This diff is too big to show here.

content/ids/lagrev-nocfep.mdnew file+8

This diff is too big to show here.

content/ids/lanlyd.mdnew file+8

This diff is too big to show here.

content/ids/mallus-fabres.mdnew file+12

This diff is too big to show here.

content/ids/mastyr-bottec.mdnew file+10

This diff is too big to show here.

content/ids/monnys-riphet.mdnew file+7

This diff is too big to show here.

content/ids/nallux-dozryl.mdnew file+12

This diff is too big to show here.

content/ids/nibtud-bidsyt.mdnew file+17

This diff is too big to show here.

content/ids/panleg-padben.mdnew file+6

This diff is too big to show here.

content/ids/pinsyt-nossub.mdnew file+18

This diff is too big to show here.

content/ids/poldec-tonteg.mdnew file+14

This diff is too big to show here.

content/ids/rabsef-bicrym.mdnew file+14

This diff is too big to show here.

content/ids/ravmel-ropdyl.mdnew file+8

This diff is too big to show here.

content/ids/rilfun-lidlen.mdnew file+8

This diff is too big to show here.

content/ids/sarlev-sarsen.mdnew file+8

This diff is too big to show here.

content/ids/sicdev-pilnup.mdnew file+8

This diff is too big to show here.

content/ids/sitful-hatred.mdnew file+8

This diff is too big to show here.

content/ids/sogrum-savluc.mdnew file+11

This diff is too big to show here.

content/ids/tagdyl-ponwyn.mdnew file+10

This diff is too big to show here.

content/ids/tambes-palped.mdnew file+10

This diff is too big to show here.

content/ids/tiplec-lacnyx.mdnew file+6

This diff is too big to show here.

content/ids/tobrun-tomnet.mdnew file+8

This diff is too big to show here.

content/ids/topfet-parmed.mdnew file+6

This diff is too big to show here.

content/ids/wicrum-wicrun.mdnew file+8

This diff is too big to show here.

content/ids/wolref-podlex.mdnew file+8

This diff is too big to show here.

content/marketplaces/azimuth-shop.mdnew file+11

This diff is too big to show here.

content/marketplaces/lanlyd.mdnew file+19

This diff is too big to show here.

content/marketplaces/mocbel-house.mdnew file+19

This diff is too big to show here.

content/marketplaces/networked-subject.mdnew file+14

This diff is too big to show here.

content/marketplaces/opensea.mdnew file+18

This diff is too big to show here.

content/marketplaces/planet-market.mdnew file+26

This diff is too big to show here.

content/marketplaces/urbit-live.mdnew file+13

This diff is too big to show here.

content/marketplaces/urbitex.mdnew file+11

This diff is too big to show here.

content/marketplaces/urbitme.mdnew file+11

This diff is too big to show here.

content/marketplaces/wexpert-systems.mdnew file+13

This diff is too big to show here.

content/organizations/assemblycapital.mdnew file+10

This diff is too big to show here.

content/organizations/dalten.mdnew file+10

This diff is too big to show here.

content/organizations/holium.mdnew file+10

This diff is too big to show here.

content/organizations/labyrinthdao.mdnew file+10

This diff is too big to show here.

content/organizations/mars-review-of-books.mdnew file+19

This diff is too big to show here.

content/organizations/nativeplanet.mdnew file+10

This diff is too big to show here.

content/organizations/quartus.mdnew file+22

This diff is too big to show here.

content/organizations/reciprocal.mdnew file+13

This diff is too big to show here.

content/organizations/sortug.mdnew file+10

This diff is too big to show here.

content/organizations/third-earth.mdnew file+10

This diff is too big to show here.

content/organizations/tirrel.mdnew file+12

This diff is too big to show here.

content/organizations/tlon.mdnew file+12

This diff is too big to show here.

content/organizations/uqbar.mdnew file+10

This diff is too big to show here.

content/organizations/urbit-foundation.mdnew file+12

This diff is too big to show here.

content/organizations/zorp.mdnew file+10

This diff is too big to show here.

content/overview/_index.mdnew file+64

This diff is too big to show here.

content/overview/interface.mdnew file+42

This diff is too big to show here.

content/overview/people-history.mdnew file+73

This diff is too big to show here.

content/overview/urbit-id.mdnew file+63

This diff is too big to show here.

content/overview/urbit-os.mdnew file+45

This diff is too big to show here.

content/podcasts/2018-11-18_a-digital-republic.mdnew file+19

This diff is too big to show here.

content/podcasts/2019-11-11_urbit.mdnew file+9

This diff is too big to show here.

content/podcasts/2020-03-23_a-new-computing-platform.mdnew file+17

This diff is too big to show here.

content/podcasts/2020-03-23_technology-and-freedom.mdnew file+18

This diff is too big to show here.

content/podcasts/2020-03-23_under-the-hood.mdnew file+15

This diff is too big to show here.

content/podcasts/2020-03-24_urbit-id-and-the-network.mdnew file+13

This diff is too big to show here.

content/podcasts/2020-03-26_built-to-last.mdnew file+21

This diff is too big to show here.

content/podcasts/2020-03-26_urbit-and-bitcoin.mdnew file+15

This diff is too big to show here.

content/podcasts/2020-04-05_tlon-operations.mdnew file+15

This diff is too big to show here.

content/podcasts/2020-11-24_humane-computing.mdnew file+11

This diff is too big to show here.

content/podcasts/2021-02-08_urbit.mdnew file+27

This diff is too big to show here.

content/podcasts/2022-01-21_the-most-beautiful-computer.mdnew file+17

This diff is too big to show here.

content/podcasts/2022-01-26_the-only-dignified-computer.mdnew file+17

This diff is too big to show here.

content/podcasts/2022-02-01_100-year-computer.mdnew file+15

This diff is too big to show here.

content/podcasts/2022-02-15_building-web3-products.mdnew file+20

This diff is too big to show here.

content/podcasts/2022-02-21_most-correct-computer.mdnew file+17

This diff is too big to show here.

content/podcasts/2022-02-27_the-combine.mdnew file+13

This diff is too big to show here.

content/podcasts/2022-03-02_theory-of-the-egirl.mdnew file+17

This diff is too big to show here.

content/podcasts/2022-03-04_nockin.mdnew file+18

This diff is too big to show here.

content/podcasts/2022-03-08_urbit-blockchains.mdnew file+16

This diff is too big to show here.

content/podcasts/2022-03-11_mars-review.mdnew file+12

This diff is too big to show here.

content/podcasts/2022-03-13_alien-invasions.mdnew file+16

This diff is too big to show here.

content/podcasts/2022-03-18_politics-of-urbit-governance.mdnew file+15

This diff is too big to show here.

content/podcasts/2022-03-23_quantum-computing.mdnew file+15

This diff is too big to show here.

content/podcasts/2022-04-07_in-lehmans-terms.mdnew file+12

This diff is too big to show here.

content/podcasts/2022-04-19_robot-opera.mdnew file+11

This diff is too big to show here.

content/podcasts/2022-05-21_diary-of-sam-frank.mdnew file+10

This diff is too big to show here.

content/podcasts/2022-05-22_cincinnati-chili.mdnew file+10

This diff is too big to show here.

content/podcasts/2022-06-04_market-bedshite.mdnew file+10

This diff is too big to show here.

content/podcasts/2022-06-22_software-as-soulcraft.mdnew file+20

This diff is too big to show here.

content/podcasts/2022-06-29_josh-lehman.mdnew file+30

This diff is too big to show here.

content/podcasts/2022-07-04_enable-people-to-run-their-own-servers.mdnew file+116

This diff is too big to show here.

content/podcasts/2022-08-04_middling.mdnew file+10

This diff is too big to show here.

content/podcasts/2022-08-11_probing-questions.mdnew file+14

This diff is too big to show here.

content/podcasts/2022-08-19_the-blind.mdnew file+9

This diff is too big to show here.

content/podcasts/2022-08-26_the-harvard-finance-bro.mdnew file+12

This diff is too big to show here.

content/podcasts/2022-09-14_insanely-bullish-on-urbit.mdnew file+13

This diff is too big to show here.

content/podcasts/2022-09-21_the-worlds-best-crypto-investor.mdnew file+12

This diff is too big to show here.

content/podcasts/2022-09-30-neal-davis-urbit-sentience-daos.mdnew file+33

This diff is too big to show here.

content/podcasts/2022-10-04-reality-maximalism-josh-lehman.mdnew file+9

This diff is too big to show here.

content/podcasts/2022-10-06_urbit-maxi-episode copy.mdnew file+9

This diff is too big to show here.

content/podcasts/2022-12-22_epicenter-ted-blackman-gary-lieberman.mdnew file+11

This diff is too big to show here.

content/podcasts/2023-01-05_lets-get-personal.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-01-19_crypto-metaphysics.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-01-24_reject-triviality.mdnew file+13

This diff is too big to show here.

content/podcasts/2023-01-26_building-future-states-with-nation3.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-01-29_urbit-for-idiots.mdnew file+11

This diff is too big to show here.

content/podcasts/2023-02-09_crypto-narratives-new-and-old.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-02-13_distributed-networked-computing.mdnew file+17

This diff is too big to show here.

content/podcasts/2023-02-23_the-urbit-episode.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-03-09_reclaiming-web-1.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-03-23_how-to-invest-in-web3-like-a-cool-kid.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-03-28_pupusas-volcanoes-and-databases.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-04-03_legacy-internet-new-internet.mdnew file+15

This diff is too big to show here.

content/podcasts/2023-04-06_the-ai-episode.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-04-11_its-urbits-all-the-way-down-with-dachus-tiprel.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-04-14_epicenter-tim-galebach.mdnew file+11

This diff is too big to show here.

content/podcasts/2023-04-20_artificial-qintelligence.mdnew file+9

This diff is too big to show here.

content/podcasts/2023-04-27_hoon-only-legal-ui-with-hastuc-dibtux.mdnew file+11

This diff is too big to show here.

content/podcasts/2023-05-11_full-metal-urbit-with-mopfel-winrux.mdnew file+15

This diff is too big to show here.

content/podcasts/2023-05-18_crypto-takes-flight.mdnew file+11

This diff is too big to show here.

content/privacy.mdnew file+89

This diff is too big to show here.

content/proposals.mdnew file+93

This diff is too big to show here.

content/rfps.mdnew file+40

This diff is too big to show here.

content/terms-of-service.mdnew file+69

This diff is too big to show here.

content/updates/2016-10-6-update.mdnew file+264

This diff is too big to show here.

content/updates/2016-5-16-roadmap.mdnew file+245

This diff is too big to show here.

content/updates/2016-7-20-update.mdnew file+160

This diff is too big to show here.

content/updates/2016-8-30-update.mdnew file+268

This diff is too big to show here.

content/updates/2017-1-30-update.mdnew file+345

This diff is too big to show here.

content/updates/2017-10-7-update.mdnew file+17

This diff is too big to show here.

content/updates/2017-11-14-update.mdnew file+217

This diff is too big to show here.

content/updates/2017-12-16-update.mdnew file+31

This diff is too big to show here.

content/updates/2017-12-2-update.mdnew file+76

This diff is too big to show here.

content/updates/2017-12-22-update.mdnew file+33

This diff is too big to show here.

content/updates/2017-3-1-update.mdnew file+108

This diff is too big to show here.

content/updates/2017-4-17-update.mdnew file+158

This diff is too big to show here.

content/updates/2017-5-11-roadmap.mdnew file+234

This diff is too big to show here.

content/updates/2017-8-11-update.mdnew file+109

This diff is too big to show here.

content/updates/2017-9-23-update.mdnew file+25

This diff is too big to show here.

content/updates/2017-9-29-update.mdnew file+17

This diff is too big to show here.

content/updates/2018-1-13-update.mdnew file+28

This diff is too big to show here.

content/updates/2018-1-6-update.mdnew file+38

This diff is too big to show here.

content/updates/2018-10-12-update.mdnew file+62

This diff is too big to show here.

content/updates/2018-10-24-update.mdnew file+40

This diff is too big to show here.

content/updates/2018-11-20-update.mdnew file+55

This diff is too big to show here.

content/updates/2018-11-6-update.mdnew file+47

This diff is too big to show here.

content/updates/2018-12-18-update.mdnew file+59

This diff is too big to show here.

content/updates/2018-2-17-update.mdnew file+39

This diff is too big to show here.

content/updates/2018-2-24-update.mdnew file+32

This diff is too big to show here.

content/updates/2018-2-5-update.mdnew file+26

This diff is too big to show here.

content/updates/2018-2-9-update.mdnew file+41

This diff is too big to show here.

content/updates/2018-3-24-update.mdnew file+57

This diff is too big to show here.

content/updates/2018-3-5-update.mdnew file+32

This diff is too big to show here.

content/updates/2018-4-14-update.mdnew file+57

This diff is too big to show here.

content/updates/2018-4-7-update.mdnew file+41

This diff is too big to show here.

content/updates/2018-5-16-update.mdnew file+50

This diff is too big to show here.

content/updates/2018-5-23-update.mdnew file+64

This diff is too big to show here.

content/updates/2018-5-29-update.mdnew file+17

This diff is too big to show here.

content/updates/2018-5-30-update.mdnew file+78

This diff is too big to show here.

content/updates/2018-6-14-update.mdnew file+71

This diff is too big to show here.

content/updates/2018-6-21-update.mdnew file+60

This diff is too big to show here.

content/updates/2018-6-6-update.mdnew file+81

This diff is too big to show here.

content/updates/2018-7-13-update.mdnew file+67

This diff is too big to show here.

content/updates/2018-7-20-update.mdnew file+58

This diff is too big to show here.

content/updates/2018-7-3-update.mdnew file+66

This diff is too big to show here.

content/updates/2018-7-30-update.mdnew file+64

This diff is too big to show here.

content/updates/2018-8-23-update.mdnew file+85

This diff is too big to show here.

content/updates/2018-8-30-update.mdnew file+57

This diff is too big to show here.

content/updates/2018-8-8-update.mdnew file+59

This diff is too big to show here.

content/updates/2018-9-11-update.mdnew file+61

This diff is too big to show here.

content/updates/2019-11-06-update.mdnew file+42

This diff is too big to show here.

content/updates/2019-12-06-update.mdnew file+42

This diff is too big to show here.

content/updates/2019-2-11-update.mdnew file+39

This diff is too big to show here.

content/updates/2019-2-25-update.mdnew file+35

This diff is too big to show here.

content/updates/2019-2-26-network-update.mdnew file+39

This diff is too big to show here.

content/updates/2019-2-4-update.mdnew file+29

This diff is too big to show here.

content/updates/2019-3-11-update.mdnew file+29

This diff is too big to show here.

content/updates/2019-3-27-update.mdnew file+21

This diff is too big to show here.

content/updates/2019-3-4-update.mdnew file+48

This diff is too big to show here.

content/updates/2019-4-11-update.mdnew file+29

This diff is too big to show here.

content/updates/2019-5-10-update.mdnew file+17

This diff is too big to show here.

content/updates/2019-5-17-update.mdnew file+21

This diff is too big to show here.

content/updates/2019-5-31-update.mdnew file+31

This diff is too big to show here.

content/updates/2019-6-14-update.mdnew file+30

This diff is too big to show here.

content/updates/2019-7-25-update.mdnew file+40

This diff is too big to show here.

content/updates/2020-02-06-update.mdnew file+46

This diff is too big to show here.

content/updates/2020-04-04-update.mdnew file+26

This diff is too big to show here.

content/updates/2020-06-15-update.mdnew file+51

This diff is too big to show here.

content/updates/2020-07-27-update.mdnew file+37

This diff is too big to show here.

content/updates/2020-09-30-update.mdnew file+65

This diff is too big to show here.

content/updates/2020-10-29-update.mdnew file+49

This diff is too big to show here.

content/updates/2020-12-01-update.mdnew file+68

This diff is too big to show here.

content/updates/2021-01-15-update.mdnew file+60

This diff is too big to show here.

content/updates/2021-02-19-update.mdnew file+81

This diff is too big to show here.

content/updates/2021-04-01-update.mdnew file+89

This diff is too big to show here.

content/updates/2021-05-05-update.mdnew file+70

This diff is too big to show here.

content/updates/2021-06-16-update.mdnew file+79

This diff is too big to show here.

content/voting-instructions.mdnew file+36

This diff is too big to show here.

gnosis-safe.mdnew file+48

This diff is too big to show here.

hoon/_index.mddeleted−24

This diff is too big to show here.

hoon/cheat-sheet.mddeleted−28

This diff is too big to show here.

hoon/hoon-expressions/_index.mddeleted−28

This diff is too big to show here.

hoon/hoon-expressions/advanced.mddeleted−203

This diff is too big to show here.

hoon/hoon-expressions/basic.mddeleted−177

This diff is too big to show here.

hoon/hoon-expressions/irregular.mddeleted−258

This diff is too big to show here.

hoon/hoon-expressions/limb/_index.mddeleted−18

This diff is too big to show here.

hoon/hoon-expressions/limb/limb.mddeleted−71

This diff is too big to show here.

hoon/hoon-expressions/limb/wing.mddeleted−44

This diff is too big to show here.

hoon/hoon-expressions/rune/_index.mddeleted−72

This diff is too big to show here.

hoon/hoon-expressions/rune/bar.mddeleted−636

This diff is too big to show here.

hoon/hoon-expressions/rune/buc.mddeleted−393

This diff is too big to show here.

hoon/hoon-expressions/rune/cen.mddeleted−471

This diff is too big to show here.

hoon/hoon-expressions/rune/col.mddeleted−245

This diff is too big to show here.

hoon/hoon-expressions/rune/constants.mddeleted−193

This diff is too big to show here.

hoon/hoon-expressions/rune/dot.mddeleted−223

This diff is too big to show here.

hoon/hoon-expressions/rune/ket.mddeleted−387

This diff is too big to show here.

hoon/hoon-expressions/rune/lus.mddeleted−176

This diff is too big to show here.

hoon/hoon-expressions/rune/mic.mddeleted−375

This diff is too big to show here.

hoon/hoon-expressions/rune/sig.mddeleted−450

This diff is too big to show here.

hoon/hoon-expressions/rune/terminators.mddeleted−79

This diff is too big to show here.

hoon/hoon-expressions/rune/tis.mddeleted−490

This diff is too big to show here.

hoon/hoon-expressions/rune/wut.mddeleted−551

This diff is too big to show here.

hoon/hoon-expressions/rune/zap.mddeleted−203

This diff is too big to show here.

hoon/hoon-tutorial/_index.mddeleted−55

This diff is too big to show here.

hoon/hoon-tutorial/ackermann.mddeleted−32

This diff is too big to show here.

hoon/hoon-tutorial/arms-and-cores.mddeleted−490

This diff is too big to show here.

hoon/hoon-tutorial/atoms-auras-and-simple-cell-types.mddeleted−779

This diff is too big to show here.

hoon/hoon-tutorial/bank-account.mddeleted−82

This diff is too big to show here.

hoon/hoon-tutorial/caesar.mddeleted−347

This diff is too big to show here.

hoon/hoon-tutorial/conditionals.mddeleted−75

This diff is too big to show here.

hoon/hoon-tutorial/doors.mddeleted−506

This diff is too big to show here.

hoon/hoon-tutorial/egg-timer.mddeleted−121

This diff is too big to show here.

hoon/hoon-tutorial/fibonacci.mddeleted−63

This diff is too big to show here.

hoon/hoon-tutorial/gall.mddeleted−81

This diff is too big to show here.

hoon/hoon-tutorial/gates.mddeleted−273

This diff is too big to show here.

hoon/hoon-tutorial/generators.mddeleted−601

This diff is too big to show here.

hoon/hoon-tutorial/hoon-syntax.mddeleted−329

This diff is too big to show here.

hoon/hoon-tutorial/iron-polymorphism.mddeleted−91

This diff is too big to show here.

hoon/hoon-tutorial/lead-polymorphism.mddeleted−157

This diff is too big to show here.

hoon/hoon-tutorial/libraries.mddeleted−185

This diff is too big to show here.

hoon/hoon-tutorial/list-of-numbers.mddeleted−134

This diff is too big to show here.

hoon/hoon-tutorial/lists.mddeleted−336

This diff is too big to show here.

hoon/hoon-tutorial/molds.mddeleted−59

This diff is too big to show here.

hoon/hoon-tutorial/nouns.mddeleted−483

This diff is too big to show here.

hoon/hoon-tutorial/recursion.mddeleted−196

This diff is too big to show here.

hoon/hoon-tutorial/setup.mddeleted−108

This diff is too big to show here.

hoon/hoon-tutorial/structures-and-complex-types.mddeleted−357

This diff is too big to show here.

hoon/hoon-tutorial/the-subject-and-its-legs.mddeleted−657

This diff is too big to show here.

hoon/hoon-tutorial/trees-sets-and-maps.mddeleted−323

This diff is too big to show here.

hoon/hoon-tutorial/type-checking-and-type-inference.mddeleted−644

This diff is too big to show here.

hoon/hoon-tutorial/type-polymorphism.mddeleted−578

This diff is too big to show here.

hoon/library/1a.mddeleted−680

This diff is too big to show here.

hoon/library/1b.mddeleted−273

This diff is too big to show here.

hoon/library/1c.mddeleted−421

This diff is too big to show here.

hoon/library/2a.mddeleted−449

This diff is too big to show here.

hoon/library/2b.mddeleted−1293

This diff is too big to show here.

hoon/library/2c.mddeleted−1251

This diff is too big to show here.

hoon/library/2d.mddeleted−373

This diff is too big to show here.

hoon/library/2e.mddeleted−276

This diff is too big to show here.

hoon/library/2f.mddeleted−437

This diff is too big to show here.

hoon/library/2g.mddeleted−105

This diff is too big to show here.

hoon/library/2h.mddeleted−798

This diff is too big to show here.

hoon/library/2i.mddeleted−1059

This diff is too big to show here.

hoon/library/2j.mddeleted−272

This diff is too big to show here.

hoon/library/2k.mddeleted−399

This diff is too big to show here.

hoon/library/2l.mddeleted−111

This diff is too big to show here.

hoon/library/2m.mddeleted−308

This diff is too big to show here.

hoon/library/2n.mddeleted−427

This diff is too big to show here.

hoon/library/2o.mddeleted−187

This diff is too big to show here.

hoon/library/2p.mddeleted−242

This diff is too big to show here.

hoon/library/2q.mddeleted−375

This diff is too big to show here.

hoon/library/3a.mddeleted−858

This diff is too big to show here.

hoon/library/3b.mddeleted−5889

This diff is too big to show here.

hoon/library/3c.mddeleted−649

This diff is too big to show here.

hoon/library/3d.mddeleted−821

This diff is too big to show here.

hoon/library/3e.mddeleted−9

This diff is too big to show here.

hoon/library/3f.mddeleted−723

This diff is too big to show here.

hoon/library/3g.mddeleted−386

This diff is too big to show here.

hoon/library/4a.mddeleted−217

This diff is too big to show here.

hoon/library/4b.mddeleted−994

This diff is too big to show here.

hoon/library/4c.mddeleted−364

This diff is too big to show here.

hoon/library/4d.mddeleted−100

This diff is too big to show here.

hoon/library/4e.mddeleted−471

This diff is too big to show here.

hoon/library/4f.mddeleted−1195

This diff is too big to show here.

hoon/library/4g.mddeleted−179

This diff is too big to show here.

hoon/library/4h.mddeleted−962

This diff is too big to show here.

hoon/library/4i.mddeleted−1054

This diff is too big to show here.

hoon/library/4j.mddeleted−1656

This diff is too big to show here.

hoon/library/4k.mddeleted−276

This diff is too big to show here.

hoon/library/4l.mddeleted−608

This diff is too big to show here.

hoon/library/4m.mddeleted−434

This diff is too big to show here.

hoon/library/4n.mddeleted−447

This diff is too big to show here.

hoon/library/4o.mddeleted−782

This diff is too big to show here.

hoon/library/5a.mddeleted−7

This diff is too big to show here.

hoon/library/5b.mddeleted−7

This diff is too big to show here.

hoon/library/5c.mddeleted−7

This diff is too big to show here.

hoon/library/5d.mddeleted−7

This diff is too big to show here.

hoon/library/5e.mddeleted−7

This diff is too big to show here.

hoon/library/5f.mddeleted−176

This diff is too big to show here.

hoon/library/5g.mddeleted−7

This diff is too big to show here.

hoon/library/_index.mddeleted−1733

This diff is too big to show here.

hoon/library/table-of-contents.mddeleted−1730

This diff is too big to show here.

hoon/library/zuse.mddeleted−10

This diff is too big to show here.

hoon/style.mddeleted−475

This diff is too big to show here.

hoon/troubleshooting.mddeleted−182

This diff is too big to show here.

hoon/workbook/_index.mddeleted−17

This diff is too big to show here.

hoon/workbook/bomb.mddeleted−140

This diff is too big to show here.

hoon/workbook/digits.mddeleted−113

This diff is too big to show here.

hoon/workbook/eightball.mddeleted−158

This diff is too big to show here.

hoon/workbook/traffic-light.mddeleted−155

This diff is too big to show here.

lib/buildGlossary.jsnew file+59

This diff is too big to show here.

lib/buildPageTree.jsnew file+111

This diff is too big to show here.

lib/cache.jsnew file+90

This diff is too big to show here.

lib/constants.jsnew file+129

This diff is too big to show here.

lib/hooks.jsnew file+71

This diff is too big to show here.

lib/lib.jsnew file+251

This diff is too big to show here.

lib/rss.jsnew file+95

This diff is too big to show here.

next.config.jsnew file+26

This diff is too big to show here.

nock/_index.mddeleted−26

This diff is too big to show here.

nock/definition.mddeleted−186

This diff is too big to show here.

nock/example.mddeleted−362

This diff is too big to show here.

nock/explanation.mddeleted−601

This diff is too big to show here.

nock/implementations.mddeleted−2322

This diff is too big to show here.

package-lock.jsonnew file+5276

This diff is too big to show here.

package.jsonnew file+58

This diff is too big to show here.

pages/404.jsnew file+33

This diff is too big to show here.

pages/[slug].jsnew file+48

This diff is too big to show here.

pages/_app.jsnew file+85

This diff is too big to show here.

pages/api/dev-search.jsnew file+8

This diff is too big to show here.

pages/api/ops-search.jsnew file+8

This diff is too big to show here.

pages/api/roadmap-search.jsnew file+8

This diff is too big to show here.

pages/api/search.jsnew file+45

This diff is too big to show here.

pages/api/sigil.jsnew file+60

This diff is too big to show here.

pages/api/urbit-org-search.jsnew file+45

This diff is too big to show here.

pages/applications/[[...application]].jsnew file+206

This diff is too big to show here.

pages/applications/submit.jsnew file+143

This diff is too big to show here.

pages/articles/[slug].jsnew file+84

This diff is too big to show here.

pages/bitcoin.jsnew file+98

This diff is too big to show here.

pages/blog.jsnew file+131

This diff is too big to show here.

pages/blog/[slug].jsnew file+118

This diff is too big to show here.

pages/campus/[[...slug]].jsnew file+312

This diff is too big to show here.

pages/communities/[slug].jsnew file+87

This diff is too big to show here.

pages/decentralized-discord.jsnew file+291

This diff is too big to show here.

pages/ecosystem/index.jsnew file+416

This diff is too big to show here.

pages/ecosystem/spotlight/[slug].jsnew file+69

This diff is too big to show here.

pages/events.jsnew file+181

This diff is too big to show here.

pages/events/[slug].jsnew file+173

This diff is too big to show here.

pages/getinvolved.jsnew file+58

This diff is too big to show here.

pages/getting-started/[[...slug]].jsnew file+314

This diff is too big to show here.

pages/grants.jsnew file+401

This diff is too big to show here.

pages/grants/[slug].jsnew file+270

This diff is too big to show here.

pages/grants/apprenticeships.jsnew file+29

This diff is too big to show here.

pages/grants/bounties.jsnew file+28

This diff is too big to show here.

pages/grants/proposals.jsnew file+29

This diff is too big to show here.

pages/grants/rfps.jsnew file+29

This diff is too big to show here.

pages/groups/[[...group]].jsnew file+136

This diff is too big to show here.

pages/groups/submit.jsnew file+152

This diff is too big to show here.

pages/ids/[id].jsnew file+241

This diff is too big to show here.

pages/ids/submit.jsnew file+170

This diff is too big to show here.

pages/index.jsnew file+430

This diff is too big to show here.

pages/marketplaces/[slug].jsnew file+84

This diff is too big to show here.

pages/organizations/[slug].jsnew file+179

This diff is too big to show here.

pages/overview/[[...slug]].jsnew file+147

This diff is too big to show here.

pages/podcasts/[slug].jsnew file+84

This diff is too big to show here.

pages/trial-over.jsnew file+35

This diff is too big to show here.

pages/trial.jsnew file+129

This diff is too big to show here.

pages/updates.jsnew file+87

This diff is too big to show here.

pages/updates/[slug].jsnew file+126

This diff is too big to show here.

postcss.config.jsnew file+6

This diff is too big to show here.

public/images/android-chrome-192x192.pngnew file

Binary file not shown.

public/images/android-chrome-512x512.pngnew file

Binary file not shown.

public/images/apple-touch-icon.pngnew file

Binary file not shown.

public/images/favicon-16x16.pngnew file

Binary file not shown.

public/images/favicon-32x32.pngnew file

Binary file not shown.

public/images/favicon.iconew file

Binary file not shown.

public/images/planet-l2-claim.gifnew file

Binary file not shown.

public/images/planet-l2-migration.gifnew file

Binary file not shown.

public/images/planet-l2-transactions.pngnew file

Binary file not shown.

public/images/sound.svgnew file+5

This diff is too big to show here.

scripts/date_to_string_upgrade.jsnew file+43

This diff is too big to show here.

scripts/event_date_upgrade.jsnew file+51

This diff is too big to show here.

tailwind.config.jsnew file+19

This diff is too big to show here.

vercel.jsonnew file+271

This diff is too big to show here.

vere/_index.mddeleted−36

This diff is too big to show here.

vere/api.mddeleted−1040

This diff is too big to show here.

vere/c.mddeleted−114

This diff is too big to show here.

vere/jetting.mddeleted−770

This diff is too big to show here.

vere/nouns.mddeleted−477

This diff is too big to show here.

vere/runtime.mddeleted−44

This diff is too big to show here.

weights.shdeleted−23

This diff is too big to show here.