on master help sign in
1066 files changed+60665−65607
since splitsnapshots
unifiedsplit
.gitignore+45−3 .gitmodules−3 .npmrc+1 .nvmrc+1 .prettierrc+5 README.markdown−3 README.md+58 _index.md−9 arvo/_index.md−112 arvo/ames.md−1937 arvo/behn.md−19 arvo/clay.md−2625 arvo/dill.md−23 arvo/eyre.md−716 arvo/ford.md−570 arvo/gall.md−2317 arvo/glossary.md−844 arvo/hall.md−1334 arvo/sail-and-udon.md−1233 arvo/ship-troubleshooting.md−171 azimuth/_index.md−5 azimuth/azimuth.md−11 azimuth/glossary.md−117 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−23 hoon/cheat-sheet.md−27 hoon/hoon-expressions/_index.md−27 hoon/hoon-expressions/advanced.md−202 hoon/hoon-expressions/basic.md−176 hoon/hoon-expressions/irregular.md−258 hoon/hoon-expressions/limb/_index.md−17 hoon/hoon-expressions/limb/limb.md−70 hoon/hoon-expressions/limb/wing.md−43 hoon/hoon-expressions/rune/_index.md−71 hoon/hoon-expressions/rune/bar.md−635 hoon/hoon-expressions/rune/buc.md−392 hoon/hoon-expressions/rune/cen.md−470 hoon/hoon-expressions/rune/col.md−244 hoon/hoon-expressions/rune/constants.md−192 hoon/hoon-expressions/rune/dot.md−222 hoon/hoon-expressions/rune/ket.md−386 hoon/hoon-expressions/rune/lus.md−175 hoon/hoon-expressions/rune/mic.md−374 hoon/hoon-expressions/rune/sig.md−449 hoon/hoon-expressions/rune/terminators.md−78 hoon/hoon-expressions/rune/tis.md−489 hoon/hoon-expressions/rune/wut.md−550 hoon/hoon-expressions/rune/zap.md−202 hoon/hoon-tutorial/_index.md−55 hoon/hoon-tutorial/ackermann.md−31 hoon/hoon-tutorial/arms-and-cores.md−489 hoon/hoon-tutorial/atoms-auras-and-simple-cell-types.md−778 hoon/hoon-tutorial/bank-account.md−81 hoon/hoon-tutorial/caesar.md−346 hoon/hoon-tutorial/conditionals.md−74 hoon/hoon-tutorial/doors.md−504 hoon/hoon-tutorial/egg-timer.md−120 hoon/hoon-tutorial/fibonacci.md−62 hoon/hoon-tutorial/gall.md−80 hoon/hoon-tutorial/gates.md−272 hoon/hoon-tutorial/generators.md−599 hoon/hoon-tutorial/hoon-syntax.md−328 hoon/hoon-tutorial/iron-polymorphism.md−90 hoon/hoon-tutorial/lead-polymorphism.md−156 hoon/hoon-tutorial/libraries.md−184 hoon/hoon-tutorial/list-of-numbers.md−132 hoon/hoon-tutorial/lists.md−336 hoon/hoon-tutorial/molds.md−58 hoon/hoon-tutorial/nouns.md−482 hoon/hoon-tutorial/recursion.md−194 hoon/hoon-tutorial/setup.md−106 hoon/hoon-tutorial/structures-and-complex-types.md−355 hoon/hoon-tutorial/the-subject-and-its-legs.md−655 hoon/hoon-tutorial/trees-sets-and-maps.md−322 hoon/hoon-tutorial/type-checking-and-type-inference.md−642 hoon/hoon-tutorial/type-polymorphism.md−576 hoon/library/1a.md−679 hoon/library/1b.md−272 hoon/library/1c.md−420 hoon/library/2a.md−448 hoon/library/2b.md−1292 hoon/library/2c.md−1250 hoon/library/2d.md−372 hoon/library/2e.md−275 hoon/library/2f.md−436 hoon/library/2g.md−104 hoon/library/2h.md−797 hoon/library/2i.md−1058 hoon/library/2j.md−271 hoon/library/2k.md−398 hoon/library/2l.md−110 hoon/library/2m.md−307 hoon/library/2n.md−426 hoon/library/2o.md−186 hoon/library/2p.md−241 hoon/library/2q.md−374 hoon/library/3a.md−857 hoon/library/3b.md−5888 hoon/library/3c.md−648 hoon/library/3d.md−820 hoon/library/3e.md−8 hoon/library/3f.md−722 hoon/library/3g.md−385 hoon/library/4a.md−216 hoon/library/4b.md−993 hoon/library/4c.md−363 hoon/library/4d.md−99 hoon/library/4e.md−470 hoon/library/4f.md−1194 hoon/library/4g.md−178 hoon/library/4h.md−961 hoon/library/4i.md−1053 hoon/library/4j.md−1655 hoon/library/4k.md−275 hoon/library/4l.md−607 hoon/library/4m.md−433 hoon/library/4n.md−446 hoon/library/4o.md−781 hoon/library/5a.md−6 hoon/library/5b.md−6 hoon/library/5c.md−6 hoon/library/5d.md−6 hoon/library/5e.md−6 hoon/library/5f.md−175 hoon/library/5g.md−6 hoon/library/_index.md−1732 hoon/library/table-of-contents.md−1729 hoon/library/zuse.md−11 hoon/style.md−474 hoon/troubleshooting.md−182 hoon/workbook/_index.md−16 hoon/workbook/bomb.md−139 hoon/workbook/digits.md−112 hoon/workbook/eightball.md−157 hoon/workbook/traffic-light.md−154 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−25 nock/definition.md−186 nock/example.md−361 nock/explanation.md−599 nock/implementations.md−2321 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−35 vere/api.md−1039 vere/c.md−113 vere/jetting.md−769 vere/nouns.md−476 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−9
@@ -1,9 +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−- [Install Urbit](/try)
8−- [Operator's Manual](/operations)
9−- [Developer's Guide](/develop)
arvo/_index.mddeleted−112
@@ -1,112 +0,0 @@
1−+++
2−title = "Arvo"
3−weight = 1
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−+++
7−Arvo is Urbit's functional operating system, written in [Hoon](@/docs/hoon/_index.md). It's composed of modules called _vanes_:
8−
9−## [Ames](@/docs/arvo/ames.md)
10−
11−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.
12−
13−## [Behn](@/docs/arvo/behn.md)
14−
15−Behn is our timer. It allows vanes and applications to set and timer events, which are managed in a simple priority queue.
16−
17−## [Clay](@/docs/arvo/clay.md)
18−
19−Clay is our filesystem and revision-control system.
20−
21−## [Dill](@/docs/arvo/dill.md)
22−
23−Dill is our terminal driver. Unix sends keyboard events to dill from the terminal, and dill produces terminal output.
24−
25−## [Eyre](@/docs/arvo/eyre.md)
26−
27−Eyre is our HTTP server. Unix sends HTTP messages to `%eyre`, and `%eyre` produces HTTP messages in response.
28−
29−## [Ford](@/docs/arvo/ford.md)
30−
31−Ford is our build system. It handles resources and publishing.
32−
33−## [Gall](@/docs/arvo/gall.md)
34−
35−Gall is the vane for controlling userspace apps.
36−
37−### [Hall](@/docs/arvo/hall.md)
38−
39−Hall isn't a vane, but an important Gall app that functions as the Urbit messaging protocol.
40−
41−## Principles
42−
43−At a high level `%arvo` takes a mess of Unix I/O events and turns them into something clean and structured for the programmer.
44−
45−`%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.
46−
47−### Ducts
48−
49−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.
50−
51−Here's a duct that was recently observed in the wild:
52−
53−```
54−~[
55− /g/a/~zod/4_shell_terminal/u/time
56− /g/a/~zod/shell_terminal/u/child/4/main
57− /g/a/~zod/terminal/u/txt
58− /d/term-mess
59− //term/1
60−]
61−```
62−
63−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.
64−
65−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
66−initial element of the empty span, so this is routed to Unix, which applies the effects.
67−
68−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.
69−
70−### Making Moves
71−
72−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:
73−
74−```
75−[duct %pass return-path=path vane-name=@tD data=card]
76−```
77−
78−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`.
79−
80−A `%give` move is analogous to a return:
81−
82−```
83−[duct %give data=card]
84−```
85−
86−Arvo pops the top path off the duct and sends the given card back to the caller.
87−
88−### Vanes
89−
90−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.
91−
92−As of this writing, we have seven vanes, which each provide the following services:
93−
94−- `%ames`: the name of both our network and the vane that communicates over it.
95−- `%behn`: a simple timer.
96−- `%clay`: our version-controlled, referentially- transparent, and global filesystem.
97−- `%dill`: a terminal driver. Unix sends keyboard events to `%dill` from either the console or telnet, and `%dill` produces terminal output.
98−- `%eyre`: an http server. Unix sends http messages to `%eyre`, and `%eyre` produces http messages in response.
99−- `%ford`: handles resources and publishing.
100−- `%gall`: manages our userspace applications. `%gall` keeps state and manages subscribers.
101−
102−### Cards
103−
104−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.
105−
106−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`.
107−
108−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`.
109−
110−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.
111−
112−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−1937
@@ -1,1937 +0,0 @@
1−+++
2−title = "Ames"
3−weight = 1
4−template = "doc.html"
5−+++
6−Our networking protocol.
7−
8−`%ames` is the name of both our network and the vane that communicates
9−over it. When Unix receives a packet over the correct UDP port, it pipes
10−it straight into `%ames` for handling. Also, all packets sent over the
11−`%ames` network are sent by the `%ames` vane. Apps and vanes may use
12−`%ames` to directly send messages to other ships. In general, apps use
13−gall and clay to communicate with other ships rather than using `%ames`
14−directly, but this isn't a requirement. Of course, gall and clay use
15−`%ames` behind the scenes to communicate across the network. These are
16−the only two vanes that use `%ames`.
17−
18−`%ames` includes several significant components. Although the actual
19−crypto algorithms are defined in zuse, they're used extensively in
20−`%ames` for encrypting and decrypting packets. Congestion control and
21−routing is handled entirely in `%ames`. Finally, the actual `%ames`
22−protocol itself, including how to route incoming packets to the correct
23−vane or app, is defined in `%ames`.
24−
25−## Commentary
26−
27−`%ames` is our networking protocol.
28−
29−First we give commentary on the code, the algorithms involved, and the
30−protocol. We trace through the code touched when a packet is sent,
31−received, acknowledged, and that acknowledgment applied. This is fairly
32−comprehensive, and contains many implementation details, but if you
33−understand this, then you understand `%ames`.
34−
35−If you've scrolled down this page, you may be intimidated by the amount
36−of Hoon code, especially if you are new to the language. Don't be afraid
37−of it, you don't have to read any of it if you don't want to -- every
38−interesting action the code takes is explained in plain English. In
39−fact, if you are new to the language, this may be a good learning
40−opportunity. Even if you don't understand every line of Hoon code,
41−you'll hopefully be able to follow most lines. By the time you've worked
42−through this, you'll have seen many common patterns and best practices.
43−Hoon, much more than other languages, is best learned by reading and
44−understanding large quantities of existing code. In this way, it is
45−similar to learning a natural language. All of this code is in
46−`arvo/ames.hoon`.
47−
48−After the commentary, we have reference documentation for all the data
49−structures that are specific to `%ames`. If you see a data structure or
50−a variable used that you don't recognize, search for it in the code, and
51−it's very likely defined in one of these data structures. We recommend
52−that another tab is kept open for easy access to the data structure
53−reference documentation. The code for these is split between
54−`arvo/ames.hoon` and `arvo/zuse.hoon`.
55−
56−The Lifecycle of a Packet (or, How a Packet Becomes Law)
57−
58−---
59−
60−Here, we will trace a packet as it makes its way through ames. There are
61−actually two pathways through ames: the legacy path through `%want`, and
62−the modern way, entered through `%wont`, with full end-to-end
63−acknowledgments. Here we will only trace the modern way, though much of
64−the path is the same for both.
65−
66−When an app (or a vane) wishes to send a packet to another ship, it must
67−send a `%wont` card:
68−
69−```hoon
70− [%wont p=sock q=path r=*] :: e2e send message
71−```
72−
73−This card takes three arguments. The `p` is a `sock`, that is, a pair of
74−two ships, the first of which is the sender and the second is the
75−receiver. But wait, you ask, why do I get to decide who is the sender?
76−Can I fake like I'm someone else? The reason is that there are
77−potentially multiple ships on the same pier, and the kernel can send a
78−message from any of them. If you attempt to send a message from a ship
79−not on your pier, then ames will refuse to send it. If you hack around
80−in your own copy of ames to go ahead and send it anyway, then the other
81−ship will reject it because your key is bad. Only send messages from
82−yourself.
83−
84−The `q` is a path, representing the place on the other side that you
85−want to receive your message. It is approximately equivalent to a port
86−number. Messages on the same path are guaranteed to arrive in the same
87−order as they were sent. No such guarantees are made across paths.
88−
89−The `r` is the actual data that you are sending. As the type implies,
90−this can be an arbitrary noun, and it will be transferred to the
91−receiver exactly as-is, in a well-typed way. Of course, this is data
92−that is sent over the wire, so be careful not to send anything too
93−massive unless you're willing to wait.
94−
95−But enough about the interface. Grepping in ames.hoon for `%wont`, we
96−find that it appears in `++knob`. We see that we go
97−directly into `++wise:am`.
98−
99−```hoon
100− ++ wise :: wise:am
101− |= [soq=sock hen=duct cha=path val=* ete=?] :: send a statement
102− ^- [p=(list boon) q=fort]
103− zork:zank:(wool:(ho:(um p.soq) q.soq) hen cha val ete)
104−```
105−
106−The inputs to this gate are exactly the sort of thing you'd expect. In
107−particular, everything in the `%wont` gate is here plus the calling duct
108−so that we know where to send the acknowledgment and `ete` to determine
109−if we're going to do the modern end-to-end acknowledgments.
110−
111−The actual line of code looks intimidating, but it's really not all that
112−bad. Working from the inside out, the call to `++um` sets up our
113−domestic server, and the call to `++ho` sets up our knowledge about the
114−neighbor we're sending to. From the outside, `++zork` and `++zank` just
115−apply the changes made to our `++um` and `++am` cores, respectively. If
116−you're familiar with the common idiom of `++abet`, that's all this is.
117−The code predates the widespread usage of that name.
118−
119−The interesting part, then, is in `++wool:ho:um:am`. Let's look at the
120−code.
121−
122−```hoon
123− ++ wool :: wool:ho:um:am
124− |= [hen=duct cha=path val=* ete=?] :: send a statement
125− ^+ +>
126− =+ ^= rol ^- rill
127− =+ rol=(~(get by ryl.bah) cha)
128− ?~(rol *rill u.rol)
129− =+ sex=sed.rol
130− :: ~& [%tx [our her] cha sex]
131− =. ryl.bah
132− %+ ~(put by ryl.bah) cha
133− rol(sed +(sed.rol), san (~(put by san.rol) sex hen))
134− =+ cov=[p=p:sen:gus q=clon:diz]
135− %+ wind [cha sex]
136− ?: ete
137− [%bund q.cov cha sex val]
138− [%bond q.cov cha sex val]
139−```
140−
141−This is slightly more complicated, but it's still not all that bad. Our
142−inputs, at least, are fairly obvious.
143−
144−If you glance at the code for a second, you'll see that
145−`++wind:ho:um:am` seems to be able to send a message, or `++meal:ames`, given
146−a `++soup`. This gate, then, just sets up the things we need to for
147−`++wind` to do its job.
148−
149−We first get `rol`, which is a `++rill:ames`, that is, a particular outbound
150−stream. This stream is specific to the path on which we're sending. If
151−the path hasn't been used before, then we create it. We let `sex` be the
152−number of messages we've already sent on this path.
153−
154−Then, we update the outbound stream by incrementing the number of
155−messages sent and placing an entry in `san.rol` that associates the
156−message number with the `duct` that sent the message. This allows us to
157−give the acknowledgment to the one who sent the message.
158−
159−We let `cov` be the current life of our crypto and our neighbor's
160−crypto. At the moment, we only need our neighbor's life, which we put
161−into the meal.
162−
163−Finally, we call `++wind:ho:um:am` with the `++soup` of the path and
164−message number and the `++meal:ames` of the payload itself. For end-to-end
165−acknowledged messages, we use `%bund`.
166−
167−```hoon
168− [%bund p=life q=path r=@ud s=*] :: e2e message
169−```
170−
171−Looking at how we create the `%bund`, we can easily see what each field
172−is for.
173−
174−Following the trail a little further, we go to `++wind:ho:um:am`.
175−
176−```hoon
177− ++ wind :: wind:ho:um:am
178− |= [gom=soup ham=meal]
179− :: ~& [%wind her gom]
180− ^+ +>
181− =^ wyv diz (zuul:diz now ham)
182− =^ feh puz (whap:puz now gom wyv)
183− (busk xong:diz feh)
184−```
185−
186−`++wind` does three things: it (1) encodes the message into a list of
187−possibly-encrypted packets, (2) puts the message into the packet pump,
188−and (3) sends any packets that are ready to be sent. Yes, our nice
189−little linear run of each gate calling exactly one other interesting
190−gate is over. We'll go in order here.
191−
192−`++zuul:lax:as:go` is the what converts a `++meal:ames` into a list of
193−actual, 1KB packets.
194−
195−```hoon
196− ++ zuul :: zuul:lax:as:go
197− |= [now=@da ham=meal] :: encode message
198− ^- [p=(list rock) q=_+>]
199− =< weft
200− ++ wasp :: null security
201− ++ weft :: fragment message
202− ++ wisp :: generate message
203−```
204−
205−For organizational purposes, `++zuul` constructs an internal core with
206−three arms. `++wasp` encodes the meal into an atom with no encryption.
207−`++wisp` encodes a meal with possible encryption (else it simply calls
208−`++wasp`). `++weft` takes the result of `++wisp` and splits it into
209−actual packets.
210−
211−```hoon
212− ++ wasp :: null security
213− ^-([p=skin q=@] [%none (jam ham)])
214−```
215−
216−This simply jams the meal, wrapping it with the `skin` of `%none`,
217−meaning no encryption.
218−
219−Since `++wisp` is a little long, we'll go through it line-by-line.
220−
221−```hoon
222− ++ wisp :: generate message
223− ^- [[p=skin q=@] q=_..wisp]
224−```
225−
226−`++wisp` produces a pair of a `skin` and an atom, which is the meal
227−encoded as a single atom and possibly encrypted.
228−
229−```hoon
230− ?: =(%carp -.ham)
231− [wasp ..wisp]
232−```
233−
234−If the meal that we're encoding is a `%carp`, then we don't encrypt it.
235−A `%carp` meal is a partial meal, used when a message is more than 1KB.
236−Since the entire message is already encrypted, we don't need to encrypt
237−each packet individually again.
238−
239−```hoon
240− ?: !=(~ yed.caq.dur)
241− ?> ?=(^ yed.caq.dur)
242− :_ ..wisp
243− :- %fast
244− %^ cat 7
245− p.u.yed.caq.dur
246− (en:r:cluy q.u.yed.caq.dur (jam ham))
247−```
248−
249−If we have a symmetric key set up with this neighbor, then we simply use
250−it. The skin `%fast` is used to indicate a symmetric key.
251−
252−```hoon
253− ?: &(=(~ lew.wod.dur) |(=(%back -.ham) =(%buck -.ham)))
254− [wasp ..wisp]
255−```
256−
257−If we do not yet have our neighbor's will, then there is no way that we
258−can seal the message so that only they may read it. If what we're
259−sending is an acknowledgment, then we go ahead and just send it in the
260−clear.
261−
262−```hoon
263− =^ tuy +>.$
264− ?:(=(~ lew.wod.dur) [*code +>.$] (griz now))
265−```
266−
267−If we don't have our neighbor's will, then we "encrypt" with a key of 0.
268−If we do have their will, then we generate a new symmetric key that we
269−will propose.
270−
271−```hoon
272− :_ ..wisp
273− =+ yig=sen
274− =+ bil=law.saf :: XX send whole will
275− =+ hom=(jam ham)
276−```
277−
278−`yig` will be the life and engine for our current crypto. `bil` is our
279−will. `hom` is the meal encoded as a single atom.
280−
281−```hoon
282− ?: =(~ lew.wod.dur)
283− :- %open
284− %^ jam
285− [~ `life`p.yig]
286− bil
287− (sign:as:q.yig tuy hom)
288−```
289−
290−If we do not have our neighbor's will, then we send our current life
291−along with our will and the message. The message itself is "signed" with
292−a key of 0.
293−
294−```hoon
295− :- %full
296− =+ cay=cluy
297− %^ jam
298− [`life`p.cay `life`p.yig]
299− bil
300− (seal:as:q.yig pub:ex:r.cay tuy hom)
301− -- :: --zuul:lax:as:go
302−```
303−
304−If we do have our neighbor's will, then we send our perception of their
305−current life, our current life, our will, and the message. The message
306−is sealed with their public key so that only they can read our message.
307−
308−Once we have the message encoded as an atom, `++weft` goes to work.
309−
310−```hoon
311− ++ weft :: fragment message
312− ^- [p=(list rock) q=_+>.$]
313− =^ gim ..weft wisp
314− :_ +>.$
315− ^- (list rock)
316−```
317−
318−We're going to produce a list of the packets to send. First, we use the
319−aforementioned `++wisp` to get the message as an atom.
320−
321−```hoon
322− =+ wit=(met 13 q.gim)
323− ?< =(0 wit)
324−```
325−
326−`wit` is the number of 1KB (2\^13 bit) blocks in the message. We assert
327−that there is at least one block.
328−
329−```hoon
330− ?: =(1 wit)
331− =+ yup=(spit [our her] p.gim q.gim)
332− [yup ~]
333−```
334−
335−If there is exactly one block, then we just call `++spit` to turn the
336−message into a packet. We'll explain what `++spit` does momentarily.
337−
338−```hoon
339− =+ ruv=(rip 13 q.gim)
340− =+ gom=(shaf %thug q.gim)
341− =+ inx=0
342−```
343−
344−If there is more than one block, then we rip it into blocks in `ruv`.
345−`gom` is a hash of the message, used as an id. `inx` is the number of
346−packets we've already made.
347−
348−```hoon
349− |- ^- (list rock)
350− ?~ ruv ~
351− =+ ^= vie
352− %+ spit
353− [our her]
354− wasp(ham [%carp (ksin p.gim) inx wit gom i.ruv])
355− :- vie
356− $(ruv t.ruv, inx +(inx))
357−```
358−
359−Here we package each block into a packet with `++spit` and produce the
360−list of packets.
361−
362−```hoon
363− ++ spit :: cake to packet
364− |= kec=cake ^- @
365− =+ wim=(met 3 p.p.kec)
366− =+ dum=(met 3 q.p.kec)
367− =+ yax=?:((lte wim 2) 0 ?:((lte wim 4) 1 ?:((lte wim 8) 2 3)))
368− =+ qax=?:((lte dum 2) 0 ?:((lte dum 4) 1 ?:((lte dum 8) 2 3)))
369− =+ wix=(bex +(yax))
370− =+ vix=(bex +(qax))
371− =+ bod=:(mix p.p.kec (lsh 3 wix q.p.kec) (lsh 3 (add wix vix) r.kec))
372− =+ tay=(ksin q.kec)
373− %+ mix
374− %+ can 0
375− :~ [3 1]
376− [20 (mug bod)]
377− [2 yax]
378− [2 qax]
379− [5 tay]
380− ==
381− (lsh 5 1 bod)
382−```
383−
384−This is how we turn a message into a real packet. This has the
385−definition of the packet format.
386−
387−`wim` is the length of the sending ship, and `dum` is the length of the
388−receiving ship. There are only five possibilities for each of those,
389−corresponding to carriers, cruisers, destroyers, yachts, and submarines.
390−These are encoded in `yax` and `qax` as 0, 0, 1, 2, and 3, respectively.
391−Thus, `wix` and `vix` are the number of bytes that must be reserved for
392−the ship names in a packet.
393−
394−Next, we construct `bod` by simply concatenating the sending ship, the
395−receiving ship, and the body of the message. Then, we get the encryption
396−mechanism from `++skin:ames`, which may be a 0, 1, 2, or 3, and put it in
397−`tay`.
398−
399−Next, we concatenate together, bit by bit, some final metadata. We use
400−three bits for our protocol number, which is incremented modulo eight
401−when there is a continuity breach or the protocol changes. We use the
402−final twenty bits of a hash of the body (which, we suppose, makes it a
403−twenty bit hash) for error-checking. We use two bits to tell how much
404−room is used in the body for the sending ship, and another two bits for
405−the receiving ship. Finally, we use five bits to store the encryption
406−type. Note that since there are only two bits worth of encryption types,
407−there are three unused bits here. This adds up to 32 bits of header
408−data. Finally, we concatenate this onto the front of the packet. Thus,
409−we can summarize the packet header format as follows.
410−
411−```
412− 0 1 2 3
413− 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
414− +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
415− |Proto| Hash of Body |yax|qax| Crypto |
416− +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
417−```
418−
419−After this, there are `yax` bits of the sender name, `qax` bits of the
420−receiver name, and up to 8192 bits of data. Thus, the maximum size of a
421−packet is achieved in a message between two submarines with 8192 bits of
422−data. This will require 32+128+128+8192 = 8480 bits, or 1060 bytes.
423−
424−This concludes our discussion of `++zuul:lax:as:go`. If you recall from
425−`++wind:ho:um:am`, the list of packets from `++zuul` is passed into
426−`++whap:pu` to update the packet pump and get any packets that can be
427−sent immediately.
428−
429−```hoon
430− ++ whap :: whap:pu
431− |= [now=@da gom=soup wyv=(list rock)] :: send a message
432− ^- [(list rock) _+>]
433− =. pyz (~(put by pyz) gom (lent wyv))
434− =. +>
435− |- ^+ +>.^$
436− ?~ wyv +>.^$
437− %= $
438− wyv t.wyv
439− nus +(nus)
440− diq (~(put by diq) (shaf %flap i.wyv) nus)
441− puq (~(put to puq) [nus `soul`[gom 0 | ~2000.1.1 i.wyv]])
442− ==
443− (harv now)
444−```
445−
446−First, we put into `pyz` the id for this message and the number of its
447−packets that have not yet been acknowledged, which is of course the
448−total number of packets since we haven't even sent the packets.
449−
450−For every packet, we change three things in the state (`++shed:ames`) of our
451−packet pump: (1) we increment `nus`, the number of packets sent; (2) we
452−put the packet number into `diq` keyed by a hash of the packet; and (3)
453−we put the packet into the packet queue, with the basic metadata of its
454−id `gom`, 0 transmissions, not live yet, last sent in the year 2000, and
455−the packet itself.
456−
457−Finally, we harvest the packet pump.
458−
459−```hoon
460− ++ harv :: harv:pu
461− |= now=@da :: harvest queue
462− ^- [(list rock) _+>]
463− ?: =(~ puq) [~ +>(rtn ~)]
464− ?. (gth caw nif) [~ +>]
465− =+ wid=(sub caw nif)
466− =| rub=(list rock)
467− =< abet =< apse
468− |%
469−```
470−
471−`++harv` contains a core for most of its work. The meat is in `++apse`.
472−First, though, it sets itself up. If there aren't any packets in the
473−queue, then we simply do nothing except set `rtn`, our next timeout, to
474−nil because we don't have any packets that may need to be retransmitted.
475−If we have more live (that is, sent and unacknowledged) packets than our
476−window size, then we don't do anything.
477−
478−Otherwise, we let `wid` be the width of our remaining packet window, and
479−we initialize `rub` to nil. `rub` will be the list of packets that are
480−ready to be sent. We then call `++apse` and pass the result to `++abet`.
481−`++apse` decides which packets are ready to be sent.
482−
483−```hoon
484− ++ apse
485− ^+ .
486− ?~ puq .
487− ?: =(0 wid) .
488− => rigt =< left
489− ?> ?=(^ puq)
490− ?: =(0 wid) .
491− ?. =(| liv.q.n.puq) .
492− :: ~& [%harv nux.q.n.puq p.n.puq]
493− %_ .
494− wid (dec wid)
495− rub [pac.q.n.puq rub]
496− nif +(nif)
497− liv.q.n.puq &
498− nux.q.n.puq +(nux.q.n.puq)
499− lys.q.n.puq now
500− ==
501−```
502−
503−If there are no remaining packets to send, or if we've filled the packet
504−window, do nothing. We call `++rigt` and `++left` to process the left
505−and right branches of the packet queue.
506−
507−Now we assert that the queue is not empty, and we again check that we
508−haven't filled the packet window. We will operate on the head of the
509−queue. If the packet is live, then do nothing. Otherwise, we go ahead
510−and send it.
511−
512−To send, we (1) decrement `wid`, our packet window width; (2) cons the
513−packet onto the `rub`, which will be returned as the list of packets to
514−send; (3) increment `nif`, the number of live packets; (4) set the
515−packet to be live; (5) increment the number of transmissions of the
516−packet; and (6) set the last sent time of the packet to now.
517−
518−```hoon
519− ++ left
520− ?> ?=(^ puq)
521− ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq])))
522− ++ rigt
523− ?> ?=(^ puq)
524− ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig])))
525−```
526−
527−These do exactly what you would expect: they traverse the packet queue
528−so that `++apse` gets called recursively through it.
529−
530−Finally, `++abet` gets called, which resolves the changes.
531−
532−```hoon
533− ++ abet
534− ?~ rub [~ +>.$]
535− [(flop rub) +>.$(rtn [~ (add rto now)])]
536−```
537−
538−This returns the packets that we wish to send, and it updates the
539−timeout so that we know when to try resending unacknowledged packets.
540−
541−This concludes our discussion of `++whap:pu`. To finish
542−`++wind:ho:um:am`, we just need to delve into `++busk:ho:um:am`. But
543−wait, in the call to `++busk`, the first argument is `xong:diz`. What is
544−this? This, my dear reader, is one more detour, this time into
545−`++xong:lax:as:go`.
546−
547−```hoon
548− ++ xong :: xong:lax:as:go
549− ^- (list ship) :: route unto
550− =+ [fro=xen too=xeno]
551− =+ ^= oot ^- (list ship)
552− =| oot=(list ship)
553− |- ^+ oot
554− ?~ too ~
555− ?: (lien fro |=(a=ship =(a i.too))) ~
556− [i.too $(too t.too)]
557− :: ~& [%xong-to [our her] (weld oot ?>(?=(^ fro) t.fro))]
558− (weld oot ?>(?=(^ fro) t.fro))
559−```
560−
561−This gets the list of intermediate ships needed to get a packet from us
562−to our neighbor. First, we get `fro` and `too`, the "canons" of ourself
563−and our neighbor, respectively.
564−
565−What is this "canon", you ask? A canon is simply a ship plus its
566−"ancestors", as defined by `++sein:title`. For example, the canon of
567−`~hoclur-bicrel` is:
568−
569−```
570− ~hoclur-bicrel/try=> (saxo:title ~hoclur-bicrel)
571− ~[~hoclur-bicrel ~tasruc ~tug]
572−```
573−
574−If we follow the algorithm in `++xong`, we see that we are simply
575−creating a list of ships that form a path from our neighbor to ourself.
576−Essentially, we look through the canon of our neighbor until we find
577−something in our own cannon -- a common ancestor. Or, if we are from
578−different carriers, then there is no common ancestor. We then weld this
579−onto the tail of our own canon. In the end, this is simply a list of
580−possible ships to try to route via to get to our neighbor, ordered by
581−preferability (that is, closeness to our neighbor). We will end up
582−trying, in order, to find a lane to these.
583−
584−Now, we can finally get to `++busk:ho:um:am`.
585−
586−```hoon
587− ++ busk :: busk:ho:um:am
588− |= [waz=(list ship) pax=(list rock)] :: send packets
589− %_ +>
590− bin
591− |- ^+ bin
592− ?~ pax bin
593− $(pax t.pax, bin (weld (flop (wist:diz now waz ~ i.pax)) bin))
594− ==
595−```
596−
597−Thankfully, `++busk` is fairly simple. We go through the list of packets
598−and convert them to `++boon:ames`s with `++wist:lax:as:go`. These boons are
599−placed into `bin`, and they end up getting processed by `++clop` (this
600−happens in `++knob`).
601−
602−```hoon
603− ++ wist :: wist:lax:as:go
604− |= $: now=@da :: route via
605− waz=(list ,@p)
606− ryn=(unit lane)
607− pac=rock
608− ==
609− ^- (list boon)
610− ?: =(our her) [[%ouzo *lane pac] ~]
611− ?~ waz ~
612− =+ dyr=?:(=(her i.waz) dur (gur i.waz))
613− ?. ?& !=(our i.waz)
614− ?=(^ lun.wod.dyr)
615− ==
616− $(waz t.waz)
617− :_ ?: ?=(%ix -.u.lun.wod.dyr)
618− $(waz t.waz)
619− ~
620− :+ %ouzo u.lun.wod.dyr
621− ?: &(=(i.waz her) =(~ ryn)) pac
622− =+ mal=(jam `meal`[%fore her ryn pac])
623− %- spit
624− ^- cake
625− :* [our i.waz]
626− ?~ yed.caq.dyr [%none mal]
627− :- %fast
628− %^ cat 7
629− p.u.yed.caq.dyr
630− (en:crub:crypto q.u.yed.caq.dyr mal)
631− ==
632−```
633−
634−This takes a sample of the current time, the list of ships that we just
635−generated, a lane if we already know it, and the packet itself.
636−
637−First, if we are sending a message to ourself, then we simply create a
638−`%ouzo` boon with a bunted lane. Otherwise, if there are no routing
639−candidates, there is nothing we can do, so we return nil.
640−
641−Next, we get the `++dore:ames` of the first routing candidate. If we're looking
642−at the neighbor to whom we're trying to send the message, then we simply
643−use the `++dore:ames` that we already have. Otherwise, we get a default `++dore:ames`.
644−
645−If we're the first routing candidate, or if we have don't have a lane to
646−this candidate, then we skip this candidate and move on to the next one.
647−
648−If we have only a provisional ip address, then we try to send on it, but
649−we also try to send on later routing candidates as well. Otherwise, we
650−only send on this one candidate.
651−
652−Finally, we create the actual `%ouzo` boon. The lane is the one from our
653−`++dore:ames`. If we're sending it directly to our intended recipient, and we
654−haven't been told to use a specific lane, then we just send the packet
655−directly. Otherwise, we wrap it in a little `%fore` meal, telling the
656−intermediary to whom we wish it to be sent. If we have already set up a
657−symmetric key with the intermediary, then we encrypt it with that.
658−Otherwise, we send it in the clear.
659−
660−Now, if you recall, we have traced all the way through from the
661−beginning when, in `++knob`, the `%wont` card was handled by a call to
662−`++wise`. There is only one more step before the packet is finally sent.
663−Looking in `++knob`, we see that the resultant list of boons is passed
664−into `++clop`, which will execute the correct actions and return a list
665−of moves. In `++clop`, we see the handling of each specific boon. The
666−one we are interested in is `%ouzo`, since that is the only one we have
667−sent thus far.
668−
669−```hoon
670− %ouzo
671− :: ~& [%send now p.bon `@p`(mug (shaf %flap q.bon))]
672− :_ fox
673− [[gad.fox [%give %send p.bon q.bon]] ~]
674−```
675−
676−Very simply, we give a `%send` gift along the special duct that goes
677−straight into the bowels of unix. This is the last stop before we drop
678−into vere, and later libuv. And then... the world.
679−
680−The packet, after its creation, embarks on a journey across physical
681−time and space into the great unknown. Hurtling through fiber-optic
682−cables at hundreds of thousands of kilometers per second, it finally
683−arrives at our neighbor's network adapter. The adapter tells unix, unix
684−tells libuv, libuv tells vere, and vere sends a `%hear` task to ames.
685−And now we reenter the kernel.
686−
687−The `%hear` task goes straight to `++knob`, just as did the `%wont` task
688−earlier.
689−
690−```hoon
691− %hear
692− (~(gnaw am [now fox]) %good p.kyz q.kyz)
693−```
694−
695−Here, though, we call `++gnaw:am` to process the packet. The arguments
696−to `++gnaw` are the same as those to the `%hear` task: the lane on which
697−the packet was received and the packet itself. The other argument is
698−just `%good`, which is a `++cape:ames` saying that we expect the packet to
699−succeed. If a formal error occurs, then since we have a transactional
700−event system, the `%hear` event will never be considered to have
701−actually happened, and unix will send a `%hole` task so that we may send
702−a negative acknowledgment.
703−
704−```hoon
705− ++ gnaw :: gnaw:am
706− |= [kay=cape ryn=lane pac=rock] :: process packet
707− ^- [p=(list boon) q=fort]
708− ?. =(2 (end 0 3 pac)) [~ fox]
709− =+ kec=(bite pac)
710− ?: (goop p.p.kec) [~ fox]
711− ?. (~(has by urb.ton.fox) q.p.kec)
712− [~ fox]
713− =< zork
714− =< zank
715− %- ~(chew la:(ho:(um q.p.kec) p.p.kec) kay ryn %none (shaf %flap pac))
716− [q.kec r.kec]
717−```
718−
719−First, we check the protocol number. If it is not correct, then we
720−simply ignore the packet entirely. Otherwise, we parse the packet with
721−`++bite`, which converts a packet atom into a `++cake:ames`, that is, a triple
722−of the `sock` (pair of sender and receiver), the `skin` (encryption
723−type), and the data.
724−
725−```hoon
726− ++ bite :: packet to cake
727− |= pac=rock ^- cake
728− =+ [mag=(end 5 1 pac) bod=(rsh 5 1 pac)]
729− =+ :* vez=(end 0 3 mag) :: protocol version
730− chk=(cut 0 [3 20] mag) :: checksum
731− wix=(bex +((cut 0 [23 2] mag))) :: width of receiver
732− vix=(bex +((cut 0 [25 2] mag))) :: width of sender
733− tay=(cut 0 [27 5] mag) :: message type
734− ==
735− ?> =(2 vez)
736− ?> =(chk (end 0 20 (mug bod)))
737− :+ [(end 3 wix bod) (cut 3 [wix vix] bod)]
738− (kins tay)
739− (rsh 3 (add wix vix) bod)
740−```
741−
742−This is exactly the inverse of `++spit`. Note that here we check both
743−the protocol number and the hash, crashing on error. Remember that a
744−crash will result in a negative acknowledgment being sent.
745−
746−Continuing in `++gnaw`, we see that if the intended recipient is not on
747−our pier, then we drop the packet.
748−
749−If we've gotten this far, then we wish to process the packet. Recall
750−that `++ho` and `++um` set up the domestic server and foreign client
751−cores, respectively, and that `++zork` and `++zank` resolve any changes
752−to these cores.
753−
754−The new stuff here, then, is the `++la` core and the `++chew` arm. The
755−`++la` sets up a core for this particular packet, containing the current
756−success/failure `++cape:ames`, the lane it was sent on, the encryption type,
757−and a hash of the packet, used as an id.
758−
759−`++chew` is called with the encryption type and the message itself. It
760−contains a little helper core inside of it, which starts immediately
761−with `++apse`.
762−
763−```hoon
764− ++ apse
765− ^+ +>.$
766− =+ oub=bust:puz
767− =+ neg==(~ yed.caq.dur.diz)
768− =. +>.$ east
769− =+ eng==(~ yed.caq.dur.diz)
770− =+ bou=bust:puz
771− =. bin
772− ?. &(oub !bou) bin
773− :_(bin [%wine [our her] " is ok"])
774− =. bin
775− ?. &(neg !eng) bin
776− :_(bin [%wine [our her] " is your neighbor"])
777− +>.$
778−```
779−
780−First, we let `oub` be true if our neighbor hasn't been responding to us
781−for more than sixteen seconds. Let `neg` be true if we haven't yet
782−proposed a symmetric key, meaning that we haven't yet corresponded with
783−this ship, so they are not our neighbor. Next, we run `++east`, which
784−we'll go into in just a minute.
785−
786−We now do the same two checks and store the results in `eng` and `bou`.
787−If our neighbor has, like the prodigal son, returned after an extended
788−absence, then we send a `%wine` boon as the proverbial fatted calf,
789−which is simply printed out to the console. Likewise, if we are meeting
790−one with whom we have never had the pleasure of acquainting ourselves,
791−we send a message to the console to that effect.
792−
793−We skipped over `++east`, which contains the meat of the processing. It
794−first decrypts the message, then calls `++chow:la:ho:um:am` with the
795−resultant meal. We'll go through each of the four cases in turn, but
796−first since each one calls `++bilk:pu`, we'll take a brief detour.
797−
798−```hoon
799− ++ bilk :: bilk:pu
800− |= now=@da :: inbound packet
801− ^+ +>
802− =+ trt=(mul 2 rtt)
803− %= +>.$
804− rue [~ now]
805− rto trt
806− rtn ?~(puq ~ [~ (add now trt)])
807− ==
808−```
809−
810−This updates the timing information in our packet pump. `rue`, the last
811−time we have heard from this neighbor, is set to now. `rto`, the
812−retransmit timeout is set to twice the current ping time, and if there
813−is anything in the packet queue, then we reset the next timeout, since
814−we've just heard a message.
815−
816−Back to `++east`.
817−
818−```hoon
819− %none
820− =. puz (bilk:puz now)
821− (chow ((hard meal) (cue msg)))
822−```
823−
824−The simplest case is when the encryption type is `%none`. We first call
825−`++bilk` to update the packet pump, then we cue (unjam) the message into
826−a meal. We hard cast it into a meal -- if the cast fails, then we do
827−want to crash since someone is sending us malformed data. Finally, we
828−send the result to `++chow` for interpretation and handling.
829−
830−```hoon
831− %fast
832− =+ [mag=`hand`(end 7 1 msg) bod=(rsh 7 1 msg)]
833− =+ dey=(kuch:diz mag)
834− ?~ dey
835− ~& [%bad-key her mag]
836− +>.$ :: ignore unknown key
837− =. puz (bilk:puz now)
838− =^ key diz u.dey
839− (chow(aut sin) ((hard meal) (cue (dy:q:sen:gus key bod))))
840−```
841−
842−For symmetric encryption, we first get the `++hand`, which is the hash of
843−the symmetric key. We pass it to `++kuch:lax:as:go`, which returns the
844−key if we either have used it before or we have proposed it. If we have
845−proposed it, then we change its status from proposed to real. If
846−`++kuch` fails, then we drop the packet and print out a `%bad-key`
847−message.
848−
849−Otherwise, we call `++bilk` as before to update the packet pump and pass
850−into `++chow` the decrypted data.
851−
852−```hoon
853− %full
854− =+ mex=((hard ,[p=[p=life q=life] q=will r=@]) (cue msg))
855− =. diz (deng:diz q.mex)
856− =+ wug=cluy:diz
857− ?> =(q.p.mex p.wug)
858− =+ gey=(sev:gus p.p.mex)
859− =+ mes=(need (tear:as:q.gey pub:ex:r.wug r.mex))
860− =. diz (wasc:diz p.mes)
861− =. puz (bilk:puz now)
862− (west(msg q.mes))
863−```
864−
865−For sealed asymmetric encryption, we first take off the the layer of
866−data that gives us the life and will of our neighbor, and we apply try
867−to extend their former will with the new data. `++deng` will fail if
868−this is impossible.
869−
870−Next, we get our most current understanding of our neighbor's crypto,
871−and we verify that it's the same life as what they're sending. Then, we
872−get our own crypto from `++sev` and decrypt the message with the public
873−key from our neighbor's crypto. We register the proposed symmetric key,
874−update the packet pump, and call `++west`, which simply casts the
875−message to a meal and calls `++chow`, reporting any error.
876−
877−```hoon
878− %open
879− =+ mex=((hard ,[p=[~ q=life] q=will r=@]) (cue msg))
880− =. diz (deng:diz q.mex)
881− =+ wug=cluy:diz
882− ?> =(q.p.mex p.wug)
883− =+ mes=(need (sure:as:r.wug *code r.mex))
884− =. puz (bilk:puz now)
885− (west(msg mes))
886−```
887−
888−Finally, for signed asymmetric encryption, we, as before, take off the
889−layer of data that gives us the life and will of our neighbor. This
890−time, of course, we do not get our own crypto -- only that of our
891−neighbor.
892−
893−The rest you have seen. We call `++deng` to extend the will, we verify
894−that their crypto life is what we think it ought to be, we "decrypt" the
895−data, we update the packet pump, and we call `++west` to call `++chow`.
896−
897−```hoon
898− ++ chow :: chow:la:ho:um:am
899− |= fud=meal :: interpret meal
900− ^+ +>
901− =. diz ?:(=(%none aut) diz (wast:diz ryn))
902− (dine fud)
903−```
904−
905−Here, if the message was encrypted at all, then we call
906−`++wast:lax:as:go`, which simply updates the lane (route) to our
907−neighbor (unless we're given a provisional route). This ensures that we
908−always have the most direct possible path to them.
909−
910−We've been handling this meal for so long, we've almost forgotten what
911−we want to do with it. The telos is of any meal to be dined on. We will
912−choose out the cases here that are important to our current
913−investigation.
914−
915−```hoon
916− %fore
917− =+ ^= lyn ^- lane
918− ?~ q.fud ryn
919− ?. ?=(%if -.u.q.fud) u.q.fud
920− [%ix +.u.q.fud]
921− :: u.q.fud
922− ?: =(our p.fud)
923− (emit %mead lyn r.fud)
924− =+ zid=(myx:gus p.fud)
925− (emir (wist:zid now xong:zid [~ lyn] r.fud))
926−```
927−
928−Forwarding is the simplest case, since we've seen all the arms before,
929−except perhaps `++emit` and `++emir`, which simply take a boon or list
930−of boons respectively and queue them up to be handled when the core
931−resolves. If we're told to forward a packet to ourselves, then we emit a
932−`%mead` boon which simply sends another `%hear` task to ourselves with
933−the data. Otherwise, we try to find a route to the recipient, as before.
934−
935−```hoon
936− %carp
937− =+ zol=(~(get by olz.weg) s.fud)
938− ?^ zol cock(kay u.zol)
939− =^ neb nys.weg
940− =+ neb=(~(get by nys.weg) s.fud)
941− ?^ neb [u.neb nys.weg]
942− =+ neb=`bait`[(kins p.fud) 0 r.fud ~]
943− [neb (~(put by nys.weg) s.fud neb)]
944− ?> (lth q.fud p.r.neb)
945− ?> =((kins p.fud) p.neb)
946− ?> =(r.fud p.r.neb)
947− =+ doy=`(unit ,@)`(~(get by q.r.neb) q.fud)
948− ?^ doy cock
949− => ^+ . %= .
950− q.r.neb (~(put by q.r.neb) q.fud t.fud)
951− q.neb +(q.neb)
952− ==
953− :: ~& [%carp q.fud s.fud q.neb p.r.neb]
954− ?: =(q.neb p.r.neb)
955− =: nys.weg (~(del by nys.weg) s.fud)
956− olz.weg (~(put by olz.weg) s.fud kay)
957− ==
958− (golf p.neb r.neb)
959− =. +>.$ cock
960− +>.$(nys.weg (~(put by nys.weg) s.fud neb))
961−```
962−
963−Here, we have received a partial message, and we're just assembling the
964−individual packets into a message. Most of this code is fairly
965−algorithmic, so we'll just hit the high points. In the beginning, we
966−check if we've already received this message, and if so, we resend the
967−acknowledgment. Remember, "always ack a dupe, never ack an ack".
968−
969−In `nys.weg` we keep track of an incoming set of partial packets,
970−indexed by the `flap` hash that comes with every packet. We check to see
971−if we have already received this partial message, and if so we
972−acknowledge it. Otherwise, we put it in `nys.weg` unless this is the
973−last message, in which case we ack the last partial message, move the
974−complete message into `olz.weg`, and call `++golf`, which assembles the
975−message and calls `++chew`, to start the dance again with the complete
976−message.
977−
978−```hoon
979− %bund
980− :: ~& [%bund q.fud r.fud]
981− ?> =(p:sen:gus p.fud)
982− (deer q.fud r.fud ?-(kay %dead ~, %good [~ s.fud]))
983−```
984−
985−What if we're just receiving a regular old, garden variety message? We
986−call `++deer` with the data from the message. If we already know that
987−the message processing will fail (that is, if we got a `%hole` card from
988−unix rather than a `%hear` card), then we don't even send the data at
989−all. Remember, if a packet fails to process, it's as if it never even
990−arrived, except that we send a negative acknowledgment.
991−
992−```hoon
993− ++ deer :: deer:la:ho:um:am
994− |= [cha=path num=@ud dut=(unit)] :: interpret message
995− ^+ +>
996− =+ rum=(fall (~(get by raz.bah) cha) *race)
997− %= +>.$
998− +>
999− ?. (gte num did.rum) :: always ack a dup
1000− (cook (~(get by bum.rum) num) cha ~ ryn dam)
1001− ?: dod.rum
1002− (coat cha rum(mis (~(put by mis.rum) num [kay ryn dam dut])))
1003− %= +>.+>.$
1004− raz.bah
1005− %+ ~(put by raz.bah) cha
1006− rum(mis (~(put by mis.rum) num [kay ryn dam dut]))
1007− ==
1008− ==
1009−```
1010−
1011−First, we get the race for this particular triple of sender, receiver,
1012−and path, creating it if it doesn't exist. If we've already acked the
1013−message, then we resend the ack. Note that `did.rum` is the number of
1014−packets we acknowledged, positively or negatively while `bum.rum` is a
1015−map of message numbers to negative acknowledgments. Thus, if a message
1016−number is less than `did.rum`, then if it's in `bum.rum` then it was
1017−negatively acknowledged, otherwise it's positively acknowledged. Thus, we
1018−are constant in space with the number of successful messages and linear
1019−in the number of failed messages. We'll document `++cook` later on, but
1020−suffice it to say that it sends an acknowledgment. It is to end-to-end
1021−acknowledgments what `++cock` is to packet-level acknowledgments.
1022−
1023−If we are still processing a message (that is, `dod.rum` is false), then
1024−we simply put this message in the map of misordered packets to be
1025−processed when their time comes. "Processing a message" in this case
1026−means that we've received the message and notified the correct
1027−application, but we're still waiting for the application-level
1028−acknowledgment.
1029−
1030−Otherwise, we're ready for a packet, so we process it.
1031−
1032−```hoon
1033− ++ coat :: coat:ho:um:am
1034− |= [cha=path rum=race] :: update input race
1035− ^+ +>
1036− =+ cun=(~(get by mis.rum) did.rum)
1037− ?~ cun
1038− +>.$(raz.bah (~(put by raz.bah) cha rum))
1039− ?. =(%good p.u.cun) +>.$
1040− ?> ?=(^ s.u.cun)
1041− %= +>.$
1042− raz.bah (~(put by raz.bah) cha rum(dod |))
1043− bin
1044− :_ bin
1045− :^ %mulk
1046− [our her]
1047− `soap:ames`[[p:sen:gus clon:diz] cha did.rum]
1048− u.s.u.cun
1049− ==
1050−```
1051−
1052−First, we grab the message we want to process and store it in `cun`. If
1053−it's a good packet, then we change `dod.rum` to false, meaning that
1054−we're in the middle of processing a packet and should not start
1055−processing another one. We also put a `%mulk` boon into the queue so
1056−that, when it all resolves, we send a mesage to the intended recipient
1057−application. The boon contains the sender, the receiver, the identity of
1058−the message, and the message itself.
1059−
1060−This bubbles up all the way back to `++knob`, where we were handling the
1061−`%hear` card. Following the logic in `++knob`, we can see that the boons
1062−get sent into `++clop` to be turned into actual arvo-level moves. We've
1063−been here before, if you recall, when we handled the `%cake` boon to
1064−send a message. Now, we're handling the `%mulk` boon, which is
1065−unfortunately slightly more complicated.
1066−
1067−```hoon
1068− %mulk
1069− :: ~& [%mulk p.bon q.bon]
1070− ?> ?=([@ @ *] q.q.bon)
1071− ?> ?=(%q i.q.q.bon)
1072− ?+ i.t.q.q.bon
1073− ~& %mulk-bad
1074− :_ fox
1075− :~ :- (claw p.p.bon)
1076− [%sick %wart p.bon i.t.q.q.bon t.t.q.q.bon r.bon]
1077− ==
1078− %ge :: %gall request
1079− ?> ?=([@ ~] t.t.q.q.bon)
1080− =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon))
1081− =+ ^= pax
1082− :+ (scot %p p.p.bon)
1083− (scot %p q.p.bon)
1084− q.q.bon
1085− :_ fox [hen %pass pax %g %rote p.bon app r.bon]~
1086− %gh :: %gall response
1087− ?> ?=([@ ~] t.t.q.q.bon)
1088− =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon))
1089− =+ ^= pax
1090− :+ (scot %p p.p.bon)
1091− (scot %p q.p.bon)
1092− q.q.bon
1093− :_ fox [hen %pass pax %g %roth p.bon app r.bon]~
1094− ==
1095−```
1096−
1097−We're dispatching messages based on the prefix of their path. Since only
1098−`%gall` apps use end-to-end acknowledgments at the moment, every path
1099−must have at least two elements, and the first one must be `%q`. Beyond
1100−that, we handle the `/q/ge` and `/q/gh` cases for gall requests and
1101−responses, respectively.
1102−
1103−In both cases, we require the next term in the path to be the name of
1104−the intended recipient `%gall` app. Thus, a message to `/q/ge/talk` for
1105−example, will send a message to the talk app.
1106−
1107−We then send a message to the app itself. The message is either a
1108−`%rote` or a `%roth` for a request and a response, respectively. The
1109−content is the `rook` or `roon` that was sent (stored in `r.bon`), but
1110−we don't actually handle that at all here. That's completely a
1111−`%gall`-level thing. We're just the messenger.
1112−
1113−Notice the path we send this over. We encode the sender, the receiver,
1114−and the path over which it was sent. This fully specifies the `race` so
1115−that when the app gives us the acknowledgment we know where to send it.
1116−
1117−We now have another interlude. We have entrusted our precious data, so
1118−carefully guarded and guided from the app on that far-away ship, to our
1119−local app. It has the ability to do whatever it pleases with it. It may
1120−take a significant amount of time to process. When the message has been
1121−handled by this app, though, it must produce an acknowledgment. Our
1122−final task is to deliver this acknowledgment to the sending app.
1123−
1124−We should describe here what exactly these oft-mentioned acknowledgments
1125−actually consist of. There are two kinds of acknowledgments: positive
1126−and negative. A positive acknowledgment contains no data other than its
1127−existence. A negative acknowledgment may optionally include a reason for
1128−said negativity. Formally, a negative acknowledgment is an `ares`, which
1129−is a unit pair of a term and a list of tanks. If this is null, this is
1130−simply a failure with no associated information. If the pair exists, the
1131−term is a short error code that is usually both human and computer
1132−readable. For example, if you try to send a message to a valid `%gall`
1133−app that doesn't have any `++poke` to handle it, then `%gall` will give
1134−a negative acknowledgment with error term `%poke-find-fail`. The list of
1135−tanks is a human-readable description of the error. This often contains
1136−a stack trace. At any rate, all this information is returned to the
1137−sending app on the other end of the wire.
1138−
1139−After this brief interlude, our story resumes in `++knap`, where we
1140−receive responses. In particular, a `%mean` indicates a negative
1141−acknowledgment while a `%nice` indicates a positive acknowledgment.
1142−
1143−```hoon
1144− ?(%mean %nice)
1145− ?> ?=([@ @ @ *] tea)
1146− =+ soq=[(slav %p i.tea) (slav %p i.t.tea)]
1147− =+ pax=t.t.tea
1148− =+ ^= fuy
1149− =< zork =< zank
1150− %^ ~(rack am [now fox]) soq pax
1151− ?-(+<.sih %mean `p.+.sih, %nice ~)
1152− => %_(. fox q.fuy)
1153− =| out=(list move)
1154− |- ^- [p=(list move) q=_+>.^$]
1155− ?~ p.fuy
1156− [(flop out) +>.^$]
1157− =^ toe fox (clop now hen i.p.fuy)
1158− $(p.fuy t.p.fuy, out (weld (flop toe) out))
1159−```
1160−
1161−Recall the format of the path we sent the message on, and you'll
1162−understand why `soq` and `pax` are the sender/receiver pair and path on
1163−which the message was sent. The rest of this is structured much like
1164−`++knob`, so we call `++rack:am` and send the resulting boons to
1165−`++clop`. Business as usual.
1166−
1167−```hoon
1168− ++ rack :: rack:am
1169− |= [soq=sock cha=path cop=coop] :: e2e ack
1170− =+ oh=(ho:(um p.soq) q.soq)
1171− =. oh (cook:oh cop cha ~)
1172− (cans:oh cha)
1173−```
1174−
1175−First, we set up `++um` and `++ho`, as we've done twice before, for our
1176−domestic and foreign servers, respectively. The other two things are
1177−new, though. Well, `++cook` is not actually new, but we delayed the
1178−explanation saying only that it sends an acknowledgment. The time has
1179−come.
1180−
1181−```hoon
1182− ++ cook :: cook:ho:um:am
1183− |= [cop=coop cha=path ram=(unit ,[ryn=lane dam=flap])]
1184− ^+ +> :: acknowledgment
1185− =+ rum=(need (~(get by raz.bah) cha))
1186− =+ lat=(~(get by mis.rum) did.rum)
1187− ?: &(?=(~ lat) ?=(~ ram)) ~&(%ack-late-or-redundant +>.$)
1188− =+ ^- [ryn=lane dam=flap]
1189− ?^ ram [ryn.u.ram dam.u.ram]
1190− ?< ?=(~ lat)
1191− [q r]:u.lat
1192− =. raz.bah
1193− ?^ ram raz.bah
1194− %+ ~(put by raz.bah) cha
1195− rum(dod &, bum ?~(cop bum.rum (~(put by bum.rum) did.rum u.cop)))
1196− =^ roc diz (zuul:diz now [%buck cop dam ~s0])
1197− (busk(diz (wast:diz ryn)) xong:diz roc)
1198−```
1199−
1200−If we are acknowledging a message that we have already acked, the `ram`
1201−will contain the new lane and flap to send the duplicate ack to. This
1202−happens if we call `++cook` in `++deer`, but it doesn't happen from
1203−`++rack`. If there is no message waiting to be acknowledged and we're
1204−not given an explicit lane and flap (that is, we're not sending a
1205−duplicate ack), then the app must have sent us multiple acknowledgments.
1206−We do the only sensible thing we can do and drop all acknowledgments
1207−after the first, printing a message. This is, in fact, an error, so it
1208−could be argued that we ought to crash. Whatever you do, don't depend on
1209−this not crashing.
1210−
1211−First, we grab the race specified by the given path, and we get the most
1212−recent in-order message, which must be the one which is being
1213−acknowledged.
1214−
1215−Then, we decide which lane/flap to respond on/to. Basically, in the
1216−usual case we respond on the lane through which the initial message was
1217−sent, which is stored along with the other packet information in
1218−`mis.rum`, since it has to be remembered across calls to ames. However,
1219−if we receive a duplicate message, then we must respond to the new
1220−message. It's quite possible the reason the other acknowledgment didn't
1221−get returned was that the lane between the ships was broken.
1222−
1223−At any rate, we update the race by saying that we've finished processing
1224−this packet (unless we're sending a duplicate ack) and, if we're sending
1225−a negative acknowledgment, putting the negative ack into `bum.rum` so
1226−that we can resend it if necessary.
1227−
1228−We encode our new message, updating the packet pump, with `++zuul`, as
1229−before, and we send it off with `++busk`, routed via `++wast` to one of
1230−the ships in `++xong`. Of course, in practice, we don't even look at the
1231−ships in `++xong` because we already have a lane directly to our
1232−neighbor (the one over which they sent their message to us).
1233−
1234−We glossed over the actual message we're sending back. We're sending a
1235−`%buck` meal, which is an acknowledgment. The `cop` specifies whether
1236−this is a positive or a negative ack, `dam` specifies the message we're
1237−acknowledging, and the `~s0` is a placeholder for the processing time
1238−required. This time is neither calculated (though it is hopefully
1239−obvious how to do so) nor used at present, but this information may be
1240−used in the future for improved congestion control. Since the round-trip
1241−time for an end-to-end acknowledged packet includes the processing time
1242−on the other end, most common congestion control algorithms will stumble
1243−when some messages take much longer to process than others. As noted,
1244−though, this is simply an opportunity for improvement -- our congestion
1245−control algorithms are relatively naive at the moment.
1246−
1247−Recall that `++busk` calls `++wist` to put the actual `%ouzo` boon in
1248−the queue, which gets handled by `++clop` to actually send the message.
1249−This is the same pipeline as sending any other message, so we'll refer
1250−you to the explanation above if you've forgotten it.
1251−
1252−The last thing we need to do on this ship is move on to the next packet
1253−in the queue if there is one. If you recall, in `++rack` after the call
1254−to `++cook` there was a call to `++cans:ho:um:am`.
1255−
1256−```hoon
1257− ++ cans :: cans:ho:um:am
1258− |= cha=path
1259− =+ rum=(need (~(get by raz.bah) cha))
1260− =. rum
1261− %= rum
1262− did +(did.rum)
1263− mis (~(del by mis.rum) did.rum)
1264− ==
1265− (coat cha rum)
1266−```
1267−
1268−This is very simple. We increment the number of packets that we've
1269−acknowledged on this race and we delete the packet that we just
1270−acknowledged from the set of misordered packets.
1271−
1272−Then, we call `++coat` again to process the next packet if we've already
1273−received it. And that's it for this.
1274−
1275−The acknowledgment now travels the same path that its forebearer, the
1276−original message, once tread, but this time not into the great unknown.
1277−The weary traveler is seeking out its familial roots, finding the app
1278−from whom sprung forth the original message way back in paragraph three.
1279−When it arrives at the network adapter of its ancestors, the adapter
1280−tells unix, unix tells libuv, libuv tells vere, and vere sends a `%hear`
1281−task to ames. Once more into the kernel.
1282−
1283−The `%hear` task is handled in `++knob` as before, leading to `++gnaw`,
1284−going over to `++chew`, `++apse`, `++chow`, and eventualy to `++dine`.
1285−We've seen most of the cases in `++dine`, but we haven't yet looked at
1286−the handling of this `%buck` meal.
1287−
1288−```hoon
1289− %buck
1290− =. +> ?.(=(%full aut) +> cock) :: finish key exch
1291− +>(..la (tock p.fud q.fud r.fud))
1292−```
1293−
1294−We send a packet level acknowledgment if we're finishing a key exchange,
1295−else we call `++tock` to process the acknowledgment.
1296−
1297−This will get a little involved, so if you don't much care about how
1298−exactly an acknowledgment happens, just know that the result gets gifted
1299−as a `%woot` card back to the app who sent it. For those brave souls who
1300−wish to see this thing through to the end, it's once more into the
1301−breach.
1302−
1303−```hoon
1304− ++ tock :: tock:ho:um:am
1305− |= [cop=coop fap=flap cot=@dr] :: e2e ack by hash
1306− ^+ +>
1307− =^ yoh puz (bick:puz now fap)
1308− =. +>.$
1309− ?~ p.yoh +>.$
1310− =^ hud +>.$
1311− (done p.u.p.yoh q.u.p.yoh)
1312− ?~ hud +>.$
1313− %= +>.$
1314− bin
1315− :_ bin
1316− `boon`[%cake [our her] [[p:sen:gus clon:diz] u.p.yoh] cop u.hud]
1317− ==
1318− (busk xong:diz q.yoh)
1319−```
1320−
1321−We're going to work through this one a little backwards since it's
1322−mostly fairly simple except the call to `++bick:pu`. In fact, we'll just
1323−skip `++bick` for the moment and finish the rest.
1324−
1325−If `++bick` succesfully acks the message, then we call `++done`.
1326−
1327−```hoon
1328− ++ done :: done:ho:um:am
1329− |= [cha=path num=@ud] :: complete outgoing
1330− ^- [(unit duct) _+>]
1331− =+ rol=(need (~(get by ryl.bah) cha))
1332− =+ rix=(~(get by san.rol) num)
1333− ?~ rix [~ +>.$]
1334− :- rix
1335− %_ +>.$
1336− ryl.bah
1337− (~(put by ryl.bah) cha rol(san (~(del by san.rol) num)))
1338− ==
1339−```
1340−
1341−This very simply gets the rill (the outgoing counterpart to a race, if
1342−you recall), pulls out of the map of outstanding messages the duct over
1343−which the original message was sent, and produces this duct while
1344−deleting that entry from the map of outstanding messages.
1345−
1346−Going back to `++tock`, we now have the duct we need to return the
1347−result over. We do the very sensible thing and put a `%cake` boon in the
1348−queue to be processed later by `++clop`.
1349−
1350−In `q.yoh` we have a list of messages that may need to be sent, which we
1351−pass to `++busk` to send, as usual. When an acknowledgment arrives, that
1352−may trigger other messages immediately. This often happens when sending
1353−more messages than the width of the logical window since for congestion
1354−control reasons another message cannot be sent until some of the earlier
1355−ones have been acknowledged.
1356−
1357−We'll look at the processing of the `%cake` boon in `++clop` before we
1358−get back to talking about `++bick`.
1359−
1360−```hoon
1361− %cake
1362− :_ fox
1363− :~ [s.bon %give %woot q.p.bon r.bon]
1364− ==
1365−```
1366−
1367−We very simply give, along the duct we found above, a `%woot` card with
1368−the ship who sent us the ack and the ack itself. This allows the
1369−application to decide what to do about the result. In case of a failure,
1370−we usually either resend the message or display it to the user.
1371−Sometimes, we recognize the error term and handle it internally. In any
1372−case, the decision of how to handle the acknowledgment is entirely up to
1373−the application. Our job is done.
1374−
1375−Well, except that we skipped `++bick:pu`. Let's go back to that.
1376−
1377−```hoon
1378− ++ bick :: bick:pu
1379− |= [now=@da fap=flap] :: ack by hash
1380− ^- [[p=(unit soup) q=(list rock)] _+>]
1381− =+ sun=(~(get by diq) fap)
1382− ?~ sun
1383− [[~ ~] +>.$]
1384− =. diq (~(del by diq) fap)
1385− =^ gub +>.$ (bock now u.sun)
1386− =^ yop +>.$ (harv now)
1387− [[gub yop] +>.$]
1388−```
1389−
1390−If you recall, in `++whap:pu` we created the packet pump's
1391−representation of the message, which included putting the message into
1392−`diq`, which maps from packet hashes to packet sequence numbers. Thus,
1393−`u.sun` is the sequence number of this particular message.
1394−
1395−We delete this message from `diq` since we have now received an ack for
1396−it. We call `++bock` to perform the ack by sequence number. We call
1397−`++harv` to harvest the packet queue, sending any messages that are now
1398−able to be sent.
1399−
1400−In `++bock`, there are three arms we haven't seen before: `++bine`,
1401−`+wept`, and `++beet`. We'll describe each of these before we get to
1402−`++bock`. `++bine` looks scariest.
1403−
1404−```hoon
1405− ++ bine :: bine:pu
1406− |= [now=@da num=@ud] :: apply ack
1407− ^- [(unit soup) _+>]
1408− ?~ puq !!
1409− ?. =(num p.n.puq)
1410− ?: (gth num p.n.puq)
1411− =+ lef=$(puq l.puq)
1412− [-.lef +.lef(puq [n.puq puq.lef r.puq])]
1413− =+ rig=$(puq r.puq)
1414− [-.rig +.rig(puq [n.puq l.puq puq.rig])]
1415− =: rtt ?. &(liv.q.n.puq =(1 nux.q.n.puq)) rtt
1416− =+ gap=(sub now lys.q.n.puq)
1417− :: ~& [%bock-trip num (div gap (div ~s1 1.000))]
1418− (div (add (mul 2 rtt) gap) 3)
1419− nif (sub nif !liv.q.n.puq)
1420− ==
1421− =+ lez=(dec (need (~(get by pyz) gom.q.n.puq)))
1422− =^ gub pyz
1423− ?: =(0 lez)
1424− [[~ gom.q.n.puq] (~(del by pyz) gom.q.n.puq)]
1425− [~ (~(put by pyz) gom.q.n.puq lez)]
1426− :- gub
1427− +>.$(puq ~(nap to puq))
1428−```
1429−
1430−The first few lines are simply looking through the packet queue until we
1431−find the correct packet to ack. This is basic queue manipulation that
1432−operates directly on the treap structure of the queue. If you understand
1433−treap queues, the logic is easy to follow. Otherwise, just trust us that
1434−by the time we get to the `=:`, the packet with sequence number `num` is
1435−on the top of the packet queue (that is, at `n.puq`).
1436−
1437−We first update the round-trip time. If the packet is either not alive
1438−or had to be transmitted more than once, then we don't have any reliable
1439−way of calculating the round-trip time since we're unsure of exactly
1440−which transmission was acknowledged. Otherwise, the round-trip time is
1441−the difference between now and when the packet was last sent. We set
1442−`rtt` by a little weighted average where the previous smoothed RTT is
1443−weighted twice as much as the RTT of the current packet. Thus,
1444−`(2*rtt+gap)/3`. This gives us a nice smooth RTT that is somewhat
1445−resilient to outlier data while still being responsive to our
1446−ever-changing world.
1447−
1448−If the packet wasn't already dead, then we decrement the number of live
1449−packets, which may allow more packets to be sent.
1450−
1451−We decrement the number of unacknowledged packets in our `pyz` for this
1452−particular message. If you recall, this was set in `++whap` to the
1453−number of packets required to send a message.
1454−
1455−If that was the last packet in the messge that needed to be acked, then
1456−we delete the messgae reference from `pyz` and produce the id of the
1457−message. Otherwise, we simply update `pyz` with the new number of
1458−unacked messages. In either case, we remove the packet from the packet
1459−queue.
1460−
1461−```hoon
1462− ++ wept :: wept:pu
1463− |= [fip=@ud lap=@ud] :: fip thru lap-1
1464− =< abet =< apse
1465− |%
1466− ++ abet +>.$
1467− ++ apse
1468− ^+ .
1469− ?~ puq .
1470− ?: (lth p.n.puq fip) ?~(l.puq . left)
1471− ?: (gte p.n.puq lap) ?~(r.puq . rigt)
1472− => rigt =< left
1473− ?> ?=(^ puq)
1474− ?.(liv.q.n.puq . .(nif (dec nif), liv.q.n.puq |))
1475− ::
1476− ++ left
1477− ?> ?=(^ puq)
1478− ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq])))
1479− ++ rigt
1480− ?> ?=(^ puq)
1481− ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig])))
1482− --
1483−```
1484−
1485−The algorithm is a simple case of traversing the packet queue.
1486−Essentialy, we mark as dead all packets in the queue between `fip` and
1487−`(dec lap)`. We also update `nif`, the number of live packets. Lest you
1488−mourn too much the passing of these packets, know that they shall soon
1489−rise again. Recall that in `++bick` after the call to `++bock` we call
1490−`++harv`. This will resend the packets that have just been labeled dead.
1491−
1492−```hoon
1493− ++ beet :: beet:pu
1494− ^+ . :: advance unacked
1495− =- +(nep ?~(foh nus u.foh))
1496− ^= foh
1497− |- ^- (unit ,@ud)
1498− ?~ puq ~
1499− ?: (lte p.n.puq nep) $(puq l.puq)
1500− =+ rig=$(puq r.puq)
1501− ?^(rig rig [~ p.n.puq])
1502−```
1503−
1504−Here we search for the next expected packet number. Basically, we search
1505−the queue for the leftmost packet whose number is greater than the
1506−current `nep`. If we don't find any such packet, we just use the total
1507−number of packets sent.
1508−
1509−We can now dive into `++bock`, our last arm.
1510−
1511−```hoon
1512− ++ bock :: bock:pu
1513− |= [now=@da num=@ud] :: ack by sequence
1514− ^- [(unit soup) _+>]
1515− =^ gym +> (bine now num)
1516− :- gym
1517− ?: (gth num nep)
1518− =+ cam=(max 2 (div caw 2))
1519− :: ~& [%bock-hole num nep cam]
1520− beet:(wept(nep num, cag cam, caw cam) nep num)
1521− =. caw ?: (lth caw cag) +(caw)
1522− (add caw !=(0 (mod (mug now) caw)))
1523− ?: =(num nep)
1524− :: ~& [%bock-fine num nif caw cag]
1525− beet
1526− :: ~& [%bock-fill num nif caw cag]
1527− +>.$
1528−```
1529−
1530−First, we call `++bine` to apply the ack to the packet pump information.
1531−We produce `gym`, which, if it exists, is the id of the packet that was
1532−acked. If we received an ack for a packet later than the one we
1533−expected, then we halve the logical packet window and kill all the
1534−earlier packets so that they may be resent.
1535−
1536−Otherwise, we possibly increase the congestion window. If the window is
1537−less than the congestion threshold, then we increment the size of the
1538−window. Otherwise, we only increment one out of every `caw` times.
1539−
1540−If we received an ack for the packet we expected, then we simply advance
1541−`nep` with `++beet`. If we received an ack for a packet earlier than we
1542−expected, we do nothing.
1543−
1544−It may be hard to believe, but we are, in fact, done. The message has
1545−been sent, received, acknowledged, and the acknowledgment has been
1546−returned to the original sender. We hope it's clear that, while the
1547−process has been somewhat involved, the algorithms are not all that
1548−complicated. If you've read this far, you know `%ames`. The only other
1549−code involves initialization, timeouts, and the like.
1550−
1551−Below, we give detailed reference documentation for the data models
1552−involved.
1553−
1554−## Data Models
1555−
1556−### `++sufi:ames`, domestic host
1557−
1558−```hoon
1559− ++ sufi :: domestic host
1560− $: hoy=(list ship) :: hierarchy
1561− val=wund :: private keys
1562− law=will :: server will
1563− seh=(map hand ,[p=ship q=@da]) :: key cache
1564− hoc=(map ship dore) :: neighborhood
1565− == ::
1566−```
1567−
1568−This is the security state of a domestic server.
1569−
1570−`hoy` is a list of the ships directly above us in the hierarchy of
1571−ships. For example, for `~hoclur-bicrel`, this would be `~tasruc` and
1572−`~tug`. See `++sein:title`.
1573−
1574−`val` is a list of our private keys.
1575−
1576−`law` is our certificate, which is a list of the XXX
1577−
1578−`seh`
1579−
1580−`hoc` is a map of ships to `++dore:ames`. The stores all the security
1581−information about foreign ships. The keys to this map are the neighbors
1582−(ships we have been in contact with) of this domestic server.
1583−
1584−### `++wund:ames`, private keys
1585−
1586−```hoon
1587− ++ wund (list ,[p=life q=ring r=acru]) :: mace in action
1588−```
1589−
1590−This is a list of our own private keys, indexed by life. The key itself
1591−is the `++ring`, and the `++acru:ames` is the encryption engine. We generate
1592−the `++acru:ames` from the private key by calling `++weur`. Thus, we can at
1593−any time regenerate our `++wund:ames` from a `++mace:ames`. The current crypto is
1594−at the head of the list and can be accessed with `++sen:as:go`.
1595−
1596−### `++ring`, private key
1597−
1598−```hoon
1599− ++ ring ,@ :: private key
1600−```
1601−
1602−This is a private key. The first byte is reserved to identify the type
1603−of cryptography. Lower-case means public key, upper-case means public
1604−key, and the letter identifies which `++acru:ames` to use.
1605−
1606−### `++pass`, public key
1607−
1608−```hoon
1609− ++ pass ,@ :: public key
1610−```
1611−
1612−This is a public key. The first byte is reserved to identify the type of
1613−cryptography. Lower-case means public key, upper-case means public key,
1614−and the letter identifies which `++acru:ames` to use.
1615−
1616−### `++mace:ames`, private secrets
1617−
1618−```hoon
1619− ++ mace (list ,[p=life q=ring]) :: private secrets
1620−```
1621−
1622−This is a list of the our private keys, indexed by life. From this we
1623−can generate a `++wund:ames` for actual use.
1624−
1625−### `++skin:ames`, encoding stem
1626−
1627−```hoon
1628− ++ skin ?(%none %open %fast %full) :: encoding stem
1629−```
1630−
1631−This defines the type of encryption used for each message. `%none`
1632−refers to messages sent in the clear, `%open` refers to signed messages,
1633−`%full` refers to sealed messages, and `%fast` refers to symmetrically
1634−encrypted messages. See `++acru:ames` for details.
1635−
1636−### `++acru:ames`, asymmetric cryptosuite
1637−
1638−```hoon
1639− ++ acru :: asym cryptosuite
1640− $_ ^? |% :: opaque object
1641− ++ as ^? :: asym ops
1642− |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
1643− ++ sign |=([a=@ b=@] _@) :: certify as us
1644− ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
1645− ++ tear |= [a=pass b=@] :: accept from a
1646− *(unit ,[p=@ q=@]) ::
1647− -- ::
1648− ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
1649− ++ dy |+([a=@ b=@] _@) :: symmetric de, hard
1650− ++ en |+([a=@ b=@] _@) :: symmetric en
1651− ++ ex ^? :: export
1652− |% ++ fig _@uvH :: fingerprint
1653− ++ pac _@uvG :: default passcode
1654− ++ pub *pass :: public key
1655− ++ sec *ring :: private key
1656− --
1657− ++ nu ^? :: reconstructors
1658− |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
1659− ++ nol |=(a=@ ^?(..nu)) :: from naked ring
1660− ++ com |=(a=@ ^?(..nu)) :: from naked pass
1661− --
1662− --
1663−```
1664−
1665−This is an opaque interface for a general asymmetric cryptosuite. Any
1666−form of asymmetric cryptography can be dropped in to be used instead of
1667−the default. Right now, there is one cryptosuite: `++crub:crypto:crypto`,
1668−which is elliptic-curve cryptography.
1669−
1670−#### `++as:acru:ames`, asymmetric operations
1671−
1672−```hoon
1673− ++ as ^? :: asym ops
1674− |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
1675− ++ sign |=([a=@ b=@] _@) :: certify as us
1676− ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
1677− ++ tear |= [a=pass b=@] :: accept from a
1678− *(unit ,[p=@ q=@]) ::
1679− -- ::
1680−```
1681−
1682−This is the core that defines the standard asymmetric cryptography
1683−operations.
1684−
1685−`++seal:as:acru:ames` allows us to send a message encrypted with someone's
1686−public key so that only they may read it. If Alice seals a message with
1687−Bob's public key, then she can be sure that Bob is the only one who can
1688−read it. This is associated with the `++skin:ames` `%full`.
1689−
1690−`++sign:as:acru:ames` allows us to sign a message with our private key so
1691−that others can verify that we sent the message. If Alice signs a
1692−message with her private key, then Bob can verify with her public key
1693−that it was indeed Alice who sent it. This is associated with the
1694−`++skin:ames` `%open`.
1695−
1696−`++sure:as:acru:ames` is the dual to `++sign:as:acru:ames`. It allows us to verify
1697−that a message we have received is indeed from the claimed sender. If
1698−Alice sends a message with her private key, then Bob can use this arm to
1699−verify that it was indeed Alice who sent it. This is associated with the
1700−`++skin:ames` `%open`.
1701−
1702−`++tear:as:acru:ames` is the dual to `++seal:as:acru:ames`. It allows us to read a
1703−message that we can be sure is only read by us. If Alice seals a message
1704−with Bob's public key, then Bob can use this arm to read it. This is
1705−associated with the `++skin:ames` `%full`.
1706−
1707−#### `++de:acru:ames`, `++dy:acru:ames`, and `++en:acru:ames`, symmetric encryption/decryption
1708−
1709−```hoon
1710− ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
1711− ++ dy |+([a=@ b=@] _@) :: symmetric de, hard
1712− ++ en |+([a=@ b=@] _@) :: symmetric en
1713−```
1714−
1715−Symmetric encryption is associated with the `++skin:ames` `%fast`.
1716−
1717−`++de:acru:ames` decrypts a message with a symmetric key, returning `~` on
1718−failure and `[~ u=data]` on success.
1719−
1720−`++dy:acru:ames` decrypts a message with a symmetric key, crashing on
1721−failure. This should almost always be defined as, and should always be
1722−semantically equivalent to, `(need (de a b))`.
1723−
1724−`++en:acru:ames` encrypts a message with a symmetric key.
1725−
1726−#### `++ex:acru:ames`, exporting data
1727−
1728−```hoon
1729− ++ ex ^? :: export
1730− |% ++ fig _@uvH :: fingerprint
1731− ++ pac _@uvG :: default passcode
1732− ++ pub *pass :: public key
1733− ++ sec *ring :: private key
1734− --
1735−```
1736−
1737−`++fig:ex:acru:ames` is our fingerprint, usually a hash of our public key.
1738−This is used, for example, in `++zeno`, where every carrier owner's
1739−fingerprint is stored so that we can ensure that carriers are indeed
1740−owned by their owners
1741−
1742−`++pac:ex:acru:ames` is our default passcode, which is unused at present.
1743−
1744−`++pub:ex:acru:ames` is the `++pass` form of our public key.
1745−
1746−`++sec:ex:acru:ames` is the `++ring` form of our private key.
1747−
1748−#### `++nu:acru:ames`, reconstructors
1749−
1750−```hoon
1751− ++ nu ^? :: reconstructors
1752− |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
1753− ++ nol |=(a=@ ^?(..nu)) :: from naked ring
1754− ++ com |=(a=@ ^?(..nu)) :: from naked pass
1755− --
1756−```
1757−
1758−These arms allow us to reconstruct a `++acru:ames` from basic data.
1759−
1760−`++pit:nu:acru:ames` constructs a `++acru:ames` from the width of our intended key
1761−and seed entropy. This is usually used in the initial construction of
1762−the `++acru:ames`.
1763−
1764−`++nol:nu:acru:ames` constructs a `++acru:ames` from a "naked ring", meaning a
1765−`++ring` without the initial byte identifying the type of crypto.
1766−
1767−`++com:nu:acru:ames` constructs a `++acru:ames` from a "naked pass", meaning a
1768−`++ring` without the initial byte identifying the type of crypto.
1769−
1770−### `++will`, certificate
1771−
1772−```hoon
1773− ++ will (list deed) :: certificate
1774−```
1775−
1776−This is a list of deeds associated with the current ship. There should
1777−be an item in this list for every ship from this point up in the
1778−hierarchy times the number of lives that each ship has had. For example,
1779−\~hoclur-bicrel may have a will with three items: one for itself, one
1780−for \~tasruc (who issued \~hoclur-bicrel's deed) and one for \~tug (who
1781−issued \~tasruc's deed).
1782−
1783−### `++deed`, identity
1784−
1785−```hoon
1786− ++ deed ,[p=@ q=step r=?] :: sig, stage, fake?
1787−```
1788−
1789−`p` is the signature of a particular deed, which is a signed copy of
1790−`q`.
1791−
1792−`q` is the stage in the identity.
1793−
1794−`r` is true if we're working on a fake network, where we don't check
1795−that the carrier fingerprints are correct. This allows us to create fake
1796−networks for development without interfering with the real network.
1797−
1798−### `++step:ames`, identity stage
1799−
1800−```hoon
1801− ++ step ,[p=bray q=gens r=pass] :: identity stage
1802−```
1803−
1804−This is a single stage in our identity. Thus, this is specific to a
1805−single life in a single ship. Everything in here may change between
1806−lives.
1807−
1808−`p`
1809−
1810−`q`
1811−
1812−`r` is the public key for this stage in the identity.
1813−
1814−### `++bray:ames`
1815−
1816−```hoon
1817− ++ bray ,[p=life q=(unit life) r=ship s=@da] :: our parent us now
1818−```
1819−
1820−XXX
1821−
1822−### `++gens:ames`, general identity
1823−
1824−```hoon
1825− ++ gens ,[p=lang q=gcos] :: general identity
1826−```
1827−
1828−`p` is the IETF language code for the preferred language of this
1829−identity. This is unused at the moment, but in the future text should be
1830−localized based on this.
1831−
1832−`q` is the description of the ship.
1833−
1834−### `++gcos:ames`, identity description
1835−
1836−```hoon
1837− ++ gcos :: id description
1838− $% [%czar ~] :: 8-bit ship
1839− [%duke p=what] :: 32-bit ship
1840− [%earl p=@t] :: 64-bit ship
1841− [%king p=@t] :: 16-bit ship
1842− [%pawn p=(unit ,@t)] :: 128-bit ship
1843− == ::
1844−```
1845−
1846−This is the description of the identity of a ship. Most types of
1847−identity have a `@t` field, which is their human-readable name. The
1848−identity of a `%duke` is more involved.
1849−
1850−A `%czar`, a carrier, is a ship with an 8-bit address. Thus, there are
1851−only 256 carriers. These are at the top of the namespace hierarchy, and
1852−the fingerprint of each carrier is stored in `++zeno`. These are the
1853−"senators" of Urbit.
1854−
1855−A `%king`, a cruiser, is a ship with a 16-bit address. Thus, there are
1856−65,536 cruisers. Each carrier may issue 256 cruisers. These are the
1857−infrastructure of Urbit.
1858−
1859−A `%duke`, a destroyer, is a ship with a 32-bit address. Thus, there are
1860−4,294,967,296 destroyers. Each cruiser may issue 65,536 cruisers. These
1861−are the individuals of Urbit.
1862−
1863−A `%earl`, a yacht, is a ship with a 64-bit address. Thus, there are
1864−18,446,744,073,709,551,616 yachts. Each destroyer may issue
1865−4,294,967,296 yachts. These are the devices of Urbit.
1866−
1867−A `%pawn`, a submarine, is a ship with a 128-bit address. Thus, there
1868−are a lot of submarines. The chance of random name collision is
1869−negligible, so submarines are not issued by any ship. They must simply
1870−assert their presence, and they are all considered children of \~zod.
1871−This is the underworld of Urbit, where anonymity reigns supreme.
1872−
1873−### `++what:ames`, logical destroyer identity
1874−
1875−```hoon
1876− ++ what :: logical identity
1877− $% [%anon ~] :: anonymous
1878− [%lady p=whom] :: female person ()
1879− [%lord p=whom] :: male person []
1880− [%punk p=sect q=@t] :: opaque handle ""
1881− == ::
1882−```
1883−
1884−This is the logical identity of a destroyer.
1885−
1886−A `%anon` is a completely anonymous destroyer. The difference between
1887−this and a submarine is that a submarine is ephemeral while a `%anon`
1888−destroyer is not. Thus, we may not know who \~hoclur-bicrel is, but we
1889−do know that it's always the same person.
1890−
1891−A `%lady` is a female person. The name used here should be a real name.
1892−
1893−A `%lord` is a male person. The name used here should be a real name.
1894−
1895−A `%punk` is a person who is identified only by a handle.
1896−
1897−### `++whom:ames`, real person
1898−
1899−```hoon
1900− ++ whom ,[p=@ud q=govt r=sect s=name] :: year/govt/id
1901−```
1902−
1903−Ths is the information associated with a real person. It is mostly
1904−information that could be observed with the briefest of interactions.
1905−
1906−`p` is the birth year.
1907−
1908−`q` is the location of a user, usually of the form "country/zip".
1909−
1910−`r` is the sect of the user.
1911−
1912−`s` is the real name of the person.
1913−
1914−### `++govt:ames`
1915−
1916−```hoon
1917− ++ govt path :: country/postcode
1918−```
1919−
1920−This is the location of the user, usually of the form "country/zip".
1921−
1922−### `++sect:ames`
1923−
1924−```hoon
1925− ++ sect ?(%black %blue %red %orange %white) :: banner
1926−```
1927−
1928−XXX
1929−
1930−### `++name:ames`
1931−
1932−```hoon
1933− ++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last
1934−```
1935−
1936−This is the given name, possible middle name/initial, possible nickname,
1937−and surname of a user.
arvo/behn.mddeleted−19
@@ -1,19 +0,0 @@
1−+++
2−title = "Behn"
3−weight = 2
4−template = "doc.html"
5−+++
6−Our simple timer.
7−
8−It allows vanes and applications to set and timer events, which are
9−managed in a simple priority queue. `%behn` produces effects to start
10−the unix timer, and when the requested `%behn` passes, unix sends wake
11−events to `%behn`, which time routes back to original sender. We don't
12−guarantee that a timer event will happen at exactly the `%behn` it was
13−set for, or even that it'll be particularly close. A timer event is a
14−request to not be woken until after the given time.
15−
16−`%eyre` uses `%behn` for timing out sessions, and `%clay` uses `%behn`
17−for keeping track of time-specified file requests. `%ames` should
18−probably use `%behn` to keep track of things like network timeouts and
19−retry timing, but it currently uses its own alarm system.
arvo/clay.mddeleted−2625
@@ -1,2625 +0,0 @@
1−+++
2−title = "Clay"
3−weight = 3
4−template = "doc.html"
5−+++
6−Our filesystem.
7−
8−`%clay` is version-controlled, referentially-transparent, and global.
9−While this filesystem is stored in `%clay`, it is mirrored to Unix for
10−convenience. Unix tells `%clay`s whenever a file changes in the Unix
11−copy of the filesystem so that the change may be applied. `%clay` tells
12−unix whenever an app or vane changes the filesystem so that the change
13−can be effected in Unix. Apps and vanes may use `%clay` to write to the
14−filesystem, query it, and subscribe to changes in it. Ford and gall use
15−`%clay` to serve up apps and web pages.
16−
17−`%clay` includes three components. First is the filesystem/version
18−control algorithms, which are mostly defined in `++ze` and `++zu` in
19−zuse. Second is the write, query, and subscription logic. Finally, there
20−is the logic for communicating requests to, and receiving requests from,
21−foreign ships.
22−
23−## Architecture
24−
25−Clay is the primary filesystem for the arvo operating system,
26−which is the core of an urbit. The architecture of clay is
27−intrinsically connected with arvo, but we assume no knowledge of
28−either arvo or urbit. We will point out only those features of
29−arvo that are necessary for an understanding of clay, and we will
30−do so only when they arise.
31−
32−The first relevant feature of arvo is that it is a deterministic
33−system where input and output are defined as a series of events
34−and effects. The state of arvo is simply a function of its event
35−log. None of the effects from an event are emitted until the
36−event is entered in the log and persisted, either to disk or
37−another trusted source of persistence, such as a Kafka cluster.
38−Consequently, arvo is a single-level store: everything in its
39−state is persistent.
40−
41−In a more traditional OS, everything in RAM can be erased at any
42−time by power failure, and is always erased on reboot. Thus, a
43−primary purpose of a filesystem is to ensure files persist across
44−power failures and reboots. In arvo, both power failures and
45−reboots are special cases of suspending computation, which is
46−done safely since our event log is already persistent. Therefore,
47−clay is not needed in arvo for persistence. Why, then, do we have a
48−filesystem? There are two answers to this question.
49−
50−First, clay provides a filesystem tree, which is a convenient
51−user interface for some applications. Unix has the useful concept
52−of virtual filesystems, which are used for everything from direct
53−access to devices, to random number generators, to the /proc
54−tree. It is easy and intuitive to read from and write to a
55−filesystem tree.
56−
57−Second, clay has a distributed revision-control system baked into
58−it. Traditional filesystems are not revision controlled, so
59−userspace software -- such as git -- is written on top of them to
60−do so. clay natively provides the same functionality as modern
61−DVCSes, and more.
62−
63−clay has two other unique properties that we'll cover later on:
64−it supports typed data and is referentially transparent.
65−
66−### Revision Control
67−
68−Every urbit has one or more "desks", which are independently
69−revision-controlled branches. Each desk contains its own mark
70−definitions, apps, doc, and so forth.
71−
72−Traditionally, an urbit has at least a base and a home desk. The
73−base desk has all the system software from the distribution. the
74−home desk is a fork of base with all the stuff specific to the
75−user of the urbit.
76−
77−A desk is a series of numbered commits, the most recent of which
78−represents the current state of the desk. A commit is composed of
79−(1) an absolute time when it was created, (2) a list of zero or
80−more parents, and (3) a map from paths to data.
81−
82−Most commits have exactly one parent, but the initial commit on a
83−desk may have zero parents, and merge commits have more than one
84−parent.
85−
86−The non-meta data is stored in the map of paths to data. It's
87−worth noting that no constraints are put on this map, so, for
88−example, both /a/b and /a/b/c could have data. This is impossible
89−in a traditional Unix filesystem since it means that /a/b is both
90−a file and a directory. Conventionally, the final element in the
91−path is its mark -- much like a filename extension in Unix. Thus,
92−/doc/readme.md in Unix is stored as /doc/readme/md in urbit.
93−
94−The data is not stored directly in the map; rather, a hash of the
95−data is stored, and we maintain a master blob store. Thus, if the
96−same data is referred to in multiple commits (as, for example,
97−when a file doesn't change between commits), only the hash is
98−duplicated.
99−
100−In the master blob store, we either store the data directly, or
101−else we store a diff against another blob. The hash is dependent
102−only on the data within and not on whether or not it's stored
103−directly, so we may on occasion rearrange the contents of the
104−blob store for performance reasons.
105−
106−Recall that a desk is a series of numbered commits. Not every
107−commit in a desk must be numbered. For example, if the base desk
108−has had 50 commits since home was forked from it, then a merge
109−from base to home will only add a single revision number to home,
110−although the full commit history will be accessible by traversing
111−the parentage of the individual commits.
112−
113−We do guarantee that the first commit is numbered 1, commits are
114−numbered consecutively after that (i.e. there are no "holes"),
115−the topmost commit is always numbered, and every numbered commit
116−is an ancestor of every later numbered commit.
117−
118−There are three ways to refer to particular commits in the
119−revision history. Firstly, one can use the revision number.
120−Secondly, one can use any absolute time between the one numbered
121−commit and the next (inclusive of the first, exclusive of the
122−second). Thirdly, every desk has a map of labels to revision
123−numbers. These labels may be used to refer to specific commits.
124−
125−Additionally, clay is a global filesystem, so data on other urbit
126−is easily accessible the same way as data on our local urbit. In
127−general, the path to a particular revision of a desk is
128−/~urbit-name/desk-name/revision. Thus, to get /try/readme/md
129−from revision 5 of the home desk on ~sampel-sipnym, we refer to
130−/~sampel-sipnym/home/5/try/readme/md. Clay's namespace is thus
131−global and referentially transparent.
132−
133−XXX reactivity here?
134−
135−### A Typed Filesystem
136−
137−Since clay is a general filesystem for storing data of arbitrary
138−types, in order to revision control correctly it needs to be
139−aware of types all the way through. Traditional revision control
140−does an excellent job of handling source code, so for source code
141−we act very similar to traditional revision control. The
142−challenge is to handle other data similarly well.
143−
144−For example, modern VCSs generally support "binary files", which
145−are files for which the standard textual diffing, patching, and
146−merging algorithms are not helpful. A "diff" of two binary files
147−is just a pair of the files, "patching" this diff is just
148−replacing the old file with the new one, and "merging"
149−non-identical diffs is always a conflict, which can't even be
150−helpfully annotated. Without knowing anything about the structure
151−of a blob of data, this is the best we can do.
152−
153−Often, though, "binary" files have some internal structure, and
154−it is possible to create diff, patch, and merge algorithms that
155−take advantage of this structure. An image may be the result of a
156−base image with some set of operations applied. With algorithms
157−aware of this set of operations, not only can revision control
158−software save space by not having to save every revision of the
159−image individually, these transformations can be made on parallel
160−branches and merged at will.
161−
162−Suppose Alice is tasked with touching up a picture, improving the
163−color balance, adjusting the contrast, and so forth, while Bob
164−has the job of cropping the picture to fit where it's needed and
165−adding textual overlay. Without type-aware revision control,
166−these changes must be made serially, requiring Alice and Bob to
167−explicitly coordinate their efforts. With type-aware revision
168−control, these operations may be performed in parallel, and then
169−the two changesets can be merged programmatically.
170−
171−Of course, even some kinds of text files may be better served by
172−diff, patch, and merge algorithms aware of the structure of the
173−files. Consider a file containing a pretty-printed JSON object.
174−Small changes in the JSON object may result in rather significant
175−changes in how the object is pretty-printed (for example, by
176−addding an indentation level, splitting a single line into
177−multiple lines).
178−
179−A text file wrapped at 80 columns also reacts suboptimally with
180−unadorned Hunt-McIlroy diffs. A single word inserted in a
181−paragraph may push the final word or two of the line onto the
182−next line, and the entire rest of the paragraph may be flagged as
183−a change. Two diffs consisting of a single added word to
184−different sentences may be flagged as a conflict. In general,
185−prose should be diffed by sentence, not by line.
186−
187−As far as the author is aware, clay is the first generalized,
188−type-aware revision control system. We'll go into the workings
189−of this system in some detail.
190−
191−### Marks
192−
193−Central to a typed filesystem is the idea of types. In clay, we
194−call these "marks". A mark is a file that defines a type,
195−conversion routines to and from the mark, and diff, patch, and
196−merge routines.
197−
198−For example, a `%txt` mark may be a list of lines of text, and it
199−may include conversions to `%mime` to allow it to be serialized
200−and sent to a browswer or to the unix filesystem. It will also
201−include Hunt-McIlroy diff, patch, and merge algorithms.
202−
203−A `%json` mark would be defined as a json object in the code, and
204−it would have a parser to convert from `%txt` and a printer to
205−convert back to `%txt`. The diff, patch, and merge algorithms are
206−fairly straightforward for json, though they're very different
207−from the text ones.
208−
209−More formally, a mark is a core with three arms, `++grab`,
210−`++grow`, and `++grad`. In `++grab` is a series of functions to
211−convert from other marks to the given mark. In `++grow` is a
212−series of functions to convert from the given mark to other
213−marks. In `++grad` is `++diff`, `++pact`, `++join`, and `++mash`.
214−
215−The types are as follows, in an informal pseudocode:
216−
217−```
218− ++ grab:
219− ++ mime: <mime> -> <mark-type>
220− ++ txt: <txt> -> <mark-type>
221− ...
222− ++ grow:
223− ++ mime: <mark-type> -> <mime>
224− ++ txt: <mark-type> -> <txt>
225− ...
226− ++ grad
227− ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
228− ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
229− ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
230− ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
231−```
232−
233−These types are basically what you would expect. Not every mark
234−has each of these functions defined -- all of them are optional
235−in the general case.
236−
237−In general, for a particular mark, the `++grab` and `++grow` entries
238−(if they exist) should be inverses of each other.
239−
240−In `++grad`, `++diff` takes two instances of a mark and produces
241−a diff of them. `++pact` takes an instance of a mark and patches
242−it with the given diff. `++join` takes two diffs and attempts to
243−merge them into a single diff. If there are conflicts, it
244−produces null. `++mash` takes two diffs and forces a merge,
245−annotating any conflicts.
246−
247−In general, if `++diff` called with A and B produces diff D, then
248−`++pact` called with A and D should produce B. Also, if `++join`
249−of two diffs does not produce null, then `++mash` of the same
250−diffs should produce the same result.
251−
252−Alternately, instead of `++diff`, `++pact`, `++join`, and
253−`++mash`, a mark can provide the same functionality by defining
254−`++sted` to be the name of another mark to which we wish to
255−delegate the revision control responsibilities. Then, before
256−running any of those functions, clay will convert to the other
257−mark, and convert back afterward. For example, the `%hoon` mark
258−is revision-controlled in the same way as `%txt`, so its `++grad`
259−is simply `++sted %txt`. Of course, `++txt` must be defined in
260−`++grow` and `++grab` as well.
261−
262−Every file in clay has a mark, and that mark must have a
263−fully-functioning `++grad`. Marks are used for more than just
264−clay, and other marks don't need a `++grad`, but if a piece of
265−data is to be saved to clay, we must know how to revision-control
266−it.
267−
268−Additionally, if a file is to be synced out to unix, then it must
269−have conversion routines to and from the `%mime` mark.
270−
271−## Using clay
272−
273−### Reading and Subscribing
274−
275−When reading from Clay, there are three types of requests. A
276−`%sing` request asks for data at single revsion. A `%next`
277−request asks to be notified the next time there's a change to
278−given file. A `%many` request asks to be notified on every
279−change in a desk for a range of changes.
280−
281−For `%sing` and `%next`, there are generally three things to be
282−queried. A `%u` request simply checks for the existence of a
283−file at a path. A `%x` request gets the data in the file at a
284−path. A `%y` request gets a hash of the data in the file at the
285−path combined with all its children and their data. Thus, `%y`
286−of a node changes if it or any of its children change.
287−
288−A `%sing` request is fulfilled immediately if possible. If the
289−requested revision is in the future, or is on another ship for
290−which we don't have the result cached, we don't respond
291−immediately. If the requested revision is in the future, we wait
292−until the revision happens before we respond to the request. If
293−the request is for data on another ship, we pass on the request
294−to the other ship. In general, Clay subscriptions, like most
295−things in Urbit, aren't guaranteed to return immediately.
296−They'll return when they can, and they'll do so in a
297−referentially transparent manner.
298−
299−A `%next` request checks query at the given revision, and it
300−produces the result of the query the next time it changes, along
301−with the revsion number when it changes. Thus, a `%next` of a
302−`%u` is triggered when a file is added or deleted, a `%next` of a
303−`%x` is triggered when a file is added, deleted, or changed, and
304−a `%next` of a `%y` is triggered when a file or any of its
305−children is added, deleted, or changed.
306−
307−A `%many` request is triggered every time the given desk has a
308−new revision. Unlike a `%next`, a `%many` has both a start and
309−an end revsion, after which it stops returning. For `%next`, a
310−single change is reported, and if the caller wishes to hear of
311−the next change, it must resubscribe. For `%many`, every revsion
312−from the start to the end triggers a response. Since a `%many`
313−request doesn't ask for any particular data, there aren't `%u`,
314−`%x`, and `%y` versions for it.
315−
316−### Unix sync
317−
318−One of the primary functions of clay is as a convenient user
319−interface. While tools exist to use clay from within urbit, it's
320−often useful to be able to treat clay like any other filesystem
321−from the Unix perspective -- to "mount" it, as it were.
322−
323−From urbit, you can run `|mount /path/to/directory %mount-point`,
324−and this will mount the given clay directory to the mount-point
325−directory in Unix. Every file is converted to `%mime` before it's
326−written to Unix, and converted back when read from Unix. The
327−entire directory is watched (a la Dropbox), and every change is
328−committed once you run `|commit %mount-point`.
329−
330−### Merging
331−
332−Merging is a fundamental operation for a distributed revision
333−control system. At their root, clay's merges are similar to
334−git's, but with some additions to accomodate typed data. There
335−are seven different merge strategies.
336−
337−Throughout our discussion, we'll say that the merge is from
338−Alice's desk to Bob's. Recall that a commit is a date (for all
339−new commits this will be the current date), a list of parents,
340−and the data itself.
341−
342−A `%init` merge should be used iff it's the first commit to a
343−desk. The head of Alice's desk is used as the number 1 commit to
344−Bob's desk. Obviously, the ancestry remains intact through
345−traversing the parentage of the commit even though previous
346−commits are not numbered for Bob's desk.
347−
348−A `%this` merge means to keep what's in Bob's desk, but join the
349−ancestry. Thus, the new commit has the head of each desk as
350−parents, but the data is exactly what's in Bob's desk. For those
351−following along in git, this is the 'ours' merge strategy, not
352−the '--ours' option to the 'recursive' merge strategy. In other
353−words, even if Alice makes a change that does not conflict with
354−Bob, we throw it away. It's Bob's way or the highway.
355−
356−A `%that` merge means to take what's in Alice's desk, but join
357−the ancestry. This is the reverse of `%this`.
358−
359−A `%fine` merge is a "fast-forward" merge. This succeeds iff one
360−head is in the ancestry of the other. In this case, we use the
361−descendant as our new head.
362−
363−For `%meet`, `%mate`, and `%meld` merges, we first find the most
364−recent common ancestor to use as our merge base. If we have no
365−common ancestors, then we fail. If we have more than one most
366−recent common ancestor, then we have a criss-cross situation,
367−which should be handled delicately. At present, we delicately
368−throw up our hands and give up, but something akin to git's
369−'recursive' strategy should be implemented in the future.
370−
371−There's a functional inclusion ordering on `%fine`, `%meet`,
372−`%mate`, and `%meld` such that if an earlier strategy would have
373−succeeded, then every later strategy will produce the same
374−result. Put another way, every earlier strategy is the same as
375−every later strategy except with a restricted domain.
376−
377−A `%meet` merge only succeeds if the changes from the merge base
378−to Alice's head (hereafter, "Alice's changes") are in different
379−files than Bob's changes. In this case, the parents are both
380−Alice's and Bob's heads, and the data is the merge base plus
381−Alice's changed files plus Bob's changed files.
382−
383−A `%mate` merge attempts to merge changes to the same file when
384−both Alice and bob change it. If the merge is clean, we use it;
385−otherwise, we fail. A merge between different types of changes --
386−for example, deleting a file vs changing it -- is always a
387−conflict. If we succeed, the parents are both Alice's and Bob's
388−heads, and the data is the merge base plus Alice's changed files
389−plus Bob's changed files plus the merged files.
390−
391−A `%meld` merge will succeed even if there are conflicts. If
392−there are conflicts in a file, then we use the merge base's
393−version of that file, and we produce a set of files with
394−conflicts. The parents are both Alice's and Bob's heads, and the
395−data is the merge base plus Alice's changed files plus Bob's
396−changed files plus the successfully merged files plus the merge
397−base's version of the conflicting files.
398−
399−That's the extent of the merge options in clay proper. In
400−userspace there's a final option `%auto`, which is the most
401−common. `%auto` checks to see if Bob's desk exists, and if it
402−doesn't we use a `%init` merge. Otherwise, we progressively try
403−`%fine`, `%meet`, and `%mate` until one succeeds.
404−
405−If none succeed, we merge Bob's desk into a scratch desk. Then,
406−we merge Alice's desk into the scratch desk with the `%meld`
407−option to force the merge. For each file in the produced set of
408−conflicting files, we call the `++mash` function for the
409−appropriate mark, which annotates the conflicts if we know how.
410−
411−Finally, we display a message to the user informing them of the
412−scratch desk's existence, which files have annotated conflicts,
413−and which files have unannotated conflicts. When the user has
414−resolved the conflicts, they can merge the scratch desk back into
415−Bob's desk. This will be a `%fine` merge since Bob's head is in
416−the ancestry of the scratch desk.
417−
418−### Autosync
419−
420−Tracking and staying in sync with another desk is another
421−fundamental operation. We call this "autosync". This doesn't mean
422−simply mirroring a desk, since that wouldn't allow local changes.
423−We simply want to apply changes as they are made upstream, as
424−long as there are no conflicts with local changes.
425−
426−This is implemented by watching the other desk, and, when it has
427−changes, merging these changes into our desk with the usual merge
428−strategies.
429−
430−Note that it's quite reasonable for two desks to be autosynced to
431−each other. This results in any change on one desk being mirrored
432−to the other and vice versa.
433−
434−Additionally, it's fine to set up an autosync even if one desk,
435−the other desk, or both desks do not exist. The sync will be
436−activated when the upstream desk comes into existence and will
437−create the downstream desk if needed.
438−
439−## Commentary
440−
441−The first part of this section will be reference documentation for the data
442−types used by our filesystem. In fact, as a general guide, we recommend
443−reading and attempting to understand the data structures used in any
444−Hoon code before you try to read the code itself. Although complete
445−understanding of the data structures is impossible without seeing them
446−used in the code, an 80% understanding greatly clarifies the code. As
447−another general guide, when reading Hoon, it rarely pays off to
448−understand every line of code when it appears. Try to get the gist of
449−it, and then move on. The next time you come back to it, it'll likely
450−make a lot more sense.
451−
452−After a description of the data models, we'll give an overview of the
453−interface that vanes and applications can use to interact with the
454−filesystem.
455−
456−Finally, we'll dive into the code and the algorithms themselves. You
457−know, the fun part.
458−
459−### Data Models
460−
461−As you're reading through this section, remember you can always come
462−back to this when you run into these types later on. You're not going to
463−remember everything the first time through, but it is worth reading, or
464−at least skimming, this so that you get a rough idea of how our state is
465−organized.
466−
467−The types that are certainly worth reading are `++raft`, `++room`,
468−`++dome:clay`, `++ankh:clay`, `++rung:clay`, `++rang:clay`, `++blob:clay`, `++yaki:clay`, and `++nori:clay`
469−(possibly in that order). All in all, though, this section isn't too
470−long, so many readers may wish to quickly read through all of it. If you
471−get bored, though, just skip to the next section. You can always come
472−back when you need to.
473−
474−### `++raft`, formal state
475−
476−```hoon
477− ++ raft :: filesystem
478− $: fat=(map ship room) :: domestic
479− hoy=(map ship rung) :: foreign
480− ran=rang :: hashes
481− == ::
482−```
483−
484−This is the state of our vane. Anything that must be remembered between
485−calls to clay is stored in this state.
486−
487−`fat` is the set of domestic servers. This stores all the information
488−that is specfic to a particular ship on this pier. The keys to this map
489−are the ships on the current pier. all the information that is specific
490−to a particular foreign ship. The keys to this map are all the ships
491−whose filesystems we have attempted to access through clay.
492−
493−`ran` is the store of all commits and deltas, keyed by hash. The is
494−where all the "real" data we know is stored; the rest is "just
495−bookkeeping".
496−
497−#### `++room`, filesystem per domestic ship
498−
499−```hoon
500− ++ room :: fs per ship
501− $: hun=duct :: terminal duct
502− hez=(unit duct) :: sync duch
503− dos=(map desk dojo) :: native desk
504− == ::
505−```
506−
507−This is the representation of the filesystem of a ship on our pier.
508−
509−`hun` is the duct we use to send messages to dill to display
510−notifications of filesystem changes. Only `%note` gifts should be
511−produced along this duct. This is set by the `%init` kiss.
512−
513−`hez`, if present, is the duct we use to send sync messages to unix so
514−that they end up in the pier unix directory. Only `%ergo` gifts should
515−be producd along this duct. This is set by `%into` and `%invo` kisses.
516−
517−`dos` is a well-known operating system released in 1981. It is also the
518−set of desks on this ship, mapped to their data.
519−
520−#### `++desk`, filesystem branch
521−
522−```hoon
523− ++ desk ,@tas :: ship desk case spur
524−```
525−
526−This is the name of a branch of the filesystem. The default desks are
527−"arvo", "main", and "try". More may be created by simply referencing
528−them. Desks have independent histories and states, and they may be
529−merged into each other.
530−
531−### `++dojo`, domestic desk state
532−
533−```hoon
534− ++ dojo ,[p=cult q=dome] :: domestic desk state
535−```
536−
537−This is the all the data that is specific to a particular desk on a
538−domestic ship. `p` is the set of subscribers to this desk and `q` is the
539−data in the desk.
540−
541−#### `++cult`, subscriptions
542−
543−```hoon
544− ++ cult (map duct rave) :: subscriptions
545−```
546−
547−This is the set of subscriptions to a particular desk. The keys are the
548−ducts from where the subscriptions requests came. The results will be
549−produced along these ducts. The values are a description of the
550−requested information.
551−
552−#### `++rave:clay`, general subscription request
553−
554−```hoon
555− ++ rave :: general request
556− $% [& p=mood] :: single request
557− [| p=moat] :: change range
558− == ::
559−```
560−
561−This represents a subscription request for a desk. The request can be
562−for either a single item in the desk or else for a range of changes on
563−the desk.
564−
565−### `++rove`, stored general subscription request
566−
567−```hoon
568− ++ rove (each mood moot) :: stored request
569−```
570−
571−When we store a request, we store subscriptions with a little extra
572−information so that we can determine whether new versions actually
573−affect the path we're subscribed to.
574−
575−#### `++mood:clay`, single subscription request
576−
577−```hoon
578− ++ mood ,[p=care q=case r=path] :: request in desk
579−```
580−
581−This represents a request for the state of the desk at a particular
582−commit, specfied by `q`. `p` specifies what kind of information is
583−desired, and `r` specifies the path we are requesting.
584−
585−#### `++moat:clay`, range subscription request
586−
587−```hoon
588− ++ moat ,[p=case q=case r=path] :: change range
589−```
590−
591−This represents a request for all changes between `p` and `q` on path
592−`r`. You will be notified when a change is made to the node referenced
593−by the path or to any of its children.
594−
595−### `++moot`, stored range subscription request
596−
597−```hoon
598− ++ moot ,[p=case q=case r=path s=(map path lobe)] ::
599−```
600−
601−This is just a `++moat:clay` plus a map of paths to lobes. This map
602−represents the data at the node referenced by the path at case `p`, if
603−we've gotten to that case (else null). We only send a notification along
604−the subscription if the data at a new revision is different than it was.
605−
606−### `++care:clay`, clay submode
607−
608−```hoon
609− ++ care ?(%u %v %w %x %y %z) :: clay submode
610−```
611−
612−This specifies what type of information is requested in a subscription
613−or a scry.
614−
615−`%u` requests the `++rang:clay` at the current moment. Because this
616−information is not stored for any moment other than the present, we
617−crash if the `++case:clay` is not a `%da` for now.
618−
619−`%v` requests the `++dome:clay` at the specified commit.
620−
621−`%w` requests the revsion number of the desk.
622−
623−`%x` requests the file at a specified path at the specified commit. If
624−there is no node at that path or if the node has no contents (that is,
625−if `q:ankh` is null), then this produces null.
626−
627−`%y` requests a `++arch` of the specfied commit at the specified path.
628−
629−`%z` requests the `++ankh` of the specified commit at the specfied path.
630−
631−### `++arch`, shallow filesystem node
632−
633−```hoon
634− ++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node
635−```
636−
637−This is analogous to `++ankh:clay` except that the we have neither our
638−contents nor the ankhs of our children. The other fields are exactly the
639−same, so `p` is a hash of the associated ankh, `u.q`, if it exists, is a
640−hash of the contents of this node, and the keys of `r` are the names of
641−our children. `r` is a map to null rather than a set so that the
642−ordering of the map will be equivalent to that of `r:ankh`, allowing
643−efficient conversion.
644−
645−#### `++case:clay`, specifying a commit
646−
647−```hoon
648− ++ case :: ship desk case spur
649− $% [%da p=@da] :: date
650− [%tas p=@tas] :: label
651− [%ud p=@ud] :: number
652− == ::
653−```
654−
655−A commit can be referred to in three ways: `%da` refers to the commit
656−that was at the head on date `p`, `%tas` refers to the commit labeled
657−`p`, and `%ud` refers to the commit numbered `p`. Note that since these
658−all can be reduced down to a `%ud`, only numbered commits may be
659−referenced with a `++case:clay`.
660−
661−#### `++dome:clay`, desk data
662−
663−```hoon
664− ++ dome :: project state
665− $: ang=agon :: pedigree
666− ank=ankh :: state
667− let=@ud :: top id
668− hit=(map ,@ud tako) :: changes by id
669− lab=(map ,@tas ,@ud) :: labels
670− == ::
671−```
672−
673−This is the data that is actually stored in a desk.
674−
675−`ang` is unused and should be removed.
676−
677−`ank` is the current state of the desk. Thus, it is the state of the
678−filesystem at revison `let`. The head of a desk is always a numbered
679−commit.
680−
681−`let` is the number of the most recently numbered commit. This is also
682−the total number of numbered commits.
683−
684−`hit` is a map of numerical ids to hashes of commits. These hashes are
685−mapped into their associated commits in `hut:rang:clay`. In general, the keys
686−of this map are exactly the numbers from 1 to `let`, with no gaps. Of
687−course, when there are no numbered commits, `let` is 0, so `hit` is
688−null. Additionally, each of the commits is an ancestor of every commit
689−numbered greater than this one. Thus, each is a descendant of every
690−commit numbered less than this one. Since it is true that the date in
691−each commit (`t:yaki`) is no earlier than that of each of its parents,
692−the numbered commits are totally ordered in the same way by both
693−pedigree and date. Of course, not every commit is numbered. If that
694−sounds too complicated to you, don't worry about it. It basically
695−behaves exactly as you would expect.
696−
697−`lab` is a map of textual labels to numbered commits. Note that labels
698−can only be applied to numbered commits. Labels must be unique across a
699−desk.
700−
701−#### `++ankh`, filesystem node
702−
703−```hoon
704− ++ ankh :: fs node (new)
705− $: p=cash :: recursive hash
706− q=(unit ,[p=cash q=*]) :: file
707− r=(map ,@ta ankh) :: folders
708− == ::
709−```
710−
711−This is a single node in the filesystem. This may be file or a directory
712−or both. In earth filesystems, a node is a file xor a directory. On
713−mars, we're inclusive, so a node is a file ior a directory.
714−
715−`p` is a recursive hash that depends on the contents of the this file or
716−directory and on any children.
717−
718−`q` is the contents of this file, if any. `p.q` is a hash of the
719−contents while `q.q` is the data itself.
720−
721−`r` is the set of children of this node. In the case of a pure file,
722−this is empty. The keys are the names of the children and the values
723−are, recursively, the nodes themselves.
724−
725−#### `++cash`, ankh hash
726−
727−```hoon
728− ++ cash ,@uvH :: ankh hash
729−```
730−
731−This is a 128-bit hash of an ankh. These are mostly stored within ankhs
732−themselves, and they are used to check for changes in possibly-deep
733−hierarchies.
734−
735−#### `++rung`, filesystem per neighbor ship
736−
737−```hoon
738− ++ rung $: rus=(map desk rede) :: neighbor desks
739− == ::
740−```
741−
742−This is the filesystem of a neighbor ship. The keys to this map are all
743−the desks we know about on their ship.
744−
745−#### `++rede`, desk state
746−
747−```hoon
748− ++ rede :: universal project
749− $: lim=@da :: complete to
750− qyx=cult :: subscribers
751− ref=(unit rind) :: outgoing requests
752− dom=dome :: revision state
753− == ::
754−```
755−
756−This is our knowledge of the state of a desk, either foreign or
757−domestic.
758−
759−`lim` is the date of the last full update. We only respond to requests
760−for stuff before this time.
761−
762−`qyx` is the list of subscribers to this desk. For domestic desks, this
763−is simply `p:dojo`, all subscribers to the desk, while in foreign desks
764−this is all the subscribers from our ship to the foreign desk.
765−
766−`ref` is the request manager for the desk. For domestic desks, this is
767−null since we handle requests ourselves.
768−
769−`dom` is the actual data in the desk.
770−
771−#### `++rind`, request manager
772−
773−```hoon
774− ++ rind :: request manager
775− $: nix=@ud :: request index
776− bom=(map ,@ud ,[p=duct q=rave]) :: outstanding
777− fod=(map duct ,@ud) :: current requests
778− haw=(map mood (unit)) :: simple cache
779− == ::
780−```
781−
782−This is the request manager for a foreign desk.
783−
784−`nix` is one more than the index of the most recent request. Thus, it is
785−the next available request number.
786−
787−`bom` is the set of outstanding requests. The keys of this map are some
788−subset of the numbers between 0 and one less than `nix`. The members of
789−the map are exactly those requests that have not yet been fully
790−satisfied.
791−
792−`fod` is the same set as `bom`, but from a different perspective. In
793−particular, the values of `fod` are the same as the values of `bom`, and
794−the `p` out of the values of `bom` are the same as the keys of `fod`.
795−Thus, we can map ducts to their associated request number and `++rave:clay`,
796−and we can map numbers to their associated duct and `++rave:clay`.
797−
798−`haw` is a map from simple requests to their values. This acts as a
799−cache for requests that have already been made. Thus, the second request
800−for a particular `++mood:clay` is nearly instantaneous.
801−
802−#### `++rang:clay`, data store
803−
804−```hoon
805− ++ rang $: hut=(map tako yaki) ::
806− lat=(map lobe blob) ::
807− == ::
808−```
809−
810−This is a set of data keyed by hash. Thus, this is where the "real" data
811−is stored, but it is only meaningful if we know the hash of what we're
812−looking for.
813−
814−`hut` is a map from hashes to commits. We often get the hashes from
815−`hit:dome:clay`, which keys them by logical id. Not every commit has an id.
816−
817−`lat` is a map from hashes to the actual data. We often get the hashes
818−from a `++yaki`, a commit, which references this map to get the data.
819−There is no `++blob:clay` in any `++yaki:clay`. They are only accessible through
820−this map.
821−
822−#### `++tako:clay`, commit reference
823−
824−```hoon
825− ++ tako ,@ :: yaki ref
826−```
827−
828−This is a hash of a `++yaki:clay`, a commit. These are most notably used as
829−the keys in `hut:rang:clay`, where they are associated with the actual
830−`++yaki:clay`, and as the values in `hit:dome:clay`, where sequential ids are
831−associated with these.
832−
833−#### `++yaki:clay`, commit
834−
835−```hoon
836− ++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit
837−```
838−
839−This is a single commit.
840−
841−`p` is a list of the hashes of the parents of this commit. In most
842−cases, this will be a single commit, but in a merge there may be more
843−parents. In theory, there may be an arbitrary number of parents, but in
844−practice merges have exactly two parents. This may change in the future.
845−For commit 1, there is no parent.
846−
847−`q` is a map of the paths on a desk to the data at that location. If you
848−understand what a `++lobe:clay` and a `++blob:clay` is, then the type signature
849−here tells the whole story.
850−
851−`r` is the hash associated with this commit.
852−
853−`t` is the date at which this commit was made.
854−
855−#### `++lobe:clay`, data reference
856−
857−```hoon
858− ++ lobe ,@ :: blob ref
859−```
860−
861−This is a hash of a `++blob:clay`. These are most notably used in `lat:rang:clay`,
862−where they are associated with the actual `++blob:clay`, and as the values in
863−`q:yaki:clay`, where paths are associated with their data in a commit.
864−
865−#### `++blob:clay`, data
866−
867−```hoon
868− ++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q
869− [%direct p=lobe q=* r=umph] ::
870− [%indirect p=lobe q=* r=udon s=lobe] ::
871− == ::
872−```
873−
874−This is a node of data. In every case, `p` is the hash of the blob.
875−
876−`%delta` is the case where we define the data by a delta on other data.
877−In practice, the other data is always the previous commit, but nothing
878−depends on this. `q` is the hash of the parent blob, and `r` is the
879−delta.
880−
881−`%direct` is the case where we simply have the data directly. `q` is the
882−data itself, and `r` is any preprocessing instructions. These almost
883−always come from the creation of a file.
884−
885−`%indirect` is both of the preceding cases at once. `q` is the direct
886−data, `r` is the delta, and `s` is the parent blob. It should always be
887−the case that applying `r` to `s` gives the same data as `q` directly
888−(with the prepreprocessor instructions in `p.r`). This exists purely for
889−performance reasons. This is unused, at the moment, but in general these
890−should be created when there are a long line of changes so that we do
891−not have to traverse the delta chain back to the creation of the file.
892−
893−#### `++udon`, abstract delta
894−
895−```hoon
896− ++ udon :: abstract delta
897− $: p=umph :: preprocessor
898− $= q :: patch
899− $% [%a p=* q=*] :: trivial replace
900− [%b p=udal] :: atomic indel
901− [%c p=(urge)] :: list indel
902− [%d p=upas q=upas] :: tree edit
903− == ::
904− == ::
905−```
906−
907−This is an abstract change to a file. This is a superset of what would
908−normally be called diffs. Diffs usually refer to changes in lines of
909−text while we have the ability to do more interesting deltas on
910−arbitrary data structures.
911−
912−`p` is any preprocessor instructions.
913−
914−`%a` refers to the trival delta of a complete replace of old data with
915−new data.
916−
917−`%b` refers to changes in an opaque atom on the block level. This has
918−very limited usefulness, and is not used at the moment.
919−
920−`%c` refers to changes in a list of data. This is often lines of text,
921−which is your classic diff. We, however, will work on any list of data.
922−
923−`%d` refers to changes in a tree of data. This is general enough to
924−describe changes to any hoon noun, but often more special-purpose delta
925−should be created for different content types. This is not used at the
926−moment, and may in fact be unimplemented.
927−
928−#### `++urge`, list change
929−
930−```hoon
931− ++ urge |*(a=_,* (list (unce a))) :: list change
932−```
933−
934−This is a parametrized type for list changes. For example, `(urge ,@t)`
935−is a list change for lines of text.
936−
937−#### `++unce`, change part of a list.
938−
939−```hoon
940− ++ unce |* a=_,* :: change part
941− $% [%& p=@ud] :: skip[copy]
942− [%| p=(list a) q=(list a)] :: p -> q[chunk]
943− == ::
944−```
945−
946−This is a single change in a list of elements of type `a`. For example,
947−`(unce ,@t)` is a single change in a lines of text.
948−
949−`%&` means the next `p` lines are unchanged.
950−
951−`%|` means the lines `p` have changed to `q`.
952−
953−#### `++umph`, preprocessing information
954−
955−```hoon
956− ++ umph :: change filter
957− $| $? %a :: no filter
958− %b :: jamfile
959− %c :: LF text
960− == ::
961− $% [%d p=@ud] :: blocklist
962− == ::
963−```
964−
965−This space intentionally left undocumented. This stuff will change once
966−we get a well-typed clay.
967−
968−#### `++upas`, tree change
969−
970−```hoon
971− ++ upas :: tree change (%d)
972− $& [p=upas q=upas] :: cell
973− $% [%0 p=axis] :: copy old
974− [%1 p=*] :: insert new
975− [%2 p=axis q=udon] :: mutate!
976− == ::
977−```
978−
979−This space intentionally left undocumented. This stuff is not known to
980−work, and will likely change when we get a well-typed clay. Also, this
981−is not a complicated type; it is not difficult to work out the meaning.
982−
983−#### `++nori:clay`, repository action
984−
985−```hoon
986− ++ nori :: repository action
987− $% [& q=soba] :: delta
988− [| p=@tas] :: label
989− == ::
990−```
991−
992−This describes a change that we are asking clay to make to the desk.
993−There are two kinds of changes that may be made: we can modify files or
994−we can apply a label to a commit.
995−
996−In the `|` case, we will simply label the current commit with the given
997−label. In the `&` case, we will apply the given changes.
998−
999−#### `++soba:clay`, delta
1000−
1001−```hoon
1002− ++ soba ,[p=cart q=(list ,[p=path q=miso])] :: delta
1003−```
1004−
1005−This describes a set of changes to make to a desk. The `cart` is simply
1006−a pair of the old hash and the new hash of the desk. The list is a list
1007−of changes keyed by the file they're changing. Thus, the paths are paths
1008−to files to be changed while `miso` is a description of the change
1009−itself.
1010−
1011−#### `++miso:clay`, ankh delta
1012−
1013−```hoon
1014− ++ miso :: ankh delta
1015− $% [%del p=*] :: delete
1016− [%ins p=*] :: insert
1017− [%mut p=udon] :: mutate
1018− == ::
1019−```
1020−
1021−There are three kinds of changes that may be made to a node in a desk.
1022−We can insert a file, in which case `p` is the contents of the new file.
1023−We can delete a file, in which case `p` is the contents of the old file.
1024−Finally, we can mutate that file, in which case the `udon` describes the
1025−changes we are applying to the file.
1026−
1027−#### `++mizu:clay`, merged state
1028−
1029−```hoon
1030− ++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state
1031−```
1032−
1033−This is the input to the `%merg` kiss, which allows us to perform a
1034−merge. The `p` is the number of the new head commit. The `q` is a map
1035−from numbers to commit hashes. This is all the new numbered commits that
1036−are to be inserted. The keys to this should always be the numbers from
1037−`let.dom` plus one to `p`, inclusive. The `r` is the maps of all the new
1038−commits and data. Since these are merged into the current state, no old
1039−commits or data need be here.
1040−
1041−#### `++riff:clay`, request/desist
1042−
1043−```hoon
1044− ++ riff ,[p=desk q=(unit rave)] :: request/desist
1045−```
1046−
1047−This represents a request for data about a particular desk. If `q`
1048−contains a `rave`, then this opens a subscription to the desk for that
1049−data. If `q` is null, then this tells clay to cancel the subscription
1050−along this duct.
1051−
1052−#### `++riot:clay`, response
1053−
1054−```hoon
1055− ++ riot (unit rant) :: response/complete
1056−```
1057−
1058−A riot is a response to a subscription. If null, the subscription has
1059−been completed, and no more responses will be sent. Otherwise, the
1060−`rant` is the produced data.
1061−
1062−#### `++rant:clay`, response data
1063−
1064−```hoon
1065− ++ rant :: namespace binding
1066− $: p=[p=care q=case r=@tas] :: clade release book
1067− q=path :: spur
1068− r=* :: data
1069− == ::
1070−```
1071−
1072−This is the data at a particular node in the filesystem. `p.p` specifies
1073−the type of data that was requested (and is produced). `q.p` gives the
1074−specific version reported (since a range of versions may be requested in
1075−a subscription). `r.p` is the desk. `q` is the path to the filesystem
1076−node. `r` is the data itself (in the format specified by `p.p`).
1077−
1078−### `++nako`, subscription response data
1079−
1080−```hoon
1081− ++ nako $: gar=(map ,@ud tako) :: new ids
1082− let=@ud :: next id
1083− lar=(set yaki) :: new commits
1084− bar=(set blob) :: new content
1085− == ::
1086−```
1087−
1088−This is the data that is produced by a request for a range of revisions
1089−of a desk. This allows us to easily keep track of a remote repository --
1090−all the new information we need is contained in the `nako`.
1091−
1092−`gar` is a map of the revisions in the range to the hash of the commit
1093−at that revision. These hashes can be used with `hut:rang:clay` to find the
1094−commit itself.
1095−
1096−`let` is either the last revision number in the range or the most recent
1097−revision number, whichever is smaller.
1098−
1099−`lar` is the set of new commits, and `bar` is the set of new content.
1100−
1101−## Public Interface
1102−
1103−As with all vanes, there are exactly two ways to interact with clay.
1104−`%clay` exports a namespace accessible through `.^`, which is described
1105−above under `++care:clay`. The primary way of interacting with clay, though,
1106−is by sending kisses and receiving gifts.
1107−
1108−```hoon
1109− ++ gift :: out result <-$
1110− $% [%ergo p=@p q=@tas r=@ud] :: version update
1111− [%note p=@tD q=tank] :: debug message
1112− [%writ p=riot] :: response
1113− == ::
1114− ++ kiss :: in request ->$
1115− $% [%info p=@p q=@tas r=nori] :: internal edit
1116− [%ingo p=@p q=@tas r=nori] :: internal noun edit
1117− [%init p=@p] :: report install
1118− [%into p=@p q=@tas r=nori] :: external edit
1119− [%invo p=@p q=@tas r=nori] :: external noun edit
1120− [%merg p=@p q=@tas r=mizu] :: internal change
1121− [%wart p=sock q=@tas r=path s=*] :: network request
1122− [%warp p=sock q=riff] :: file request
1123− == ::
1124−```
1125−
1126−There are only a small number of possible kisses, so it behooves us to
1127−describe each in detail.
1128−
1129−```hoon
1130− $% [%info p=@p q=@tas r=nori] :: internal edit
1131−
1132− [%into p=@p q=@tas r=nori] :: external edit
1133−```
1134−
1135−These two kisses are nearly identical. At a high level, they apply
1136−changes to the filesystem. Whenever we add, remove, or edit a file, one
1137−of these cards is sent. The `p` is the ship whose filesystem we're
1138−trying to change, the `q` is the desk we're changing, and the `r` is the
1139−request change. For the format of the requested change, see the
1140−documentation for `++nori:clay` above.
1141−
1142−When a file is changed in the unix filesystem, vere will send a `%into`
1143−kiss. This tells clay that the duct over which the kiss was sent is the
1144−duct that unix is listening on for changes. From within Arvo, though, we
1145−should never send a `%into` kiss. The `%info` kiss is exactly identical
1146−except it does not reset the duct.
1147−
1148−```hoon
1149− [%ingo p=@p q=@tas r=nori] :: internal noun edit
1150−
1151− [%invo p=@p q=@tas r=nori] :: external noun edit
1152−```
1153−
1154−These kisses are currently identical to `%info` and `%into`, though this
1155−will not always be the case. The intent is for these kisses to allow
1156−typed changes to clay so that we may store typed data. This is currently
1157−unimplemented.
1158−
1159−```hoon
1160− [%init p=@p] :: report install
1161−```
1162−
1163−Init is called when a ship is started on our pier. This simply creates a
1164−default `room` to go into our `raft`. Essentially, this initializes the
1165−filesystem for a ship.
1166−
1167−```hoon
1168− [%merg p=@p q=@tas r=mizu] :: internal change
1169−```
1170−
1171−This is called to perform a merge. This is most visibly called by
1172−:update to update the filesystem of the current ship to that of its
1173−sein. The `p` and `q` are as in `%info`, and the `r` is the description
1174−of the merge. See `++mizu:clay` above.
1175−
1176−XX
1177−`XX [%wake ~] :: timer activate XX`
1178−XX\
1179−XX This card is sent by unix at the time specified by `++doze`. This
1180−time is XX usually the closest time specified in a subscription request.
1181−When `%wake` is XX called, we update our subscribers if there have been
1182−any changes.
1183−
1184−```hoon
1185− [%wart p=sock q=@tas r=path s=*] :: network request
1186−```
1187−
1188−This is a request that has come across the network for a particular
1189−file. When another ship asks for a file from us, that request comes to
1190−us in the form of a `%wart` kiss. This is handled by trivially turning
1191−it into a `%warp`.
1192−
1193−```hoon
1194− [%warp p=sock q=riff] :: file request
1195−```
1196−
1197−This is a request for information about a particular desk. This is, in
1198−its most general form, a subscription, though in many cases it is the
1199−trivial case of a subscription -- a read. See `++riff:clay` for the format of
1200−the request.
1201−
1202−## Lifecycle of a Local Read
1203−
1204−There are two real types of interaction with a filesystem: you can read,
1205−and you can write. We'll describe each process, detailing both the flow
1206−of control followed by the kernel and the algorithms involved. The
1207−simpler case is that of the read, so we'll begin with that.
1208−
1209−When a vane or an application wishes to read a file from the filesystem,
1210−it sends a `%warp` kiss, as described above. Of course, you may request
1211−a file on another ship and, being a global filesystem, clay will happily
1212−produce it for you. That code pathway will be described in another
1213−section; here, we will restrict ourselves to examining the case of a
1214−read from a ship on our own pier.
1215−
1216−The kiss can request either a single version of a file node or a range
1217−of versions of a desk. Here, we'll deal only with a request for a single
1218−version.
1219−
1220−As in all vanes, a kiss enters clay via a call to `++call`. Scanning
1221−through the arm, we quickly see where `%warp` is handled.
1222−
1223−```hoon
1224− ?: =(p.p.q.hic q.p.q.hic)
1225− =+ une=(un p.p.q.hic now ruf)
1226− =+ wex=(di:une p.q.q.hic)
1227− =+ ^= wao
1228− ?~ q.q.q.hic
1229− (ease:wex hen)
1230− (eave:wex hen u.q.q.q.hic)
1231− =+ ^= woo
1232− abet:wao
1233− [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
1234−```
1235−
1236−We're following the familar patern of producing a list of moves and an
1237−updated state. In this case, the state is `++raft`.
1238−
1239−We first check to see if the sending and receiving ships are the same.
1240−If they're not, then this is a request for data on another ship. We
1241−describe that process later. Here, we discuss only the case of a local
1242−read.
1243−
1244−At a high level, the call to `++un` sets up the core for the domestic
1245−ship that contains the files we're looking for. The call to `++di` sets
1246−up the core for the particular desk we're referring to.
1247−
1248−After this, we perform the actual request. If there is no rave in the
1249−riff, then that means we are cancelling a request, so we call
1250−`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
1251−call `++abet:de` to resolve our various types of output into actual
1252−moves. We produce the moves we found above and the `++un` core resolved
1253−with `++pish:un` (putting the modified desk in the room) and `++abet:un`
1254−(putting the modified room in the raft).
1255−
1256−Much of this is fairly straightforward, so we'll only describe `++ease`,
1257−`++eave`, and `++abet:de`. Feel free to look up the code to the other
1258−steps -- it should be easy to follow.
1259−
1260−Although it's called last, it's usually worth examining `++abet` first,
1261−since it defines in what ways we can cause side effects. Let's do that,
1262−and also a few of the lines at the beginning of `++de`.
1263−
1264−```hoon
1265− =| yel=(list ,[p=duct q=gift])
1266− =| byn=(list ,[p=duct q=riot])
1267− =| vag=(list ,[p=duct q=gift])
1268− =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
1269− =| tag=(list ,[p=duct q=path c=note])
1270− |%
1271− ++ abet
1272− ^- [(list move) rede]
1273− :_ red
1274− ;: weld
1275− %+ turn (flop yel)
1276− |=([a=duct b=gift] [hun %give b])
1277− ::
1278− %+ turn (flop byn)
1279− |=([a=duct b=riot] [a %give [%writ b]])
1280− ::
1281− %+ turn (flop vag)
1282− |=([a=duct b=gift] [a %give b])
1283− ::
1284− %+ turn (flop say)
1285− |= [a=duct b=path c=ship d=[p=@ud q=riff]]
1286− :- a
1287− [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
1288− ::
1289− %+ turn (flop tag)
1290− |=([a=duct b=path c=note] [a %pass b c])
1291− ==
1292−```
1293−
1294−This is very simple code. We see there are exactly five different kinds
1295−of side effects we can generate.
1296−
1297−In `yel` we put gifts that we wish to be sent along the `hun:room` duct
1298−to dill. See the documentation for `++room` above. This is how we
1299−display messages to the terminal.
1300−
1301−In `byn` we put riots that we wish returned to subscribers. Recall that
1302−a riot is a response to a subscription. These are returned to our
1303−subscribers in the form of a `%writ` gift.
1304−
1305−In `vag` we put gifts along with the ducts on which to send them. This
1306−allows us to produce arbitrary gifts, but in practice this is only used
1307−to produce `%ergo` gifts.
1308−
1309−In `say` we put messages we wish to pass to ames. These messages are
1310−used to request information from clay on other piers. We must provide
1311−not only the duct and the request (the riff), but also the return path,
1312−the other ship to talk to, and the sequence number of the request.
1313−
1314−In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
1315−the only notes we pass here are `%wait` and `%rest` to the timer vane.
1316−
1317−Now that we know what kinds of side effects we may have, we can jump
1318−into the handling of requests.
1319−
1320−```hoon
1321− ++ ease :: release request
1322− |= hen=duct
1323− ^+ +>
1324− ?~ ref +>
1325− =+ rov=(~(got by qyx) hen)
1326− =. qyx (~(del by qyx) hen)
1327− (mabe rov (cury best hen))
1328− =. qyx (~(del by qyx) hen)
1329− |- ^+ +>+.$
1330− =+ nux=(~(get by fod.u.ref) hen)
1331− ?~ nux +>+.$
1332− %= +>+.$
1333− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
1334− fod.u.ref (~(del by fod.u.ref) hen)
1335− bom.u.ref (~(del by bom.u.ref) u.nux)
1336− ==
1337−```
1338−
1339−This is called when we're cancelling a subscription. For domestic desks,
1340−`ref` is null, so we're going to cancel any timer we might have created.
1341−We first delete the duct from our map of requests, and then we call
1342−`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
1343−have started a timer. We'll describe `++best` and `++mabe` momentarily.
1344−
1345−Although we said we're not going to talk about foreign requests yet,
1346−it's easy to see that for foreign desks, we cancel any outstanding
1347−requests for this duct and send a message over ames to the other ship
1348−telling them to cancel the subscription.
1349−
1350−```hoon
1351− ++ best
1352− |= [hen=duct tym=@da]
1353− %_(+> tag :_(tag [hen /tyme %t %rest tym]))
1354−```
1355−
1356−This simply pushes a `%rest` note onto `tag`, from where it will be
1357−passed back to arvo to be handled. This cancels the timer at the given
1358−duct (with the given time).
1359−
1360−```hoon
1361− ++ mabe :: maybe fire function
1362− |* [rov=rove fun=$+(@da _+>.^$)]
1363− ^+ +>.$
1364− %- fall :_ +>.$
1365− %- bind :_ fun
1366− ^- (unit ,@da)
1367− ?- -.rov
1368− %&
1369− ?. ?=(%da -.q.p.rov) ~
1370− `p.q.p.rov
1371− %|
1372− =* mot p.rov
1373− %+ hunt
1374− ?. ?=(%da -.p.mot) ~
1375− ?.((lth now p.p.mot) ~ [~ p.p.mot])
1376− ?. ?=(%da -.q.mot) ~
1377− ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
1378− ==
1379−```
1380−
1381−This decides whether the given request can only be satsified in the
1382−future. In that case, we call the given function with the time in the
1383−future when we expect to have an update to give to this request. This is
1384−called with `++best` to cancel timers and with `++bait` to start them.
1385−
1386−For single requests, we have a time if the request is for a particular
1387−time (which is assumed to be in the future). For ranges of requests, we
1388−check both the start and end cases to see if they are time cases. If so,
1389−we choose the earlier time.
1390−
1391−If any of those give us a time, then we call the given funciton with the
1392−smallest time.
1393−
1394−The more interesting case is, of course, when we're not cancelling a
1395−subscription but starting one.
1396−
1397−```hoon
1398− ++ eave :: subscribe
1399− |= [hen=duct rav=rave]
1400− ^+ +>
1401− ?- -.rav
1402− &
1403− ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
1404− ~& [%clay-fail p.q.p.rav %now now]
1405− !!
1406− =+ ver=(aver p.rav)
1407− ?~ ver
1408− (duce hen rav)
1409− ?~ u.ver
1410− (blub hen)
1411− (blab hen p.rav u.u.ver)
1412−```
1413−
1414−There are two types of subscriptions -- either we're requesting a single
1415−file or we're requesting a range of versions of a desk. We'll dicuss the
1416−simpler case first.
1417−
1418−First, we check that we're not requesting the `rang` from any time other
1419−than the present. Since we don't store that information for any other
1420−time, we can't produce it in a referentially transparent manner for any
1421−time other than the present.
1422−
1423−Then, we try to read the requested `mood:clay` `p.rav`. If we can't access
1424−the request data right now, we call `++duce` to put the request in our
1425−queue to be satisfied when the information becomes available.
1426−
1427−This case occurs when we make a request for a case whose (1) date is
1428−after the current date, (2) number is after the current number, or (3)
1429−label is not yet used.
1430−
1431−```hoon
1432− ++ duce :: produce request
1433− |= [hen=duct rov=rove]
1434− ^+ +>
1435− =. qyx (~(put by qyx) hen rov)
1436− ?~ ref
1437− (mabe rov (cury bait hen))
1438− |- ^+ +>+.$ :: XX why?
1439− =+ rav=(reve rov)
1440− =+ ^= vaw ^- rave
1441− ?. ?=([%& %v *] rav) rav
1442− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
1443− =+ inx=nix.u.ref
1444− %= +>+.$
1445− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
1446− nix.u.ref +(nix.u.ref)
1447− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
1448− fod.u.ref (~(put by fod.u.ref) hen inx)
1449− ==
1450−```
1451−
1452−The code for `++duce` is nearly the exact inverse of `++ease`, which in
1453−the case of a domestic desk is very simple -- we simply put the duct and
1454−rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
1455−Recall that `ref` is null for domestic desks and that `++mabe` fires the
1456−given function with the time we need to be woken up at, if we need to be
1457−woken up at a particular time.
1458−
1459−```hoon
1460− ++ bait
1461− |= [hen=duct tym=@da]
1462− %_(+> tag :_(tag [hen /tyme %t %wait tym]))
1463−```
1464−
1465−This sets an alarm by sending a `%wait` card with the given time to the
1466−timer vane.
1467−
1468−Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
1469−subscription. This occurs when we make (1) a `%x` request for a file
1470−that does not exist, (2) a `%w` request with a case that is not a
1471−number, or (3) a `%w` request with a nonempty path. The `++blub` is
1472−exactly what you would expect it to be.
1473−
1474−```hoon
1475− ++ blub :: ship stop
1476− |= hen=duct
1477− %_(+> byn [[hen ~] byn])
1478−```
1479−
1480−We notify the duct that we're cancelling their subscription since it
1481−isn't satisfiable.
1482−
1483−Otherwise, we have received the desired information, so we send it on to
1484−the subscriber with `++blab`.
1485−
1486−```hoon
1487− ++ blab :: ship result
1488− |= [hen=duct mun=mood dat=*]
1489− ^+ +>
1490− +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
1491−```
1492−
1493−The most interesting arm called in `++eave` is, of course, `++aver`,
1494−where we actually try to read the data.
1495−
1496−```hoon
1497− ++ aver :: read
1498− |= mun=mood
1499− ^- (unit (unit ,*))
1500− ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
1501− ~& [%clay-fail p.q.mun %now now]
1502− !!
1503− =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
1504− ?^ ezy ezy
1505− =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
1506− ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
1507−```
1508−
1509−We check immediately that we're not requesting the `rang` for any time
1510−other than the present.
1511−
1512−If this is a foreign desk, then we check our cache for the specific
1513−request. If either this is a domestic desk or we don't have the request
1514−in our cache, then we have to actually go read the data from our dome.
1515−
1516−We need to do two things. First, we try to find the number of the commit
1517−specified by the given case, and then we try to get the data there.
1518−
1519−Here, we jump into `arvo/zuse.hoon`, which is where much of the
1520−algorithmic code is stored, as opposed to the clay interface, which is
1521−stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
1522−
1523−```hoon
1524− ++ case-to-aeon :: case-to-aeon:ze
1525− |= lok=case :: act count through
1526− ^- (unit aeon)
1527− ?- -.lok
1528− %da
1529− ?: (gth p.lok lim) ~
1530− |- ^- (unit aeon)
1531− ?: =(0 let) [~ 0] :: avoid underflow
1532− ?: %+ gte p.lok
1533− =< t
1534− %- tako-to-yaki
1535− %- aeon-to-tako
1536− let
1537− [~ let]
1538− $(let (dec let))
1539− ::
1540− %tas (~(get by lab) p.lok)
1541− %ud ?:((gth p.lok let) ~ [~ p.lok])
1542− ==
1543−```
1544−
1545−We handle each type of `case:clay` differently. The latter two types are
1546−easy.
1547−
1548−If we're requesting a revision by label, then we simply look up the
1549−requested label in `lab` from the given dome. If it exists, that is our
1550−aeon; else we produce null, indicating the requested revision does not
1551−yet exist.
1552−
1553−If we're requesting a revision by number, we check if we've yet reached
1554−that number. If so, we produce the number; else we produce null.
1555−
1556−If we're requesting a revision by date, we check first if the date is in
1557−the future, returning null if so. Else we start from the most recent
1558−revision and scan backwards until we find the first revision committed
1559−before that date, and we produce that. If we requested a date before any
1560−revisions were committed, we produce `0`.
1561−
1562−The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
1563−
1564−```hoon
1565− ++ aeon-to-tako ~(got by hit)
1566−
1567− ++ tako-to-yaki ~(got by hut) :: grab yaki
1568−```
1569−
1570−We simply look up the aeon or tako in their respective maps (`hit` and
1571−`hut`).
1572−
1573−Assuming we got a valid version number, `++aver` calls
1574−`++read-at-aeon:ze`, which reads the requested data at the given
1575−revision.
1576−
1577−```hoon
1578− ++ read-at-aeon :: read-at-aeon:ze
1579− |= [oan=aeon mun=mood] :: seek and read
1580− ^- (unit)
1581− ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
1582− ?^(r.mun ~ [~ oan])
1583− (read:(rewind oan) mun)
1584−```
1585−
1586−If we're requesting the revision number with a case other than by
1587−number, then we go ahead and just produce the number we were given.
1588−Otherwise, we call `++rewind` to rewind our state to the given revision,
1589−and then we call `++read` to get the requested information.
1590−
1591−```hoon
1592− ++ rewind :: rewind:ze
1593− |= oan=aeon :: rewind to aeon
1594− ^+ +>
1595− ?: =(let oan) +>
1596− ?: (gth oan let) !! :: don't have version
1597− +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
1598−```
1599−
1600−If we're already at the requested version, we do nothing. If we're
1601−requesting a version later than our head, we are unable to comply.
1602−
1603−Otherwise, we get the hash of the commit at the number, and from that we
1604−get the commit itself (the yaki), which has the map of path to lobe that
1605−represents a version of the filesystem. We call `++checkout-ankh` to
1606−checkout the commit, and we replace `ank` in our context with the
1607−result.
1608−
1609−```hoon
1610− ++ checkout-ankh :: checkout-ankh:ze
1611− |= hat=(map path lobe) :: checkout commit
1612− ^- ankh
1613− %- cosh
1614− %+ roll (~(tap by hat) ~)
1615− |= [[pat=path bar=lobe] ank=ankh]
1616− ^- ankh
1617− %- cosh
1618− ?~ pat
1619− =+ zar=(lobe-to-noun bar)
1620− ank(q [~ (sham zar) zar])
1621− =+ nak=(~(get by r.ank) i.pat)
1622− %= ank
1623− r %+ ~(put by r.ank) i.pat
1624− $(pat t.pat, ank (fall nak _ankh))
1625− ==
1626−```
1627−
1628−Twice we call `++cosh`, which hashes a commit, updating `p` in an
1629−`ankh`. Let's jump into that algorithm before we describe
1630−`++checkout-ankh`.
1631−
1632−```hoon
1633− ++ cosh :: locally rehash
1634− |= ank=ankh :: NB v/unix.c
1635− ank(p rehash:(zu ank))
1636−```
1637−
1638−We simply replace `p` in the hash with the `cash` we get from a call to
1639−`++rehash:zu`.
1640−
1641−```hoon
1642− ++ zu !: :: filesystem
1643− |= ank=ankh :: filesystem state
1644− =| myz=(list ,[p=path q=miso]) :: changes in reverse
1645− =| ram=path :: reverse path into
1646− |%
1647− ++ rehash :: local rehash
1648− ^- cash
1649− %+ mix ?~(q.ank 0 p.u.q.ank)
1650− =+ axe=1
1651− |- ^- cash
1652− ?~ r.ank _@
1653− ;: mix
1654− (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
1655− $(r.ank l.r.ank, axe (peg axe 2))
1656− $(r.ank r.r.ank, axe (peg axe 3))
1657− ==
1658−```
1659−
1660−`++zu` is a core we set up with a particular filesystem node to traverse
1661−a checkout of the filesystem and access the actual data inside it. One
1662−of the things we can do with it is to create a recursive hash of the
1663−node.
1664−
1665−In `++rehash`, if this node is a file, then we xor the remainder of the
1666−hash with the hash of the contents of the file. The remainder of the
1667−hash is `0` if we have no children, else we descend into our children.
1668−Basically, we do a half SHA-256 of the xor of the axis of this child and
1669−the half SHA-256 of the xor of the name of the child and the hash of the
1670−child. This is done for each child and all the results are xored
1671−together.
1672−
1673−Now we return to our discussion of `++checkout-ankh`.
1674−
1675−We fold over every path in this version of the filesystem and create a
1676−great ankh out of them. First, we call `++lobe-to-noun` to get the raw
1677−data referred to be each lobe.
1678−
1679−```hoon
1680− ++ lobe-to-noun :: grab blob
1681− |= p=lobe :: ^- *
1682− %- blob-to-noun
1683− (lobe-to-blob p)
1684−```
1685−
1686−This converts a lobe into the raw data it refers to by first getting the
1687−blob with `++lobe-to-blob` and converting that into data with
1688−`++blob-to-noun`.
1689−
1690−```hoon
1691− ++ lobe-to-blob ~(got by lat) :: grab blob
1692−```
1693−
1694−This just grabs the blob that the lobe refers to.
1695−
1696−```hoon
1697− ++ blob-to-noun :: grab blob
1698− |= p=blob
1699− ?- -.p
1700− %delta (lump r.p (lobe-to-noun q.p))
1701− %direct q.p
1702− %indirect q.p
1703− ==
1704−```
1705−
1706−If we have either a direct or an indirect blob, then the data is stored
1707−right in the blob. Otherwise, we have to reconstruct it from the diffs.
1708−We do this by calling `++lump` on the diff in the blob with the data
1709−obtained by recursively calling the parent of this blob.
1710−
1711−```hoon
1712− ++ lump :: apply patch
1713− |= [don=udon src=*]
1714− ^- *
1715− ?+ p.don ~|(%unsupported !!)
1716− %a
1717− ?+ -.q.don ~|(%unsupported !!)
1718− %a q.q.don
1719− %c (lurk ((hard (list)) src) p.q.don)
1720− %d (lure src p.q.don)
1721− ==
1722− ::
1723− %c
1724− =+ dst=(lore ((hard ,@) src))
1725− %- roly
1726− ?+ -.q.don ~|(%unsupported !!)
1727− %a ((hard (list ,@t)) q.q.don)
1728− %c (lurk dst p.q.don)
1729− ==
1730− ==
1731−```
1732−
1733−This is defined in `arvo/hoon.hoon` for historical reasons which are
1734−likely no longer applicable. Since the `++umph` structure will likely
1735−change we convert clay to be a typed filesystem, we'll only give a
1736−high-level description of this process. If we have a `%a` udon, then
1737−we're performing a trivial replace, so we produce simply `q.q.don`. If
1738−we have a `%c` udon, then we're performing a list merge (as in, for
1739−example, lines of text). The merge is performed by `++lurk`.
1740−
1741−```hoon
1742− ++ lurk :: apply list patch
1743− |* [hel=(list) rug=(urge)]
1744− ^+ hel
1745− =+ war=`_hel`~
1746− |- ^+ hel
1747− ?~ rug (flop war)
1748− ?- -.i.rug
1749− &
1750− %= $
1751− rug t.rug
1752− hel (slag p.i.rug hel)
1753− war (weld (flop (scag p.i.rug hel)) war)
1754− ==
1755− ::
1756− |
1757− %= $
1758− rug t.rug
1759− hel =+ gur=(flop p.i.rug)
1760− |- ^+ hel
1761− ?~ gur hel
1762− ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
1763− war (weld q.i.rug war)
1764− ==
1765− ==
1766−```
1767−
1768−We accumulate our final result in `war`. If there's nothing more in our
1769−list of merge instructions (unces), we just reverse `war` and produce
1770−it. Otherwise, we process another unce. If the unce is of type `&`, then
1771−we have `p.i.rug` lines of no changes, so we just copy them over from
1772−`hel` to `war`. If the unice is of type `|`, then we verify that the
1773−source lines (in `hel`) are what we expect them to be (`p.i.rug`),
1774−crashing on failure. If they're good, then we append the new lines in
1775−`q.i.rug` onto `war`.
1776−
1777−And that's really it. List merges are pretty easy. Anyway, if you
1778−recall, we were discussing `++checkout-ankh`.
1779−
1780−```hoon
1781− ++ checkout-ankh :: checkout-ankh:ze
1782− |= hat=(map path lobe) :: checkout commit
1783− ^- ankh
1784− %- cosh
1785− %+ roll (~(tap by hat) ~)
1786− |= [[pat=path bar=lobe] ank=ankh]
1787− ^- ankh
1788− %- cosh
1789− ?~ pat
1790− =+ zar=(lobe-to-noun bar)
1791− ank(q [~ (sham zar) zar])
1792− =+ nak=(~(get by r.ank) i.pat)
1793− %= ank
1794− r %+ ~(put by r.ank) i.pat
1795− $(pat t.pat, ank (fall nak _ankh))
1796− ==
1797−```
1798−
1799−If the path is null, then we calculate `zar`, the raw data at the path
1800−`pat` in this version. We produce the given ankh with the correct data.
1801−
1802−Otherwise, we try to get the child we're looking at from our parent
1803−ankh. If it's already been created, this succeeds; otherwise, we simply
1804−create a default blank ankh. We place ourselves in our parent after
1805−recursively computing our children.
1806−
1807−This algorithm really isn't that complicated, but it may not be
1808−immediately obvious why it works. An example should clear everything up.
1809−
1810−Suppose `hat` is a map of the following information.
1811−
1812−```
1813− /greeting --> "customary upon meeting"
1814− /greeting/english --> "hello"
1815− /greeting/spanish --> "hola"
1816− /greeting/russian/short --> "привет"
1817− /greeting/russian/long --> "Здравствуйте"
1818− /farewell/russian --> "до свидания"
1819−```
1820−
1821−Furthermore, let's say that we process them in this order:
1822−
1823−```
1824− /greeting/english
1825− /greeting/russian/short
1826− /greeting/russian/long
1827− /greeting
1828− /greeting/spanish
1829− /farewell/russian
1830−```
1831−
1832−Then, the first path we process is `/greeting/english` . Since our path
1833−is not null, we try to get `nak`, but because our ankh is blank at this
1834−point it doesn't find anything. Thus, update our blank top-level ankh
1835−with a child `%greeting`. and recurse with the blank `nak` to create the
1836−ankh of the new child.
1837−
1838−In the recursion, we our path is `/english` and our ankh is again blank.
1839−We try to get the `english` child of our ankh, but this of course fails.
1840−Thus, we update our blank `/greeting` ankh with a child `english`
1841−produced by recursing.
1842−
1843−Now our path is null, so we call `++lobe-to-noun` to get the actual
1844−data, and we place it in the brand-new ankh.
1845−
1846−Next, we process `/greeting/russian/short`. Since our path is not null,
1847−we try to get the child named `%greeting`, which does exist since we
1848−created it earlier. We put modify this child by recursing on it. Our
1849−path is now `/russian/short`, so we look for a `%russian` child in our
1850−`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
1851−path is now `/short`, so we look for a `%short` child in our
1852−`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
1853−Now our path is null, so we set the contents of this node to `"привет"`,
1854−and we're done processing this path.
1855−
1856−Next, we process `/greeting/russian/long`. This proceeds similarly to
1857−the previous except that now the ankh for `/greeting/russian` already
1858−exists, so we simply reuse it rather than creating a new one. Of course,
1859−we still must create a new `/greeting/russian/long` ankh.
1860−
1861−Next, we process `/greeting`. This ankh already exists, so after we've
1862−recursed once, our path is null, and our ankh is not blank -- it already
1863−has two children (and two grandchildren). We don't touch those, though,
1864−since a node may be both a file and a directory. We just add the
1865−contents of the file -- "customary upon meeting" -- to the existing
1866−ankh.
1867−
1868−Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
1869−already exists, but it doesn't have a `%spanish` child, so we create
1870−that, taking care not to disturb the contents of the `/greeting` file.
1871−We put "hola" into the ankh and call it good.
1872−
1873−Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
1874−doesn't exist, so we create it. Clearly the newly-created ankh doesn't
1875−have any children, so we have to add a `%russian` child, and in this
1876−child we put our last content -- "до свидания".
1877−
1878−We hope it's fairly obvious that the order we process the paths doesn't
1879−affect the final ankh tree. The tree will be constructed in a very
1880−different order depending on what order the paths come in, but the
1881−resulting tree is independent of order.
1882−
1883−At any rate, we were talking about something important, weren't we? If
1884−you recall, that concludes our discussion of `++rewind`, which was
1885−called from `++read-at-aeon`. In summary, `++rewind` returns a context
1886−in which our current state is (very nearly) as it was when the specified
1887−version of the desk was the head. This allows `++read-at-aeon` to call
1888−`++read` to read the requested information.
1889−
1890−```hoon
1891− ++ read :: read:ze
1892− |= mun=mood :: read at point
1893− ^- (unit)
1894− ?: ?=(%v p.mun)
1895− [~ `dome`+<+<.read]
1896− ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
1897− ?^(r.mun ~ [~ let])
1898− ?: ?=(%w p.mun)
1899− =+ ^= yak
1900− %- tako-to-yaki
1901− %- aeon-to-tako
1902− let
1903− ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
1904− ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
1905− (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
1906−```
1907−
1908−If we're requesting the dome, then we just return that immediately.
1909−
1910−If we're requesting the revision number of the desk and we're not
1911−requesting it by number, then we just return the current number of this
1912−desk. Note of course that this was really already handled in
1913−`++read-at-aeon`.
1914−
1915−If we're requesting a `%w` with a specific revision number, then we do
1916−something or other with the commit there. It's kind of weird, and it
1917−doesn't seem to work, so we'll ignore this case.
1918−
1919−Otherwise, we descend into the ankh tree to the given path with
1920−`++descend-path:zu`, and then we handle specific request in `++query`.
1921−
1922−```hoon
1923− ++ descend-path :: descend recursively
1924− |= way=path
1925− ^+ +>
1926− ?~(way +> $(way t.way, +> (descend i.way)))
1927−```
1928−
1929−This is simple recursion down into the ankh tree. `++descend` descends
1930−one level, so this will eventually get us down to the path we want.
1931−
1932−```hoon
1933− ++ descend :: descend
1934− |= lol=@ta
1935− ^+ +>
1936− =+ you=(~(get by r.ank) lol)
1937− +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
1938−```
1939−
1940−`ram` is the path that we're at, so to descend one level we push the
1941−name of this level onto that path. We update the ankh with the correct
1942−one at that path if it exists; else we create a blank one.
1943−
1944−Once we've decscended to the correct level, we need to actually deal
1945−with the request.
1946−
1947−```hoon
1948− ++ query :: query:ze
1949− |= ren=?(%u %v %x %y %z) :: endpoint query
1950− ^- (unit ,*)
1951− ?- ren
1952− %u [~ `rang`+<+>.query]
1953− %v [~ `dome`+<+<.query]
1954− %x ?~(q.ank ~ [~ q.u.q.ank])
1955− %y [~ as-arch]
1956− %z [~ ank]
1957− ==
1958−```
1959−
1960−Now that everything's set up, it's really easy. If they're requesting
1961−the rang, dome, or ankh, we give it to them. If the contents of a file,
1962−we give it to them if it is in fact a file. If the `arch`, then we
1963−calculate it with `++as-arch`.
1964−
1965−```hoon
1966− ++ as-arch :: as-arch:ze
1967− ^- arch :: arch report
1968− :+ p.ank
1969− ?~(q.ank ~ [~ p.u.q.ank])
1970− |- ^- (map ,@ta ,~)
1971− ?~ r.ank ~
1972− [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
1973−```
1974−
1975−This very simply strips out all the "real" data and returns just our own
1976−hash, the hash of the file contents (if we're a file), and a map of the
1977−names of our immediate children.
1978−
1979−## Lifecycle of a Local Subscription
1980−
1981−A subscription to a range of revisions of a desk initially follows the
1982−same path that a single read does. In `++aver`, we checked the head of
1983−the given rave. If the head was `&`, then it was a single request, so we
1984−handled it above. If `|`, then we handle it with the following code.
1985−
1986−```hoon
1987− =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
1988− ?~ nab
1989− ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
1990− (duce hen (rive rav))
1991− =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
1992− ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
1993− (blub hen)
1994− =+ top=?~(huy let.dom u.huy)
1995− =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
1996− =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
1997− =. +>.$
1998− ?: =(sar ear) +>.$
1999− =+ fud=(~(make-nako ze lim dom ran) u.nab top)
2000− (bleb hen u.nab fud)
2001− ?^ huy
2002− (blub hen)
2003− =+ ^= ptr ^- case
2004− [%ud +(let.dom)]
2005− (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
2006− ==
2007−```
2008−
2009−Recall that `++case-to-aeon:ze` produces the revision number that a case
2010−corresponds to, if it corresponds to any. If it doesn't yet correspond
2011−to a revision, then it produces null.
2012−
2013−Thus, we first check to see if we've even gotten to the beginning of the
2014−range of revisions requested. If not, then we assert that we haven't yet
2015−gotten to the end of the range either, because that would be really
2016−strange. If not, then we immediately call `++duce`, which, if you
2017−recall, for a local request, simply puts this duct and rove into our
2018−cult `qyx`, so that we know who to respond to when the revision does
2019−appear.
2020−
2021−If we've already gotten to the first revision, then we can produce some
2022−content immediately. If we've also gotten to the final revision, and
2023−that revision is earlier than the start revision, then it's a bad
2024−request and we call `++blub`, which tells the subscriber that his
2025−subscription will not be satisfied.
2026−
2027−Otherwise, we find the data at the given path at the beginning of the
2028−subscription and at the last available revision in the subscription. If
2029−they're the same, then we don't send a notification. Otherwise, we call
2030−`++gack`, which creates the `++nako` we need to produce. We call
2031−`++bleb` to actually produce the information.
2032−
2033−If we already have the last requested revision, then we also tell the
2034−subscriber with `++blub` that the subscription will receive no further
2035−updates.
2036−
2037−If there will be more revisions in the subscription, then we call
2038−`++duce`, adding the duct to our subscribers. We modify the rove to
2039−start at the next revision since we've already handled all the revisions
2040−up to the present.
2041−
2042−We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
2043−`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
2044−we'll start with that.
2045−
2046−```hoon
2047− ++ bleb :: ship sequence
2048− |= [hen=duct ins=@ud hip=nako]
2049− ^+ +>
2050− (blab hen [%w [%ud ins] ~] hip)
2051−```
2052−
2053−We're given a duct, the beginning revision number, and the nako that
2054−contains the updates since that revision. We use `++blab` to produce
2055−this result to the subscriber. The case is `%w` with a revision number
2056−of the beginning of the subscription, and the data is the nako itself.
2057−
2058−We call `++lobes-at-path:ze` to get the data at the particular path.
2059−
2060−```hoon
2061− ++ lobes-at-path :: lobes-at-path:ze
2062− |= [oan=aeon pax=path] :: data at path
2063− ^- (map path lobe)
2064− ?: =(0 oan) ~
2065− %- mo
2066− %+ skim
2067− %. ~
2068− %~ tap by
2069− =< q
2070− %- tako-to-yaki
2071− %- aeon-to-tako
2072− oan
2073− |= [p=path q=lobe]
2074− ?| ?=(~ pax)
2075− ?& !?=(~ p)
2076− =(-.pax -.p)
2077− $(p +.p, pax +.pax)
2078− == ==
2079−```
2080−
2081−At revision zero, the theoretical common revision between all
2082−repositories, there is no data, so we produce null.
2083−
2084−We get the list of paths (paired with their lobe) in the revision
2085−referred to by the given number and we keep only those paths which begin
2086−with `pax`. Converting to a map, we now have a map from the subpaths at
2087−the given path to the hash of their data. This is simple and efficient
2088−to calculate and compare to later revisions. This allows us to easily
2089−tell if a node or its children have changed.
2090−
2091−Finally, we will describe `++make-nako:ze`.
2092−
2093−```hoon
2094− ++ make-nako :: gack a through b
2095− |= [a=aeon b=aeon]
2096− ^- [(map aeon tako) aeon (set yaki) (set blob)]
2097− :_ :- b
2098− =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
2099− %+ reachable-between-takos
2100− (~(get by hit) a) :: if a not found, a=0
2101− (aeon-to-tako b)
2102− ^- (map aeon tako)
2103− %- mo %+ skim (~(tap by hit) ~)
2104− |= [p=aeon *]
2105− &((gth p a) (lte p b))
2106−```
2107−
2108−We need to produce four things -- the numbers of the new commits, the
2109−number of the latest commit, the new commits themselves, and the new
2110−data itself.
2111−
2112−The first is fairly easy to produce. We simply go over our map of
2113−numbered commits and produce all those numbered greater than `a` and not
2114−greater than `b`.
2115−
2116−The second is even easier to produce -- `b` is clearly our most recent
2117−commit.
2118−
2119−The third and fourth are slightly more interesting, though not too
2120−terribly difficult. First, we call `++reachable-between-takos`.
2121−
2122−```hoon
2123− ++ reachable-between-takos
2124− |= [a=(unit tako) b=tako] :: pack a through b
2125− ^- [(set tako) (set lobe)]
2126− =+ ^= sar
2127− ?~ a ~
2128− (reachable-takos r:(tako-to-yaki u.a))
2129− =+ yak=`yaki`(tako-to-yaki b)
2130− %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
2131− |- ^- (set tako) :: walk onto sar
2132− ?: (~(has in sar) r.yak)
2133− ~
2134− =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
2135− %- ~(uni in ber)
2136− ^- (set tako)
2137− %+ roll p.yak
2138− |= [yek=tako bar=(set tako)]
2139− ^- (set tako)
2140− ?: (~(has in bar) yek) :: save some time
2141− bar
2142− %- ~(uni in bar)
2143− ^$(yak (tako-to-yaki yek))
2144−```
2145−
2146−We take a possible starting commit and a definite ending commit, and we
2147−produce the set of commits and the set of data between them.
2148−
2149−We let `sar` be the set of commits reachable from `a`. If `a` is null,
2150−then obviously no commits are reachable. Otherwise, we call
2151−`++reachable-takos` to calculate this.
2152−
2153−```hoon
2154− ++ reachable-takos :: reachable
2155− |= p=tako :: XX slow
2156− ^- (set tako)
2157− =+ y=(tako-to-yaki p)
2158− =+ t=(~(put in _(set tako)) p)
2159− %+ roll p.y
2160− |= [q=tako s=_t]
2161− ?: (~(has in s) q) :: already done
2162− s :: hence skip
2163− (~(uni in s) ^$(p q)) :: otherwise traverse
2164−```
2165−
2166−We very simply produce the set of the given tako plus its parents,
2167−recursively.
2168−
2169−Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
2170−the ending commit. With this, we create a set that is the union of `sar`
2171−and all takos reachable from `b`.
2172−
2173−We pass `sar` into `++new-lobes` to get all the lobes referenced by any
2174−tako referenced by `a`. The result is passed into `++new-lobes-takos` to
2175−do the same, but not recomputing those in already calculated last
2176−sentence. This produces the sets of takos and lobes we need.
2177−
2178−```hoon
2179− ++ new-lobes :: object hash set
2180− |= [b=(set lobe) a=(set tako)] :: that aren't in b
2181− ^- (set lobe)
2182− %+ roll (~(tap in a) ~)
2183− |= [tak=tako bar=(set lobe)]
2184− ^- (set lobe)
2185− =+ yak=(tako-to-yaki tak)
2186− %+ roll (~(tap by q.yak) ~)
2187− |= [[path lob=lobe] far=_bar]
2188− ^- (set lobe)
2189− ?~ (~(has in b) lob) :: don't need
2190− far
2191− =+ gar=(lobe-to-blob lob)
2192− ?- -.gar
2193− %direct (~(put in far) lob)
2194− %delta (~(put in $(lob q.gar)) lob)
2195− %indirect (~(put in $(lob s.gar)) lob)
2196− ==
2197−```
2198−
2199−Here, we're creating a set of lobes referenced in a commit in `a`. We
2200−start out with `b` as the initial set of lobes, so we don't need to
2201−recompute any of the lobes referenced in there.
2202−
2203−The algorithm is pretty simple, so we won't bore you with the details.
2204−We simply traverse every commit in `a`, looking at every blob referenced
2205−there, and, if it's not already in `b`, we add it to `b`. In the case of
2206−a direct blob, we're done. For a delta or an indirect blob, we
2207−recursively add every blob referenced within the blob.
2208−
2209−```hoon
2210− ++ new-lobes-takos :: garg & repack
2211− |= [b=(set lobe) a=(set tako)]
2212− ^- [(set tako) (set lobe)]
2213− [a (new-lobes b a)]
2214−```
2215−
2216−Here, we just update the set of lobes we're given with the commits we're
2217−given and produce both sets.
2218−
2219−This concludes our discussion of a local subscription.
2220−
2221−## Lifecycle of a Foreign Read or Subscription
2222−
2223−Foreign reads and subscriptions are handled in much the same way as
2224−local ones. The interface is the same -- a vane or app sends a `%warp`
2225−kiss with the request. The difference is simply that the `sock` refers
2226−to the foreign ship.
2227−
2228−Thus, we start in the same place -- in `++call`, handling `%warp`.
2229−However, since the two side of the `sock` are different, we follow a
2230−different path.
2231−
2232−```hoon
2233− =+ wex=(do now p.q.hic p.q.q.hic ruf)
2234− =+ ^= woo
2235− ?~ q.q.q.hic
2236− abet:(ease:wex hen)
2237− abet:(eave:wex hen u.q.q.q.hic)
2238− [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
2239−```
2240−
2241−If we compare this to how the local case was handled, we see that it's
2242−not all that different. We use `++do` rather than `++un` and `++de` to
2243−set up the core for the foreign ship. This gives us a `++de` core, so we
2244−either cancel or begin the request by calling `++ease` or `++eave`,
2245−exactly as in the local case. In either case, we call `++abet:de` to
2246−resolve our various types of output into actual moves, as described in
2247−the local case. Finally, we call `++posh` to update our raft, putting
2248−the modified rung into the raft.
2249−
2250−We'll first trace through `++do`.
2251−
2252−```hoon
2253− ++ do
2254− |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
2255− =+ ^= rug ^- rung
2256− =+ rug=(~(get by hoy.ruf) him)
2257− ?^(rug u.rug *rung)
2258− =+ ^= red ^- rede
2259− =+ yit=(~(get by rus.rug) syd)
2260− ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
2261− ((de now ~ ~) [who him] syd red ran.ruf)
2262−```
2263−
2264−If we already have a rung for this foreign ship, then we use that.
2265−Otherwise, we create a new blank one. If we already have a rede in this
2266−rung, then we use that, otherwise we create a blank one. An important
2267−point to note here is that we let `ref` in the rede be `[~ *rind]`.
2268−Recall, for domestic desks `ref` is null. We use this to distinguish
2269−between foreign and domestic desks in `++de`.
2270−
2271−With this information, we create a `++de` core as usual.
2272−
2273−Although we've already covered `++ease` and `++eave`, we'll go through
2274−them quickly again, highlighting the case of foreign request.
2275−
2276−```hoon
2277− ++ ease :: release request
2278− |= hen=duct
2279− ^+ +>
2280− ?~ ref +>
2281− =+ rov=(~(got by qyx) hen)
2282− =. qyx (~(del by qyx) hen)
2283− (mabe rov (cury best hen))
2284− =. qyx (~(del by qyx) hen)
2285− |- ^+ +>+.$
2286− =+ nux=(~(get by fod.u.ref) hen)
2287− ?~ nux +>+.$
2288− %= +>+.$
2289− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
2290− fod.u.ref (~(del by fod.u.ref) hen)
2291− bom.u.ref (~(del by bom.u.ref) u.nux)
2292− ==
2293−```
2294−
2295−Here, we still remove the duct from our cult (we maintain a cult even
2296−for foreign desks), but we also need to tell the foreign desk to cancel
2297−our subscription. We do this by sending a request (by appending to
2298−`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
2299−the foreign ship to cancel the subscription. Since we don't anymore
2300−expect a response on this duct, we remove it from `fod` and `bom`, which
2301−are the maps between ducts, raves, and request sequence numbers.
2302−Basically, we remove every trace of the subscription from our request
2303−manager.
2304−
2305−In the case of `++eave`, where we're creating a new request, everything
2306−is exactly identical to the case of the local request except `++duce`.
2307−We said that `++duce` simply puts the request into our cult. This is
2308−true for a domestic request, but distinctly untrue for foreign requests.
2309−
2310−```hoon
2311− ++ duce :: produce request
2312− |= [hen=duct rov=rove]
2313− ^+ +>
2314− =. qyx (~(put by qyx) hen rov)
2315− ?~ ref +>.$
2316− |- ^+ +>+.$ :: XX why?
2317− =+ rav=(reve rov)
2318− =+ ^= vaw ^- rave
2319− ?. ?=([%& %v *] rav) rav
2320− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
2321− =+ inx=nix.u.ref
2322− %= +>+.$
2323− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
2324− nix.u.ref +(nix.u.ref)
2325− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
2326− fod.u.ref (~(put by fod.u.ref) hen inx)
2327− ==
2328−```
2329−
2330−If we have a request manager (i.e. this is a foreign desk), then we do
2331−the approximate inverse of `++ease`. We create a rave out of the given
2332−request and send it off to the foreign desk by putting it in `say`. Note
2333−that the rave is created to request the information starting at the next
2334−revision number. Since this is a new request, we put it into `fod` and
2335−`bom` to associate the request with its duct and its sequence number.
2336−Since we're using another sequence number, we must increment `nix`,
2337−which represents the next available sequence number.
2338−
2339−And that's really it for this side of the request. Requesting foreign
2340−information isn't that hard. Let's see what it looks like on the other
2341−side. When we get a request from another ship for information on our
2342−ship, that comes to us in the form of a `%wart` from ames.
2343−
2344−We handle a `%wart` in `++call`, right next to where we handle the
2345−`%warp` case.
2346−
2347−```hoon
2348− %wart
2349− ?> ?=(%re q.q.hic)
2350− =+ ryf=((hard riff) s.q.hic)
2351− :_ ..^$
2352− :~ :- hen
2353− :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
2354− %c
2355− [%warp [p.p.q.hic p.p.q.hic] ryf]
2356− ==
2357−```
2358−
2359−Every request we receive should be of type `riff`, so we coerce it into
2360−that type. We just convert this into a new `%warp` kiss that we pass to
2361−ourself. This gets handled like normal, as a local request. When the
2362−request produces a value, it does so like normal as a `%writ`, which is
2363−returned to `++take` along the path we just sent it on.
2364−
2365−```hoon
2366− %writ
2367− ?> ?=([@ @ *] tea)
2368− =+ our=(need (slaw %p i.tea))
2369− =+ him=(need (slaw %p i.t.tea))
2370− :_ ..^$
2371− :~ :- hen
2372− [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
2373− ==
2374−```
2375−
2376−Since we encoded the ship we need to respond to in the path, we can just
2377−pass our `%want` back to ames, so that we tell the requesting ship about
2378−the new data.
2379−
2380−This comes back to the original ship as a `%waft` from ames, which comes
2381−into `++take`, right next to where we handled `%writ`.
2382−
2383−```hoon
2384− %waft
2385− ?> ?=([@ @ ~] tea)
2386− =+ syd=(need (slaw %tas i.tea))
2387− =+ inx=(need (slaw %ud i.t.tea))
2388− =+ ^= zat
2389− =< wake
2390− (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
2391− =^ mos ruf
2392− =+ zot=abet.zat
2393− [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
2394− [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
2395−```
2396−
2397−This gets the desk and sequence number from the path the request was
2398−sent over. This determines exactly which request is being responded to.
2399−We call `++knit:de` to apply the changes to our local desk, and we call
2400−`++wake` to update our subscribers. Then we call `++abet:de` and
2401−`++posh` as normal (like in `++eave`).
2402−
2403−We'll examine `++knit` and `++wake`, in that order.
2404−
2405−```hoon
2406− ++ knit :: external change
2407− |= [inx=@ud rot=riot]
2408− ^+ +>
2409− ?> ?=(^ ref)
2410− |- ^+ +>+.$
2411− =+ ruv=(~(get by bom.u.ref) inx)
2412− ?~ ruv +>+.$
2413− => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
2414− %_ .
2415− bom.u.ref (~(del by bom.u.ref) inx)
2416− fod.u.ref (~(del by fod.u.ref) p.u.ruv)
2417− ==
2418− ?~ rot
2419− =+ rav=`rave`q.u.ruv
2420− %= +>+.$
2421− lim
2422− ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
2423− ::
2424− haw.u.ref
2425− ?. ?=(& -.rav) haw.u.ref
2426− (~(put by haw.u.ref) p.rav ~)
2427− ==
2428− ?< ?=(%v p.p.u.rot)
2429− =. haw.u.ref
2430− (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
2431− ?. ?=(%w p.p.u.rot) +>+.$
2432− |- ^+ +>+.^$
2433− =+ nez=[%w [%ud let.dom] ~]
2434− =+ nex=(~(get by haw.u.ref) nez)
2435− ?~ nex +>+.^$
2436− ?~ u.nex +>+.^$ :: should never happen
2437− =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
2438− ?>(?=(^ ref.roo) roo)
2439− %= $
2440− haw.u.ref (~(del by haw.u.ref) nez)
2441− ==
2442−```
2443−
2444−This is kind of a long gate, but don't worry, it's not bad at all.
2445−
2446−First, we assert that we're not a domestic desk. That wouldn't make any
2447−sense at all.
2448−
2449−Since we have the sequence number of the request, we can get the duct
2450−and rave from `bom` in our request manager. If we didn't actually
2451−request this data (or the request was canceled before we got it), then
2452−we do nothing.
2453−
2454−Else, we remove the request from `bom` and `fod` unless this was a
2455−subscription request and we didn't receive a null riot (which would
2456−indicate the last message on the subscription).
2457−
2458−Now, if we received a null riot, then if this was a subscription request
2459−by date, then we update `lim` in our request manager (representing the
2460−latest time at which we have complete information for this desk) to the
2461−date that was requested. If this was a single read request, then we put
2462−the result in our simple cache `haw` to make future requests faster.
2463−Then we're done.
2464−
2465−If we received actual data, then we put it into our cache `haw`. Unless
2466−it's a `%w` request, we're done.
2467−
2468−If it is a `%w` request, then we try to get the `%w` at our current head
2469−from the cache. In general, that should be the thing we just put in a
2470−moment ago, but that is not guaranteed. The most common case where this
2471−is different is when we receive desk updates out of order. At any rate,
2472−since we now have new information, we need to apply it to our local copy
2473−of the desk. We do so in `++edis`, and then we remove the stuff we just
2474−applied from the cache, since it's not really a true "single read", like
2475−what should really be in the cache.
2476−
2477−```hoon
2478− ++ edis :: apply subscription
2479− |= nak=nako
2480− ^+ +>
2481− %= +>
2482− hit.dom (~(uni by hit.dom) gar.nak)
2483− let.dom let.nak
2484− lat.ran %+ roll (~(tap in bar.nak) ~)
2485− =< .(yeb lat.ran)
2486− |= [sar=blob yeb=(map lobe blob)]
2487− =+ zax=(blob-to-lobe sar)
2488− %+ ~(put by yeb) zax sar
2489− hut.ran %+ roll (~(tap in lar.nak) ~)
2490− =< .(yeb hut.ran)
2491− |= [sar=yaki yeb=(map tako yaki)]
2492− %+ ~(put by yeb) r.sar sar
2493− ==
2494−```
2495−
2496−This shows, of course, exactly why nako is defined the way it is. To
2497−become completely up to date with the foreign desk, we need to merge
2498−`hit` with the foreign one so that we have all the revision numbers. We
2499−update `let` so that we know which revision is the head.
2500−
2501−We merge the new blobs in `lat`, keying them by their hash, which we get
2502−from a call to `++blob-to-lobe`. Recall that the hash is stored in the
2503−actual blob itself. We do the same thing to the new yakis, putting them
2504−in `hut`, keyed by their hash.
2505−
2506−Now, our local dome should be exactly the same as the foreign one.
2507−
2508−This concludes our discussion of `++knit`. Now the changes have been
2509−applied to our local copy of the desk, and we just need to update our
2510−subscribers. We do so in `++wake:de`.
2511−
2512−```hoon
2513− ++ wake :: update subscribers
2514− ^+ .
2515− =+ xiq=(~(tap by qyx) ~)
2516− =| xaq=(list ,[p=duct q=rove])
2517− |- ^+ ..wake
2518− ?~ xiq
2519− ..wake(qyx (~(gas by *cult) xaq))
2520− ?- -.q.i.xiq
2521− &
2522− =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
2523− ?^ cas
2524− %= $
2525− xiq t.xiq
2526− ..wake ?~ u.cas (blub p.i.xiq)
2527− (blab p.i.xiq p.q.i.xiq u.u.cas)
2528− ==
2529− =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
2530− ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
2531− $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
2532− ::
2533− |
2534− =+ mot=`moot`p.q.i.xiq
2535− =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
2536− ?~ nab
2537− $(xiq t.xiq, xaq [i.xiq xaq])
2538− =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
2539− ?~ huy
2540− =+ ptr=[%ud +(let.dom)]
2541− %= $
2542− xiq t.xiq
2543− xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
2544− ..wake =+ ^= ear
2545− (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
2546− ?: =(s.p.q.i.xiq ear) ..wake
2547− =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
2548− (bleb p.i.xiq let.dom fud)
2549− ==
2550− %= $
2551− xiq t.xiq
2552− ..wake =- (blub:- p.i.xiq)
2553− =+ ^= ear
2554− (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
2555− ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
2556− =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
2557− (bleb p.i.xiq +(u.nab) fud)
2558− ==
2559− ==
2560− --
2561−```
2562−
2563−This is even longer than `++knit`, but it's pretty similar to `++eave`.
2564−We loop through each of our subscribers `xiq`, processing each in turn.
2565−When we're done, we just put the remaining subscribers back in our
2566−subscriber list.
2567−
2568−If the subscriber is a single read, then, if this is a foreign desk
2569−(note that `++wake` is called from other arms, and not only on foreign
2570−desks). Obviously, if we find an identical request there, then we can
2571−produce the result immediately. Referential transparency for the win. We
2572−produce the result with a call to `++blab`. If this is a foreign desk
2573−but the result is not in the cache, then we produce `++blub` (canceled
2574−subscription with no data) for reasons entirely opaque to me. Seriously,
2575−it seems like we should wait until we get an actual response to the
2576−request. If someone figures out why this is, let me know. At any rate,
2577−it seems to work.
2578−
2579−If this is a domestic desk, then we check to see if the case exists yet.
2580−If it doesn't, then we simply move on to the next subscriber, consing
2581−this one onto `xaq` so that we can check again the next time around. If
2582−it does exist, then we call `++balk` to fulfill the request and produce
2583−it.
2584−
2585−`++balk` is very simple, so we'll describe it here before we get to the
2586−subscription case.
2587−
2588−```hoon
2589− ++ balk :: read and send
2590− |= [hen=duct oan=@ud mun=mood]
2591− ^+ +>
2592− =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
2593− ?~ vid (blub hen) (blab hen mun u.vid)
2594−```
2595−
2596−We call `++read-at-aeon` on the given request and aeon. If you recall,
2597−this processes a `mood` at a particular aeon and produces the result, if
2598−there is one. If there is data at the requested location, then we
2599−produce it with `++blab`. Else, we call `++blub` to notify the
2600−subscriber that no data can ever come over this subscriptioin since it
2601−is now impossible for there to ever be data for the given request.
2602−Because referential transparency.
2603−
2604−At any rate, back to `++wake`. If the given rave is a subscription
2605−request, then we proceed similarly to how we do in `++eave`. We first
2606−try to get the aeon referred to by the starting case. If it doesn't
2607−exist yet, then we can't do anything interesting with this subscription,
2608−so we move on to the next one.
2609−
2610−Otherwise, we try to get the aeon referred to by the ending case. If it
2611−doesn't exist yet, then we produce all the information we can. We call
2612−`++lobes-at-path` at the given aeon and path to see if the requested
2613−path has actually changed. If it hasn't, then we don't produce anything;
2614−else, we produce the correct nako by calling `++bleb` on the result of
2615−`++make-nako`, as in `++eave`. At any rate, we move on to the next
2616−subscription, putting back into our cult the current subscription with a
2617−new start case of the next aeon after the present.
2618−
2619−If the aeon referred to by the ending case does exist, then we drop this
2620−subscriber from our cult and satisfy its request immediately. This is
2621−the same as before -- we check to see if the data at the path has
2622−actually changed, producing it if it has; else, we call `++blub` since
2623−no more data can be produced over this subscription.
2624−
2625−This concludes our discussion of foreign requests.
arvo/dill.mddeleted−23
@@ -1,23 +0,0 @@
1−+++
2−title = "Dill"
3−weight = 4
4−template = "doc.html"
5−+++
6−Our terminal driver.
7−
8−Unix sends keyboard events to `%dill` from either the console or telnet,
9−and `%dill` produces terminal output. The only app that should directly
10−talk to `%dill` is the terminal app. Command-line apps are run by,
11−receive input from, and produce output to, the `%shell` app, which is
12−controlled by `%terminal`, which talks to `%dill`, which talks to unix.
13−Clay also uses `%dill` directly to print out the filesystem change
14−events, but this is questionable behavior.
15−
16−`%dill` has two main components. First, it controls the terminal on a
17−very basic, event-by-event level. This includes keeping track of things
18−like the dimensions of the terminal, the prompt type (plain text or
19−password), which duct to produce effects on, and so forth. Second, it
20−handles terminal events, keystroke by keystroke. Most characters are
21−simply pushed onto the buffer and blitted to the screen, but some
22−characters, including control-modified keys, arrow keys, etc. require
23−special handling. Most of the readline functionality is in `%dill`.
arvo/eyre.mddeleted−716
@@ -1,716 +0,0 @@
1−+++
2−title = "Eyre"
3−weight = 5
4−template = "doc.html"
5−+++
6−Our HTTP server.
7−
8−Unix sends http messages to `%eyre`, and `%eyre` produces http messages
9−in response. In general, apps and vanes do not call `%eyre`; rather,
10−`%eyre` calls apps and vanes. `%eyre` uses `%ford` and `%gall` to
11−functionally publish pages and facilitate communication with apps.
12−
13−`%eyre` primarily parses web requests and handles them in a variety of
14−ways, depending on the control string. Nearly all of these are
15−essentially stateless, like functional publishing with `%ford`.
16−Additionally, there's a fairly significant component that handles
17−`%gall` messaging and subscriptions, which must be stateful.
18−
19−## Reference
20−
21−### State
22−
23−Stored
24−
25−- `++bolo`
26−- `++cyst`
27−- `++stem`
28−
29−Runtime
30−
31−- `perk`
32− + `perk-auth`
33−- `pest`
34−- `even`
35−
36−### Cores
37−
38−- `++handle`
39− + `++parse`
40− - `++as...`
41−- `++ya`
42−- `++ix`
43−
44−## Commentary
45−
46−
47−Let us follow the loading of a simple cli app, as it bounces from
48−browser to server to browser and back.
49−
50−### Initial request
51−
52−An http request for `http://sampel-sipnym.urbit.org/cli` will be [redirected](dns)
53−to the `%eyre` on ~sampel-sipnym, and come in as a `%this` task.
54−
55−From arvo, requests enter `++call`, which after some type reification are passed
56−along to `++apex:ye`. In the case of a `%this` task, its components are
57−parsed(see `++zest:epur`, `++eat-headers`) and handed off to `++handle`, wrapped
58−in `++emule` to produce a `++fail` page in case of error. `++apex:handle` will
59−`++process` the request to a `pest` or a `++done` core, and in the former case
60−`++resolve` the pest into an outgoing card.
61−
62−XX it also seems to affect the current ship, test that serving ship name is consistently correct
63−
64−The pest is produced by `++process`, which will first further `++parse` the
65−request, and if this does not make the response immediately obvious,
66−`++process-parsed` the resulting `perk`.
67−
68−`++parse` produces the `perk`, by attempting to interpret the `pork`(url path)
69−[`++as-magic-filename`](#mage), `++as-beam`, and `++as-aux-request`. In this
70−case, `/cli` is parsed by the second case as a `%beam` query to `/=cli=`: a path
71−which starts with a valid ship name is expected to be a full clay(well, ford)
72−path, and one starting with a term implies the current serving ship and a case
73−of `0`, the current revision.
74−
75−XX spur: when the desks are merged, `/cli` shall point to `/=main=/pub/cli`
76−
77−The parsed `perk` generates a `%f %boil` note, `mark`ed as its extension(here
78−defaulting to `%urb`) and `wire`d with `~` to return unaltered to the client. It
79−goes on to `++resolve` by being passed to `++ford-get-beam`, which translates
80−the perk it into a `%boil` `++ford-req`, adding an `++fcgi` path-segment
81−containing query string and `++fcgi-cred:for-client` auth information.
82−
83−`%ford`s translation of `/=cli=/hymn/hook` to a self-refreshing `%urb` html page
84−[deserves its own commentary](/docs/arvo/ford#commentary), but
85−we resume in `%eyre` when the `%made` sign arrives in `++take`, and soon after
86−`++axon:ye`. There the `wire`, or rather the `whir` it has been verified to be,
87−determines that the response should be served immediately. However, as the mark
88−is not `%mime`, another trip to `%ford` is required to encode it, on the same
89−wire; afterwards, the value of the `%mime` cage is verified to be of the correct type, and finally
90−delivered back up the requesting duct as a successful `%thou` HTTP response.
91−
92−XX `%cast %mime` used to be in ford-get-beam, is there a reason it was removed?
93−
94−## Back into the breach, or: auxilary requests
95−
96−Now, it was mentioned that this result is self-refreshing: the `%urb`
97−translation door injects a `;script@"/~/on/{deps}.js"` into every page, `deps`
98−is a ford-readable hash of the set of resources that page construction depended
99−on.
100−
101−This triggers another `%this` request. Its handling is identical to that of
102−`/cli` up until `++parse`, where it is seen not `++as-beam` but
103−`++as-aux-request`(auxillary requests starting with `/~/` or `/~~/`).
104−`/on/[hash]` is a long-`%poll`, which `++process-parsed`, for a `.js` mark,
105−answers with a direct `%js`. Its contents are the static `++poll:js`, which
106−initiates the long-polling loop, run against an injected `urb.js` of
107−`{poll:[hash]}`.
108−
109−A `%js` `pest` is `resolve`d as a `text/javascript` success `%this`.
110−
111−When `poll.js` is received by the client, it opens an `XMLHttpRequest` for
112−`/~/on/{window.urb.poll}.json`, bringing us back to `%poll:process`.
113−
114−In the case of a non-`%js` `/~/on/`, `%poll:process-parsed` turns into a
115−`++new-dependency`, which stores the listening duct, and `pass-note`s a `%wasp`
116−with the deps-hash back to `%ford` whence it came. While this occured, the page
117−has loaded.
118−
119−Some indeterminate amount of time afterwards, with dropped `/~/on/{...}.json`s
120−being retried upon expiring and also being stored, a `%news` sign arrives in
121−`++axon`, and the hash in question is retrieved from the wire, and the listening
122−long-polls retrieved by the hash. Each receives a 205 "Reload parent view" HTTP
123−response, which `poll.js` dutifully executes, and a fixed typo of markdown is
124−rendered.
125−
126−## Authentication
127−
128−Now, while this accurately reflects the presentation of e.g. a markdown file,
129−`/cli` is an application front-end, and one that permits only owner access. Its
130−second script is `@"/~~/~/at/main/lib/urb.js"`, semantically equivalent to
131−`/~/as/own/~/at/main/lib/urb.js`, and handled as follows.
132−
133−In `++as-aux-request`, `%as %own` becomes `%auth %get our` perk, which
134−`++process` passes to `++process-parsed` passes to `++process-auth`. There, a
135−`yac` "ya" core is built `++for-client`: a `++cookie-prefix`, which is just the
136−serving ship name, is used to get a `++session-from-cookies`, here nil as the
137−client has no cookie set. In lieu of a cookie, a `++new-ya` is constructed, with
138−a random token `hole` and a `++new-cyst` which fills out `cyst` session state
139−from request data.
140−
141−Returning to `++process-auth`, `%get` checks if the yac is authenticated with
142−the requested credentials(`anon` requests are always granted), which for the
143−fresh new `cyst` is not the case (more on success [later](#auth-ok)). Unless
144−authenticating as a [foreign ship](#xeno), the only thing left is to
145−`++show-login-page`, which detects that the requested resource is not `%html`,
146−and produces a `%red` pest. For `%js`, `%red`irections `++resolve` to
147−`++auth-redir:js`, a line of javascript which prepends `/~~` to the url path.
148−
149−The owner-authenticated main page request similarly ends in `++show-login-page`,
150−which for the empty session is an `[%htme ++login-page:xml]`, `resolve`d to
151−`++give-html` with a 401 "unathorized".
152−
153−The login page shows a simple prompt, and requests `/~/at/auth.js` to handle the
154−submission. And so we are, once again, attempting to divine if what we're doing
155−makes sense `++as-aux-request`.
156−
157−To understand `/~/at`, there will first be a brief diversion to `~/auth.json`.
158−`auth.json`, perk `[%auth %json]`, in `++process-auth` serves `++stat-json:ya`,
159−containing such information as the serving ship, which identities are associated
160−with this session, and `oryx`, a CSRF token. An oryx must be present on all
161−stateful requests, in this case executing a log in. It also saves the new/old
162−session using `abet`.
163−
164−XX explain `ixor` here and not [later](#ixor)?
165−
166−`/~/at` is an alternate interface, which injects `auth.json` data into the
167−requested file. `/~/at/auth.js`, then, is a request for the built-in `auth:js`
168−(parsed to and processed from an `[%auth %js ~]` perk), with session data added
169−as `window.urb`. And indeed, ``[`%js /~/at/auth]`` is parsed to
170−``[%auth at [`%js /auth]``, which in `++process-auth` is re-`process`ed to
171−`[%js ++auth:js]`, which is `++resolve`d after an `++add-json` of
172−the relevant data. The yac cookies are also passed to `resolve`, which
173−`++add-cookies` injects into the `httr`.
174−
175−It is at this point that there is first occasion for user input, namely the password.
176−
177−The `auth:js` script sends a `PUT` request, also to `/~/auth.json`. In `parse`,
178−the first nontrivial `++check-oryx` occurs, `++grab-body` the request oryx and
179−ensuring it is recorded for the session. The request parsed with `++need-body`
180−to a `[%auth %try {password}]` perk. `%get:process-auth` checks it against
181−`++load-secret`, upon success updates the session with `++logon:ya`, and
182−serves a fresh `auth.json` which reflects the changed `user`. Upon receiving
183−this, the page is refreshed to retry the original request.
184−
185−### Post-authentication: app communication.
186−
187−Upon refresh, `/~~/cli` brings us for the third time to `%get:process-auth`, but
188−this time the cookie is set, and the `yac` fetched contains the serving ship as
189−authenticated. The `++handle` sample is updated to reflect the requesting ship,
190−and the `process` continues for the rest of the pork, once again serving the
191−ford page.
192−
193−The `/~/on/[deps].json` poll starts anew, and `/~~/~/at/main/lib/urb.js` we now
194−know to serve the window.urb necessary to make requests, and the `urb.js`
195−standard library which extends it with a number of wrappers to them and other
196−useful functions.
197−
198−One of those functions is `urb.bind`, which is used to subscribe to application
199−data. Userspace javascript sets `urb.appl` to `/tic`, and binds `lines` to a
200−`;pre;` text display, using a callback.
201−
202−This triggers a `PUT` to `/~/is/{ixor}/cli/lines.json`, where `ixor` is a hash
203−of `oryx` that identifies the connection. `++as-aux-request`, an `%is` is a
204−`%subs` subscription update update, which for `%put` forwards to
205−`++add-subs:ix`, the ix core fetched `++for-view` by hashing the request
206−`++oryx-to-ixor`.
207−
208−A view has all the state associated with a client that must be
209−remembered between events. In this case, this is what app/path the request duct
210−is associated with; but mainly, `++add-subs:ix` will `pass-note` to `%gall` so
211−it `%show`s the data on the path, current and future.
212−
213−This will immediately(assuming the ship is local) result in a `%nice` by the
214−`/cli` app, returning `{ok:true}` `++nice-json` to `urb.bind`'s second callback
215−as `{ok:true}`. The initial `%rush` results also arrive, and in `++axon` are
216−converted to json using `++back`(ford `%cast` wrapper), and when `%made` get
217−passed to `++get-rush:ix`. There the source application/path are decoded by
218−duct, and then the full event goes to `++get-even`; `++add-even` inserts it to
219−the queue, and as there is no long poll it simply stays there.
220−
221−Upon receipt, the client realizes the long-poll isn't actually running, so that
222−is started using `urb.poll`. At `/~/of/{ixor}`, perk
223−`[%view ixor ~ {sequence-number}]`, it is `process`ed by `++poll:ix` (the cyst
224−is retrieved by `++ire-ix` form global state, using the perk `ixor`): the
225−sequence number is in the past, so the previously received `%rush` is
226−`++give-even`. After deleting the previous message in the queue and invoking
227−`++pass-took` to signal `%gall` of this occurrence, the data is annotated with
228−the source app+path `++subs-to-json`, and returned to the polling duct.
229−
230−On the client, the user callback receives the `/cli` history, and displays it on
231−the page. The `/~/of` long poll is continued, this time reaching `++poll:ix`
232−with the "pending" sequence number, and being stored in the `cyst` for its troubles.
233−
234−Its next update proceeds idenitcally, but first it must be triggered, which
235−happens when the user enters "(add 2 2)\n", firing an `urb.send` from the event
236−handler. This sends a `POST` request to `/~/to/cli/json.json`, perk `%mess`,
237−`++process`ed to a `%g %mess`. Were the mark not `%json`, a `%ford` conversion
238−would occur first, and `%made:axon` would send the gall message proper. In
239−either case, eventually a `%mean` or `%nice` arrives, is encoded as json, and
240−sent to the client callback.
241−
242−## A path not taken: magic filenames
243−
244−The `/robots.txt` and `/favicon.(ico|png)` files are static, and served
245−immediately when caught by a `++parse`.
246−
247−XX index.html?
248−
249−## A path not taken: foreign auth
250−
251−While this example details a login `/~/as/own`, it is possible to be
252−authenticated as any ship on the network. A request for such seen in
253−`%get:process-auth` is passed to `++foreign-auth:ya`, which sends an
254−`%ames /lon` message to the ship in question. The foreign ship stores the
255−inquiry, calculates(the local) `++our-host` and responds with a `/hat`,
256−containing the redirection host, which is stored by `++foreign-hat`; it is later
257−used to send the client to a `/~/am` url on the foreign client, which acts as a
258−normal login page but later sends the client back. XX expand, basically the
259−status quo is you're logged in and `/~/as/foo` is ignored, just setting your
260−`urb.user` XX
261−
262−
263−### A path not taken: deauthentication
264−
265−`/~/away`, perk `[%away ~]`, produces a static `++logout-page:xml`, which also
266−uses `/~/at/auth.js`, to send a `DELETE /~/auth.json`, perk `[%auth %del]`. This
267−executes `++logoff:ya` for the cookie session, resolving to `++abut` to wipe it
268−from memory.
269−
270−### A path not taken: unsubscription
271−
272−`DELETE /~/is/app/path/within` works much like `PUT /~/is/app/path/within`,
273−`++del-subs:ix` acting as reverse of `++add-subs` by deleting the duct binding
274−and sending `%g %nuke`.
275−
276−
277−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
278−
279−### Appendix A: DNS
280−
281−The `*.urbit.org` domain can be used to access destroyers and cruisers. In the
282−common case oh hosted ships, this is done by dynamic DNS directly to the hosting
283−instance. We do not speak of the uncommon case. When ports are blocked and
284−infrastructure crumbles around you, only imported martian networking can be
285−trusted: the `%get` and `%got` [gram]()s are used to proxy [`%this` requests]() and
286−[`%thou` responses]() respectively.
287−
288−## Specification
289−
290−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.
291−
292−This document outlines the following:
293−
294−1. [`perk`](#perk), a `pork` subset that defines what URLs the client can send to `%eyre`.
295−
296−2. [the values stored on the client](#client), both statically in cookies and dynamically as the `window.urb` object, which facilitate this transaction.
297−
298−3. [`task`](#task), the requests `%eyre` will accept.
299−
300−4. [`gift`](#gift), the responses it will give to those requests.
301−
302−5. [`note`](#note), the set of arvo requests that %eyre makes to the other vanes.
303−
304−6. [`whir`](#whir), a `wire` subset, the associated dynamic state
305−
306−7. [`sign`](#sign), the responses `%eyre` accepts
307−
308−8. [`bolo`](#bolo), the state stored between separate events.
309−
310−## 1. URL structure
311−
312−There exist several URL forms accepted by `%eyre`.
313−
314−### 1.1 Functional request
315−
316−The simplest of them is a static `%f` functional publish request:
317−
318−```
319− GET /[ship]/[desk]/[case]/path/to/file.[mark]
320−```
321−e.g.
322−
323−```
324− /~pittyp-pittyp/main/5/lib/urb.js
325−```
326−A `case` of 0 signifies the most recent version.
327−
328−If no file extension is provided, the default `mark` is `%urb`, which consists of `%html` injected with an auto-refresh script.
329−
330−A shorter form:
331−
332−```
333− /path/to.[mark]
334−```
335−is prepended with the [default request path](#prefix). For example, if `%eyre`
336−is configured with a root of `/<our>/main/0/pub`, then `/doc/arvo` is
337−interpreted as a request for `/=main=/pub/doc/arvo.urb`.
338−
339−Auxiliary paths start with `/~/`, and provide other functionality, such as:
340−
341−### 1.2 Auto-reload
342−
343−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.
344−- `/~/on/[hash].json` retuns `true` when a page may require updating.
345−- `/~/on/[hash].js` is a lightweight script that polls for the above. It is primarily used in error messages.
346−
347−### 1.3 Authentication
348−
349−Authenticated requests are accomplished through sessions, tracked with cookies which are set on the first such request.
350−- `/~/as/[user]/...` is an authenticated request to `...`, where `user` can be a `@p` ship, `'own'`, `'any'`, or `'anon'`.
351− + `'anon'` is a randomly-generated per-session submarine, and requires no further authentication.
352− + `'own'` represents the serving ship. The short form of `/~/as/own/` is `/~~/`
353− + `'any'` requires a network ship, chosen with a prompt if unknown. The short form of `/~/as/any/` is `/_/`
354− + Auth requests are handled in three ways:
355− + 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`.
356− + 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.
357− + III. otherwise, [send a message](#foreign) to the claimed ship, and redirect the user to `https://[foreign-host]/~/am/[ses]/...#[current-host]&?code=[code]`
358−- `/~/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>/...`
359−- `/~/away.html` is a log-out page.
360−- `/~/auth.json` returns `{ship,oryx,user,auth}`: the serving ship, a CSRF token, active user, and all allowed users respectively.
361−- `/~/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.
362−
363−So far, all the paths specified have been GET requests. Authentication, however, requires sending data. This is also done at the `/~/auth.json` endpoint.
364−- `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"}`
365−- `POST {oryx,ship?} /~/auth.json?DELETE` revokes authorization. Response as above.
366−
367−### 1.4 Messaging
368−
369−- `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`.
370−- `POST {oryx, wire, xyro} /~/to/<ship>/[app]/[mark].json` is a foreign message send, as above.
371−
372−### 1.5 Subscriptions
373−
374−- `/~/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.
375− + `/~/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)
376−- `/~/in/[hash].json` is a dual to [`/~/on`](#on-change). It binds `mod` events, which echo the requesting token.
377−- `/~/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.
378−
379−
380−
381−### 1.6 Ablative
382−
383−These interfaces will temporarily exist to aid development, and are to be considered unstable.
384−- `/~/debug/...` access normally inaccessible pages. For example, `/~/debug/as.html` will present the login page, regardless of current session status.
385−
386−
387−## 2. Client state
388−
389−Some information is stored on, and provided to, browser clients
390−
391−### 2.1 Cookies
392−
393−Authenticated users receive a cookie on the domain of `*.urbit.org`. The cookie contains a client session token, keyed by the serving ship.
394−
395−### 2.2 Authentication
396−
397−It is common(e.g. by the `%urb` mark) to set window.urb to the contents of `/~/auth.json`:
398−- `ship` is the serving ship
399−- `oryx` is a unique CSRF token that identifies this view, bound to the session cookie
400−- `ixor` is a hash of `oryx`, used as an insecure view identifier
401−- `user` is the authenticated/generated ship name
402−- `auth` is a list of identities usable by this session
403−
404−### 2.3 Client library
405−
406−To this object, `/main/lib/urb.js` adds helpers:
407−- `app` is an optional app name to send messages to by default
408−- `send({data,mark?='json',app?=urb.app,ship?}, cb?)` delivers messages
409−- `bind({path,app?=urb.app}, cb)` subscribes by path
410−- `drop({path,app?=urb.app}, cb?)` pulls the subscription
411−- `util` is an object containing methods for converting between JavaScript types and Hoon atom odors.
412−
413−## 3. Requests
414−
415−## `[%born port=@ud]`, unix init
416−
417−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)
418−
419−**Gifts given in response:** none.
420−
421−## `[%hiss p=mark q=cage]`, outbound http
422−
423−Userspace http request, converted by `%ford` into an actual `hiss`.
424−
425−**Gifts given in response:** a [`%sigh`]()
426−
427−### 3.1 `[%this httq]`, inbound http
428−
429−The primary `%eyre` request type comes from the host system, and constitutes an inbound http request. It consists of five parts:
430−
431−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`
432−
433−II. `q=meth`, an http method
434−
435−III. `r=@t`, the unparsed URL
436−
437−IV. `s=mess`, an associative list of header keys/values
438−
439−V. `t=(unit octs)`, the request body, if any.
440−
441−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).
442−
443−- A ford request results in a [`%boil` note](#boil).
444−- `/~/[name].js` is generated from [session](#sink) or [view](#stem) state, and [served](#mime) as `%js`.
445−- `/~/am` generates a login page.
446−- `/~/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.
447−- `/~/at` and `/~/auth.json` generate a new `oryx` and store it in the [session state](#sink).
448−- `/~/in` and `/~/is` affect [view state](#stem), possibly sending subscriptions or unsubscriptions to `%f` and `%g` respectively, and are generated from view state.
449−- `/~/on` is saved to the `bolo` by `hash`, and translated to a [`%wasp` note](#wasp).
450−- `/~/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.
451−- `/~/to` transforms into a [`%g` message](#mess).
452−
453−**Gifts given in response:** a [`%thou`](), or a [`%that`](#that) followed by multiple [`%thar`]()s.
454−
455−### 3.2 `[%thud ~]`, inbound close
456−
457−Sent when an unresponded-to request is cancelled. The [live](#live) effect of the request is looked up, and
458−- `%exec` ford boil requests are cancelled with `[%exec ~]`
459−- `%wasp` ford deps requests are cancelled with `[%wasp |]`
460−- `%poll` session polls `%rest` the session heartbeat timeout
461−
462−### 3.3 `[%thin p=@ud]`, delivery failure
463−
464−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.
465−
466−
467−**Gifts given in response:** None.
468−
469−### 3.4 ``[%wart sock [path *]]``, inbound message
470−
471−Sometimes, messages are received from other ships. They are expected to take the from of a [`gram`]().
472−
473−**Gifts given in response:** [`%nice` or `%mean`](#ack).
474−
475−#### 3.4.1 `gram`
476−
477−There are three messages of note, all concerning authentication
478−- `[/lon ses]` is a login request, which contains the session wishing to authenticate.
479−- 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.
480−- 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.
481−
482−**Gifts given in response:** nice?
483−
484−## 4. Responses
485−
486−### 4.1 `[%nice ~]`, `[%mean ares]`, network acknowledgement
487−
488−A `%nice` is given upon receiving an [ames message](#gram), indicating succesful receipt. `%mean` is currently unused directly, but reserved for error conditions.
489−
490−## `[%sigh p=cage]`, inbound http response
491−
492−An HTTP response gets converted to the requested mark, or `%tang` in case of error.
493−
494−### 4.2 `[%thou httr]`, full HTTP response
495−
496−Most requests are served with one coherent response, consisting of
497−- `p=@ud`, an HTTP status code
498−- `q=mess`, response headers
499−- `r=(unit octs)`, an optional body
500−
501−### 4.3 `[%that httr]`, partial HTTP response
502−
503−[EventStream responses](#of-ixor) consist of multiple sequential chunks. Treated as `%thou`, except the request is kept open.
504−
505−### 4.4 `[%thar (unit octs)]`, partial HTTP body
506−
507−Complementing `%that`, `%thar` is a body chunk, containing an event. An empty `%thar` signals for the connection to be closed.
508−
509−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.
510−
511−#### 4.4.1 `even`, event types
512−
513−There are three events that a [client subscription](#subs) will be given.
514−
515−- `[%news hash]` is a `%f` update, and contains the relevant dependency token.
516−- `[%mean [term path] ares]` is a sourced subscription error.
517−
518−## 5. Vane requests
519−
520−### 5.1 ``[%a %wont sock `[path *]`gram]``, outbound message
521−
522−The `%a` interface provides conveyance of [messages](#gram) over UDP.
523−
524−Signs a `%woot` upon message arrival.
525−
526−
527−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.
528−The `%b` timer interface is used to schedule the next such event, or cancel past scheduled ones when a connection closes.
529−
530−Signs a `%wake` upon timer activation.
531−
532−### 5.3 `[%f %wasp @uvI]`, dependency listen
533−
534−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`.
535−
536−Signs a `%writ` upon change.
537−
538−### 5.4 `[%f %exec (unit silk)]`, functional transformations
539−
540−The `%f` interface converts nouns from one form to another. An empty unit represents cancellation.
541−
542−Signs a `%made` containing the computation result.
543−
544−The `silk`s used are as follows:
545−
546−### `[%cast %mime %boil mark beam [%web span ~]]`, file load
547−
548−The simplest functional request is the construction of a page. Saved as a [live](#live) request in case of cancellation.
549−- The `mark` is the request extension, defaulting to `%html`.
550−- A `beam`(path in `%clay`) is decoded from the request path.
551−- A `/web/<nyp ced quy>` virtual path is appended, span-encoding method, auth, and query string.
552−
553−### `[%cast mark %done ~ cage]`, convert
554−
555−This is used when communicating with apps, in both directions.
556−- 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]`.
557−- 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.
558−
559−### 5.5 `%g`, app actions
560−
561−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.
562−
563−### `[%mess hapt ship cage]`, app message
564−
565−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.
566−
567−Signs a `%nice` or `%mean`, in userspace or upon crashing.
568−
569−### `[%show hapt ship path]`, app subscription
570−
571−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`.
572−
573−Signs a `%nice` on init, `%rush` on data, and a `%mean` in subscription termination.
574−
575−### `[%took hapt ship]`, %rush confirmation
576−
577−A `%took` must be sent to acknowledge the receipt of subscription data, which in this case occurs automatically.
578−
579−Causes no signs.
580−
581−### `[%nuke hapt $|(ship [ship path])]`, subscription cancel
582−
583−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.
584−
585−Signs an empty `%mean` for each open subscription that is closed.
586−
587−## 6. In-flight metadata
588−
589−Various state can be associated with requests, but not necessarily be returned in responses to them.
590−
591−### 6.1 `~`, dropthrough
592−
593−If the response should be sent statelessly further up the duct, the `wire` is empty. This is used in `%f` pure functional page generation.
594−
595−### 6.2 `[?(%y %n) ...]`, stability
596−
597−The first element of a [`%b` timer](#wait) path distinguishes between live(%y) and dying(%n) channels.
598−
599−### 6.3 `/of/[ixor]`, view
600−
601−Designates which stream to act upon. Present on `%b` timer cards.
602−
603−### 6.4 `/on/<deps>`
604−
605−Present on `%f` dependency news. Looked up in [the state](#bolo) to see if any response is necessary.
606−
607−### 6.5 `/to/<hasp>/<ship>`, app
608−
609−Present on `%f` translations of message marks
610−
611−### 6.6 `/is/[ixor]/{hasp path}`, subscription
612−
613−Subscription requests. Present on `%g` subscription requests, and `%f` translations of [`%rush` subscription data](#show).
614−
615−## 7. Vane responses
616−
617−The goal of requests is to cause some manner of result. Specifically,
618−
619−### 7.1 `[%a %woot ship coop]`, acknowledgement
620−
621−A [message](#mess) which has been acknowledged remotely.
622−
623−### 7.2 `[%b %wake ~]`, timer
624−
625−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.
626−
627−### 7.3 `[%f %news ~]`, dependency update
628−
629−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.
630−
631−### 7.4 `[%f %made (each bead (list tank))]`, compute result
632−
633−Further action depends on the [`wire`](#whir). It can:
634−- Be empty, designating direct request data, which is [served](#mime) back up the `duct`.
635−- 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`.
636−- 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.
637−
638−### 7.5 `%g`, applications
639−
640−The `%g` interface sends several responses.
641−
642−### `[%nice ~]` and `[%mean ares]`, acknowledgment
643−
644−These are given as a response to `%mess`, with an empty wire, and `%show`s, with a [subscription wire](#wire-is).
645−The former is [served](#mime) back to the requester(i.e. the remaining duct), and the latter returned to the client.
646−
647−#### 7.5 `[%rush cage]`, subscription data
648−
649−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.
650−
651−## 8. Server state
652−
653−There is a quantity of data that persists between events.
654−
655−### 8.1 Global
656−
657−- `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`.
658−- `(jar ship hart)` remembered hostnames in order of preference, made accessible through `.^`
659− + 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]`.
660−- `(jug deps (each duct oryx))`, `/~/on` and `/~/in` endpoints listening to `%c` updates.
661−- `(map duct live)`, inbound request state
662−- `(map ixor oryx)`, open `/~/of` streams.
663−- `(map oryx stem)`, open view state.
664−- `(map hole sink)`, session state.
665−- `(map hole ,[ship ?])`, foreign session names, along with their origin ships and whether they are authorized to act on our behalf.
666−
667−### 8.2 `live`, per-request state
668−
669−To honor request cancellations, each unserved request must track which effect it is causing.
670−+ `[%exec whir]` if it is a ford data request
671−+ `[%wasp (list @uvH)]` if it is a ford dependency poll
672−+ `[%xeno ship]` if this is a proxied request
673−+ `[%poll ixor]` if this is a session long-poll
674−
675−### 8.3 `sink`, per-session state
676−
677−Each `hole` has associated authentication state.
678−- `priv`, a random secret that verifies the session, stored in cookie.
679−- `[ship (set ship)]`, the `ship` a session is acting as and any others it has been authorized with.
680−- `(jug ship ,[path duct])`, authentication `/~/as` requests waiting on foreign ships.
681−- `(set oryx)`, views associated with this session. Dual of `hole` in `stem`.
682−
683−### 8.4 `stem`, per-view state
684−
685−Each `oryx` has active subscription state.
686−- `hole`, session in which this view resides. Dual of `(set oryx)` in `sink`.
687−- `ixor`, a cached hash of the `oryx` that is used as a subscription id, by the `/~/of` EventStream.
688−- `[,@u (map ,@u even)]`, queued [events](#even). Has a maximum size.
689−- `(unit ,[duct @u ?])`, http connection, its last received event, and whether it is a long-poll request.
690−- `(set deps)`, subscribed `/~/in` points. Mirrored in `bolo`.
691−- `(map ,[hasp path] mark)`, subscribed `/~/is` points
692−- `(que duct)`, where any `%nice`/`%mean
693−
694−## Appendix A: Glossary
695−
696−- An `oryx` is a CSRF token used for [authenticated requests](#auth)
697−- `mean.json` is a rendering of hoon `ares`: an error message formatted as `{fail:'type',mess:"Error message"}`
698−- `urb.js` is the standard client-side implementation of the `%eyre` protocols, normally found in `/=main=/lib`
699−- 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).
700−
701−## Appendix B: EventSource
702−
703−UNIMPLEMENTED
704−
705−For more information, see <http://dev.w3.org/html5/eventsource/>
706−
707−An EventSource is a stream of events, encoded in a conceptually infinite `GET` request. Each event is formatted as
708−```
709− http
710− id: {number}
711− event: {type}
712− data: {contents}
713− data: {more-contents}
714−```
715−
716−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−570
@@ -1,570 +0,0 @@
1−+++
2−title = "Ford"
3−weight = 6
4−template = "doc.html"
5−+++
6−Our typed and marked computation engine.
7−
8−A variety of different services are provided by `%ford`, but they mostly
9−involve compiling hook files, slapping/slamming code with marked data,
10−and converting data between marks, including validating data to a mark.
11−Throughout every computation, `%ford` keeps track of which resources are
12−dependencies so that the client may be aware when one or more
13−dependencies are updated.
14−
15−`%ford` neither accepts unix events nor produces effects. It exists
16−entirely for the benefit of applications and other vanes, in particular
17−`%gall`. `%eyre` exposes the functional publishing aspects of `%ford`
18−while `%gall` uses `%ford` to control the execution of applications.
19−`%clay` is intended to use `%ford` to managed marked data, but this is
20−not yet reality.
21−
22−## Cards
23−
24−`%ford` accepts just one card, `%exec`. This is misleading, however,
25−since there are fourteen different `silk`s that may be used with it. In
26−every case, the expected response to a `%exec` card is a `%made` gift
27−with either an error or the produced result along with its set of
28−dependencies.
29−
30−Silks may autocons, so that the product of a cell of silks is a cell of
31−the product of the two silks.
32−
33−### `%bake`
34−
35−Tries to functionally produce the file at a given beam with the given
36−mark and heel. It fails if there is no way to translate at this level.
37−
38−### `%boil`
39−
40−Functionally produces the file at a given beam with the given mark and
41−heel. If there is no way to translate at this beam, we pop levels off
42−the stack and attempt to bake there until we find a level we can bake.
43−This should almost always be called instead of `%bake`.
44−
45−### `%call`
46−
47−Slams the result of one silk against the result of another.
48−
49−### `%cast`
50−
51−Translates the given silk to the given mark, if possible. This is one of
52−the critical and fundamental operations of ford.
53−
54−### `%diff`
55−
56−Diffs the two given silks (which must be of the same mark), producing a
57−cage of the mark specified in `++mark` in `++grad` for the mark of the
58−two silks.
59−
60−### `%done`
61−
62−Produces exactly its input. This is rarely used on its own, but many
63−silks are recursively defined in terms of other silks, so we often need
64−a silk that simply produces its input. A monadic return, if you will.
65−
66−### `%dude`
67−
68−Computes the given silk with the given tank as part of the stack trace
69−if there is an error.
70−
71−### `%dune`
72−
73−Produces an error if the cage is empty. Otherwise, it produces the value
74−in the unit.
75−
76−### `%mute`
77−
78−Takes a silk and a list of changes to make to the silk. At each wing in
79−the list we put the value of the associated silk.
80−
81−### `%pact`
82−
83−Applies the second silk as a patch to the first silk. The second silk
84−must be of the mark specified in `++mark` in `++grad` for the mark of
85−the first silk.
86−
87−### `%plan`
88−
89−Performs a structured assembly directly. This is not generally directly
90−useful because several other silks perform supersets of this
91−functionality. We don't usually have naked hoods outside ford.
92−
93−### `%reef`
94−
95−Produces a core containing the entirety of Zuse and Hoon, suitable for
96−running arbitrary code against. The mark is `%noun`.
97−
98−### `%ride`
99−
100−Slaps a hoon against a subject silk. The mark of the result is `%noun`.
101−
102−### `%vale`
103−
104−Validates untyped data from a ship against a given mark. This is an
105−extremely useful function.
106−
107−## Ford runes
108−
109−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.
110−
111−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.
112−
113−### `/+` import from lib/
114−
115−The `/+` rune accepts a filename as an argument. It interprets that filename
116−as a hoon source file within the `lib` directory. This is how we import a shared
117−library in urbit.
118−
119−To run this example, put this code in your desk at `gen/faslus.hoon` and run
120−`+faslus` in your dojo. This example is a generator. For more information on
121−generators, see the [generator docs](@/docs/hoon/hoon-tutorial/generators.md).
122−
123−```hoon
124−/+ time-to-id
125−::
126−:- %say
127−|= {{now/@da * *} $~ $~}
128−:- %noun
129−(time-to-id now)
130−```
131−
132−produces: `"c.314d"` (or something similar depending on when you run it)
133−
134−You can import multiple libraries with a single `/+` rune by separating them
135−with commas.
136−
137−Replace the code in `gen/faslus.hoon` with the following:
138−
139−```hoon
140−/+ time-to-id, hep-to-cab
141−::
142−:- %say
143−|= {{now/@da * *} $~ $~}
144−:- %noun
145−=/ id (time-to-id now)
146−=/ str "my-id-is-{id}"
147−(hep-to-cab (crip str))
148−```
149−
150−This should print something like `my_id_is_c.3588`.
151−
152−Another feature of the
153−`/+` and `/-` runes is the ability to specify the ship and case from which to
154−load the library.
155−
156−Example:
157−
158−```
159−/+ time-to-id, hep-to-cab/4/~zod
160−```
161−
162−will load the `hep-to-cab` library from `~zod` at `%clay` revision `4`.
163−
164−### `/-` import from sur/
165−
166−The `/-` rune accepts a filename as an argument. It interprets that filename as
167−a hoon source file within the `sur` directory. The `sur` directory contains
168−shared structures that can be used by other parts of urbit. This is somewhat
169−similar to including a header file in C.
170−
171−Example:
172−
173−```hoon
174−/- talk
175−::
176−*serial:talk
177−```
178−
179−produces: `0v0`
180−
181−`/-` can also take multiple files as arguments, and the ship and case of those
182−arguments can be specified. See the `/+` docs for more details about the syntax
183−for those features.
184−
185−### `/~` twig by hand
186−
187−`/~ <twig>` produces a "horn" that evaluates a twig and places the product in
188−the subject. Arbitrary hoon can be in the twig. A
189−horn is a data
190−structure representing a `%ford` static resource.
191−
192−Example:
193−
194−```hoon
195−/~ [a=0 b=1]
196−[a b]
197−```
198−
199−produces: `[0 1]`
200−
201−In wide-form, `/~` always takes a tuple (which may be a degenerate tuple of one element), and produces it.
202−
203−Example:
204−```hoon
205−/~[%something]
206−```
207−produces: `%something`
208−
209−```hoon
210−/~[%a %b]
211−```
212−produces: `[%a %b]`
213−
214−### `//` include a file by relative path
215−
216−`// <rel-path>` parses `rel-path` as a hoon twig, and then adds the resulting
217−twig to the subject. Note that the result type of this rune is not a horn, but
218−just a hoon twig, so its result can't be used as an argument to other runes
219−that expect a horn. There is no wide-form for this rune.
220−
221−Example:
222−```hoon
223−// %/file-to-include
224−::
225−(frobnicate:file-to-include %.n)
226−
227−:: contents of file-to-include.hoon
228−|%
229−++ frobnicate
230− |= a/? ^+ a
231− !a
232−--
233−```
234−produces: `%.y`
235−
236−_Note: `%` means current directory, which in a hoon file will resolve to the
237−"directory" containing that file. Also, %clay doesn't have first-class
238−directories the way unix filesystems do. Whereas in unix, a directory is a
239−special kind of file, in %clay it's just a path prefix, and there is no file
240−stored at that path._
241−
242−### `/=` wrap a face around an included horn
243−
244−`/=` runs a horn (usually produced by another ford rune), takes the result of
245−that horn, and wraps a face around it.
246−
247−Example:
248−```hoon
249−/= foo /~ [a=0 b=1]
250−::
251−[a.foo b.foo]
252−```
253−produces: `[0 1]`
254−
255−In wide-form, `/=` uses `=` as a delimiter: `/=foo=/~[a=0 b=1]`
256−
257−### `/:` evaluate at path, and `/<mark>/` render mark at current path
258−
259−`/:` takes a path and a horn, and evaluates the horn with the current path set to the supplied path.
260−`/mar/` renders the mark 'mar' at the current path.
261−
262−Example:
263−```hoon
264−/= hoo-source /: /path/to/hoon-file /hoon/
265−::
266−`@t`hoo-source
267−```
268−
269−produces the text of the hoon file at "/path/to/hoon-file/hoon".
270−
271−`/hoon/` renders the current path using the `%hoon` mark, which in this case
272−passes the contents through unchanged. In general, rendering a file with a
273−mark will potentially run the contents through a series of conversion
274−operations. For details on marks, see the
275−[Gall docs](gall).
276−
277−Here's an example that includes a mark conversion:
278−```hoon
279−/= page /: /path/to/html/file /mime/
280−::
281−page
282−
283−:: contents of /path/to/html/file:
284−<html><head><title>My Fascinating Blog</title></head></html>
285−```
286−produces:
287−`[[%text %html ~] 60 '<html><head><title>My Fascinating Blog</title></head></html>']`
288−
289−This result includes the MIME type ('text/html'), the content length in bytes,
290−and the HTML itself.
291−
292−In wide-form, `/:` uses `:` as a delimiter: `/=page=/:/path/to/html/file:/mime/`
293−
294−### `/!mark/` evaluate as hoon, then pass through mark
295−
296−Example:
297−```hoon
298−/= mime /: /%/some-hoon-file /!mime/
299−::
300−mime
301−
302−:: contents of /%/some-hoon-file:
303−%produces-a-cord
304−```
305−produces: `[[%text %plain ~] 15 'produces-a-cord']`
306−
307−### `/&` pass through a series of marks
308−
309−`/&` passes a horn through multiple marks, right-to-left. It has both a
310−wide-form and a tall-form syntax. In wide-form, it takes a series of mark
311−arguments followed by a horn. In tall-form, it takes a single mark followed by
312−a horn.
313−
314−```hoon
315−/= some-text /: /%/text-file /&mime&/txt/
316−::
317−some-text
318−```
319−produces: `[[%text %plain ~] p=17 q='Hi I\'m some text\0a']`
320−
321−This example shows two of the ways marks are used. The first way is what
322−happens with the `/txt/` mark: we use it to find a file in clay with that
323−extension, without performing any conversions. Since this file is stored with
324−the `%txt` mark in `%clay`, its type is a `wain`: a list of cords, where each
325−cord is a single line. Once we've read the file, the `%mime` mark converts the
326−`wain` to a triple that includes the MIME type ("text/plain"), the content
327−length in bytes, and the content itself as a cord.
328−
329−```hoon
330−/= page /&html&elem&/~[;div.foo;]
331−::
332−page
333−```
334−produces: `'<html><head></head><body><div class="foo"></div></body></html>'`
335−
336−This runs the sail expression `;div.foo;` through the `%elem` mark, then
337−through the `%html` mark. The `/~` rune produces an item of mark `noun`. The
338−`%elem` mark converts the mark of the expression from `noun` to `elem` by
339−checking that the type fits in `manx` (a hoon/sail type indicating an XML
340−element). The `%html` mark recognizes the `%elem` and converts it to an HTML
341−string with enclosing `<html>`, `<head>`, and `<body>` tags.
342−
343−It's possible to use wide-form `/&` with more than two marks, by using `&` as a
344−delimiter between marks and adding a `/` before the last mark, like:
345−`/&d&c&b&/a/`. The last argument here can actually be any arbitrary horn, not
346−just a mark: `/&c&b&/:path:/mark/`
347−
348−Tall-form `/&` takes only two arguments: a mark and a horn. The mark does not
349−need to be enclosed in `/`'s: `/& html /elem/`
350−
351−### `/|` short-circuiting 'or'
352−
353−`/|` takes a series of horns and produces the first one (left-to-right) that
354−succeeds. If none succeed, it produces stack traces from all of its arguments.
355−
356−Example:
357−```hoon
358−/= res /: /%/path/to/file
359−/|
360− /!elem/
361− /elem/
362−==
363−::
364−res
365−```
366−tries to parse the file at `/%/path/to/file` as a hoon expression and evaluate
367−it (`/!elem/`), and then if that fails, tries to convert the file to an HTML
368−element directly (`/elem/`). This is used in urbit's `tree` publishing system
369−to enable a user to place either a hoon file or a static file in a directory,
370−and have them both result in webpages, with preference given to treating the
371−file as hoon to be evaluated.
372−
373−Wide-form `/|` encloses its arguments in parentheses, with a single space as a delimiter:
374−`/|(/!elem/ /elem/)`
375−
376−### `/_` unfiltered: run a horn on each file in the current directory
377−
378−`/_` can be used in two ways: filtered and unfiltered.
379−
380−Unfiltered `/_` takes a horn as an argument. It produces a new horn representing the
381−result of mapping the supplied horn over the list of files in the current
382−directory. The keys in the resulting map are the basenames of the files in the
383−directory, and each value is the result of running that horn on the contents of
384−the file.
385−
386−Example:
387−```hoon
388−/= kids /_ /hoon/
389−::
390−`(map term cord)`kids
391−```
392−
393−produces a value of type `(map term cord)`, where each key is the basename (the
394−filename without the prefix), and each value is the result of running the
395−contents of the file through the `%hoon` mark, which validates that it's valid
396−hoon code and returns it unmodified. So, the resulting map associates basenames
397−with file contents.
398−
399−Wide-form unfiltered `/_` doesn't need a delimiter: `/= kids /_/hoon/`
400−
401−### `/_` filtered: run a horn on each file in the directory matching an aura
402−
403−Filtered `/_` takes an aura and a horn, and filters the list of files in the
404−current directory by whether their filenames can be parsed to an atom of that
405−aura. It then produces a map where each key is the filename after parsing into
406−that atom type, and each value is the result of running the horn on the
407−contents of that file.
408−
409−Example:
410−```hoon
411−/= timed-posts /_ @da /md/
412−`(map @da @t)`timed-posts
413−```
414−produces a map from dates to cords. This product will only contain files whose
415−names are parsable into `@da` dates. The values are the file contents converted
416−to a cord of markdown-formatted text.
417−
418−Wide-form filtered `/_` uses `_` as a delimiter: `/= timed-posts /_@da_/md/`
419−
420−### `/;` operate on
421−
422−`/;` takes a twig and a horn. The twig should evaluate to a gate, which is then slammed
423−with the result of the horn as its sample.
424−
425−Example:
426−```hoon
427−/= goo
428− /; |=({a/@ b/@} +(b))
429− /~ [a=0 b=1]
430−::
431−goo
432−```
433−
434−produces: `2`
435−
436−Here's a slightly more complex example with runes that use the filesystem:
437−```hoon
438−/= file-length
439− /; |=(a/@t (lent (crip a)))
440− /: /%/path/to/hoon/file /hoon/
441−::
442−file-length
443−```
444−produces the number of bytes in the file "/%/path/to/hoon/file."
445−
446−### `/,` switch by path
447−
448−`/,` is a switch statement, which picks a branch to evaluate based on
449−whether the current path matches the path in the switch statement.
450−Takes a sequence of pairs of (path, horn) terminated by a `==`. No wide-form.
451−
452−Example:
453−```hoon
454−/= just-right
455− /: /===/right-path :: set path to /%/right-path
456− /,
457− /wrong-path /~ ~
458− /another-wrong-path /~ ~
459− /right-path /~ %evaluate-me :: only evaluate this horn
460− ==
461−::
462−`@t`just-right
463−```
464−
465−produces: `'evaluate-me'`
466−
467−### `/.` list
468−
469−Produce a null-terminated list from a sequence of horns, terminated by a `==`. No wide-form.
470−
471−Example:
472−```hoon
473−/= vanes
474− /.
475− /~ %ames
476− /~ %behn
477− /~ %clay
478− /~ %dill
479− /~ %eyre
480− /~ %ford
481− /~ %gall
482− ==
483−::
484−vanes
485−```
486−produces: `[%ames %behn %clay %dill %eyre %ford %gall ~]`.
487−
488−### `/*` heterogeneous map
489−
490−_DEPRECATED_
491−TODO: remove
492−
493−### `/^` cast
494−
495−`/^` takes a mold and a horn, and casts the result of the horn to the mold.
496−
497−Example:
498−```hoon
499−/= liz /^ (list @) :: cast to real list
500− /~ ~[1 2 3] :: no 'i' or 't' faces
501−::
502−?< ?=($~ liz) :: prevent find-fork
503−i.liz
504−```
505−
506−produces: `1`
507−
508−Without the cast, we wouldn't be able to access the 'i' face of the list.
509−
510−Wide-form `/^` uses `^` as a delimiter: `/^(list @)^/~[1 2 3 ~]`
511−
512−### `/#` insert dephash
513−
514−`/#` takes a horn and produces a cell of the dependency
515−hash of the result of the horn, and the result itself.
516−
517−Example:
518−```hoon
519−/= inline /^ {dep/@uvH txt/@t} /# /: /%/my-script /js/
520−::
521−;= ;script: (trip txt.inline) :: set script contents
522− ;script@"/~/on/{<dep.inline>}.js"; :: set script src
523−==
524−```
525−produces two `<script>` tags. The first has its contents set to the contents
526−of the JavaScript file we loaded from clay. The second is an auto-update
527−script that polls the server to check whether the dependency hash has changed.
528−This pattern is used in urbit's `tree` web publishing system.
529−
530−Wide-form `/#` does not need a delimiter:
531−`/= inline /^ {dep/@uvH txt/@t} /#/:/%/my-script:/js/`
532−
533−### `/$` process extra arguments
534−
535−`/$` will slam a gate on whatever extra arguments have been supplied to this build.
536−At the moment, only HTTP requests forwarded by `%eyre` contain any extra arguments,
537−and using this rune outside of that context will cause an error. Requests from `%eyre`
538−contain an argument representing the query string, which can be parsed using the
539−standard library gate `++fuel:html`.
540−
541−Example:
542−```hoon
543−/= gas /$ fuel:html
544−::
545−:*
546− %who {<(~(get ju aut.ced.gas) 0)>}
547− %where {(spud s.bem.gas)}
548− %case {(scow %ud p.r.bem.gas)}
549−==
550−```
551−produces: [%who '~zod' %where /ford/pages/web %case 60]
552−
553−Wide-form `/$` takes its arguments inside brackets, like `/~`:
554−`/=gas=/$[fuel:html]`
555−
556−### `/%` propagate extra arguments into renderers
557−
558−`/%` will forward extra arguments (usually from `%eyre`) on to any enclosed `/renderer/`'s. Without this,
559−renderers that use `/$` to read the extra arguments will crash.
560−
561−Example:
562−```hoon
563−/= dat /% /tree-json/
564−::
565−dat
566−```
567−produces the results of running `ren/tree-json` on the current path. This renderer needs the query string,
568−which is one of the extra arguments passed in from `%eyre`.
569−
570−Wide-form `/%` has no delimiter: `/%/tree-json/`
arvo/gall.mddeleted−2317
@@ -1,2317 +0,0 @@
1−+++
2−title = "Gall Apps"
3−weight = 6
4−template = "doc.html"
5−+++
6−This is documentation about how to write Gall apps. Some knowledge of Hoon is assumed.
7−
8−> Note: the last major revision of these lessons was in 2016. They need to be
9− rewritten; in some ways they are outdated, and in other ways they were not
10− always accessible enough to beginners. We are planning to rewrite these in the
11− near future. There is still useful information to be found in the meantime.
12−
13−## API Connectors
14−
15−> 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!
16−
17−Most people have lots of data stored in online services, many of
18−which have APIs. API connectors allow the user to access this
19−data from within their Urbit.
20−
21−A security driver allows the user to make authenticated requests
22−to the service's API, but the user still needs to know the API
23−and send and receive JSON. An API connector puts a layer of
24−porcelain over this to allow the user easier control over their
25−data.
26−
27−Each connector should perform two basic functions. First, it
28−should expose a tree of the data in the service that's accessible
29−through `.^` and FUSE. Second, it should expose event streams as
30−actions occur in the service. Let's take a look at how the `%gh`
31−app accomplishes both for Github.
32−
33−After starting `%gh` (`|start %gh`), let's look at the root of
34−the tree that `%gh` exposes:
35−
36−```
37−~your-urbit:dojo> .^(arch %gy /=gh=)
38−[fil=~ dir={[p=~.issues q=~]}]
39−```
40−
41−`%gh` is currently a skeleton -- it contains examples of all the
42−functionality necessary for a connector, but many endpoints
43−aren't implemented. As we can see here, only issues are
44−implemented. We can explore this tree:
45−
46−```
47−~your-urbit:dojo> .^(arch %gy /=gh=/issues)
48−[fil=~ dir={[p=~.by-repo q=~] [p=~.mine q=~]}]
49−```
50−
51−And eventually:
52−
53−```
54−/- gh
55−.^(issue:gh %gx /=gh=/issues/by-repo/philipcmonktest/testing/7)
56−<issue...>
57−login.user:.^(issue:gh %gx /=gh=/issues/by-repo/philipcmonktest/testing/7)
58−'philipcmonktest'
59−```
60−
61−The other thing an API connector needs to do is expose event
62−streams. One straightforward way to use this capacity is with
63−the `:pipe` app:
64−
65−```
66−:pipe|connect %gh /listen/philipcmonktest/testing/issues/'issue_comment' %public
67−```
68−
69−Now creating an issue results in the following message in your
70−`%public` `:talk` channel:
71−
72−```
73−~your-urbit[philipcmonktest@github]: opened issue ##11: i found a bug!
74−```
75−
76−You'll also get notifications of issue status changes and
77−comments.
78−
79−As is often the case, the best way to write an API connector is
80−to copy an existing one and modify it. We'll dissect the Github
81−connector here. This code is in `/=home=/app/gh/hoon`, and it's
82−also reproduced at the bottom of this page (in case the code
83−drifts out of sync with this doc).
84−
85−We'll go over the two parts to an API connector (one-time reading vs listening
86−for events) separately.
87−
88−#### Reading
89−
90−A connector exposes a tree of data. Every read request has a
91−`care`, which is generally either `%x` or `%y. `%x` is a request
92−for a particular piece of data, while `%y` is a request for a
93−directory listing. Roughly, `%x` means Unix `cat` and `%y` means
94−Unix `ls`.
95−
96−> 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.
97−
98−The usual flow for implementing this tree of data makes heavy use
99−of the `connector` library. This library is well documented in
100−the source, so check out `/=home=/lib/connector/hoon`.
101−
102−The `connector` library needs to be initialized with definitions
103−of `move` and `sub-result` (all the types of data that can be
104−returned by a place). This can just be a line at the top of the
105−main core:
106−
107−```hoon
108−=+ connector=(connector move sub-result) :: Set up connector library
109−```
110−
111−Most of the Github-specific logic is in `++places`, which is a
112−list of all the places we can request. A place consists of:
113−
114−```hoon
115−++ place
116− $: guard/mold
117− read-x/$-(path move)
118− read-y/$-(path move)
119− sigh-x/$-(jon/json (unit sub-result))
120− sigh-y/$-(jon/json (unit arch))
121− ==
122−```
123−
124−- `guard`, the type of the paths we should match. For example, to match `/issues/<user>/<repo>` use `{$issues @t @t $~}`.
125−
126−- `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.
127−
128−- `read-y`, same as `read-x` except with care `%y`.
129−
130−- `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.
131−
132−- `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.
133−
134−Filling out the list of places is a lot of grunt work, but most
135−places are fairly straightforward, and the `++read-*` helper
136−functions are useful. Check out the library source for more
137−information on those.
138−
139−Besides the list of places, we just need to handle the flow of
140−control. `++peek` and `++peer-scry` are the interface we expose
141−to the rest of the system while `++sigh-httr` and `++sigh-tang`
142−are used to handle responses when we make HTTP requests.
143−
144−- `++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`.
145−
146−- `++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.
147−
148−- 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.
149−
150−- 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.
151−
152−That's really all there is to the reading portion of API
153−connectors.
154−
155−One of the most accessible ways to jump into Arvo programming is
156−to just add more places to an existing API connector. It's
157−useful, small in scope, and comes in bite-sized chunks since most
158−places are less than ten lines of code.
159−
160−#### Listening
161−
162−Listening for events is fairly service-specific. In some
163−services, we poll for changes. The Twitter connector has an
164−example of this, but note that it predates the `connector`
165−library and is thus more complicated than it needs to be, and the
166−interface it exposes isn't standard. In Github, we power our
167−event streams with webhooks.
168−
169−For Github, when someone subscribes to
170−`/listen/<user>/<repo>/<events...>`, we want to produce
171−well-typed results when they occur.
172−
173−We only want to create one webhook per event, so in our state we
174−have `hook`, which is a map of event names to the set of bones
175−which are subscribed to that event. We must always keep this
176−up-to-date.
177−
178−Flow of control starts in `++peer-listen`, where we just call
179−`++listen`. In `++listen`, for each event in the list of events,
180−we check to see if we have that hook set up (by checking whether
181−it exists in `hook`). If so, we call `++update-hook` to add the
182−current bone to the set of listeners. Otherwise, we call
183−`++create-hook`, which sends a request to Github to set up the
184−new webhook. We also create an entry in `hook` with the current
185−bone.
186−
187−When we created the webhook, we told Github to send the event to
188−`/~/to/gh/gh-<event>.json?anon&wire=/`. This turns into a poke.
189−Let's parse out this url. The first `gh` is the app name to
190−poke. The next portion, `gh-<event>` is the mark to convert the
191−JSON to. For example, when the "issues" event fires, it'll get
192−converted to mark `gh-issues`. This mark has a conversion
193−routine from `json` to the `issues` type, which is defined in the
194−`gh` structure (`/=home=/sur/gh/hoon`). Once this conversion
195−happens, the `gh` app will get poked with the correctly marked
196−data in `++poke`.
197−
198−In `++poke`, we check `hook` to find the subscribers to the event
199−that was fired, and we update them.
200−
201−That's really all there is to it. Webhook flow isn't well
202−standardized, so even if your chosen service is powered by
203−webhooks, your listening code might look rather different. The
204−point is to expose the correct interface.
205−
206−
207−#### Github API Connector Code
208−
209−In case the code in `/=home=/app/gh/hoon` drifts out of sync with
210−this doc:
211−
212−```
213−:: This is a connector for the Github API v3.
214−::
215−:: You can interact with this in a few different ways:
216−::
217−:: - .^({type} %gx /=gh={/endpoint}) to read data or
218−:: .^(arch %gy /=gh={/endpoint}) to explore the possible
219−:: endpoints.
220−::
221−:: - subscribe to /listen/{owner}/{repo}/{events...} for
222−:: webhook-powered event notifications. For event list, see
223−:: https://developer.github.com/webhooks/.
224−::
225−:: This is written with the standard structure for api
226−:: connectors, as described in lib/connector.hoon.
227−::
228−/? 314
229−/- gh, plan-acct
230−/+ gh-parse, connector
231−::
232−!:
233−=> |%
234− +$ move (pair bone card)
235− +$ card
236− $% [%diff sub-result]
237− [%them wire (unit hiss:eyre)]
238− [%hiss wire [%~ %~] %httr [%hiss hiss:eyre]]
239− ==
240− ::
241− :: Types of results we produce to subscribers.
242− ::
243− +$ sub-result
244− $% [%arch arch]
245− [%gh-issue issue:gh]
246− [%gh-list-issues (list issue:gh)]
247− [%gh-issues issues:gh]
248− [%gh-issue-comment issue-comment:gh]
249− [%json json]
250− [%null %~]
251− ==
252− ::
253− :: Types of webhooks we expect.
254− ::
255− +$ hook-response
256− $% [%gh-issues issues:gh]
257− [%gh-issue-comment issue-comment:gh]
258− ==
259− --
260−=+ connector=(connector move sub-result) :: Set up connector library
261−::
262−|_ $: hid=bowl:gall
263− hook=(map @t [id=@t listeners=(set bone)]) :: map events to listeners
264− ==
265−:: ++ prep _`. :: Clear state when code changes
266−::
267−:: List of endpoints
268−::
269−++ places
270− |= wir=wire
271− ^- (list place:connector)
272− =+ (helpers:connector ost.hid wir "https://api.github.com")
273− => |% :: gh-specific helpers
274− ++ sigh-list-issues-x
275− |= jon=json
276− %+ bind ((ar:jo issue:gh-parse) jon)
277− |= issues=(list issue:gh)
278− gh-list-issues+issues
279− ::
280− ++ sigh-list-issues-y
281− |= jon=json
282− %+ bind ((ar:jo issue:gh-parse) jon)
283− |= issues=(list issue:gh)
284− :- `(shax (jam issues))
285− (malt (turn issues |=(issue:gh [(rsh 3 2 (scot %ui number)) ~])))
286− --
287− :~ ^- place :: /
288− :* guard=,%~
289− read-x=read-null
290− read-y=(read-static %issues ~)
291− sigh-x=sigh-strange
292− sigh-y=sigh-strange
293− ==
294− ^- place :: /issues
295− :* guard=,[%issues %~]
296− read-x=read-null
297− read-y=(read-static %mine %by-repo ~)
298− sigh-x=sigh-strange
299− sigh-y=sigh-strange
300− ==
301− ^- place :: /issues/mine
302− :* guard=,[%issues %mine %~]
303− read-x=(read-get /issues)
304− read-y=(read-get /issues)
305− sigh-x=sigh-list-issues-x
306− sigh-y=sigh-list-issues-y
307− ==
308− ^- place :: /issues/by-repo
309− :* guard=,[%issues %by-repo %~]
310− read-x=read-null
311− ^= read-y
312− |= pax=path
313− =+ /(scot %p our.hid)/home/(scot %da now.hid)/web/plan
314− =+ .^([* acc=(map knot plan-acct)] %cx -)
315− ::
316− ((read-static usr:(~(got by acc) %github) ~) pax)
317− sigh-x=sigh-strange
318− sigh-y=sigh-strange
319− ==
320− ^- place :: /issues/by-repo/<user>
321− :* guard=,[%issues %by-repo @t %~]
322− read-x=read-null
323− read-y=|=(pax=path (get /users/[-.+>.pax]/repos))
324− sigh-x=sigh-strange
325− ^= sigh-y
326− |= jon=json
327− %+ bind ((ar:jo repository:gh-parse) jon)
328− |= repos=(list repository:gh)
329− [~ (malt (turn repos |=(repository:gh [name ~])))]
330− ==
331− ^- place :: /issues/by-repo/<user>/<repo>
332− :* guard=,[%issues %by-repo @t @t %~]
333− read-x=|=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues))
334− read-y=|=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues))
335− sigh-x=sigh-list-issues-x
336− sigh-y=sigh-list-issues-y
337− ==
338− ^- place :: /issues/by-repo/<user>/<repo>
339− :* guard=,[%issues %by-repo @t @t @t %~]
340− ^= read-x
341− |=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues/[-.+>+>.pax]))
342− ::
343− read-y=(read-static ~)
344− ^= sigh-x
345− |= jon=json
346− %+ bind (issue:gh-parse jon)
347− |= issue=issue:gh
348− gh-issue+issue
349− ::
350− sigh-y=sigh-strange
351− ==
352− ==
353−::
354−:: When a peek on a path blocks, ford turns it into a peer on
355−:: /scry/{care}/{path}. You can also just peer to this
356−:: directly.
357−::
358−:: We hand control to ++scry.
359−::
360−++ peer-scry
361− |= pax=path
362− ^- [(list move) _+>.$]
363− ?> ?=([care:clay *] pax)
364− :_ +>.$ :_ ~
365− (read:connector ost.hid (places %read pax) i.pax t.pax)
366−::
367−:: HTTP response. We make sure the response is good, then
368−:: produce the result (as JSON) to whoever sent the request.
369−::
370−++ sigh-httr
371− |= [way=wire res=httr:eyre]
372− ^- [(list move) _+>.$]
373− ?. ?=([%read care:clay @ *] way)
374− ~& res=res
375− [~ +>.$]
376− =* style i.way
377− =* ren i.t.way
378− =* pax t.t.way
379− :_ +>.$ :_ ~
380− :+ ost.hid %diff
381− (sigh:connector (places ren style pax) ren pax res)
382−::
383−:: HTTP error. We just print it out, though maybe we should
384−:: also produce a result so that the request doesn't hang?
385−::
386−++ sigh-tang
387− |= [way=wire tan=tang]
388− ^- [(list move) _+>.$]
389− %- (slog >%gh-sigh-tang< tan)
390− [[ost.hid %diff null+~]~ +>.$]
391−::
392−:: We can't actually give the response to pretty much anything
393−:: without blocking, so we just block unconditionally.
394−::
395−++ peek
396− |= [ren=@tas tyl=path]
397− ^- (unit (unit (pair mark *)))
398− ~ ::``noun=[ren tyl]
399−::
400−::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
401−:: Webhook-powered event streams (/listen) ::
402−::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
403−::
404−:: To listen to a webhook-powered stream of events, subscribe
405−:: to /listen/<user>/<repo>/<events...>
406−::
407−:: We hand control to ++listen.
408−::
409−++ peer-listen
410− |= pax=path
411− ^- [(list move) _+>.$]
412− ?. ?=([@ @ *] pax)
413− ~& [%bad-listen-path pax]
414− [~ +>.$]
415− (listen pax)
416−::
417−:: This core handles event subscription requests by starting or
418−:: updating the webhook flow for each event.
419−::
420−++ listen
421− |= pax=path
422− =| mow=(list move)
423− =< abet:listen
424− |%
425− ++ abet :: Resolve core.
426− ^- [(list move) _+>.$]
427− [(flop mow) +>.$]
428− ::
429− ++ send-hiss :: Send a hiss
430− |= hiz=hiss:eyre
431− ^+ +>
432− =+ wir=`wire`[%x %listen pax]
433− +>.$(mow [[ost.hid %hiss wir `~ %httr [%hiss hiz]] mow])
434− ::
435− :: Create or update a webhook to listen for a set of events.
436− ::
437− ++ listen
438− ^+ .
439− =+ pax=pax :: TMI-proofing
440− ?> ?=([@ @ *] pax)
441− =+ events=t.t.pax
442− |- ^+ +>+.$
443− ?~ events
444− +>+.$
445− ?: (~(has by hook) i.events)
446− $(+>+ (update-hook i.events), events t.events)
447− $(+>+ (create-hook i.events), events t.events)
448− ::
449− :: Set up a webhook.
450− ::
451− ++ create-hook
452− |= event=@t
453− ^+ +>
454− ?> ?=([@ @ *] pax)
455− =+ clean-event=`tape`(turn (trip event) |=(a=@tD ?:(=('_' a) '-' a)))
456− =. hook
457− %+ ~(put by hook) (crip clean-event)
458− =+ %+ fall
459− (~(get by hook) (crip clean-event))
460− *[id=@t listeners=(set bone)]
461− [id (~(put in listeners) ost.hid)]
462− %- send-hiss
463− :* %+ scan
464− =+ [(trip i.pax) (trip i.t.pax)]
465− "https://api.github.com/repos/{-<}/{->}/hooks"
466− auri:de-purl:html
467− %post ~ ~
468− %- as-octs:mimes:html %- crip %- en-json:html %- pairs:enjs:format :~
469− name+s+%web
470− active+b+&
471− events+a+~[s+event] ::(turn `(list ,@t)`t.t.pax |=(a=@t s=a))
472− :- %config
473− %- pairs:enjs:format :~
474− =+ =+ clean-event
475− "http://107.170.195.5:8443/~/to/gh/gh-{-}.json?anon&wire=/"
476− [%url s+(crip -)]
477− [%'content_type' s+%json]
478− ==
479− ==
480− ==
481− ::
482− :: Add current bone to the list of subscribers for this event.
483− ::
484− ++ update-hook
485− |= event=@t
486− ^+ +>
487− =+ hok=(~(got by hook) event)
488− %_ +>.$
489− hook
490− %+ ~(put by hook) event
491− hok(listeners (~(put in listeners.hok) ost.hid))
492− ==
493− --
494−::
495−:: Pokes that aren't caught in more specific arms are handled
496−:: here. These should be only from webhooks firing, so if we
497−:: get any mark that we shouldn't get from a webhook, we reject
498−:: it. Otherwise, we spam out the event to everyone who's
499−:: listening for that event.
500−::
501−++ poke
502− |= response=hook-response
503− ^- [(list move) _+>.$]
504− =+ hook-data=(~(get by hook) (rsh 3 3 -.response))
505− ?~ hook-data
506− ~& [%strange-hook hook response]
507− [~ +>.$]
508− :: ~& response=response
509− :_ +>.$
510− %+ turn ~(tap in listeners.u.hook-data)
511− |= ost=bone
512− [ost %diff response]
513−--
514−```
515−
516−## Generators
517−
518−Up until now we've poked apps directly. This requires the user to
519−specify the mark, and it requires the app to accept the arguments in a
520−way that's convenient for users to input. This is the "plumbing" way to
521−interact with apps. Generators are the "porcelain" layer. This is why
522−when you run a command like `+ls` or `|merge`, there are no marks in
523−sight.
524−
525−At that point, we just used the
526−generators to produce values -- we didn't pipe their results into apps.
527−In the dojo cast, the role of a generator is to take a list of arguments
528−and produce a value, which is often, though not always, piped into an
529−app. Generators are pure, stateless functions, and they cannot send
530−moves.
531−
532−`+ls` and `+cat` are commonly-used generators that produce a directory
533−listing and print out a file, respectively. These are useful in
534−themselves, so we generally don't pipe the results into an app.
535−
536−Another generator is `+hood/merge`. Try running `+hood/merge` with the
537−normal arguments for `|merge`:
538−
539−```
540−> +hood/merge %home our %they
541−[syd=%home her=~zod sud=%they cas=[%da p=~2018.10.4..21.11.49..901c] gem=%auto]
542−
543−> +hood/merge %home our %they, =gem %this
544−[syd=%home her=~zod sud=%they cas=[%da p=~2018.10.4..21.12.11..ee32] gem=%this]
545−```
546−
547−This didn't run any merge, it just constructed the command that, if sent
548−to `:hood`, would run it. Note first that, even though it's not printed,
549−this value has mark `kiln-merge`. Also, the merge strategy `gem=%auto`
550−was added automatically. Optional arguments are straightforward with
551−generators.
552−
553−In general, generators are prepended by either `+` or `|`. The general
554−form is `+generator`, but often generators are created specifically to
555−work with a single app, they're usually placed in a subdirectory of gen
556−and run with `|`. Thus, if `my-generator` generator is made for use with
557−`:my-app`, then `my-generator` is put in
558−`/gen/my-app/my-generator.hoon`, and can be run directly with
559−`+my-app/my-generator <args>`. If you want to pipe the result into
560−`:my-app`, then run `:my-app +my-app/my-generator <args>`. Because this
561−pattern is so common, this can be abbreviated to
562−`:my-app|my-generator <args>`. Because most built-in commands are
563−generators for the `:hood` app, `:hood|generator <args>` can be
564−shortened to `|generator <args>`.
565−
566−Let's write a generator called `:pong` that takes an urbit address, which is of
567−mark `urbit`, and sends that urbit the message `'howdy'`. First--without a
568−generator--let's make `:ping` that does the same, except that
569−it lets the user optionally specify the message as well.
570−
571−We'll need a new mark for our arguments. Let's call it
572−`ping-message`.
573−
574−> 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).
575−
576−```hoon
577−::
578−:::: /mar/ping/message/hoon
579− ::
580−/? 314
581−|_ [to=@p message=@t]
582−++ grab
583− |%
584− +$ noun [@p @t]
585− --
586−--
587−```
588−
589−The app can easily be modified to use this (`/app/ping.hoon`):
590−
591−```hoon
592−:: Allows one ship to ping another with a string of text
593−::
594−:::: /app/ping/hoon
595− ::
596−/? 314
597−|%
598− +$ move [bone term wire *]
599−--
600−!:
601−|_ [bowl:gall state=%~]
602−::
603−++ poke-ping-message
604− |= [to=@p message=@t]
605− ~& 'sent'
606− ^- [(list move) _+>.$]
607− :- ^- (list move)
608− :~ `move`[ost %poke /sending [to dap] %atom message]
609− ==
610− +>.$
611−::
612−++ poke-atom
613− |= arg=@
614− ~& 'received'
615− ^- [(list move) _+>.$]
616− ::
617− ~& [%receiving (@t arg)]
618− [~ +>.$]
619−::
620−++ coup |=(* `+>)
621−--
622−```
623−
624−Now we can run this with:
625−
626−```
627−~fintud-macrep:dojo> |start %ping
628−>=
629−
630−~fintud-macrep:dojo> :ping &ping-message [~sampel-sipnym 'heyya']
631−>=
632−```
633−
634−And on `~sampel-sipnym`, assuming it's running `:ping` as well,
635−we see `[%receiving 'heyya']`.
636−
637−This is an annoying way to invoke the app, though. The `[]` are
638−mandatory, and optional arguments are hard. Let's make a generator,
639−`+send` to make everything nicer. Since it's specific to
640−`:ping`, let's put it in `/gen/ping/send.hoon`:
641−
642−```hoon
643−:- %say
644−|= [^ [to=@p message=?(%~ [text=@t %~])] %~]
645−[%ping-message to ?~(message 'howdy' text.message)]
646−```
647−
648−A couple of new things here. Firstly, `message=?(%~ [text=@t %~])] %~]`
649−should be read as "the message is either null or a pair of text and
650−null". Generator argument lists are always null-terminated, which makes
651−it convenient to accept lists in tail position (which are particularly
652−annoying without generators). `?(a b)` is the irregular form of
653−`$?(a b)`, which is a union type. Thus, `?(a b)` means the type of
654−anything that's in either `a` or `b`. Thus, in our case,
655−`?(~ [text=@t ~])` is either null or a pair of text and null.
656−
657−This is run as follows:
658−
659−```
660−~fintud-macrep:dojo> :ping|send ~sampel-sipnym
661−>=
662−
663−~fintud-macrep:dojo> :ping|send ~sampel-sipnym 'how do you do'
664−>=
665−```
666−
667−Which causes `~sampel-sipnym` to print `[%receiving 'howdy']` and
668−`[%receiving 'how do you do']`.
669−
670−(Note: `:ping|send ~sampel-sipnym` is short for `:ping +ping/send ~sampel-sipnym`.)
671−
672−**Exercises**:
673−
674−- Create a generator for `:sum` from [State](#state) so that you can run `:sum|add 5` to add numbers to it.
675−
676−- Create a generator for `:click` from [Web Apps](#backend) so that you can run `:click|poke` to poke it.
677−
678−
679−## Writing an HTTP Request
680−
681−There's a variety of arvo services we haven't touched on yet.
682−Let's figure out how to make HTTP requests and set timers.
683−
684−Let's build an uptime-monitoring system. It'll ping a web
685−service periodically and print out an error when the response
686−code isn't 2xx. Save the following as `app/up.hoon`:
687−
688−```hoon
689−:: Up-ness monitor. Accepts atom url, 'on', or 'off'
690−::
691−:::: /hoon/up/app
692− ::
693−/? 314
694−|%
695−+$ move [bone card]
696−+$ card
697− $% [%hiss wire unit-iden=$~ mark=%httr cage=[mark=%purl vase=purl:eyre]]
698− [%wait wire @da]
699− ==
700−+$ action
701− $% [%on $~] :: enable polling('on')
702− [%off $~] :: disable polling('off)
703− [%target p=cord] :: set poll target('http://...')
704− ==
705−--
706−|_ [hid=bowl:gall on=_| in-progress=_| target=@t]
707−++ poke-atom
708− |= url-or-command=@t ^- (quip move _+>)
709− =+ ^- act/action
710− ?: ?=($on url-or-command) [%on ~]
711− ?: ?=($off url-or-command) [%off ~]
712− [%target url-or-command]
713− ?- -.act
714− $target [~ +>.$(target p.act)]
715− $off [~ +>.$(on |)]
716− $on
717− :- ?: |(on in-progress) ~
718− [ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]~
719− +>.$(on &, in-progress &)
720− ==
721−++ sigh-httr
722− |= [wir=wire code=@ud headers=mess:eyre body=(unit octs)]
723− ~& 'arrive here'
724− ^- [(list move) _+>.$]
725− ?: &((gte code 200) (lth code 300))
726− ~& [%all-is-well code]
727− :_ +>.$
728− [ost.hid %wait /timer (add ~s10 now.hid)]~
729− ~& [%we-have-a-problem code]
730− ~& [%headers headers]
731− ~& [%body body]
732− :_ +>.$
733− [ost.hid %wait /timer (add ~s10 now.hid)]~
734−++ wake-timer
735− |= [wir=wire $~] ^- (quip move _+>)
736− ?: on
737− :_ +>.$
738− [ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]~
739− [~ +>.$(in-progress |)]
740−::
741−++ prep ~& target _`. :: computed when the source file changes;
742−-- :: here it prints target then resets our state
743−```
744−
745−There's some fancy stuff going on here. We'll go through it line by
746−line, though.
747−
748−There's two kinds of cards we're sending to arvo. A `%hiss` move tells
749−`%eyre` to make an HTTP request. It expects a `(unit iden)`, which will
750−be null here because we aren't doing any authentication; a mark, in this
751−case the http request mark `&httr`; and some data in the form of a
752−`cage`, which is a `[mark vase]`. This is confusing, so the mold in the
753−code quoted above includes a bunch of otherwise unnecessary faces for
754−the purpose of illustration. Compare: `[%hiss p=(unit user) q=mark
755−r=cage]` from `zuse`.
756−
757−> 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`.
758−
759−> 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`.
760−
761−A `purl:eyre` is a parsed url structure, which can be created with `de-purl:html`,
762−which is a function that takes a url as text and parses it into a `(unit
763−purl:eyre)`. Thus, the result is null if and only if the url is malformed.
764−'Purl' is also the mark which will be applied to this result.
765−
766−When you send this request, you can expect a `%sigh` with the
767−response, which we handle later on in `++sigh-httr`.
768−
769−For `%wait`, you just pass a `@da` (absolute date), and arvo will
770−produce a `%wake` when the time comes.
771−
772−> 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.
773−
774−Let's take a look at our state:
775−
776−```hoon
777−|_ [hid=bowl:gall on=_| in-progress=_| target=@t]
778−```
779−
780−We have three pieces of app-specific state. `target` is the url
781−we're monitoring. `on` and `in-progress` are booleans
782−representing, respectively, whether or not we're supposed to keep
783−monitoring and whether or not we're in the middle of a request.
784−
785−The type of booleans is usually written as `?`, which is a union
786−of `&` (true) and `|` false. This type defaults to `&` (true). In our
787−case, we want both of these to default to `|` (false). Because
788−of that, we use `_|` as the type. `_value` means "take the type
789−of `value`, but make the default value be `value`". Thus, our
790−type is still a boolean, just like `?`, but the default value is
791−`|` (false).
792−
793−> 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.
794−
795−Let's take a look at `++poke-atom`. When we're poked with an atom, we
796−first check whether the atom is `'off'`. If so, we set our state
797−variable `on` to false.
798−
799−If not, we check whether the atom is `'on'`. If so, we set `on` and
800−`in-progress` to true. If it was already either on or in progress, then
801−we don't take any other immediate action. If it was both off and not in
802−progress, then we send an HTTP request.
803−
804−If the argument is neither 'off' nor 'on', then we assume it's an
805−actual url, so we save it in `target`.
806−
807−Here's the move that sends the HTTP request:
808−
809−```hoon
810−[ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]
811−```
812−
813−> 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.
814−
815−The correspondence between this move and `[bone card]` can be hard to
816−visualize on one line. Here it is more pedantically:
817−
818−```hoon
819−:* bone=ost.hid :: the move
820− term=%hiss
821− wire=/request
822− unit-iden=~
823− mark=%httr
824− cage=[%purl (need (de-purl:html target))]
825−==
826−```
827−
828−When the HTTP response comes back, we handle it with
829−`++sigh-httr`, which, along with the wire the request was sent
830−on, takes the status code, the response headers, and the response
831−body.
832−
833−We check whether the status code is between 200 and 300. If so,
834−all is well, and we print a message saying so. We start the
835−timer for ten seconds after the present time.
836−
837−If we got a bad status code, then we print out the entire
838−response and start the timer again.
839−
840−After ten seconds, arvo will give us a `%wake` event, which will
841−be handled in `++wake-timer`. If we're still supposed to keep
842−monitoring, we send the same HTTP request as before. Otherwise,
843−we set `in-progress` to false.
844−
845−Let's try it out:
846−
847−```
848−~fintud-macrep:dojo> |start %up
849−>=
850−~fintud-macrep:dojo> :up &atom 'http://www.google.com'
851−>=
852−[%all-is-well 200]
853−[%all-is-well 200]
854−~fintud-macrep:dojo> :up &atom 'http://example.com'
855−>=
856−[%all-is-well 200]
857−~fintud-macrep:dojo> :up &atom 'http://google.com'
858−>=
859−[%we-have-a-problem 301]
860−[ %headers
861− ~[
862− [p='X-Frame-Options' q='SAMEORIGIN']
863− [p='X-XSS-Protection' q='1; mode=block']
864− [p='Content-Length' q='219']
865− [p='Server' q='gws']
866− [p='Cache-Control' q='public, max-age=2592000']
867− [p='Expires' q='Sun, 10 Jan 2016 23:45:05 GMT']
868− [p='Date' q='Fri, 11 Dec 2015 23:45:05 GMT']
869− [p='Content-Type' q='text/html; charset=UTF-8']
870− [p='Location' q='http://www.google.com/']
871− ]
872−]
873−[ %body
874− [ ~
875− [ p=219
876− q
877− \/'<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">\0a<TITLE>301 Moved</TI\/
878− TLE></HEAD><BODY>\0a<H1>301 Moved</H1>\0aThe document has moved\0a<A HREF="http://www.google.com/">her
879− e</A>.\0d\0a</BODY></HTML>\0d\0a'
880− \/ \/
881− ]
882− ]
883−]
884−~fintud-macrep:dojo> :up &atom 'off'
885−```
886−
887−## Marks
888−
889−We've used predefined marks already, but we haven't yet created
890−our own marks. Let's write a sample mark of our own, then chain
891−it together with some preexisting ones to have fun with type
892−conversions.
893−
894−Let's make a small "cord" mark. "Cord" is a name we use for `@t`
895−text, but there's no predefined mark for it. Let's put the following code in:
896−`/mar/cord.hoon`:
897−
898−```hoon
899−/? 314
900−|_ cod=@t
901−++ grab
902− |%
903− ++ atom |=(arg=@ `@t`(scot %ud arg))
904− --
905−++ grow
906− |%
907− ++ md cod
908− --
909−--
910−```
911−
912−`/? 314` is the required
913−version number, just like in apps. After that everything's in a
914−`|_`, which is a `|%` core, but with input arguments. In our
915−case, the argument is the marked data.
916−
917−There are three possible top-level arms in the `|_` core,
918−`++grab`, `++grow`, and `++grad` (which is used for revision
919−control, covered elsewhere). `++grab` specifies
920−functions to convert from another mark to the current mark.
921−`++grow` specifies how to convert from the current mark to
922−another one.
923−
924−In our case, we only define one arm in `++grab`, namely `++atom`.
925−This allows us to convert any atom to a cord. `++scot` is a
926−standard library function in `hoon.hoon` which pretty-prints
927−atoms of various types. We want to treat the atom as an
928−unsigned decimal number, so we give `%ud` and the given argument
929−to `++scot`. Thus, the form of an arm in `++grab` is
930−`|=(other-mark-type this-mark-value)`.
931−
932−In `++grow`, we just convert to the `md` mark, which is just a
933−`@t` internally, but it has fancy conversion functions to things
934−like html. `++md` isn't a function because the "argument" is
935−already a `@t`, so we can just produce the new value directly.
936−
937−Let's play around a bit with this mark. First, let's take a
938−marked atom and convert it to our new mark.
939−
940−```
941−~fintud-macrep:dojo> &atom 9
942−9
943−
944−~fintud-macrep:dojo> &cord &atom 9
945−'9'
946−
947−~fintud-macrep:dojo> &cord &atom &cord &atom 9
948− '57'
949−```
950−
951−ASCII 9 is 57. There's no requirement, implicit or otherwise,
952−that conversions back and forth between marks be inverses of each
953−other. These are semantic conversions, in that they refer to the
954−same concept. They're not isomorphisms.
955−
956−Let's play around a little more:
957−
958−```
959−~fintud-macrep:dojo> &md &cord &atom 17
960−'17'
961−
962−~fintud-macrep:dojo> &hymn &md &cord &atom 17
963−[ [%html ~]
964− [[%head ~] ~]
965− [[%body ~] [g=[n=%pre a=~] c=~[[g=[n=%$ a=~[[n=%$ v="17"]]] c=~]]] ~]
966− ~
967−]
968−```
969−
970−That was exciting. If you squint at that, it looks an
971−awful lot like html. Our value `17` is still in there, in the
972−body. `urb` is the mark we render most web pages to. It makes
973−sure you have a complete skeleton of a web page. Of course, by
974−the time this gets to the web page, it's plain html. Let's do
975−the final step in the conversion.
976−
977−```
978−~fintud-macrep:dojo> &mime &hymn &md &cord &atom 17
979−[[%text %html ~] p=52 q='<html><head></head><body><pre>17</pre></body></html>']
980−```
981−
982−This is a mime-typed octet stream with type `/text/html`, length
983−121 bytes, and our lowly number `17` rendered to a web page.
984−`cord` was just one step in the chain.
985−
986−Of course, arvo can infer some parts of this chain:
987−
988−```
989−~fintud-macrep:dojo> &cord 17
990−'17'
991−```
992−
993−Likewise, `md` is the only way to get from `cord` to `hymn`, so
994−that can be omitted. If we omit the `hymn`, though, we get:
995−
996−```
997−~fintud-macrep:dojo> &mime &cord 17
998−[[%text %x-markdown ~] p=2 q='17']
999−```
1000−
1001−Here, we converted straight from `cord` to `md` to `mime`. Arvo
1002−decided that was the most straightforward conversion, but it
1003−gives a different result than passing it through the `hymn`
1004−mark.
1005−
1006−The minimal correct input, then, is `&mime &hymn &cord &atom 17`.
1007−
1008−## Network Messages
1009−
1010−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.
1011−
1012−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`:
1013−
1014−```hoon
1015−:: Accepts any noun from dojo and prints it out
1016−::
1017−:::: /===/app/echo/hoon
1018− ::
1019−!: :: enables debug printfs
1020−|% :: forms a core with subject as payload
1021−+$ move [bone card] :: defines echo app's arvo move mold
1022−+$ card $% $~ :: defines card (data) mold as null tagged union
1023− == :: end of mold definition; see $%
1024−-- :: end of card arm definition
1025−:: ::
1026−|_ [bow=bowl:gall $~] :: forms a core with bowl (app state) as sample
1027−++ poke-noun :: begin definition of poke-noun arm
1028− |= non=* :: forms a gate which accepts any noun
1029− ^- [(list move) _+>.$] :: casts product to mold of moves and context
1030− ~& echo+noun+non :: debug printf, i.e. '[%echo %noun *]'
1031− [~ +>.$] :: produce a cell of empty list and our state
1032−-- :: end of poke-noun arm definition
1033−```
1034−
1035−Save this as `echo.hoon` in the `/app` directory of your urbit's pier.
1036−
1037−This is a very simple app that does only one thing. If you poke it with
1038−a value, it prints that value out. To try this out, you have to start
1039−the app, then you can poke it from the command line with the following
1040−commands:
1041−
1042−```
1043−~fintud-macrep:dojo> |start %echo
1044−>=
1045−
1046−~fintud-macrep:dojo> :echo 5
1047−[%echo %noun 5]
1048−>=
1049−
1050−~fintud-macrep:dojo> :echo [1 2]
1051−[%echo %noun [1 2]]
1052−>=
1053−```
1054−
1055−> 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.
1056−
1057−Most of the app code should be simple enough to guess its function. The
1058−important part of this code is the definition of `++poke-noun`.
1059−
1060−Once an app starts, it's always running in the background and you interact with
1061−it by sending it messages. The most straightforward way to do that is to poke it
1062−from the command line, which we we did with `:echo 5`
1063−(`:[app-name] [argument(s)]`).
1064−
1065−In this case, `++poke-noun` takes an argument (**sample**) `arg` and
1066−prints it to dojo with `~&` ([sigpam](/docs/hoon/hoon-expressions/rune/sig#sigpam/)).
1067−This is an unusual rune that formally "does nothing", but the interpreter
1068−detects it and printfs the first child, before executing the second as if the
1069−first didn't exist. This is a slightly hacky way of printing to the console,
1070−but we'll get to the correct way later on.
1071−
1072−But what does `++poke-noun` produce? Recall that `^-` casts to a type. In this
1073−case, it's declaring that the end result (**product**) of the function
1074−(`++poke-noun`'s **gate**) will be of type `[(list) _+>.$]`. But what does this
1075−mean?
1076−
1077−The phrase to remember is "a list of moves and our state". Urbit is a message
1078−passing system, so whenever we want to do something that interacts with the rest
1079−of the system, we send a message. Thus, a move is Arvo's equivalent of a
1080−syscall. The first thing that `++poke-noun` produces is a list of messages,
1081−called "moves". In this case, we don't actually want the system to do anything,
1082−so we produce the empty list, `~` (in the `[~ +>.$]` line).
1083−
1084−The second thing `++poke-noun` produces is our state. `+>.$` refers to a
1085−particular address in our subject where our formal app state is stored.
1086−It'll become clear why this is later on, but for now pretend that `+>.$`
1087−is a magic invocation that means "app state".
1088−
1089−Let's look at another example. Say we want to
1090−only accept a number, and then print out the square of that number.
1091−
1092−```hoon
1093−:: Accepts an atom from the dojo and squares it.
1094−::
1095−:::: /===/app/square/hoon
1096− ::
1097−!:
1098−|% :: no moves in :square
1099−+$ move [bone card] :: no cards in :square
1100−+$ card $% $~
1101− ==
1102−--
1103−:: :: stateless
1104−|_ [bow=bowl:gall $~]
1105−++ poke-atom
1106− |= tom=@
1107− ^- [(list move) _+>.$]
1108− ~& square+(mul tom tom)
1109− [~ +>.$]
1110−--
1111−```
1112−
1113−Save this as `square.hoon` in the `/app` directory of your urbit's pier.
1114−
1115−A few things have changed. Firstly, we no longer accept arbitrary nouns because
1116−we can only square atoms (integers, in this case an unsigned one). Thus, our
1117−argument is now `tom=@`. Secondly, it's `++poke-atom` rather than `++poke-noun`.
1118−
1119−### Intro to marks
1120−
1121−Are there other `++poke`s? Yes. In fact, `noun` and `atom` are just two
1122−of arbitrarily many "marks". A mark is fundamentally a type definition,
1123−but accessible at the Arvo level. Each mark is defined in the `/mar`
1124−directory. Some marks have conversion routines to other marks, and some
1125−have diff, patch, and merge algorithms. None of these are required for a
1126−mark to exist, however.
1127−
1128−`noun` and `atom` are two predefined marks. In your `/mar` directory,
1129−there are already many more, and you may add more at will. The type
1130−associated with `noun` is `*`, and the type associated with `atom` is
1131−`@`.
1132−
1133−When we poke an app from anywhere, we do so with a mark that searches
1134−for the corresponding (`++poke-[mark]`) arm. Data constructed on the
1135−command line is by default marked with `noun`. In this case, the app is
1136−expecting an atom, so we have to explicitly mark the data with `atom`
1137−using `&[mark]`. Try the following commands:
1138−
1139−```
1140−~fintud-macrep:dojo> |start %square
1141−>=
1142−
1143−~fintud-macrep:dojo> :square 6
1144−gall: %square: no poke arm for noun
1145−
1146−~fintud-macrep:dojo> :square &atom 6
1147−[%square 36]
1148−>=
1149−```
1150−
1151−> Recall the bug where `%square` may get printed above the input line.
1152−
1153−Marks are powerful, and they're the backbone of Urbit's data pipeline,
1154−so we'll be getting quite used to them.
1155−
1156−**Exercise**:
1157−
1158−- Write an app that computes fizzbuzz on its input.
1159−
1160−#### Sending a message to another urbit
1161−
1162−Let's write our first network message! Here's `examples/app/pong.hoon`:
1163−
1164−```hoon
1165−:: Allows one urbit to send the string 'Pong' to
1166−:: another urbit.
1167−::
1168−:::: /===/app/pong/hoon
1169− ::
1170−!:
1171−|%
1172−+$ move [bone card]
1173−+$ card $% [$poke wire dock poke-contents]
1174− ==
1175−+$ poke-contents $% [$atom @]
1176− ==
1177−--
1178−|_ [bow=bowl:gall $~] :: stateless
1179−::
1180−++ poke-urbit
1181− |= to=ship
1182− ^- [(list move) _+>.$]
1183− ~& pong+'Outgoing pong!'
1184− :_ +>.$
1185− ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong']]
1186−::
1187−++ poke-atom
1188− |= tom=@
1189− ^- [(list move) _+>.$]
1190− ~& pong+'Incoming pong!'
1191− ~& pong+received+`@t`tom
1192− [~ +>.$]
1193−::
1194−++ coup |=(* [~ +>.$])
1195−::
1196−--
1197−```
1198−
1199−
1200−Run it with these commands:
1201−
1202−```
1203−~fintud-macrep:dojo> |start %pong
1204−>=
1205−
1206−~fintud-macrep:dojo> :pong &urbit ~sampel-sipnym
1207−>=
1208−```
1209−
1210−Replace `~sampel-sipnym` with another urbit. The easiest thing to do is to start
1211−a comet, a free and disposable Urbit identity. If you don't know how to start a
1212−comet, see [the user setup section](@/operations.md). Don't forget to start
1213−the `%pong` app on that urbit, too. You should see, on the foreign
1214−urbit, this output:
1215−
1216−```hoon
1217−[%pong 'Incoming pong!']
1218−[%pong %received 'Pong']
1219−```
1220−
1221−Most of the code should be straightforward. In `++poke-atom`, the only new thing
1222−is the expression `` `@t`tom ``, which is **casting** the argument `tom` to type
1223−`@t`. As we already know, `@t` is the type of "cord" (text string).
1224−
1225−The more interesting part is in `++poke-urbit`. The `urbit` mark is an urbit
1226−identity, and the Hoon type associated with it is `ship` or `@p` (the "p"
1227−stands for "phonetic base").
1228−
1229−Recall that in a `++poke` arm we produce "a list of moves and our state". Until
1230−now, we've left the list of moves empty, since we haven't wanted to tell Arvo to
1231−do anything in particular. Now we want to send a message to another urbit. Thus,
1232−we produce a list with one element:
1233−
1234−```hoon
1235−~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong]]
1236−```
1237−
1238−#### Moves
1239−
1240−The general form of a move is `[bone term wire *]`.
1241−
1242−Or, in pseudo-code:
1243−
1244−`["cause" sys-call/action tack-new-layer-on-cause action-specific information]`
1245−
1246−Let's walk through each of these elements step by step.
1247−
1248−###### Bones ("cause")
1249−
1250−If you look up `++bone` in `hoon.hoon`, you'll see that it's a number (`@ud`),
1251−and that it's an opaque reference to a duct. `++duct` in `hoon.hoon` is a list
1252−of `wire`s, where `++wire` is an alias for `++path`. `++path` is a list of
1253−`++knot`s, which are ASCII text. Thus, a duct is a list of paths, and a bone is
1254−an opaque reference to it (in the same way that a Unix file descriptor is an
1255−opaque reference to a file structure). Thus, to truly understand bones, we must
1256−understand ducts.
1257−
1258−A duct is a stack of causes, again, represented as paths, which are called wires.
1259−At the bottom of every duct is a unix event, such as a keystroke, network
1260−packet, file change, or timer event. When Arvo is given this event, it routes
1261−the event to appropriate kernel module for handling.
1262−
1263−Sometimes, the module can immediately handle the event and produce any necessary
1264−results. For example, when we poked the `++poke-atom` arm above, we poked %gall,
1265−our application server, which was able to respond to our poke directly. When the
1266−module cannot service the request itself, it sends instructions to another
1267−kernel module or application (through the %gall module) to do a specified
1268−action, and produces the result from that.
1269−
1270−Furthermore, when one module sends a message to another kernel module or
1271−application, it also sends along the duct it was given with its new wire tacked
1272−onto the top. Now the duct has two entries, with the unix event on the bottom
1273−and the kernel module that handled it on top. This process can continue
1274−indefinitely, pushing more and more wires onto the top of the duct. When an
1275−entity finally produces a result, a wire is popped off the duct, and the result
1276−is passed all the way back down, repeating the process of wire popping
1277−sequentially until the bottom of the duct is reached.
1278−
1279−In effect, a duct is an Arvo-level call stack. It's worth noting that while in
1280−traditional call stacks a function call happens synchronously and returns
1281−exactly once. In Arvo, multiple moves can be sent at once, are evaluated
1282−asynchronously, and each one may be responded to zero or more times.
1283−
1284−The point to take home is that whatever caused `++poke-urbit` to be called is
1285−also the root cause for the network message we're trying to send. Thus, we say
1286−to send the network message along the given bone `ost`.
1287−
1288−##### Wire (path)
1289−
1290−Of course, we have to push a new wire onto our duct before passing it along (or
1291−responding to it directly) anywhere. This wire can have any data we want in it,
1292−but we don't need anything specific here, so we just use the wire `/sending`
1293−(`/elem1/elem2/elemN` is one syntax used to create `++path`s and `++wire`s of N
1294−elements). If we were expecting a response (which we're not), it would come back
1295−along the `/sending` wire, meaning that the path `/sending` will be passed back
1296−to the response handler as an argument. Although it's not required, it's
1297−generally a good idea to make the wire human-readable for bug-handling purposes.
1298−
1299−##### Term (sys-call)
1300−
1301−Each move also has a `term`, composed of lowercase ASCII and/or `-`. This `term`
1302−has the sign `@tas`. In this case, our `term` is `%poke`, which is the name of
1303−the particular kind of move we're sending. You can always use `%poke` to message
1304−an app. Other common names include `%warp`, to read from the filesystem;
1305−`%wait`, to set a timer; and `%them`, to send an http request.
1306−
1307−The move ends with `*` (that is, any noun) since each type of move takes
1308−different data. In our case, a `%poke` move takes a target (urbit and app) and
1309−marked data, then pokes the arm of the corresponding mark on that app on that
1310−urbit with that data. `[to-urbit-address %pong]` is the target urbit and app,
1311−`%atom` is the `mark`, and`'Pong'` is the data.
1312−
1313−When Arvo receives a `%poke` move, it calls the appropriate `++poke`.
1314−The same mechanism is used for sending messages between apps on the same
1315−urbit as for sending messages between apps on different urbits.
1316−
1317−> 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.
1318−
1319−**Exercises**:
1320−
1321−- Extend either of the apps in the first two exercises to accept input over the network in the same way as `pong`.
1322−
1323−- Modify `pong.hoon` to print out a message when it receives acknowledgement.
1324−
1325−- 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:
1326−
1327−```
1328−~fintud-macrep:dojo> :even &atom 18
1329−[%even 18]
1330−[%odd 9]
1331−[%even 28]
1332−[%even 14]
1333−[%odd 7]
1334−[%even 22]
1335−[%odd 11]
1336−[%even 34]
1337−[%odd 17]
1338−[%even 52]
1339−[%even 26]
1340−[%odd 13]
1341−[%even 40]
1342−[%even 20]
1343−[%even 10]
1344−[%odd 5]
1345−[%even 16]
1346−[%even 8]
1347−[%even 4]
1348−[%even 2]
1349−%success
1350−```
1351−
1352−- 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.
1353−
1354−
1355−## Security Drivers
1356−
1357−A security driver is a file in `/=home=/sec/<tld>/<domain>/hoon`
1358−that handles the authentication for all HTTP requests to
1359−`https://<domain>.<tld>`. When anything in Urbit makes an HTTP
1360−request through `%eyre` (our web server), it checks to see if we
1361−have a security driver for the requested domain, and if so
1362−filters the request through the driver. The security driver will
1363−usually either decorate the request with the needed credentials
1364−if it has them, or else it will guide the user through the
1365−process of authenticating Urbit with the service.
1366−
1367−Each web service needs its own security driver, but most of them
1368−are pretty standard. We recommend starting with an existing
1369−security driver based on your needed authentication method (e.g.
1370−basic auth, OAuth1, OAuth2), and changing whatever is specific to
1371−your service.
1372−
1373−The best strategy for building security drivers is to copy a
1374−similar one and tweak it until it works for you. The best
1375−representatives are Github for Basic Authentication, Twitter for
1376−OAuth1, Slack for OAuth2 when access tokens don't expire, and
1377−Google APIs for OAuth2 when access tokens do expire. In most
1378−cases you'll need to make very few changes to one of these
1379−models.
1380−
1381−Still, it's worth seeing one or two built from the ground up.
1382−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.)
1383−
1384−The
1385−simplest way to interact with the Github API is to just fetch
1386−https://api.github.com from the dojo. First, run this:
1387−
1388−```
1389−> |init-auth-basic /com/github
1390−```
1391−
1392−Input your Github username and password as directed. Next:
1393−
1394−```
1395−~your-urbit:dojo> +https://api.github.com
1396−```
1397−
1398−> 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!
1399−
1400−Github exposes a few endpoints to the general web, and the root
1401−endpoint is one of them. This gives you a textual representation
1402−of a JSON object that contains a bunch of urls to other parts of
1403−Github's API. This is exactly the same response you would get
1404−from just running `curl https://api.github.com` on UNIX.
1405−
1406−If we don't have a security driver for Github yet, many of the
1407−endpoints won't be accessible, or they will only have publicly
1408−accessible information. Most of what we care about requires us
1409−to be authenticated.
1410−
1411−#### Basic auth
1412−
1413−Here's a simple security driver:
1414−
1415−```hoon
1416−:: Test url +https://api.github.com/user
1417−::
1418−:::: /hoon/github/com/sec
1419− ::
1420−/+ basic-auth
1421−!:
1422−|_ [bal=(bale keys:basic-auth) $~]
1423−++ aut ~(standard basic-auth bal ~)
1424−++ filter-request out-adding-header:aut
1425−--
1426−```
1427−
1428−Github supports authentication through either Basic
1429−Authentication or OAuth2. We'll show the basic auth example
1430−first, but in general we'd prefer OAuth2.
1431−
1432−Since this driver is for Github, put it in
1433−`/=home=/sec/com/github/hoon`.
1434−
1435−To try this out, we first have to initialize our credentials with
1436−`|init-auth-basic`, which prompts for the url of the service
1437−(api.github.com), username, and password. It stores this
1438−information in a manner that `%eyre` knows how to decode and send
1439−put into your `bale`. Note that `|init-auth-basic` is standard for
1440−basic auth, but other auth schemes (like OAuth) are initialized
1441−in other ways.
1442−
1443−After you've run `|init-auth-basic`, you should be able to run
1444−`+https://api.github.com/user` and get a response indicating who
1445−you're logged in as.
1446−
1447−You can similarly POST:
1448−
1449−```
1450−~your-urbit:dojo> +https://api.github.com/gists &json _(cork de-json:html need) '{"files":{"file1.txt":{"content":"can\'t stop the signal"}}}'
1451−```
1452−
1453−This creates a gist, go to `https://gist.github.com/<username>` to
1454−see it.
1455−
1456−The `+url` syntax used in "source" position makes a GET request,
1457−but if you pass it data it will make a POST request with that
1458−data as the body. This request is authenticated seamlessly. You
1459−can send data of any mark as long as it has a conversion path to
1460−`%mime`.
1461−
1462−Let's take a look at the code and see if we can figure out what's
1463−happening here:
1464−
1465−```hoon
1466−/+ basic-auth
1467−```
1468−
1469−First, we load a library called `basic-auth`. This library
1470−exposes two items. `keys` is the type of the basic auth key,
1471−which is essentially a base64'd username and password.
1472−`standard` accepts a `bale` and produces a core with everything
1473−we'll need to implement basic auth.
1474−
1475−Every security driver needs some amount of state, which is stored
1476−in `bale`. `bale` contains:
1477−
1478−- `our`, our urbit name
1479−- `now`, the current time
1480−- `eny`, 256 bits of entropy
1481−- `byk`, the urbit, desk and case which the security driver is running from
1482−- `usr`, the particular identity we're logging in with
1483−- `dom`, the site we're accessing
1484−- `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`.
1485−
1486−Additionally, a security driver contains at least one out of the
1487−five "special" arms:
1488−
1489−- `++filter-request` is a function which takes a hiss (http request) and produces a `sec-move` (defined in zuse), which is one of:
1490− - `[%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.
1491− - `[%give httr]`, where httr is an http response. This immediately returns an http response to the sender.
1492− - `[%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.
1493− - `[%redo ~]`, which redoes the request.
1494− - `%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.
1495−- `++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.
1496−- `++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.
1497−- `++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`.
1498−- `++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 `~`.
1499−
1500−For basic auth, we only have to worry about `++filter-request`,
1501−since all we need to do is add the correct header to each
1502−request. Our `++aut` core contains a function
1503−`++out-addding-header`, which does exactly what we want.
1504−
1505−Where do the keys come from, though? Remember we ran
1506−`|init-auth-basic` to input them. This just prompts you for the
1507−service url, username, and password, and it stores them next to
1508−the driver. In our case, that's
1509−`/=home=/sec/com/gitub/api/atom`. These keys are stored
1510−encrypted, and you don't want to edit them directly. `%eyre`
1511−loads them directly into your `bale`.
1512−
1513−#### OAuth2
1514−
1515−Most services are better accessed through some form of OAuth.
1516−Github can be accessed with OAuth2, which is a little more
1517−complicated than basic auth, but not hugely so.
1518−
1519−The basic steps for OAuth2 are these:
1520−
1521−- create an app and get its client id and client secret (on Github)
1522−- store these in Urbit (with `|init-oauth2`)
1523−- try to make a request that requires authentication. The security driver should prompt you to visit a particular url.
1524−- visit the url and click "authorize", which gives the app access to your account
1525−- the security driver will turn the code it receives into an access token
1526−- on every request, include that access token
1527−
1528−Creating an app is easy and
1529−[well-documented](https://github.com/settings/applications/new).
1530−If necessary, set the callback url to
1531−`/~/ac/github.com/_state/in`, and note its client id and client
1532−secret.
1533−
1534−Run `|init-oauth2`, which will prompt for the hostname
1535−(api.github.com), client id, and client secret. This will store
1536−the information, encrypted, in `/=home=/sec/com/github.atom`,
1537−just as with Basic Authentication.
1538−
1539−Now we need a security driver. Use this:
1540−
1541−```hoon
1542−:: Test url +https://api.github.com/user
1543−::
1544−:::: /hoon/github/com/sec
1545− ::
1546−/+ oauth2
1547−!:
1548−::::
1549− ::
1550−|_ [bal=(bale keys:oauth2) tok=token:oauth2]
1551−++ scopes :: comment out scopes to taste
1552− :~ 'user' 'user:email' 'user:follow' 'public_repo' 'repo'
1553− 'repo_deployment' 'repo:status' 'delete_repo' 'notifications'
1554− 'gist' 'read:repo_hook' 'write:repo_hook' 'admin:repo_hook'
1555− 'admin:org_hook' 'read:org' 'write:org' 'admin:org'
1556− 'read:public_key' 'write:public_key' 'admin:public_key'
1557− ==
1558−:: ++aut is a "standard oauth2" core, which implements the
1559−:: most common handling of oauth2 semantics. see lib/oauth2 for more details,
1560−:: and examples at the bottom of the file.
1561−++ aut (~(standard oauth2 bal tok) . |=(tok/token:oauth2 +>(tok tok)))
1562−++ filter-request
1563− %^ out-add-query-param:aut 'access_token'
1564− scope=~[%client %admin]
1565− oauth-dialog='https://github.com/login/oauth/authorize'
1566−::
1567−++ receive-auth-query-string
1568− %- in-code-to-token:aut
1569− url='https://github.com/login/oauth/api/access_token'
1570−++ receive-auth-response bak-save-token:aut
1571−--
1572−```
1573−
1574−The oauth2 library provides the main "engine" in `standard`, just
1575−like in basic auth, except that we also have to specify a
1576−function to save the access token when we get it. It's worth
1577−noting that this library is well documented in the source,
1578−including examples: `/=home=/lib/oauth2/hoon`.
1579−
1580−Running `+http://api.github.com/user` tries to make a request to
1581−Github with authentication. This loads into the bale the keys,
1582−which are of type `keys:oauth2`, defined in the oauth2 library.
1583−We don't have to worry about the specifics of these keys -- the
1584−library handles them -- but they include the client id and the
1585−client secret.
1586−
1587−Before the request is sent, `%eyre` calls `++filter-request` to
1588−decorate it with authentication headers. Since we don't yet have
1589−an access token, we need to prompt the user to visit the "dialog"
1590−url. `++out-add-query-param` checks whether we have a token, and
1591−if we don't it produces `%show` and a message telling the user to
1592−visit the `oauth-dialog` url we provide, with the extra query
1593−parameters added (client id, scopes, and state).
1594−
1595−When the user visits that url, Github will ask them to log in and
1596−authorize the application. When they do so, Github will post a
1597−request to `/~/ac/github.com/_state/in` with a code in the query
1598−string. `%eyre` sends the query string to
1599−`++receive-auth-query-string`, which is a function that takes a
1600−quay and produces a `sec-move`. `++in-code-to-token` from our
1601−`aut` takes the `code` parameter from the quay and uses it to
1602−create a request to the given url. This request includes the
1603−client id, the client secret, and the code we just got.
1604−
1605−Github's response to that request includes an access token in its
1606−body. This is handled in `++receive-auth-response`.
1607−`++bak-save-token` extracts that token and gives it to the
1608−function that we passed in the definition of `++aut`. In our
1609−case, we just save that token into our state for later usage.
1610−
1611−Now we have the credentials we need, so `++filter-request` is
1612−called with the original request, and `++out-add-query-param`
1613−passes the request through with the addition of the query
1614−parameter `access_token`.
1615−
1616−Just like with Basic Authentication, you should be able to run
1617−`+https://api.github.com/user` and get a response indicating who
1618−you're logged in as.
1619−
1620−Some drivers a slightly more complicated. For example, Github's
1621−access token's don't expire, but that's not the case for all
1622−service. The googleapis driver shows the flow when the access
1623−token can expire. Twitter uses OAuth1, for which we have another
1624−library.
1625−
1626−Remember, of course, that the best strategy for building security
1627−drivers is to copy a similar one and tweak it to taste.
1628−
1629−## State
1630−
1631−In the last section we built a few small apps that sent moves. These apps were
1632−entirely stateless, however. Most useful apps require some amount of state.
1633−Let's build a trivial stateful app. It'll keep a running the sum of all the
1634−atoms we poke it with. Here's `examples/app/sum.hoon`:
1635−
1636−```hoon
1637−:: Keeps track of the sum of all the atoms it has been
1638−:: poked with and prints the sum out
1639−::
1640−:::: /===/app/sum/hoon
1641− ::
1642−!:
1643−|%
1644−+$ move [bone card]
1645−+$ card $% $~
1646− ==
1647−--
1648−|_ [bow=bowl:gall sum=@]
1649−::
1650−++ poke-atom
1651− |= tom=@
1652− ^- [(list move) _+>.$]
1653− ~& sum+(add sum tom)
1654− [~ +>.$(sum (add sum tom))]
1655−::
1656−++ coup
1657− |= [wir=wire err=(unit tang)]
1658− ^- [(list move) _+>.$]
1659− ?~ err
1660− ~& sum+success+'Poke succeeded!'
1661− [~ +>.$]
1662− ~& sum+error+'Poke failed. Error:'
1663− ~& sum+error+err
1664− [~ +>.$]
1665−::
1666−--
1667−```
1668−
1669−We can start it with `|start %sum`, and then run it:
1670−
1671−```
1672−~fintud-macrep:dojo> :sum &atom 5
1673−[%sum 5]
1674−>=
1675−
1676−~fintud-macrep:dojo> :sum &atom 2
1677−[%sum 7]
1678−>=
1679−
1680−~fintud-macrep:dojo> :sum &atom 15
1681−[%sum 22]
1682−>=
1683−```
1684−
1685−We can see that app state is being saved, but when, where, and how?
1686−
1687−The state is stored as the second thing in the `|_` line. In our case, it's
1688−simply an atom named `sum`. We change it by producing our state not with
1689−`+>.$` (as before), but with `+>.$(sum (add sum tom))`. We've seen all these
1690−parts before, but you might not recognize them.
1691−
1692−Recall in the first chapter that we recursed with the expression
1693−`$(b (add 3 b))`. This meant "produce `$` with `b` changed to `(add 3 b)`.
1694−Similarly, `+>.$(sum (add sum tom))` means "produce `+>.$` (i.e. our
1695−context, which contains our state) with `sum` changed to `(add sum tom)`.
1696−
1697−At a high level, then, when we handle state, we do it explicitly. It's passed in
1698−and produced explicitly. In Unix systems, application state is just a block of
1699−memory, which you need to serialize to disk if you want to keep it around for
1700−very long.
1701−
1702−In Urbit, app state is a single (usually complex) value. In our example, we have
1703−very simple state, so we defined `sum=@`, meaning that our state is an atom.
1704−Of course, `sum` is just a name, and you're free to name your state whatever
1705−you like. But let's clarify a couple other things before we continue.
1706−
1707−First, `bowl` is a set of general global states. This set is managed by the
1708−system. It includes things like `now` (the current time), `our` (our urbit
1709−identity), and `eny` (512 bits of guaranteed-fresh entropy). For the full list
1710−of things in `++bowl`, search for `++ bowl` (note: two spaces) in
1711−`/arvo/zuse.hoon`.
1712−
1713−> 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.
1714−
1715−The second thing we should clear up is this: Urbit needs no "serialize to disk"
1716−step. Everything you produce in the app state is persistent across calls to the
1717−app, restarts of the urbit, and even power failure. If you want to write to the
1718−Unix filesystem, you can, but it's not needed for persistence. Urbit has
1719−transactional events, which makes it an [ACID operating
1720−system](https://en.wikipedia.org/wiki/ACID). Thus, you don't have to worry about
1721−persistence when programming in Urbit, or ever go through the hassle of having
1722−to set up and write to a database.
1723−
1724−**Exercises**:
1725−
1726−- Modify `:sum` to reset the counter when you poke it with 0.
1727−
1728−- Write an app called `last` that prints out the previous value you poked it with.
1729−
1730−Sample output:
1731−
1732−```
1733−~fintud-macrep:dojo> :last 7
1734−[%last 0]
1735−>=
1736−
1737−~fintud-macrep:dojo> :last [1 2 3]
1738−[%last 7]
1739−>=
1740−
1741−~fintud-macrep:dojo> :last 'howdy'
1742−[%last [1 2 3]]
1743−```
1744−
1745−
1746−## Subscriptions
1747−
1748−We've dealt fairly extensively with "poke" messages to an app, but these
1749−are somewhat limited. A poke is a one-way message, but more often we
1750−want to subscribe to updates from another app. You could build a
1751−subscription model out of one-way pokes, but it's such a common pattern
1752−that it's built into Arvo.
1753−
1754−Let's take a look at two apps, `:source` and `:sink`. First,
1755−`:source`:
1756−
1757−```hoon
1758−:: Sends subscription updates to sink.hoon
1759−::
1760−:::: /===/app/source/hoon
1761− ::
1762−!:
1763−::
1764−|%
1765− +$ move [bone card]
1766− +$ card $% [%diff diff-contents]
1767− ==
1768−+$ diff-contents $% [%noun *]
1769− ==
1770−--
1771−::
1772−|_ [bow=bowl:gall $~]
1773−::
1774−++ poke-noun
1775− |= non=*
1776− ^- [(list move) _+>.$]
1777− :_ +>.$
1778− %+ turn (prey:pubsub:userlib /example-path bow)
1779− |=([o=bone *] [o %diff %noun non])
1780−::
1781−++ peer-example-path
1782− |= pax=path
1783− ^- [(list move) _+>.$]
1784− ~& source+peer-notify+'Someone subscribed to you!'
1785− ~& source+[ship+src.bow path+pax]
1786− [~ +>.$]
1787−::
1788−++ coup
1789− |= [wir=wire err=(unit tang)]
1790− ^- [(list move) _+>.$]
1791− ?~ err
1792− ~& source+success+'Poke succeeded!'
1793− [~ +>.$]
1794− ~& source+error+'Poke failed. Error:'
1795− ~& source+error+err
1796− [~ +>.$]
1797−::
1798−++ reap
1799− |= [wir=wire err=(unit tang)]
1800− ^- [(list move) _+>.$]
1801− ?~ err
1802− ~& source+success+'Peer succeeded!'
1803− [~ +>.$]
1804− ~& source+error+'Peer failed. Error:'
1805− ~& source+error+err
1806− [~ +>.$]
1807−::
1808−--
1809−```
1810−
1811−Save this as `source.hoon` in the `/app` directory of your urbit's pier.
1812−
1813−And secondly, `:sink`:
1814−
1815−```hoon
1816−:: Sets up a simple subscription to source.hoon
1817−::
1818−:::: /===/app/sink/hoon
1819− ::
1820−!:
1821−|%
1822−+$ move [bone card]
1823−+$ card $% [%peer wire dock path]
1824− [%pull wire dock $~]
1825− ==
1826−--
1827−::
1828−|_ [bow=bowl:gall val=?]
1829−::
1830−++ poke-noun
1831− |= non=*
1832− ^- [(list move) _+>.$]
1833− ?: &(=(%on non) val)
1834− :_ +>.$(val |)
1835− :~ :* ost.bow
1836− %peer
1837− /subscribe
1838− [our.bow %source]
1839− /example-path
1840− ==
1841− ==
1842− ?: &(=(%off non) !val)
1843− :_ +>.$(val &)
1844− ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
1845− ~& ?: val
1846− sink+unsubscribed+'You are now unsubscribed!'
1847− sink+subscribed+'You are now subscribed!'
1848− [~ +>.$]
1849−::
1850−++ diff-noun
1851− |= [wir=wire non=*]
1852− ^- [(list move) _+>.$]
1853− ~& sink+received-data+'You got something!'
1854− ~& sink+data+non
1855− [~ +>.$]
1856−::
1857−++ coup
1858− |= [wir=wire err=(unit tang)]
1859− ^- [(list move) _+>.$]
1860− ?~ err
1861− ~& sink+success+'Poke succeeded!'
1862− [~ +>.$]
1863− ~& sink+error+'Poke failed. Error:'
1864− ~& sink+error+err
1865− [~ +>.$]
1866−::
1867−++ reap
1868− |= [wir=wire err=(unit tang)]
1869− ^- [(list move) _+>.$]
1870− ?~ err
1871− ~& sink+success+'Peer succeeded!'
1872− [~ +>.$]
1873− ~& sink+error+'Peer failed. Error:'
1874− ~& sink+error+err
1875− [~ +>.$]
1876−::
1877−--
1878−```
1879−
1880−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).
1881−
1882−Two notes:
1883−
1884−- `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.
1885−
1886−- 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 => |_`
1887−
1888−Here's some sample output of the two working together:
1889−
1890−```
1891−~fintud-macrep:dojo> |start %source
1892−>=
1893−
1894−~fintud-macrep:dojo> |start %sink
1895−>=
1896−
1897−~fintud-macrep:dojo> :sink %on
1898−[%source %peer-notify 'Someone subscribed to you!']
1899−[%source [%ship ~fintud-macrep] %path /]
1900−[%sink %success 'Peer succeeded!']
1901−>=
1902−
1903−~fintud-macrep:dojo> :source 5
1904−[%sink %received-data 'You got something!']
1905−[%sink %data 5]
1906−>=
1907−
1908−~fintud-macrep:dojo> :sink %off
1909−>=
1910−
1911−~fintud-macrep:dojo> :source 6
1912−>=
1913−
1914−~fintud-macrep:dojo> :sink %on
1915−[%source %peer-notify 'Someone subscribed to you!']
1916−[%source [%ship ~fintud-macrep] %path /]
1917−[%sink %success 'Peer succeeded!']
1918−>=
1919−
1920−~fintud-macrep:dojo> :source 7
1921−[%sink %received-data 'You got something!']
1922−[%sink %data 7]
1923−>=
1924−```
1925−
1926−###### :source
1927−
1928−Hopefully you can get a sense for what's happening here. When we poke
1929−`:sink` with `%on`, `:sink` subscribes to `:source`,
1930−and so whenever we poke `:source`, `:sink` gets the update and
1931−prints it out. Then we unsubscribe by poking `:sink` with `%off`, and
1932−`:sink` stops getting updates. We then resubscribe.
1933−
1934−There's a fair bit going on in this code. Let's look at `:source`
1935−first.
1936−
1937−Our definition of `move` is fairly specific, since we're only going to
1938−sending one kind of move. The `%diff` move is a subscription update, and
1939−its content is marked data which gall routes to our subscribers.
1940−
1941−This is a slightly different kind of move than we've dealt with so
1942−far. It's producing a result rather than calling other
1943−code (i.e. it's a return rather than a function call), so if you recall
1944−the discussion of ducts, a layer gets popped off the duct rather than
1945−added to it. This is why no wire is needed for the move -- we won't
1946−receive anything in response to it.
1947−
1948−Anyways, there are four functions (arms) inside the `|_`. We already know when
1949−`++poke-noun` is called. `++peer-example-path` is called when someone tries to
1950−subscribe to our app. Of course, you don't just subscribe to an app; you
1951−subscribe to a path on that app. This path comes in as the argument to `++peer`.
1952−
1953−In our case, we don't care what path you subscribed on, and all we do is print
1954−out that you subscribed. Arvo keeps track of your subscriptions, so you don't
1955−have to. You can access your subscribers by looking at `sup` in the bowl that's
1956−passed in. `sup` is of type `(map bone {@p path})`, which associates bones with
1957−the urbit who subscribed, and which path they subscribed on. If you want to
1958−communicate with your subscribers, send them messages along their bone.
1959−
1960−`++poke-noun` "spams" the given argument to all our subscribers.
1961−There's a few things we haven't seen before. Firstly, `:_(a b)` is the
1962−same as `[b a]`. It's just a convenient way of formatting things when
1963−the first thing in a cell is much more complicated than the second.
1964−Thus, we're producing our state unchanged.
1965−
1966−Our list of moves is the result of a call to `++turn`. `++turn` is what many
1967−languages call "map" -- it runs a function on every item in a list and collects
1968−the results in a list. The list is `(prey:pubsub:userlib /example-path bow)` and the function
1969−is the `|=` line right after it.
1970−
1971−`prey:pubsub:userlib` is a standard library function defined in `zuse.hoon`. It takes a path
1972−and a bowl and gives you a list of the subscribers who are subscribed on a path
1973−that begins with the given path. "Prey" is short for "prefix".
1974−
1975−Now we have the list of relevant subscribers. This a list of triples,
1976−`[bone @p path]`, where the only thing we really need is the bone, because we
1977−don't need to know their urbit or what exact path they subscribed on. Thus, our
1978−transformer function takes `[o=bone *]` and produces `[o %diff %noun non]`,
1979−which is a move that provides bone `o` with this subscription update:
1980−`[%noun non]`". This is fairly dense code, but what it's doing is
1981−straightforward!
1982−
1983−###### :sink
1984−
1985−`:source` should now make sense. `:sink` is a little longer, but not much more
1986−complicated.
1987−
1988−In `:sink`, our definition of of `++move` is different. All moves start
1989−with a `bone`, and we conventionally refer to the second half as the "card", so
1990−that we can say a move is an action that sends a card along a bone.
1991−
1992−We have two kinds of cards here: we `%peer` to start a subscription, and we
1993−`%pull` to stop it. Both of these are "forward" moves that may receive a
1994−response, so they need a wire to tack onto the duct before they pass it on. They
1995−also need a target, which is a pair of an urbit and an app name. Additionally,
1996−`%peer` needs a path on that app to subscribe too. `%pull` doesn't need this,
1997−because its semantics are to cancel any subscriptions coming over this duct. If
1998−your bone and wire are the same as when you subscribed, then the cancellation
1999−will happen correctly.
2000−
2001−The only state we need for `:sink` is a boolean to indicate whether
2002−we're already subscribed to `:source`. We use `val=?`, where `?`
2003−is the sign of type boolean (similar to `*`, `@`), which defaults to true (that
2004−is, `0`).
2005−
2006−In `++poke-noun` we check our input to see both if it's `%on` and we're
2007−available (`val` is true). If so, we produce the move to subscribe to
2008−`:source`:
2009−
2010−```hoon
2011−:~ :* ost.bow
2012− %peer
2013− /subscribe
2014− [our.bow %source]
2015− /example-path
2016− ==
2017−==
2018−```
2019−
2020−Also, in the preceding lines, we set `val` to false (`|`) with `+>.$(val |)`.
2021−Remember that the `:_` constructs an inverted cell, with the first child
2022−(`+>.$(val |` in our case) as the tail and the second child as the head. Here,
2023−the cell we produce when our subscription is `%on` and `val` is true has a
2024−head with our new state where `val` is set to false and a tail of our list of
2025−moves, which is shown in the code block above.
2026−
2027−Otherwise, if our input is `%off` and we're already subscribed (i.e. `val`
2028−is false), then we unsubscribe from `:source` and set `val` back to true (`&`),
2029−again using our handy inverted cell constructor mold `:_`:
2030−
2031−```hoon
2032−:_ +>.$(val &)
2033−~[[ost.bow %pull /subscribe [our.bow %source] ~]]
2034−```
2035−
2036−It's important to send over the same bone and wire (`/subscribe`) as the
2037−one we originally subscribed on.
2038−
2039−If neither of these cases are true, then we print our current subscription
2040−state, based on whether `val` is true or false, and return a cell containing
2041−a null list of moves and our unchanged app state:
2042−
2043−```hoon
2044−~& ?: val
2045− sink+unsubscribed+'You are now unsubscribed!'
2046− sink+subscribed+'You are now subscribed!'
2047−[~ +>.$]
2048−```
2049−
2050−`++diff-noun` is called when we get a `%diff` update along a subscription with a
2051−mark of `noun`. `++diff-noun` is given the wire that we originally passed with
2052−the `%peer` subscription request along and the data we got back. In our case we
2053−just print out the data:
2054−
2055−```hoon
2056−~& sink+received-data+'You got something!'
2057−~& sink+data+non
2058−```
2059−
2060−`++reap` is called when we receive an acknowledgment as to whether the
2061−subscription was handled successfully. You can remember that `++reap` is the
2062−counterpart to `++peer` as it's pronounced like 'peer' backwards. Similarly,
2063−`coup` is similar to 'poke' backwards.
2064−
2065−Moving forward, `++reap` is given the wire we attempted to subscribe over,
2066−possibly along with an error message in cases of failure. `(unit type)` means
2067−"either `~` or `[~ type]`, which means it's used like Haskell's "maybe" or C's
2068−nullability. If `err` is `~`, then the subscription was successful and we tell
2069−that to the user. Otherwise, we print out the error message.
2070−
2071−
2072−## Backend
2073−
2074−We've done purely functional web pages as hook files, and we've
2075−done command line apps, so now let's interact with an app over
2076−the web. The fundamental concepts are no different than from the
2077−command line -- you send "poke" messages to apps and subscribe to
2078−data streams. The only difference is that you do it with
2079−javascript.
2080−
2081−Let's create a small web app that counts the number of times you
2082−poke it. There'll be a button to poke the app, and line of text
2083−below it saying how many times the app has been poked. We can
2084−update this by subscribing our page to the relevant path on its app.
2085−
2086−Save the following as `click.hoon` in the `/app` directory of your urbit's pier.
2087−
2088−```hoon
2089−/? 314
2090−!:
2091−|%
2092−++ move [bone %diff %mark *]
2093−--
2094−!:
2095−|_ [hid=bowl:gall clicks=@]
2096−++ poke-click
2097− |= click=%click
2098− ~& [%poked +(clicks)]
2099− :_ +>.$(clicks +(clicks))
2100− %+ turn (prey:pubsub:userlib /the-path hid)
2101− |=([o=bone *] [o %diff %clicks +(clicks)])
2102−++ peer-the-path
2103− |= pax=path
2104− [[[ost.hid %diff %clicks clicks] ~] +>.$]
2105−--
2106−```
2107−
2108−There's nothing really new here, except that we use a couple of
2109−new marks, `click` and `clicks`. When we get poked with a
2110−`click`, we increment the variable `clicks` in our state and tell
2111−all our subscribers the new value. When someone subscribes to us
2112−on the path `/the-path`, we immediately give them the current
2113−number of clicks.
2114−
2115−Let's take a look at the new marks. Save this as `/mar/click.hoon`:
2116−
2117−```hoon
2118−|_ click=%click
2119−++ grab
2120− |%
2121− ++ noun |=(* %click)
2122− ++ json
2123− |= jon=^json
2124− ?> =('click' (need (so:dejs-soft:format jon)))
2125− %click
2126− --
2127−--
2128−```
2129−
2130−The mark `click` has type `%click`, which means the only
2131−valid value is `%click`. We can convert from `noun` by just
2132−producing `%click`.
2133−
2134−We also convert from json by parsing a json string with `so:dejs-soft:format`,
2135−asserting the parsing succeeded with `need`, and asserting the
2136−result was 'click' with `?>`, which asserts that its first child
2137−is true.
2138−
2139−> 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`.
2140−
2141−> `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)`.
2142−
2143−We can test this mark from the command line (don't forget to start your app with `|start %click`)
2144−
2145−```
2146−~fintud-macrep:dojo> &click %click
2147−%click
2148−
2149−~fintud-macrep:dojo> &click &json [%s 'click']
2150−%click
2151−
2152−~fintud-macrep:dojo> &click &json &mime [/text/json (as-octs:mimes:html '"click"')]
2153−%click
2154−
2155−~fintud-macrep:dojo> &click &json &mime [/text/json (as-octs:mimes:html '"clickety"')]
2156−/~fintud-macrep/home/0/mar/click:<[7 5].[8 11]>
2157−ford: casting %json to %click
2158−ford: cast %click
2159−```
2160−
2161−And save the following as `/mar/clicks.hoon`:
2162−
2163−```hoon
2164−|_ clicks=@
2165−++ grab
2166− |%
2167− ++ noun @
2168− --
2169−++ grow
2170− |%
2171− ++ json
2172− (frond:enjs:format %clicks (numb:enjs:format clicks))
2173− --
2174−--
2175−```
2176−
2177−`clicks` is just an atom. We convert to json by creating an
2178−object with a single field "clicks" with our value.
2179−
2180−> 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.
2181−
2182−```
2183−~fintud-macrep:dojo> &json &clicks 6
2184−[%o p={[p='clicks' q=[%n p=~.6]]}]
2185−```
2186−
2187−Now that we know the marks involved, take another look at the app
2188−above. Everything should be pretty straightforward. Let's poke
2189−the app from the command line.
2190−
2191−```
2192−~fintud-macrep:dojo> |start %click
2193−>=
2194−~fintud-macrep:dojo> :click &click %click
2195−[%poked 1]
2196−>=
2197−~fintud-macrep:dojo> :click &click %click
2198−[%poked 2]
2199−>=
2200−```
2201−
2202−**Exercise**:
2203−
2204−- Modify `:sink` from the subscriptions chapter to listen to `:click` and print out the subscription updates on the command line.
2205−
2206−## Frontend
2207−
2208−> Note: the instructions below are outdated and do not work in the current version of Urbit. Feel free to experiment though.
2209−
2210−That's all that's needed for the back end. The front end is just
2211−some "sail" html (Hoon markup for XML) and javascript. Here's `/web/pages/click.hoon`:
2212−
2213−```
2214−;html
2215− ;head
2216− ;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js");
2217− ;script(type "text/javascript", src "/~/at/lib/js/urb.js");
2218− ;title: Clickety!
2219− ==
2220− ;body
2221− ;div##cont
2222− ;input##go(type "button", value "Poke!");
2223− ;div##err(class "disabled");
2224− ;div##clicks;
2225− ==
2226− ;script(type "text/javascript", src "/pages/click/click.js");
2227− ==
2228−==
2229−```
2230−
2231−You should recognize the sail syntax from an earlier chapter.
2232−Aside from jquery, we also include `urb.js`, which is a framework
2233−for interacting with urbit.
2234−
2235−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`.
2236−
2237−We have a button labeled "Poke!" and a div with id `clicks` where
2238−we'll put the number of clicks. We also include a small
2239−javascript file where the client-side application logic can be
2240−found. It's in `/web/pages/click.js`:
2241−
2242−```js
2243−$(function() {
2244− var clicks, $go, $clicks, $err
2245−
2246− $go = $('##go')
2247− $clicks = $('##clicks')
2248− $err = $('##err')
2249−
2250− $go.on("click",
2251− function() {
2252− window.urb.send(
2253− "click", {mark: "click-click"}
2254− ,function(err,res) {
2255− if(err)
2256− return $err.text("There was an error. Sorry!")
2257− if(res.data !== undefined &&
2258− res.data.ok !== undefined &&
2259− res.data.ok !== true)
2260− $err.text(res.data.res)
2261− else
2262− console.log("poke succeeded");
2263− })
2264− })
2265−
2266− window.urb.appl = "click"
2267− window.urb.bind('/the-path',
2268− function(err,dat) {
2269− clicks = dat.data.clicks
2270− $clicks.text(clicks)
2271− }
2272− )
2273−})
2274−```
2275−
2276−We set up two event handlers. When we click the button, we run
2277−`window.urb.send`, which sends a poke to the app specified as the first argument, in this case our :click app. The arguments
2278−are data, parameters, and the callback. The data is the specific
2279−data we want to send. The parameters are all optional, but here's a list
2280−of the available ones:
2281−
2282−- `ship`: target urbit. Defaults to `window.urb.ship`, which
2283− defaults to the urbit which served the page.
2284−- `appl`: target app. Defaults to `window.urb.appl`, which
2285− defaults to null.
2286−- `mark`: mark of the data. Defaults to `window.urb.send.mark`,
2287− which defaults to "json".
2288−- `wire`: wire of the poke. Defaults to `/`.
2289−
2290−In our case, we specify only that the mark is "click".
2291−
2292−The callback function is called when we receive an
2293−acknowledgment. If there was an error, we put it in the `err`
2294−div that we defined above. Otherwise, we printf to the console a
2295−message saying the poke succeeded. As is common, we gray
2296−out the button when it is clicked. It is only reenabled when positive acknowledgement is received.
2297−
2298−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`:
2299−
2300−- `ship`: target urbit. Defaults to `window.urb.ship`, which defaults to the urbit which served the page.
2301−- `appl`: target app. Defaults to `window.urb.appl`, which defaults to null.
2302−- `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".
2303−- `wire`: wire of the subscription. Defaults to the given path.
2304−
2305−The callback function here just updates the data in the `clicks`
2306−div. A truly robust app would intelligently handle errors, of
2307−course.
2308−
2309−Note that the app doesn't have anything web-specific in itself.
2310−As far as it knows, it's just receiving pokes and subscriptions.
2311−The javascript is fairly pure as well, sending and receiving json
2312−everywhere. The marks are the translation layer, and they're the
2313−only things that need to know how the hoon types map to json.
2314−
2315−**Exercise**:
2316−
2317−- 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−844
@@ -1,844 +0,0 @@
1−+++
2−title = "Arvo Glossary"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−Urbit is renowned for its exotic terminology. Here's a simple overview
8−from the strange words within.
9−
10−As Dijkstra put it: "The purpose of abstraction is not to be vague, but
11−to create a new semantic level in which one can be absolutely precise."
12−
13−This glossary only covers terms the Arvo side of the project. You can find the
14−Azimuth glossary [here](../azimuth/glossary)
15−
16−### application
17−
18−Also known as an “app,” an _application_ is a Hoon program that can hold state.
19−
20−### arm
21−
22−An _arm_ is a named, functionally-computed attribute of a [core](#core).
23−
24−The [hoon](#a-hoon) of each arm is compiled to a Nock formula, with the
25−enclosing [core](#core) itself as the subject.
26−
27−There are two kinds of arms: _dry_ and _wet_. Most arms are
28−dry.
29−
30−#### dry
31−
32− normal, `++`, polymorphic by means of _variance_
33−
34− For a dry arm, we ask: is the new payload compatible with the old
35− payload (against which the core was compiled)?
36−
37−#### wet
38−
39− unusual, `+-`, polymorphic by means of _genericity_
40−
41− A wet arm uses the hoon as a macro. We create a new type analysis
42− path, which works as if we expanded the callee with the caller's
43− context.
44−
45−_See [advanced types](/docs/hoon/hoon-expressions/advanced/)_.
46−
47−
48−
49−### Arvo
50−
51−The Urbit operating system and kernel. Arvo's state is a pure function of its
52−event log, and it serves as the Urbit event manager. It contains vanes, which are
53−kernel modules that perform essential system operations. Arvo itself can only
54−deal with one file at a time. For more, it relies on Ford, the build-system
55−vane.
56−
57−Arvo being purely functional means that the it is a function that is:
58−
59−`(state, event) → (state, effects)`
60−
61−Arvo coordinates and reloads vanes. It can be thought of as a traffic-director.
62−Any vane needs to go through Arvo before reaching another vane. Events and
63−their effects happen like so:
64−
65−`Unix event → vere (the virtual machine that runs Urbit) → Arvo → vane → Arvo`
66−
67−Arvo is located in `/home/sys/arvo.hoon` within your urbit.
68−
69−More in-depth information on Arvo can be found
70−[`here`](@/docs/arvo/_index.md).
71−
72−Below are Arvo modules, which are called "vanes".
73−
74−#### Ames
75−
76− The networking vane. Ames handles all things UDP. Here live the protocols for
77− discovering and interacting with other urbits. It’s also the name for the Urbit
78− network itself. All communication is signed and encrypted.
79−
80− Ames is located in `/home/sys/vane/ames.hoon` within your urbit.
81−
82− More in-depth information on Ames can be found
83− [`here`](@/docs/arvo/ames.md).
84−
85−#### Behn
86−
87− The timing vane. Behn allows for applications to schedule events, which are
88− managed in a simple priority queue. For example, Clay, the Urbit filesystem,
89− uses Behn to keep track of time-specific file requests. Eyre, the Urbit web
90− vane, uses Behn for timing-out HTTP sessions.
91−
92− Behn is located in `/home/sys/vane/behn.hoon` within your urbit.
93−
94−#### Clay
95−
96− The filesystem and typed revision-control vane. Think of Clay as a
97− continuously synced git. It handles file-change events and maps them from Urbit
98− to Unix and vice versa.
99−
100− A common way to use it is to create a pier, a directory that exists in and is
101− visible in Unix.
102−
103− Clay is located at `/home/sys/vane/clay.hoon` within your urbit.
104−
105− Basic information on using Clay can be found
106− [`here`](@/operations.md). An in-depth explanation
107− of the architecture can be found
108− [`here`](@/docs/arvo/clay.md).
109−
110−#### Dill
111−
112− The terminal-driver vane. You run your urbit in your Unix terminal, and
113− Unix sends every event -- such as a keystroke or a change in the dimensions of
114− the terminal window -- to be handled by Dill. Dill acts as an intermediary for
115− anything that uses keyboard events. This is why there’s some input lag in
116− Urbit’s command-line interface. (Optimization will come later!)
117−
118− A keyboard event's journey from Unix to Dojo, the Urbit shell, can be imagined
119− as diagrammed below:
120− ```
121− Keystroke in Unix -> Vere (virtual machine) -> Arvo -> Dill -> the Dojo
122− ```
123−
124− Dill is located at `/home/sys/vane/clay.hoon` within your urbit.
125−
126− More in-depth information on Dill can be found
127− [`here`](@/docs/arvo/dill.md).
128−
129−#### Eyre
130−
131− The web-server vane. Anything HTTP-related lives here. Unix sends HTTP messages
132− though to Eyre, and Eyre produces HTTP messages in response.
133−
134− In general, apps and vanes do not call Eyre; rather, Eyre calls apps and vanes.
135− Eyre uses Ford and Gall to functionally publish pages and facilitate
136− communication with apps.
137−
138− Eyre is located at `/home/sys/vane/eyre.hoon` within your urbit.
139−
140− More in-depth information on Eyre can be found
141− [`here`](@/docs/arvo/eyre.md).
142−
143−#### Ford
144−
145− The build-system vane. Ford is capable of sequencing generic asynchronous
146− computations. Its uses include linking source files into programs, assembling
147− live-updating websites, and performing file-type conversions.
148−
149− Ford neither accepts Unix events nor produces Unix effects. It exists
150− entirely for the benefit of Urbit applications and other vanes, in particular
151− Gall.
152−
153− Ford is located at `/home/sys/vane/ford.hoon` within your urbit.
154−
155− More in-depth information on Ford can be found
156− [`here`](@/docs/arvo/ford.md).
157−
158−#### Gall
159−
160− The application-management vane. Userspace apps -- daemons, really -- are
161− started, stopped, and sandboxed by Gall. Gall provides developers with a
162− consistent interface for hooking their app up to the operating system. It allows
163− applications and other vanes to send messages to applications and subscribe to
164− data streams. Messages coming into Gall are routed to the intended application,
165− and the response comes back along the same route. If the intended target is on
166− another ship, Gall will route it, behind the scenes, through Ames to the other
167− ship.
168−
169− Gall is located at `/home/sys/vane/gall.hoon` within your urbit.
170−
171− More in-depth information on Gall can be found
172− [`here`](@/docs/arvo/gall.md).
173−
174−### atom
175−
176−An atom is any natural number, including zero. The atom is the most basic data
177−type in [Nock](#nock) and [Hoon](#hoon). A Hoon atom type describes a Nock
178−atom with two additional pieces of metadata: an [_aura_](#aura), and an
179−optional constant.
180−
181−An atom type is _warm_ or _cold_ based on whether the constant exists.
182−
183−
184−#### warm
185−
186− If the constant is `~` (null), any atom is in the type.
187−
188−#### cold
189−
190− If the constant is `[~ atom]`, its only legal value is `atom`.
191−
192−_See [basic types](@/docs/hoon/hoon-expressions/basic.md)_
193−
194−### aura
195−
196−An aura is a soft atom type. They appear as strings beginning with `@`. Auras
197−represent the structure of an atom, print format, or other semantics. Its
198−constraints on the value of an atom aren't enforced in any way.
199−
200−You can cast something to an aura, like a decimal, and get back its hexademical.
201−For example:
202−
203−```
204− > =a `@`29
205− > ^- @ux a
206− 0x1d
207−```
208−
209−Auras are an advisory type system. You can go up or down, but not sideways in
210−the hierarchy. `@t` and `@` can each be cast to the other, but @t can’t be cast
211−to `@u`, for example, without first being cast to the empty aura `@`.
212−
213−For example
214−
215−```
216− > ^- @ 'c' :: 'c' is of the aura @t
217− 99
218−
219− > ^- @u 'c'
220− ! exit
221−```
222−
223−Here is a non-exhaustive list of auras:
224−
225−```
226−Aura Meaning Example Literal Syntax
227−-------------------------------------------------------------------------
228−@d date
229− @da absolute date ~2018.5.14..22.31.46..1435
230−@n nil ~
231−@p phonemic string (ship name) ~sorreg-namtyv
232−@r IEEE floating-point
233− @rd double precision (64 bits) .~6.02214085774e23
234− @rh half precision (16 bits) .~~3.14
235−@s signed integer, sign-bit low
236− @sb signed binary --0b11.1000
237− @sd signed decimal --1.000.056
238− @sx signed hexadecimal -0x5f5.e138
239−@t UTF-8 text (cord) 'howdy'
240− @ta ASCII text (knot) ~.howdy
241− @tas ASCII text symbol (term) %howdy
242−@u unsigned integer
243− @ub unsigned binary 0b11.1000
244− @ud unsigned decimal 1.000.056
245− @ux unsigned hexadecimal 0x5f5.e138
246−```
247−
248−You can find the list of all auras [here](@/docs/hoon/hoon-expressions/rune/constants.md).
249−
250−### blocksize
251−
252−Blocksize is the power-of-two bitwidth of an atom. So, an atom with a blocksize
253−of `3` has a bitwidth of `2^3`, which is 8. A bitwidth of 8, in turn, can
254−represent `2^8` values, or 256.
255−
256−### cast
257−
258−To cast is to put a Hoon expression through the compiler’s type-checker to test
259−whether the expression is guaranteed to evaluate to a product that falls within
260−the desired type. If the expression is not guaranteed to behave in this way,
261−then the compiler will halt with a nest-fail crash. Proper Hoon code will
262−include a cast for the product type of each gate.
263−
264−The cast rune is `^-` (pronounced "ket-hep"). So, to cast to a list of atoms,
265−we write `^- (list @)`. The irregular form of that expression is ``(list @)``.
266−
267−### cell
268−
269−In Nock and Hoon, a _cell_ is an ordered pair of [nouns](#noun).
270−
271−Syntax: `[a b]`.
272−
273−Cells orient to the right; for example, the noun [2 6 14 15] is short for
274−[2 [6 [14 15]]].
275−
276−
277−### clam
278−
279−A clam is the use of a structure as a gate. Usually used to verify marks from
280−other urbits.
281−
282−```
283− > ((list @t) [97 98 ~])
284− <|a b|>
285−```
286−
287−### cord
288−
289−In Hoon, `cord` is an aura for representing atoms as strings. UTF-8,
290−least-significant bit first. Represented as the aura `@t`.
291−
292−```
293− > `@t`478.560.413.032
294− 'hello'
295−```
296−
297−### core
298−
299−A _core_ is a [cell](#nock-cell) of `[code data]`, where we call the
300−code head the _battery_ and the data tail the _payload_. All code-data
301−structures in normal languages (functions, objects, modules, etc.)
302−translate to cores in Hoon.
303−
304−#### battery
305−
306− The code-containing head of a core.
307−
308−#### payload
309−
310− The data-containing tail of a core.
311−
312−_See [basic types](@/docs/hoon/hoon-expressions/basic.md)._
313−
314−### Dojo
315−
316−The Dojo is the Urbit shell; the command line where you run programs,
317−expressions, and system commands. It’s a CLI that is encountered right when
318−an urbit is started for the first time. It is somewhat analogous to Bash, the
319−Unix terminal, and more analogous to a Hoon REPL.
320−
321−You’ll notice that many things can’t be written here; this is normal. The Dojo
322−enforces syntactical correctness right at the command line. Strings that can’t
323−be continued into a valid expression are automatically trimmed back to something
324−that can be. Some syntactically invalid expressions can be completed, but the
325−Dojo will prevent them from being entered as a command. You can play around
326−with this functionality learn what syntax is kosher.
327−
328−
329−### duct
330−
331−A duct is an Arvo-level call stack. At the beginning of every duct is a Unix
332−event, such as a keystroke, network packet, timer event, or file change.
333−
334−A duct is a `list` of `wire`s. A wire is itself a `list` of `knot`s. A `knot`
335−is, in turn, a knot.
336−
337−### face
338−
339−A _face_ is the Hoon analog to what is a variable name in most other
340−programming languages. Faces are metadata labels for legs, allowing us to
341−address parts. Because there is no metadata in Nock, faces cannot exist in Nock.
342−
343−```
344− > a=2
345− a=2
346−```
347−
348−In the above example, `a` is the face and `2` is the value.
349−
350−Hoon has no scope or symbol-table; there is only the subject. To "declare" a
351−"variable" is to construct a new subject: `[name=value old-subject]`.
352−
353−_See [advanced types](@/docs/hoon/hoon-expressions/advanced.md)_.
354−
355−
356−### flag
357−
358−A `flag` is Hoon's version of a boolean. `0` (`%.y`) is _yes_, `1` (`%.n`) is
359−_no_.
360−
361−### gate
362−
363−A _gate_ is a [core](#core) with one [arm](#arm) -- Hoon's closest
364−analog to a function. To call a gate on an argument, replace the sample
365−(at [tree address](@/docs/hoon/hoon-expressions/limb/limb.md) `+6`
366−in the core) with the argument, and then compute the arm.
367−
368−The payload of a gate has a shape of `[sample context]`.
369−
370−#### sample
371−
372− The argument tuple.
373−
374−#### context
375−
376− The subject in which the gate was defined.
377−
378−_See [basic types](@/docs/hoon/hoon-expressions/basic.md),
379−[`%-` ("cenhep")](@/docs/hoon/hoon-expressions/rune/cen.md#cenhep) (the
380−[rune](#rune) for calling a `gate`)._
381−
382−### generator
383−
384−A _generator_ is like a limited Hoon script: it’s a shell command that produces
385−a value before disappearing. Generators take an input [noun](#noun) (a value)
386−and produce an output `noun` by performing calculations on its arguments,
387−prompting for input, or making HTTP requests.
388−
389−You need a `bar` rune like `|=` in your generator, because a generator is
390−essentially a function that you’re calling.
391−
392−Generators, unlike [apps](#application), hold no state. They are pure,
393−stateless functions, and they cannot send [moves](#move). Because of this,
394−generators are have a more narrow use than apps. Among the non-trivial uses of
395−a a generator is moving data into apps -- they’re the backbone of Urbit’s
396−information pipeline.
397−
398−Generators are run from the `/gen` directory of your current desk. For example,
399−to run a generator named `whatever.hoon`, you would type `> +whatever` in the
400−[Dojo](@/operations/#using-the-shell).
401−
402−### glyph
403−
404−A _glyph_ is a single, non-alphanumeric ASCII character. Each glyph has its own
405−monosyllabic name, which allows the efficient communication of Hoon-related
406−information in speech. [`Runes`](#rune) are composed of two glyphs.
407−Below is a complete list of glyphs with their associated pronunciations.
408−
409−```
410−ace [1 space] gal < pal (
411−bar | gap [>1 space, nl] par )
412−bas \ gar > sel [
413−buc $ hax # mic ;
414−cab _ hep - ser ]
415−cen % kel { sig ~
416−col : ker } soq '
417−com , ket ^ tar *
418−doq " lus + tic `
419−dot . pam & tis =
420−fas / pat @ wut ?
421−zap !
422−```
423−
424−### Hall
425−
426−_Hall_ is the Urbit communication back-end. It’s a messaging bus that can work
427−with clients of all sorts. [`:talk`](#talk), the built-in chat client, is one
428−such app that uses Hall.
429−
430−_More information on Hall can be found [here](@/docs/arvo/hall.md)._
431−
432−#### circle
433−
434− A circle is the “audience” of your messages -- who can receive them. It can be
435− thought of as a chat channel, but this is a little too narrow. More
436− specifically, it’s a named collection of messages created by and hosted on a
437− ship’s Hall, usually represented as `~ship-name/circle-name`. On Talk,
438− Urbit’s built-in chat front-end, the first circle that you will likely
439− encounter is `~dopzod/urbit-help`.
440−
441−### Hood
442−
443−_Hood_ orchestrates many of the Urbit initialization systems necessary
444−for boot.
445−
446−### Hoon
447−
448−Hoon is a strict, higher-order typed functional language that compiles itself
449−to Nock.
450−
451−The Hoon source file is located in `/home/sys/hoon.hoon` within your urbit.
452−
453−_More information can be found in the [hoon](@/docs/hoon/_index.md) section._
454−
455−#### Mint
456−
457− _Mint_ is the Hoon compiler function. Mint takes the subject type and the
458− expression source (a [hoon](#a-hoon), for example) and produces the product
459− type and nock formula. So [type hoon] is mapped to [type nock].
460−
461−### hoon
462−
463−A _hoon_ (lowercase) is the result of parsing a Hoon source expression into an
464−AST node. These AST nodes are nouns, like all other Hoon data. Because every
465−Hoon program is, in its entirety, a single expression of Hoon, the result of
466−parsing the whole thing into an AST is a single `hoon`.
467−
468−A hoon is a tagged union of the form `[%tag data]`, where the tag
469−is a constant such as `%brts` (from the source [rune](#rune) `|=`,
470−i.e. "bartis"), and is matched up with the appropriate type of data
471−(often more `hoon`s, from source subexpressions). For example, the
472−expression `:-(2 17)`, once parsed into an AST, becomes the following:
473−
474−```
475−[%clhp p=[%sand p=%ud q=2] q=[%sand p=%ud q=17]]
476−```
477−
478−The `%clhp` is produced from the rune `:-` (i.e. "colhep"). The 2 and
479−17 have each been parsed as `%sand`-tagged hoons, which represent
480−atoms (in this case each with an aura of `%ud`, i.e. unsigned
481−decimal).
482−
483−To parse Hoon source into a hoon AST, use `ream` on a `cord`
484−containing Hoon source. Try the following in [Dojo](@/operations/#using-the-shell):
485−
486−```
487−(ream ':+(12 7 %a)')
488−```
489−
490−The result should be:
491−
492−```
493−[%clls p=[%sand p=%ud q=12] q=[%sand p=%ud q=7] r=[%rock p=%tas q=97]]
494−```
495−
496−See [expression reference](@/docs/hoon/hoon-expressions/rune/_index.md) for the full list of hoons.
497−
498−### irregular form
499−
500−Irregular forms are alternative ways of writing Hoon expressions, alternatives
501−to the digraphic runes such as `:~`. Irregular forms are usually more compact
502−than regular forms.=
503−
504−_See [irregular forms](@/docs/hoon/hoon-expressions/irregular.md)._
505−
506−### jet
507−
508−A _jet_ is a piece of C code that have equivalent products to a piece of Hoon or
509−Nock code. They are used for performance reasons; jets are meant to be faster
510−than the code that they are substituting for.
511−
512−Jets are necessary for mathematics, performance-wise, because Nock handles it
513−so inefficiently. Nock, for example, can’t decrement (reduce a number by one)
514−except by starting building a loop that starts from zero and increments to a
515−number just below.
516−
517−_See [API overview](@/docs/vere/api.md)._
518−
519−### lark
520−
521−A lark is an expression that returns a [limb](#limb) at the specified
522−address in a cell. Using `-` by itself returns the head of the subject, and
523−using `+` by itself returns the tail:
524−
525−```
526−> -:[[4 5] [6 [14 15]]]
527−[4 5]
528−
529−> +:[[4 5] [6 [14 15]]]
530−[6 14 15]
531−```
532−
533−You can combine `+` or `-` with either of `>` or `<` to get a more specific limb
534−of the subject. `-<` returns the head of the head; `->` returns the tail of the
535−head; `+<` returns the head of the tail; and `+>` returns the tail of the tail.
536−By alternating the `+`/`-` symbols with `<`/`>` symbols, you can go as deep as
537−you desire.
538−
539−```
540−> +>-:[[4 5] [6 [14 15]]]
541−14
542−
543−> +>+:[[4 5] [6 [14 15]]]
544−15
545−```
546−
547−### limb
548−
549−A _limb_ is an attribute or variable reference. A limb is an [arm](#arm) or a
550−[leg](#leg).
551−
552−To resolve a _limb_ named "foo", the subject is searched depth-first,
553−head-first for either a face named "foo" or a core with an arm of
554−"foo". If a face is found, the result is a leg, if a core is
555−found, the result is the product of the arm.
556−
557−#### leg
558−
559− a subexpression, or subtree of the
560− [subject](#nock-subject).
561−
562−#### wing
563−
564− a search path into the subject, composed of
565− limbs. Search occurs from right to left (`a.b` means `b` within `a`).
566−
567−_See [Limbs and wings](@/docs/hoon/hoon-expressions/limb/_index.md)_
568−
569−### move
570−
571−A move is the [Arvo](#arvo) equivalent of a syscall.
572−
573−### noun
574−
575−In [Nock](#nock) and [Hoon](#hoon), a _noun_ is an atom or a cell.
576−
577−### Nock
578−
579−Nock is a Turing-complete, non-lambda combinator interpreter. It's
580−Urbit's low-level programming language. Nock is functional and typeless.
581−
582−#### noun
583−
584− an _atom_ or a _cell_.
585−
586−#### atom
587−
588− any natural number, including zero.
589−
590−#### cell
591−
592− any ordered pair of nouns.
593−
594−
595−#### subject
596−
597− a noun - the data against which a _formula_ is evaluated.
598−
599−#### formula
600−
601− a noun - a function at the nock level.
602−
603−#### product
604−
605− a noun - the result of evaluating a formula against a subject.
606−
607−_See the [Nock definition](@/docs/nock/definition.md)._
608−
609−### mark
610−
611−A _mark_ is Urbit's version of a MIME type, if a MIME type was an
612−executable specification. The mark is just a label that's used as a path
613−to a local source file in the Arvo filesystem. This source file defines
614−a core that can mold untrusted data, diff and patch, convert to other
615−marks, etc.
616−
617−If this sounds like magic, it isn't quite magic. There's no way
618−for different urbits to make sure they mean the same thing by the
619−same mark. However, when incompatibility happens, marks ensure
620−that we at least handle the situation in a predictable way.
621−
622−#### metal
623−
624−Every core has a _metal_ which defines its variance model (ie, the
625−properties of the type of a compatible core). The default is `gold`
626−(invariant).
627−
628−- `gold`: _invariant_
629−- `lead`: _bivariant_
630−- `zinc`: _covariant_
631−- `iron`: _contravariant_
632−
633−_See [advanced types](@/docs/hoon/hoon-expressions/advanced.md)_.
634−
635−### ship
636−
637−An Urbit _ship_ is: a cryptographic title on a _will_ signed by private key; a
638−human-memorable name; and a packet-routing address. Ships are classed by the
639−number of bits in their address:
640−
641−```
642− Size Name Parent Object Example
643− ----- ------ ------ ------ -------
644− 2^8 galaxy ~ supernode ~zod
645− 2^16 star galaxy supernode ~dozbud
646− 2^32 planet star user ~tasfyn-partyv
647− 2^64 moon planet device ~sigsam-nimbot-tasfyn-partyv
648− 2^128 comet ~ bot ~racmus-mollen-fallyt-linpex--watres-sibbur-modlux-rinmex
649−```
650−
651−Any ship can be called an _urbit_. The lowercase "u" distinguishes it from Urbit
652−the software stack and Urbit the network.
653−
654−_You can find a longer-form summary [here.](https://urbit.org/posts/essays/the-urbit-address-space/)._
655−
656−An Urbit identity is a string like `~firbyr-napbes`. It means nothing,
657−but it's easy to remember and say out loud. `~firbyr-napbes` is actually
658−just a 32-bit number (`3.237.967.392`, to be exact), like an IP address,
659−that we turn into a human-memorable string. The full name of this string
660−can be viewed by typing `our` in the Dojo, Urbit's shell. This is useful
661−when running a ship with a longer name, such as a _moon_ or a _comet_.
662−
663−Technically, an urbit is a secure digital identity that you own and
664−control with a cryptographic key, like a Bitcoin wallet. As in Bitcoin,
665−the supply of urbits is mathematically limited. This keeps the network
666−friendly, by making spam and abuse expensive.
667−
668−An urbit name is just a number; smaller numbers make shorter names.
669−Shorter names are easier to remember, so they're more valuable. So
670−urbits are classified by the number of bits in their name. (A ship name
671−is just a scrambled base-256 representation of the number.)
672−
673−A 32-bit urbit (like `~firbyr-napbes`) is called a _planet._ A 16-bit
674−urbit (like `~pollev)` is a _star._ An 8-bit ship (like `~mun`) is a
675−_galaxy._ A planet is an identity for an independent, adult human. Stars
676−and galaxies are network infrastructure.
677−
678−Each planet or star is launched by its _parent,_ the star or galaxy
679−whose number is its bottom half. So the planet `~firbyr-napbes`,
680−`0xdead.beef` or `3.735.928.559`, is the child of `~pollev`, `0xbeef` or
681−`48.879`, whose parent is `~mun`, `0xef`, `239`. The galaxy at the address of
682−`0` is `~zod`.
683−
684−#### pier
685−
686− A ship's _pier_ is its Unix directory. For planets, the name of the pier is
687− usually the planet name.
688−
689−### structure
690−
691−A _structure_ is an idempotent [gate](#gate) (function) that constructs and
692−validates types in Hoon.
693−
694−An example: Arvo [marks](#mark) use Hoon's type system via structures to
695−validate untrusted network data.
696−
697−Here's some common structure terminology:
698−
699−#### bunt
700−
701− A bunt is the default value of a [structure](#structure). It's also a verb;
702− to _bunt_ a structure is to produce the bunt of that structure. For example,
703− bunting `@` results in `0`, and bunting `@t` results in `''`. Bunting is
704− performed with `*` followed by the structure in question:
705−
706− ```
707− > *@
708− 0
709− > *@t
710− ''
711− ```
712−
713−#### icon: The type of the mold's range
714−
715−_See [mold hoons](/docs/hoon/hoon-expressions/rune/buc/)._
716−
717−### rune
718−
719−A Hoon _rune_ is a pair of ASCII symbols used to begin a
720−[Hoon expression](#a-hoon).
721−
722−For example, the rune [`?:`](@/docs/hoon/hoon-expressions/rune/wut.md#wutcol) is
723−Hoon's most common conditional, a branch on a boolean test. The first
724−symbol in a rune represents a family of related runes. For example, the
725−[`?` family](@/docs/hoon/hoon-expressions/rune/wut.md) are all conditionals.
726−
727−The result of parsing a Hoon source expression&mdash;the rune, followed
728−by its respective children&mdash;into an AST node is simply called
729−a [`hoon`](#a-hoon).
730−
731−Runes have two syntactic forms, _tall_ and _flat_:
732−
733−#### tall
734−
735− multiple lines, no parentheses, two or more spaces between tokens
736−
737− Example:
738−
739− ```
740− > %+ add 2 2
741− 4
742− ```
743−
744−#### flat
745−
746− one line, parentheses, one space between tokens
747−
748− Example:
749− ```
750− > %+(add 2 2) :: regular flat form
751− 4
752−
753− > (add 2 2) :: irregular flat form
754− 4
755− ```
756−
757−Tall hoons can contain flat hoons, but not vice versa. All irregular
758−forms are flat.
759−
760−_See [hoon concept](#a-hoon),
761−[expressions](@/docs/hoon/hoon-expressions/rune/_index.md).
762−
763−### Sail
764−
765−_Sail_ is the Hoon markup language for XML.
766−
767−### scry
768−
769−To _scry_ means to request data from the Arvo namespace and bring it
770−to userspace.
771−
772−_See [.^ (dot-ket)](@/docs/hoon/hoon-expressions/rune/dot.md#dotket)._
773−
774−### slot
775−
776−`slot` is the name for Hoon's tree-addressing scheme.
777−
778−Every cell has a head and a tail, each of which may be either an atom or
779−a cell. Therefore every noun is a binary tree. `+1` or `.` resolves to
780−the whole cell (technically this would work against an atom as well).
781−The head of `+n` is `+2n`, the tail is `+(2n+1)`.
782−
783−`+7` is a special address for gates, because the position is defined
784−(by convention) as the context of a gate and of all cores.
785−
786−### talk
787−
788−_Talk_ is Urbit's built-in chat app. It’s one example of an app that can be
789−built on top of Hall, the Urbit back-end messaging system.
790−
791−_See [Messaging](@/operations/#messaging). for more information._
792−
793−### type
794−
795−A Hoon _type_ defines a set (finite or infinite) of nouns and ascribes
796−some semantics to it. There is no direct syntax for defining
797−types; they are always defined by inference (i.e., by
798−[`mint`](#mint)), usually using a constructor ([structure](#structure)).
799−
800−All types are assembled out of base types defined in `++type`.
801−(Look up `++ type` in hoon.hoon for examples.) When the compiler
802−does type-inference on a program, it assembles complex types out
803−of the simpler built-in types.
804−
805−#### nest
806−
807− `nest` is an internal Hoon function on two types which performs a type
808− compatibility test. `nest` produces yes if the
809− set of nouns in the second type is provably a subset of the first.
810− If `nest` produces no, the Hoon programmer will receive a `nest-fail`
811− error. This is one of the most commons errors in Hoon programming.
812−
813− _See [advanced types](@/docs/hoon/hoon-expressions/advanced.md)_ and [troubleshooting](@/docs/reference/troubleshooting.md).
814−
815−
816−### Unit
817−
818−Hoon's equivalent of a nullable pointer or a Haskell Maybe. If `q` is `~`,
819−null, the type is _warm_; any atom is in the type. If `q` is `[~ x]`, where
820−`x` is any atom, the type is _cold_; its only legal value is the constant `x`.
821−
822−### Vane
823−
824−A _vane_ is an [Arvo](#arvo) module. Each Vane is a single file because Arvo
825−cannot, on its own, deal with programs that are split between multiple files.
826−Some vanes can do this, however.
827−
828−### Vere (pronounced “vair”)
829−
830−The runtime system, written in C, that implements [Nock](#nock). All
831−It’s written in C. Vere-level errors are prepended with as `bail:`.
832−
833−Vere is a virtual machine: it pretends to be hardware, and is the single point
834−of contact between your Urbit and the rest of your system. But more than that,
835−Vere handles the Urbit event log and handles jets. It’s also contains the i/o
836−drivers for Urbit’s vanes, responsible for generating events from Unix and
837−applying effects to Unix.
838−
839−### Zuse
840−
841−_Zuse_ is a defined interface for vanes. It contains the part of the Hoon
842−standard library that is specific to Arvo functionality.
843−
844−Arvo is located in `/home/sys/zuse.hoon` within your urbit.
arvo/hall.mddeleted−1334
@@ -1,1334 +0,0 @@
1−+++
2−title = "Hall"
3−weight = 7
4−template = "doc.html"
5−+++
6−> Last major revision of this tutorial: 2017. Some of the information and Hoon syntax here may
7− be outdated.
8−
9−
10−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.
11−
12−## Table of contents
13−
14−- [Hall Architecture](#hall-architecture)
15−
16−- [The Hall Interface](#the-hall-interface)
17−
18−- [The New Gall Model](#the-new-gall-model)
19−
20−# Hall Architecture
21−
22−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.
23−
24−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).
25−
26−## Talk
27−
28−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.
29−
30−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`.
31−
32−
33−## Structures & functionality
34−
35−### Circles
36−
37−```hoon
38−++ circle {hos/ship nom/term} :: native target
39−```
40−
41−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.
42−
43−### Messages
44−
45−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.
46−
47−```hoon
48−++ speech :> content body
49− $% {$lin pat/? msg/cord} :< no/@ text line
50− {$url url/purf:eyre} :< parsed url
51− {$exp exp/cord res/(list tank)} :< hoon line
52− {$ire top/serial sep/speech} :< in reply to
53− {$fat tac/attache sep/speech} :< attachment
54− {$app app/term sep/speech} :< app message
55− {$inv inv/? cir/circle} :< inv/ban for circle
56− == ::
57−```
58−
59−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.
60−
61−```hoon
62−++ audience (set circle) :< destinations
63−++ serial @uvH :< unique identifier
64−++ thought :> inner message
65− $: uid/serial :< unique identifier
66− aud/audience :< destinations
67− wen/@da :< timestamp
68− sep/speech :< content
69− == ::
70−```
71−
72−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.
73−
74−```hoon
75−++ telegram {aut/ship thought} :< whose message
76−++ envelope {num/@ud gam/telegram} :< outward message
77−```
78−
79−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.
80−
81−### Participant metadata
82−
83−Messages aren't the only thing a subscription gets us. We're also kept up to date with relevant metadata.
84−
85−```hoon
86−++ crowd {loc/group rem/(map partner group)} :< our & srcs presences
87−++ group (map ship status) :< presence map
88−++ status {pec/presence man/human} :< participant
89−++ presence :> status type
90− $? $gone :< absent
91− $idle :< idle
92− $hear :< present
93− $talk :< typing
94− == ::
95−++ human :> human identifier
96− $: han/(unit cord) :< handle
97− tru/(unit truename) :< true name
98− == ::
99−++ truename {fir/cord mid/(unit cord) las/cord} :< real-life name
100−```
101−
102−`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.
103−
104−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.
105−
106−### Configurations
107−
108−```hoon
109−++ lobby {loc/config rem/(map circle config)} :< our & srcs configs
110−++ config :> circle config
111− $: src/(set circle) :< active sources
112− cap/cord :< description
113− fit/filter :< message rules
114− con/control :< restrictions
115− == ::
116−++ filter :> content filters
117− $: cas/? :< dis/allow capitals
118− utf/? :< dis/allow non-ascii
119− == ::
120−++ control {sec/security ses/(set ship)} :< access control
121−```
122−
123−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?
124−
125−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.
126−
127−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.
128−
129−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.
130−
131−```hoon
132−++ security :> security mode
133− $? $channel :< blacklist
134− $village :< whitelist
135− $journal :< pub r, whitelist w
136− $mailbox :< our r, blacklist w
137− == ::
138−```
139−
140−A `channel` is publicly readable and writable, with a blacklist for blocking.
141−A `village` is privately readable and writable, with a whitelist for inviting.
142−A `journal` is publicly readable and privately writable, with a whitelist for authors.
143−A `mailbox` is readable by its owner and publicly writable, with a blacklist for blocking.
144−
145−### Stories
146−
147−To see how that all ties together, we're going to take a look at Hall's state.
148−
149−```hoon
150−++ state :> hall state
151− $: stories/(map term story) :< conversations
152− :: ... ::
153− == ::
154−++ story :> wire content
155− $: grams/(list telegram) :< all messages
156− locals/group :< local presence
157− remotes/(map circle group) :< remote presence
158− shape/config :< configuration
159− mirrors/(map circle config) :< remote config
160− :: ... ::
161− == ::
162−```
163−
164−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.
165−
166−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.
167−
168−### General use
169−
170−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.
171−
172−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.
173−
174−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.
175−
176−### Public membership
177−
178−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.
179−
180−
181−## Interfaces for applications
182−
183−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.
184−
185−### Interactions
186−
187−Hall can be commanded by poking it with `action`s.
188−
189−```hoon
190−++ action :> user action
191− $% :: circle configuration ::
192− {$create nom/term des/cord sec/security} :< create circle
193− {$delete nom/term why/(unit cord)} :< delete + announce
194− {$depict nom/term des/cord} :< change description
195− {$filter nom/term fit/filter} :< change message rules
196− {$permit nom/term inv/? sis/(set ship)} :< invite/banish
197− {$source nom/term sub/? srs/(set source)} :< un/sub to/from src
198− :: messaging ::
199− {$convey tos/(list thought)} :< post exact
200− {$phrase aud/audience ses/(list speech)} :< post easy
201− :: personal metadata ::
202− {$notify aud/audience pes/(unit presence)} :< our presence update
203− {$naming aud/audience man/human} :< our name update
204− :: changing shared ui ::
205− {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
206− {$nick who/ship nic/cord} :< new identity
207− :: misc changes ::
208− {$public add/? cir/circle} :< show/hide membership
209− == ::
210−```
211−
212−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.
213−
214−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.
215−
216−`%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.
217−
218−"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.
219−
220−### Queries, prizes and rumors
221−
222−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.
223−
224−```hoon
225−++ query :> query paths
226− $% {$client $~} :< shared ui state
227− $: $circle :> story query
228− nom/naem :< circle name
229− wat/(set circle-data) :< data to get
230− ran/range :< query duration
231− == ::
232− :: ... ::
233− == ::
234−++ circle-data :> kinds of circle data
235− $? $grams :< messages
236− $group-l :< local presence
237− $group-r :< remote presences
238− $config-l :< local config
239− $config-r :< remote configs
240− == ::
241−++ range :> inclusive msg range
242− %- unit :< ~ means everything
243− $: hed/place :< start of range
244− tal/(unit place) :< opt end of range
245− == ::
246−++ place :> range indicators
247− $% {$da @da} :< date
248− {$ud @ud} :< message number
249− == ::
250−++ prize :> query result
251− $% $: $client :< /client
252− gys/(jug char (set partner)) :< glyph bindings
253− nis/(map ship cord) :< nicknames
254− == ::
255− {$circle burden} :< /circle
256− :: ... ::
257− == ::
258−++ burden :< full story state
259− $: gaz/(list telegram) :< all messages
260− cos/lobby :< loc & rem configs
261− pes/crowd :< loc & rem presences
262− == ::
263−```
264−
265−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.
266−
267−`/client` queries produce shared UI state. That is, glyph bindings and nicknames.
268−`/circle` queries produce the entire public state of the requested story, including remotes.
269−
270−Any changes to the results of these queries are communicated via the following `rumor`s. It's a fairly long list of potential changes,
271−
272−```hoon
273−++ rumor :< query result change
274− $% {$client rum/rumor-client} :< /client
275− {$circle rum/rumor-story} :< /circle
276− :: ... ::
277− == ::
278−++ rumor-client :< changed ui state
279− $% {$glyph diff-glyph} :< un/bound glyph
280− {$nick diff-nick} :< changed nickname
281− == ::
282−++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
283−++ diff-nick {who/ship nic/cord} :< changed nickname
284−++ diff-story :> story change
285− $% {$new cof/config} :< new story
286− {$config cir/circle dif/diff-config} :< new/changed config
287− {$status cir/circle who/ship dif/diff-status} :< new/changed status
288− {$remove $~} :< removed story
289− :: ... ::
290− == ::
291−++ rumor-story ::> story rumor
292− $? diff-story ::< both in & outward
293− $% {$gram nev/envelope} ::< new/changed msgs
294− == == ::
295−++ diff-config :> config change
296− $% {$full cof/config} :< set w/o side-effects
297− {$source add/? src/source} :< add/rem sources
298− {$caption cap/cord} :< changed description
299− {$filter fit/filter} :< changed filter
300− {$secure sec/security} :< changed security
301− {$permit add/? sis/(set ship)} :< add/rem to b/w-list
302− {$remove $~} :< removed config
303− == ::
304−++ diff-status :> status change
305− $% {$full sat/status} :< fully changed status
306− {$presence pec/presence} :< changed presence
307− {$human dif/diff-human} :< changed name
308− {$remove $~} :< removed status
309− == ::
310−++ diff-human :> name change
311− $% {$full man/human} :< fully changed name
312− {$handle han/(unit cord)} :< changed handle
313− {$true tru/(unit truename)} :< changed true name
314− == ::
315−```
316−
317−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.
318−
319−
320−## Communication between Halls
321−
322−Halls can communicate with other Halls by sending commands and subscription updates.
323−
324−### Commands
325−
326−To request changes to a story, Halls can send `command`s.
327−
328−```hoon
329−++ command :> effect on story
330− $% {$publish tos/(list thought)} :< deliver
331− {$present nos/(set term) dif/diff-status} :< status update
332− :: ... ::
333− == ::
334−```
335−
336−A `%publish` command contains messages. These are sent to foreign Halls to be published to their stories.
337−
338−The `%present` command is used for sending status updates about our ship.
339−
340−### Querying
341−
342−Halls can query other halls. Here's the peer move we send when we open a query on a foreign circle:
343−
344−```hoon
345−:* ost.bol :< bone
346− %peer :< move type
347− /[our-circle]/[host]/[query-path] :< rumor path
348− [host %hall] :< query target
349− /circle/[their-circle]/[data]/[start]/[end] :< query path
350−== ::
351−```
352−
353−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.
354−
355−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.
356−
357−### Federation implementation
358−
359−Along the way so far, we've skipped some parts of structures. Most of those relate to federation. Let's see what we missed.
360−
361−```hoon
362−++ query :> query paths
363− $% {$burden who/ship} :< duties to share
364− {$report $~} :< duty reports
365− :: ... ::
366− == ::
367−++ prize :> query result
368− $% {$burden sos/(map term burden)} :< /burden
369− :: ... ::
370− == ::
371−++ rumor :< query result change
372− $% {$burden nom/term rum/rumor-story} :< /burden
373− :: ... ::
374− == ::
375−++ diff-story ::
376− $% {$bear bur/burden} :< new inherited story
377− :: ... ::
378− == ::
379−++ burden :> full story state
380− $: gaz/(list telegram) :< all messages
381− cos/lobby :< loc & rem configs
382− pes/crowd :< loc & rem presences
383− == ::
384−```
385−
386−We briefly touched upon how federation works on the higher level. On the lower, this is how things go down.
387−
388−1. When Hall boots on a star or galaxy, it starts querying its parent's `/burden` path. (Galaxies query ~zod.)
389−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.
390−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.
391−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.
392−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.
393−
394−
395−## Hall implementation
396−
397−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.
398−
399−First though, it's useful to understand how Hall's code is structured. It consists of primary cores, designed to work optimally with Gall.
400−
401−- `++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.
402−- `++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.
403−
404−Both those cores also have a core within themselves dedicated solely to dealing with stories, `++so` and `++sa` respectively.
405−
406−Once all work in an engine core has finished, its `-done` arm is called to produce the result of all the core's computation.
407−
408−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.
409−Below the diagrams you will find brief explanations of the involved arms. In a particularly bright future, these might be available on-hover instead.
410−For brevity, utility arms that aren't a direct and important part of the flow have been omitted.
411−
412−(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.)
413−
414−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.
415−
416−### Subscriptions
417−
418−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).
419−Upon receiving a valid peer on a `/circle` path, the subscribing ship is added to that circle's presence map.
420−
421−![subscriptions implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-subscriptions.png)
422−
423−```hoon
424−++ poke-talk-action :< we got poked with an action.
425− ++ ta-action :< applies an action.
426− ++ ta-config :< (re)configures a story.
427−:: ::
428−++ peer :< we got peered.
429− ++ g-query :< resolves query to prize.
430− ++ ta-subscribe :< act upon subscription.
431− ++ so-attend :< adds a ship's status to the story.
432−```
433−
434−### Rumors
435−
436−Once a query has opened, Hall will receive updates on it, rumors. The changes describes in these rumors are applied via the following flow.
437−
438−![rumor implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-rumors.png)
439−
440−```hoon
441−++ diff-talk-rumor :< we got a query update.
442− ++ ta-hear :< applies a rumor to the story it's intended for.
443− ++ so-hear :< applies a %circle rumor to the story.
444− ++ so-config-full :< splits a %full diff-config into separate changes.
445− ++ so-bear :< accept burden, assimilate into the story's state.
446− ++ so-lesson :< sends a report with presences.
447−```
448−
449−### Messaging
450−
451−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.
452−
453−![messaging implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-messaging.png)
454−
455−```hoon
456−++ poke-talk-action :< we got poked with an action.
457− ++ ta-action :< applies an action.
458−:: ::
459−++ poke-talk-command :< we get poked with a command.
460− ++ ta-apply :< applies a command.
461− ++ ta-think :< consumes each message in the given list.
462− ++ ta-consume :< conducts a message to each partner in audience.
463− ++ ta-conduct :< records or sends a message.
464− ++ ta-transmit :< sends a message to a partner.
465− ++ ta-record :< stores a message in a story.
466− ++ so-learn :< either adds or modifies a message.
467−```
468−
469−
470−## The future
471−
472−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.
473−
474−### Features and functionality
475−
476−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.
477−
478−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.
479−
480−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.
481−This functionality brings its own large sets of challenges that need to be tackled.
482−
483−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?
484−
485−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.
486−
487−More minor functionalities that need to be implemented include:
488−- Extended permissions management. Being able to black-/whitelist entire ship classes.
489−- Improved presence functionality. Actually using the presence system, and sending "typing", "idle", etc. statuses.
490−- Polls.
491−
492−And, of course, there's a lot that the Talk client can improve on as well.
493−
494−
495−## Further reading
496−
497−To gain a more thorough understanding of Hall's inner workings, take a look at its source code. It comes with inline documentation.
498−[On Github.](https://github.com/urbit/urbit/blob/master/pkg/arvo/app/hall.hoon)
499−
500−To see an expansive example of a Hall client, take a look at the code of Talk. It, too, comes with inline documentation.
501−[On Github.](https://github.com/urbit/urbit/blob/master/pkg/arvo/app/talk.hoon)
502−
503−# The Hall Interface
504−
505−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.
506−
507−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`.
508−
509−## Queries
510−
511−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.
512−
513−### /client
514−
515−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.
516−
517−```hoon
518−++ query ::
519− $% {$client $~} :< shared ui state
520− :: .... ::
521− == ::
522−```
523−
524−Valid paths include:
525−
526−```
527−:> all shared ui state
528−/client
529−```
530−
531−#### /client prize
532−
533−Contains a map of glyphs and the audiences that they map to, as well as a map of ships and their locally set nicknames.
534−
535−```hoon
536−++ prize :> query result
537− $% {$client prize-client} :< /client
538− :: ... ::
539− == ::
540−++ prize-client :> shared ui state
541− $: gys/(jug char audience) :< glyph bindings
542− nis/(map ship nick) :< local nicknames
543− == ::
544−```
545−
546−#### /client rumor
547−
548−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.
549−
550−```hoon
551−++ rumor :> query result change
552− $% {$client rum/rumor-client} :< /client
553− :: ... ::
554− == ::
555−++ rumor-client :< changed ui state
556− $% {$glyph diff-glyph} :< un/bound glyph
557− {$nick diff-nick} :< changed nickname
558− == ::
559−++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
560−++ diff-nick {who/ship nic/nick} :< changed nickname
561−```
562−
563−
564−### /public
565−
566−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.
567−
568−```hoon
569−++ query ::
570− $% {$public $~} :< public memberships
571− :: .... ::
572− == ::
573−```
574−
575−Valid paths include:
576−
577−```
578−:> all public memberships
579−/public
580−```
581−
582−#### /public prize
583−
584−Contains the set of circles the user has on their public list.
585−
586−```hoon
587−++ prize :> query result
588− $% {$public cis/(set circle)} :< /public
589− :: ... ::
590− == ::
591−```
592−
593−#### /public rumor
594−
595−Contains a circle that was either added or removed from the public list.
596−
597−```hoon
598−++ rumor :> query result change
599− $% {$public add/? cir/circle} :< /public
600− :: ... ::
601− == ::
602−```
603−
604−### /peers
605−
606−To allow a circle owner to inspect who is currently subscribed to their stories, they can issue a query to retrieve subscription data.
607−
608−```hoon
609−++ query ::
610− $% {$peers nom/naem} :< readers of story
611− :: .... ::
612− == ::
613−```
614−
615−Query paths are structured as follows:
616−
617−```
618−/peers/[circle-name]
619−```
620−
621−Valid paths include:
622−
623−```
624−:> peers for circle %urbit-help
625−/peers/urbit-help
626−```
627−
628−#### /peers prize
629−
630−Contains a map of ships and the different queries they currently have active for the selected story.
631−
632−```hoon
633−++ prize :> query result
634− $% {$peers pes/(jar ship query)} :< /peers
635− :: ... ::
636− == ::
637−```
638−
639−#### /peers rumor
640−
641−Contains a ship and a query, and a flag to indicate whether that subscription has started or ended.
642−
643−```hoon
644−++ rumor :> query result change
645− $% {$peers add/? who/ship qer/query} :< /peers
646− :: ... ::
647− == ::
648−```
649−
650−### /circle
651−
652−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.
653−
654−
655−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`.
656−
657−```hoon
658−++ query ::
659− $% $: $circle :> story query
660− nom/naem :< circle name
661− wer/(unit circle) :< from source
662− wat/(set circle-data) :< data to get
663− ran/range :< query duration
664− == ::
665− :: .... ::
666− == ::
667−++ circle-data :> kinds of circle data
668− $? $grams :< messages
669− $group-l :< local presence
670− $group-r :< remote presences
671− $config-l :< local config
672− $config-r :< remote configs
673− == ::
674−++ range :> inclusive msg range
675− %- unit :< ~ means everything
676− $: hed/place :< start of range
677− tal/(unit place) :< opt end of range
678− == ::
679−++ place :> range indicators
680− $% {$da @da} :< date
681− {$ud @ud} :< message number
682− == ::
683−```
684−
685−Query paths are structured as follows:
686−
687−```
688−/circle/[circle-name]/(from-circle)/[what/data]/(range-start(/range-end))
689−(from-circle) : optional message source, ~ship/circle
690−[what/data] : one or more of grams, group, group-l, group-r,
691− : config, config-l, config-r, combined using /
692−(range) : an optional range with an optional end, its points denoted
693− : in either message number (@ud) or date (@da)
694−```
695−
696−Valid paths include:
697−
698−```
699−:> get all messages from circle %urbit-help
700−/circle/urbit-help/grams
701−:> get all messages, all presences and local configs from %urbit-help
702−/circle/urbit-help/grams/group/config-l
703−:> get all messages %urbit-help has heard from its source ~zod/fora
704−/circle/urbit-help/~zod/fora/grams
705−:> get the first 100 messages from %urbit-help
706−/circle/urbit-help/grams/0/99
707−:> get the first 100 messages %urbit-help has heard from its source ~zod/fora
708−/circle/urbit-help/~zod/fora/grams/0/99
709−:> get all messages from %urbit-help, starting now
710−/circle/urbit-help/grams/group/(scow %da now)
711−:> get all messages from %urbit-help, starting now, ending at the 100th message
712−/circle/urbit-help/grams/(scow %da now)/99
713−:> get local presences from %urbit-help for a week
714−/circle/urbit-help/group-l/(scow %da now)/(scow %da (add now ~d7))
715−```
716−
717−#### /circle prize
718−
719−Contains (where applicable) messages in envelopes (with message numbers), as well as local and remote configurations and presences.
720−
721−```hoon
722−++ prize :> query result
723− $% {$circle package} :< /circle
724− :: ... ::
725− == ::
726−++ package :> story state
727− $: nes/(list envelope) :< messages
728− cos/lobby :< loc & rem configs
729− pes/crowd :< loc & rem presences
730− == ::
731−```
732−
733−#### /circle rumor
734−
735−Contains a detailed change description of the data relevant to the query that changed.
736−
737−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.
738−
739−```hoon
740−++ rumor :> query result change
741− $% {$circle rum/rumor-story} :< /circle
742− :: ... ::
743− == ::
744−++ rumor-story :> story rumor
745− $% {$new cof/config} :< new story
746− {$gram src/circle nev/envelope} :< new/changed message
747− {$config cir/circle dif/diff-config} :< new/changed config
748− {$status cir/circle who/ship dif/diff-status} :< new/changed status
749− {$remove $~} :< removed story
750− == ::
751−++ diff-config :> config change
752− $% {$full cof/config} :< set w/o side-effects
753− {$source add/? src/source} :< add/rem sources
754− {$caption cap/cord} :< changed description
755− {$filter fit/filter} :< changed filter
756− {$secure sec/security} :< changed security
757− {$permit add/? sis/(set ship)} :< add/rem to b/w-list
758− {$remove $~} :< removed config
759− == ::
760−++ diff-status :> status change
761− $% {$full sat/status} :< fully changed status
762− {$presence pec/presence} :< changed presence
763− {$human dif/diff-human} :< changed name
764− {$remove $~} :< removed status
765− == ::
766−++ diff-human :> name change
767− $% {$full man/human} :< fully changed name
768− {$handle han/(unit cord)} :< changed handle
769− {$true tru/(unit truename)} :< changed true name
770− == ::
771−```
772−
773−
774−## Actions
775−
776−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`.
777−
778−### Circle configuration
779−
780−Since all of these apply to a specific circle, they all specify a name `nom` of the circle to operate on.
781−
782−```hoon
783−++ action :> user action
784− $% {$create nom/naem des/cord sec/security} :< create circle
785− {$delete nom/naem why/(unit cord)} :< delete + announce
786− {$depict nom/naem des/cord} :< change description
787− {$filter nom/naem fit/filter} :< change message rules
788− {$permit nom/naem inv/? sis/(set ship)} :< invite/banish
789− {$source nom/naem sub/? srs/(set source)} :< un/sub to/from src
790− :: ... ::
791− ==
792−```
793−
794−`%create`: Creates a circle with description `des` and security mode `sec`. If this mode is a whitelist, the user is automatically added to it.
795−
796−`%delete`: Deletes the circle. If a reason `why` is provided, posts that as the last message to the circle before deleting it.
797−
798−`%depict`: Set the description of the circle to `des`.
799−
800−`%filter`: Set the filter (message sanitation rules) for the circle to `fit`.
801−
802−`%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.
803−
804−`%source`: Add or remove sources to/from the circle, un/subscribing it to/from the `grams`, `group-l` and `config-l` each one.
805−
806−### Messaging
807−
808−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.
809−
810−```hoon
811−++ action :> user action
812− $% {$convey tos/(list thought)} :< post exact
813− {$phrase aud/audience ses/(list speech)} :< post easy
814− :: ...
815− ==
816−```
817−
818−`%convey`: Sends the thoughts to their audiences.
819−
820−`%phrase`: Turns the speeches into thoughts by applying sane defaults for metadata (auto-generated `uid`, `now` for `wen`), and then sends those thoughts.
821−
822−### Personal metadata
823−
824−These concern the presence users have in circles they are participating in.
825−
826−```hoon
827−++ action :> user action
828− $% {$notify aud/audience pes/(unit presence)} :< our presence update
829− {$naming aud/audience man/human} :< our name update
830− :: ... ::
831− ==
832−```
833−
834−`%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.)
835−
836−`%naming`: Sets the user's name (handle and real name) for the given audience. Good clients can display these in place of ship names.
837−
838−### Changing shared UI
839−
840−When the user makes any changes to shared UI elements (elements that should persist between clients), this has to be communicated to Hall.
841−
842−```hoon
843−++ action :> user action
844− $% {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
845− {$nick who/ship nic/nick} :< new identity
846− :: ... ::
847− ==
848−```
849−
850−`%glyph`: Adds or removes a binding of a glyph to an audience.
851−
852−`%nick`: Sets a local nickname for a ship. An empty nickname `''` means the ship has no nickname.
853−
854−### Miscellaneous changes
855−
856−```hoon
857−++ action :> user action
858− $% {$public add/? cir/circle} :< show/hide membership
859− :: ... ::
860− ==
861−```
862−
863−`%public`: Adds or removes a circle to/from the user's public membership list.
864−
865−# The New Gall Model
866−
867−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.
868−
869−New `%gall` has not yet fully solidified. As such, its structure and naming are tentative.
870−
871−## Renewing a pillar of Arvo
872−
873−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.
874−
875−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.
876−
877−### Problems
878−
879−Imagine a `++poke`, `++diff`, or even a `++peer` arm. In current implementations, you'll often see their product defined through cast as the following:
880−`^- (quip move +>)`
881−Or (sadly) more commonly:
882−`^- {(list move) _+>.$}`
883−
884−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?"
885−
886−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.
887−
888−> 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.
889−
890−**~sorreg-namtyv**
891−
892−### Solutions
893−
894−Let's imagine a world in which Gall **does** help, in both of those places.
895−
896−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.
897−
898−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.
899−
900−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.
901−
902−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.
903−
904−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.
905−
906−
907−## As seen in new Gall
908−
909−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.
910−
911−### Structures
912−
913−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.
914−
915−`brain`: application state.
916−`delta`: change to application state.
917−`opera`: side-effect, operation, move.
918−`query`: request (to an app) for data on a specific path.
919−`prize`: query result.
920−`rumor`: change to a query result.
921−
922−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.
923−
924−### Arms
925−
926−This also wouldn't be Urbit if we couldn't boil that down to a few simple pseudocode functions. Let's try, shall we?
927−
928−```hoon
929−++ bake |= {brain delta} ^- {brain opera}
930−++ peek |= {brain query} ^- (unit (unit prize))
931−++ feel |= {query delta} ^- (unit rumor)
932−++ gain |= {prize rumor} ^- prize
933−
934−:: for any given brain, delta and query:
935−.= (peek brain:(bake brain delta) query)
936− (gain rumor:(feel query delta) prize:(peek brain query))
937−```
938−
939−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.
940−
941−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.
942−
943−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.
944−`++prep`, `++poke` and `++pull` continue to function as they do right now.
945−
946−For a more verbose specification of all of these, see the new Gall spec.
947−
948−
949−## By example
950−
951−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.
952−(The app code in its entirety can be found [here](example).)
953−
954−### State & deltas
955−
956−Below is the application state, and the deltas we'll be using to modify it.
957−
958−```hoon
959−|%
960−++ brain {num/@ud $~} :< application state
961−++ delta :> state change
962− $% {$increment $~} :< +1
963− {$decrement $~} :< -1
964− == ::
965−```
966−
967−Fairly simple, right? We store a number, and every change either in- or decrements it.
968−
969−### Queries & rumors
970−
971−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.
972−
973−```hoon
974−++ query :> valid queries
975− $% {$number $~} :< current number
976− {$mul-of val/@ud} :< is num multiple of?
977− == ::
978−++ prize :> query results
979− $% {$number num/@ud} :< /number
980− {$mul-of mul/?} :< /mul-of
981− == ::
982−++ rumor :> query result changes
983− $% {$number delta} :< /number
984− {$mul-of mul/?} :< /mul-of
985− == ::
986−--
987−```
988−
989−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.
990−
991−### Responding to queries
992−
993−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.
994−
995−```hoon
996−|_ {bol/bowl brain}
997−::
998−++ leak :> read permission
999− |= {who/ship qer/query}
1000− ^- ?
1001− & :: everyone's allowed
1002−```
1003−
1004−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."
1005−
1006−```hoon
1007−++ peek :> synchronous read
1008− |= qer/query
1009− ^- (unit (unit prize))
1010− ?- -.qer
1011− $number ``[%number num]
1012− $mul-of ?: =(0 mul.qer) [~ ~]
1013− ``[%mul-of =(0 (mod num mul.qer))]
1014− ==
1015−```
1016−
1017−
1018−### Updating state & query results
1019−
1020−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.
1021−
1022−```hoon
1023−++ poke-loob :> regular old poke
1024− |= inc/?
1025− ^- (list delta)
1026− :_ ~
1027− ?: inc [%increment ~]
1028− [%decrement ~]
1029−::
1030−++ bake :> apply delta to state
1031− |= del/delta
1032− ^- (quip opera +>)
1033− :- ~
1034− ?- -.del
1035− $increment +>(num +(num))
1036− $decrement +>(num (dec num))
1037− ==
1038−```
1039−
1040−`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.
1041−
1042−```hoon
1043−++ feel :> delta to rumor
1044− |= {qer/query del/delta}
1045− ^- (unit rumor)
1046− ?- -.qer
1047− $number
1048− `[%number del]
1049− ::
1050− $mul-of
1051− :: since we only want to send a rumor if result
1052− :: changed, we need to deduce the old state from
1053− :: the current state and the delta. depends on the
1054− :: fact that state changes before ++feel. funky!
1055− :: we could, of course, store mul/? in state, and
1056− :: make a delta for it, but should we need to?
1057− =/ old
1058− .= 0
1059− %+ mod
1060− ?- -.del
1061− $increment (dec num)
1062− $decrement +(num)
1063− ==
1064− mul.qer
1065− =/ new =(0 (mod num mul.qer))
1066− ?: =(old new) ~
1067− `[%mul-of new]
1068− ==
1069−```
1070−
1071−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.
1072−
1073−
1074−## Criticism
1075−
1076−- 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.
1077−
1078−- 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.
1079−
1080−- 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?
1081−
1082−- 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.
1083−
1084−- 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?
1085−
1086−- 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.)
1087−
1088−
1089−## The original new-Gall spec
1090−
1091−`~sorreg-namtyv`
1092−
1093−```hoon
1094−=> |%
1095− --
1096−|* $: :> vinyl: historical state (including version)
1097− :> brain: working state of the application (not including version)
1098− :> delta: grain of change across all state
1099− :> prize: (pair mark noun) for namespace value
1100− :> rumor: (pair mark noun) for namespace diff
1101− :> opera: (pair bone card) for operation (old ++move)
1102− :>
1103− vinyl/mold
1104− brain/mold
1105− delta/mold
1106− prize/mold
1107− rumor/mold
1108− opera/mold
1109− ==
1110−|_ $: :> ops: pending operations, in reverse order
1111− :> ego: current state
1112− :>
1113− ops/(list opera)
1114− ego/brain
1115− ==
1116−:: :: ++bake
1117−++ bake :< apply delta
1118− |= $: :> del: change
1119− :>
1120− del/delta
1121− ==
1122− :> core after change (including operations)
1123− ^- _+>
1124− !!
1125−:: :: ++cope
1126−++ cope :< transaction result
1127− |= $: :> weg: forward identity
1128− :> het: success or error report
1129− :>
1130− weg/(list coin)
1131− het/(unit tang)
1132− ==
1133− :> actions in reverse order
1134− :>
1135− ^- (list delta)
1136− !!
1137−:: :: ++fail
1138−++ fail :< process error
1139− |= $: :> why: error dump
1140− :>
1141− why/tang
1142− ==
1143− :> actions in reverse order
1144− :>
1145− ^- (list delta)
1146− !!
1147−:: :: ++feel
1148−++ feel :< update
1149− |= $: :> del: change
1150− :> pex: preparsed path, inside-first
1151− :>
1152− del/delta
1153− pex/(list coin)
1154− ==
1155− :> query updates in reverse order
1156− :>
1157− ^- (list rumor)
1158− !!
1159−:: :: ++hear
1160−++ hear :< subscription update
1161− |= $: :> weg: forward identity
1162− :>
1163− weg/(list coin)
1164− ==
1165− :> actions in reverse order
1166− :>
1167− ^- (list delta)
1168− !!
1169−:: :: ++pull
1170−++ pull :< subscription cancel
1171− |= $: :> weg: forward identity
1172− :> het: error report, if any
1173− :>
1174− weg/(list coin)
1175− het/(unit tang)
1176− ==
1177− :> actions in reverse order
1178− :>
1179− ^- (list delta)
1180− !!
1181−:: :: ++leak
1182−++ leak :< check access
1183− |= $: :> lec: leakset (~ means public)
1184− :> pex: preparsed path, inside-first
1185− :>
1186− lec/(unit (set ship))
1187− pex/(list coin)
1188− ==
1189− :> if path `pex` is visible to ships in `lec`
1190− ^- ?
1191− !!
1192−:: :: ++load
1193−++ look :< asynchronous read
1194− |= $: :> pex: preparsed path, inside-first
1195− :>
1196− pex/(list coin)
1197− ==
1198− :> actions in reverse order
1199− ^- _+>
1200− !!
1201−:: :: ++prep
1202−++ prep :< load system
1203− |= $: old/vinyl
1204− ==
1205− :> core after boot
1206− ^- _+>
1207− !!
1208−:: :: ++peek
1209−++ peek :< synchronous read
1210− |= $: :> pex: preparsed path, inside-first
1211− :>
1212− pex/(list coin)
1213− ==
1214− :> value at `pec`; ~ for unavailable, [~ ~] for invalid
1215− :>
1216− ^- (unit (unit prize))
1217− !!
1218−:: :: ++poke
1219−++ poke :< generic poke
1220− |= $: :> ost: opaque cause
1221− :> msg: message with mark and vase
1222− :>
1223− ost/bone
1224− msg/cage
1225− ==
1226− :> actions in reverse order
1227− :>
1228− ^- (list delta)
1229− !!
1230−:: :: ++pour
1231−++ pour :< arvo response
1232− |= $: :> weg: forward identity
1233− :> sin: response card
1234− :>
1235− weg/(list coin)
1236− sin/sign
1237− ==
1238− :> actions in reverse order
1239− :>
1240− ^- (list delta)
1241− !!
1242−--
1243−```
1244−
1245−## A new-Gall example app
1246−
1247−```hoon
1248−:: counter app
1249−:: new gall example, may or may not compile.
1250−::
1251−|%
1252−++ query :> valid queries
1253− $% {$number $~} :< current number
1254− {$mul-of val/@ud} :< is num multiple of?
1255− == ::
1256−++ prize :> query results
1257− $% {$number num/@ud} :< /number
1258− {$mul-of mul/?} :< /mul-of
1259− == ::
1260−++ rumor :> query result changes
1261− $% {$number delta} :< /number
1262− {$mul-of mul/?} ::TODO or just flip? :< /mul-of
1263− == ::
1264−:: the above would ordinarily be placed in sur/, ::
1265−:: since other apps might want to use it. ::
1266−++ brain {num/@ud $~} :< application state
1267−++ delta :> state change
1268− $% {$increment $~} :< +1
1269− {$decrement $~} :< -1
1270− == ::
1271−--
1272−::
1273−|_ {bol/bowl brain}
1274−::
1275−++ leak :> read permission
1276− |= {who/ship qer/query}
1277− ^- ?
1278− & :: everyone's allowed
1279−::
1280−++ peek :> synchronous read
1281− |= qer/query
1282− ^- (unit (unit prize))
1283− ?- -.qer
1284− $number ``[%number num]
1285− $mul-of ?: =(0 mul.qer) [~ ~]
1286− ``[%mul-of =(0 (mod num mul.qer))]
1287− ==
1288−::
1289−++ poke-loob :> regular old poke
1290− |= inc/?
1291− ^- (list delta)
1292− :_ ~
1293− ?: inc [%increment ~]
1294− [%decrement ~]
1295−::
1296−++ bake :> apply delta to state
1297− |= del/delta
1298− ^- (quip opera +>)
1299− :- ~
1300− ?- -.del
1301− $increment +>(num +(num))
1302− $decrement +>(num (dec num))
1303− ==
1304−::
1305−++ feel :> delta to rumor
1306− |= {qer/query del/delta}
1307− ^- (unit rumor)
1308− ?- -.qer
1309− $number
1310− `[%number del]
1311− ::
1312− $mul-of
1313− :: since we only want to send a rumor if result
1314− :: changed, we need to deduce the old state from
1315− :: the current state and the delta. depends on the
1316− :: fact that state changes before ++feel. funky!
1317− :: we could, of course, store mul/? in state, and
1318− :: make a delta for it, but should we need to?
1319− =/ old
1320− .= 0
1321− %+ mod
1322− ?- -.del
1323− $increment (dec num)
1324− $decrement +(num)
1325− ==
1326− mul.qer
1327− =/ new =(0 (mod num mul.qer))
1328− ?: =(old new) ~
1329− `[%mul-of new]
1330− ==
1331−::
1332−:: not pictured: ++path-to-query
1333−--
1334−```
arvo/sail-and-udon.mddeleted−1233
@@ -1,1233 +0,0 @@
1−+++
2−title = "Sail and Udon"
3−weight = 7
4−template = "doc.html"
5−+++
6−
7−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.
8−
9−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.
10−
11−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.
12−
13−## Table of Contents
14−
15−- [Getting Started](#getting-started)
16−
17−- [Sail: A Guide](#sail)
18−
19−- [Udon: A Guide](#udon)
20−
21−## Getting Started {#getting-started}
22−
23−Before starting with either Sail or Udon, make sure that your ship is
24−[mounted to Unix](@/operations#booting-a-ship)
25−
26−To host that output, your ship also has a web-server that can be found at
27−`localhost` (default port 80) if it’s your first ship that’s running on the
28−machine, `http://localhost:8081/` if it’s the second ship on that same machine,
29−and so on. In the startup messages, a ship will tell you which HTTP port it's
30−using.
31−
32−Udon and Sail files are often run as independent files (`.udon` and `.hoon`
33−respectively), but for the purpose of this guide, we will run them out of the
34−`frontpage.hoon` file located in the `/gen` directory. The default content of
35−`frontpage.hoon` is Sail code.
36−
37−To use `frontpage.hoon`, we use a `|serve` command like this one in your ship's
38−Dojo:
39−
40−```
41−|serve /test %home /gen/frontpage/hoon
42−```
43−
44−This command has three arguments:
45−- The first is the URL we want to bind our site to. We chose `/test`, so the URL
46−we will find our site at is `localhost/test`.
47−- The second is the desk we want to serve. We will be serving from `%home` in
48−this tutorial.
49−- The third is the file that we want to serve. In this tutorial, we will be
50−using `/gen/frontpage/hoon`, which refers to `frontpage.hoon`.
51−
52−Run the command `|serve /test %home /gen/frontpage/hoon`. Now navigate to
53−`localhost/test` (or `localhost:8081/test` if your ship is on that port) in your
54−browser, and you should see the rendered Sail.
55−
56−**Note:** Important to remember that every time you edit a file in your ship's
57−pier (Unix directory), including `frontpage.hoon`, you need to run `|commit %home`
58−to copy those changes to Urbit.
59−
60−## <a name="sail"></a>Sail: A Guide
61−
62−It’s easy to see how Sail can directly translate to HTML:
63−
64−### Sail code
65−
66−```
67−;html
68− ;head
69− ;title: My first webpage
70− ==
71− ;body
72− ;h1: Welcome!
73− ; Hello, world!
74− ; We're on the web.
75− ;div;
76− ;script@"http://unsafely.tracking.you/cookiemonster.js";
77− ==
78−==
79−```
80−
81−### HTML code
82−
83−```
84−<html>
85− <head>
86− <title>My first webpage</title>
87− </head>
88− <body>
89− <h1>Welcome!</h1>
90− Hello, world!
91− We’re on the web.
92− <div></div>
93− <script src="http://unsafely.tracking.you/cookiemonster.js"></script>
94− </body>
95−</html>
96−```
97−
98−You can test above Sail code by placing it
99−under `^- manx` in your `frontpage.hoon` file, and then running `|commit %home`
100−in the Dojo. If you've already run the `|serve` command code from the first
101−section, the new content should appear at `localhost/test`.
102−
103−It shouldn't be hard to see the similarities between Sail and HTML. So let's go
104−into more detail about what the differences are.
105−
106−### Tags and Closing
107−
108−In Sail, tag heads are written with the tag name prepended by `;`. Unlike in
109−HTML, there are different ways on closing tags, depending on the needs of the
110−tag. One of the nice things about Hoon is that you don’t have to be constantly
111−closing expressions; Sail inherits this convenience.
112−
113−#### Empty
114−
115−Empty tags are closed with a `;` following the tag. Example:
116−
117−```
118−;div;
119−```
120−
121−Equals:
122−
123−```
124−<div></div>
125−```
126−
127−#### Filled
128−
129−Filled tags are closed via line-break. To fill text inside, add `:` after the
130−tag name, then insert your plain text following a space. Example:
131−
132−```
133−;h1: The title
134−```
135−
136−Equals:
137−
138−```
139−<h1>The title</h1>
140−```
141−
142−#### Nested
143−
144−To nest tags, simply create a new line. Nested tags need to be closed
145−with `==`, because they expect a list of sub-tags. If we nest a line of plain
146−text with no tag, a `<p>` is prepended.
147−
148−Sail, like Hoon, is white-space sensitive. Unlike in Hoon, however, two spaces
149−(called a "gap") is not necessarily equivalent to a line-break in Sail.
150−
151−```
152−;body
153− ;h1: Blog title
154− This is some good content.
155−==
156−```
157−
158−Equals:
159−
160−```
161−<body>
162− <h1>Blog title</h1>
163− <p>This is some good content.</p>
164−</body>
165−```
166−
167−
168−Conversely, if we want to write a string with no tag at all, then we can prepend
169−those untagged lines with `;`.
170−
171−```
172−;body
173− ;h1: Welcome!
174− ; Hello, world!
175− ; We’re on the web.
176−==
177−```
178−
179−Equals:
180−
181−```
182−<body>
183− <h1>Welcome!</h1>
184− Hello, world!
185− We’re on the web.
186−</body>
187−```
188−
189−
190−#### Attributes
191−
192−Attributes are key-value pairs that go into an HTML node.
193−
194−Adding attributes is simple: just add the desired attribute between parentheses,
195−right after the tag name without a space. We separate different attributes of
196−the same node by using `,`.
197−
198−Attributes can be used in two forms: flat, which uses one line; and tall, which
199−uses multiple lines, when a single line would not be practical. Flat forms and
200−flat forms are two syntaxes of semantically equivalent expressions.
201−
202−
203−#### Generic
204−
205−The code below produces a “Submit” button on the page.
206−
207−Wide-form Sail:
208−
209−```
210−;input(type "submit", value "Submit");
211−```
212−
213−Tall-form Sail:
214−
215−```
216−;input
217− =type "submit"
218− =value "Submit";
219−==
220−```
221−
222−Equals:
223−
224−```
225−<input type="submit" value="Submit">`
226−```
227−
228−#### IDs
229−
230−```
231−;nav#header: Menu
232−```
233−
234−Equals:
235−
236−```
237−<nav id="header">Menu</nav>
238−```
239−
240−Add `#` after tag name to add an ID.
241−
242−#### Classes
243−
244−`;h1.text-blue: Title` equals `<h1 class="text-blue">Title</h1>`
245−
246−Add `.` after tag name to add a class. However, if you want a class name that
247−contains a space, you will need to use use the syntax of a generic attribute:
248−
249−`;div(class "logo inverse");` equals `<div class="logo inverse"></div>`
250−
251−
252−#### Image
253−
254−`;img@"example.png";`
255−
256−Equals
257−
258−`<img src="example.png"/>`
259−
260−Add `@` after the tag name to link your source.
261−
262−To add attributes to the image, like size specifications, add the
263−desired attribute after the `"` of the image name and before the final `;` of
264−the `img` tag.
265−
266−For example:
267−
268−`;img@"https://urbit.org/example.png"(width "100%");`
269−
270−#### Linking
271−
272−`;a/"urbit.org": A link to Urbit.org`
273−
274−Equals
275−
276−`<a href="urbit.org">A link to Urbit.org</a>`
277−
278−Add `/` after tag name to start an href.
279−
280−### Hoon in Sail
281−
282−Our first example is useful to understand how Sail syntax translates to HTML
283−syntax, but Sail finds its usefulness in the fact that it can be used seamlessly
284−with Hoon code.
285−
286−One place where Sail diverges from HTML is that it supports string
287−interpolation. In Sail, the contents of all tags are a string type called `tape`
288−unless otherwise designated. Tapes are delineated by the double quotes `""`.
289−That’s important, because tapes can be interpolated with Hoon expressions,
290−provided that those expressions produce something a tape as well. Interpolation
291−is done by wrapping the code to be inserted in `{}`. In your Dojo prompt, try
292−the command below (without the `>`):
293−
294−```
295−> "I am a l{(mul 3 11)}t Urbit user."
296−! exit
297−```
298−
299−Oh no! That command produced a nest-fail error, which indicates that there was
300−a problem related to Hoon type-system. We used the proper `{}` syntax for
301−interpolation, and we used the proper function-call syntax inside of it. So
302−what happened?
303−
304−Trying the `mul` function on its own will help answer this question. Try the
305−following command in your Dojo:
306−
307−```
308−> (mul 3 11)
309−33
310−```
311−
312−This should work, producing `33`, an atom. That’s our problem. The
313−interpolation expression expects a tape, but our first command tried to
314−interpolate with something that results in an atom. Try this now:
315−
316−```
317−> <(mul 3 11)>
318−"33"
319−```
320−
321−We get a similar result, but we know that it’s a tape because it’s wrapped in
322−`""`. Bingo! With this knowledge, let’s perform a successful interpolation:
323−
324−```
325−> "I am a l{<(mul 3 11)>}t Urbit user."
326−"I am a l33t Urbit user."
327−```
328−
329−Great!
330−
331−### The Subject
332−
333−The default subject of a Sail file is different from the subject that
334−expressions in the Dojo or a Hoon generator are evaluated against.
335−
336−To see this difference, first save the code below to a file at
337−`home/web/pages/sub.hoon` and view the rendering at
338−`http://localhost:8080/pages/sub`.
339−
340−```
341−;html
342− ;head;
343− ;body
344− {<.>}
345− ==
346−==
347−```
348−
349−Then enter the following command in the Dojo:
350−
351−```
352−> .
353−```
354−
355−You'll notice that the Sail subject is like a stripped-down version of the Dojo
356−subject. Its final line should match the Dojo subject.
357−
358−Now swap the code below into your Sail file.
359−
360−```
361−/= gas /$ fuel:html
362−;html
363− ;head;
364− ;body
365− {<.>}
366− ==
367−==
368−```
369−
370−You'll find that the resulting Sail subject is much larger. If you look closely,
371−you'll see that there's some new similarities with the Dojo subject, such as
372−containing the name of your ship. There's also some new differences, since
373−`fuel:html` contains things that are specifically useful for performing
374−web-related operations.
375−
376−### A More Interesting Example
377−
378−Now let’s apply knowledge of string interpolation and the Sail subject in a Sail
379−source file. The following code produces more interesting things than the
380−example we saw before.
381−
382−```
383−/= gas /$ fuel:html
384−=/ show-list &
385−=+ wid=(met 3 p.bem.gas)
386−=/ what-kind
387−?: (lte wid 1) "galaxy"
388−?: =(2 wid) "star"
389−?: (lte wid 4) "planet"
390−?: (lte wid 8) "moon"
391− "comet"
392−;html
393− ;head
394− ;meta(charset "utf-8");
395− ;title: A more advanced page
396− ==
397− ;body
398− ;h1: This is the Title
399− ; This is a
400− ;a/"http://urbit.org": link to Urbit.org.
401− ;span: Check it out!
402− ;+ ?: show-list
403− ;ol
404− ;li(style "color: green"): We're doing interesting stuff now.
405− ;li: We're pretty-printing this sum with Hoon: {<(add 50 50)>}.
406− ;li: The code above is shorthand for {(scow %ud (add 50 50))}.
407− ;li: I am {(trip '~lodleb-ritrul')}.
408− ;li: Actually, my name is {<p.bem.gas>}. I'm a {what-kind}.
409− ==
410− ;div: My name is {<p.bem.gas>}. I'm a {what-kind}.
411− ==
412−==
413−```
414−
415−Save the above Sail code in to `home/web/pages/secondsail.hoon` and access the
416−resulting page by navigating to `http://localhost:8080/pages/secondsail` in
417−your browser.
418−
419−There are some interesting things here. Let’s go through this code piece by
420−piece.
421−
422−```
423−/= gas /$ fuel:html
424−```
425−
426−Later in this code we want produce the name of the ship is hosting it, something
427−that looks like ~lodleb-ritrul. In a generator, we could produce our ship name
428−by writing `our` -- try it in the Dojo. But remember that Sail is rendered
429−against its own subject, `our` is not part of the default subject. To augment
430−our subject with the information that we need, we use `/= gas /$ fuel:html`.
431−
432−The above expression uses two Ford runes, `/=` and `/$`, to add the relevant
433−information to the current subject. We can pull the ship’s name out of this
434−augmented subject later. It's important to note that these runes are not part of
435−Hoon. They are part of Ford, our build system.
436−
437−`/$` is used to get data from the environment, and `/=` adds that data to
438−subject in the face `gas`. The
439−[Ford user manual](https://urbit.org/docs/arvo/internals/ford/runes/) has
440−details on these and other Ford runes, but understanding these runes isn’t
441−necessary for the purposes of this tutorial.
442−
443−`fuel:html` gets extra data from your ship’s Eyre module, which handles all
444−things HTTP, and sticks it in the subject when Eyre renders a page. This
445−includes the name of the ship, which is what we look for in the next line, but
446−it includes much more.
447−
448−`p.bem.gas` is an expression that looks for `p` within `bem` within `gas`, the
449−face that we stored the above `fuel:html` expression in. That wing happens to
450−resolve to the name of the ship that is hosting the web-server. If we wanted to
451−access the current desk, we would use the wing expression `q.bem.gas`.
452−
453−You can take a look at what you can access by typing `fuel:html` in the Dojo,
454−and then explore it by modifying your wing expression in your Sail file
455−accordingly.
456−
457−```
458−=/ show-list &
459−```
460−
461−The above line of code stores a variable used later for a conditional. `&` means
462−`true`, meaning that any evaluation of `show-list` will be true until changed in
463−the source code.
464−
465−```
466−=+ wid=(met 3 p.bem.gas)
467−=/ what-kind
468− ?: (lte wid 1) "galaxy"
469− ?: =(2 wid) "star"
470− ?: (lte wid 4) "planet"
471− ?: (lte wid 8) "moon"
472− "comet"
473−```
474−
475−This code chunk is a series of conditionals that checks the host ship’s name to
476−see what its value is.
477−
478−The first line, `=+ wid=(met 3 p.bem.gas)`, combines a new noun with the
479−subject and gives it the face `wid`. This noun is produced by the the
480−standard-library function [`met`](/docs/reference/library/2c), which measures the number of
481−[blocks](/docs/reference/library/1c/) of size `a` within `b`. Blocks are units that have a
482−bitwidth of `2^a`. So, in this case, it measures how many bytes (blocks of size
483−3 are bitwidths of 8; `2^3 = 8`) are fully contained in your ship's address.
484−
485−Galaxies contain zero to one 3-blocks; stars contain two 3-blocks; planets
486−contain three to four 3-blocks; moons contain five to eight 3-blocks; comets
487−contain nine to sixteen 3-blocks. Each test uses `lte`, the
488−less-than-or-equal-to function, to determine if `wid` is of a given size. The
489−result of this series of tests is added to the subject and given the face
490−`what-kind`.
491−
492−Ship names are simply another representation of atoms, and ship
493−categories are different ranges of possible atomic values. Because of this, we
494−perform less-than tests to see what kind of ship is running the web-server.
495−
496−```
497−;html
498− ;head
499− ;meta(charset "utf-8");
500− ;title: A more advanced page
501− ==
502−```
503−
504−Sail proper begins here. These four lines are four nodes. The `;html` node
505−indicates that the contained code should be rendered as HTML; this tag is closed
506−on the final line. The `;head` node contains metadata, and is closed three lines
507−later. The `;meta` node sets the character set to UTF-8, and the `;title` node
508−sets the title of the page that shows up in the browser tab.
509−
510−```
511− ;body
512− ;h1: This is the Title
513− ; This is a
514− ;a/"http://urbit.org": link to Urbit.org.
515− ;span: Check it out!
516−```
517−
518−The first line here opens, of course, the body node. The second line creates
519−header text.
520−
521−The third, fourth, and fifth lines of code here construct a single line with an
522−inline link.
523−`; This is a` begins the rendered line with plain text.
524−
525−`;a/"http://urbit.org": link to Urbit.org.` continues that same rendered line,
526−and creates hyperlinked text out of `link to Urbit.org.`
527−
528−`;span: Check it out!` continues that same rendered line further. `;span:`
529−has the same use as `<span>` in HTML, and by following it with just a `:` and no
530−attributes, it continues the line without formatting. Following `;span:` with
531−**two** spaces causes there to be single space following the produced `<span>`
532−element, because one of those spaces is syntactically necessary.
533−
534−In the following lines, we beginning to use some Hoon expressions again.
535−
536−```
537− ;+ ?: show-list
538− ;ol
539−```
540−
541−In the top line in the chunk above, we use the `;+` Sail rune, which
542−resolves an expression to a single node. That expression, in this case, is
543−`?:`, which tests the truth value of `show-list`, which we assigned the value
544−`&` (meaning “true”) at the beginning of the program. It’s closed by the `==` on
545−the last line.
546−
547−Thus, this program resolves to the first child of `show-list`, the node `;ol`.
548−That node creates an ordered list, and the items contained within that node.
549−
550−```
551− ;li(style "color: green"): We're doing more interesting stuff now.
552−```
553−
554−The line above is the only element of this list that does not use
555−Hoon proper. The line renders as green, as interpreted by the browser,
556−because of the Sail attribute.
557−
558−The next items in the list use `{}`. Recall that these braces, pronounced “lob”
559−and “rob” in Hoon-speak, allow for the interpolation of code within a string.
560−
561−```
562− ;li: We're pretty-printing this sum with Hoon: {<(add 50 50)>}.
563−```
564−
565−The line above is interpolated with Hoon code that produces the sum of 50 plus
566−50, which is wrapped in `<>` to put the product in double quotes to make it a
567−tape, like the rest of the line.
568−
569−
570−```
571− ;li: The code above is shorthand for {(scow %ud (add 50 50))}.
572−```
573−
574−The `{(scow %ud (add 50 50)}` on this line is just a different way
575−writing the `{<(add 50 50)>}` expression. `scow` is a Hoon function that turns a
576−noun into a `tape`, Hoon’s string type. `%ud` tells `scow` that its argument
577−should be displayed in the form of an unsigned decimal.
578−
579−
580−```
581− ;li: I am {(trip '~lodleb-ritrul')}.
582−```
583−
584−`trip` is a function that takes a `cord` and produces a `tape`. A piece of
585−data of the cord type is one big atom formed from adjacent unicode bytes and
586−delineated by `''`. Remember that all text rendered in Sail is treated as a
587−tape. So, by converting `~lodleb-ritrul` to a tape, it can be included in the
588−tape that we are trying to insert it into without getting a type error.
589−
590−```
591− ;li: Actually, my name is {<p.bem.gas>}. I'm a {what-kind}.
592− ==
593−```
594−
595−The line above has interpolated code that uses a wing expression to access the
596−name of the host ship, and then accesses the face `what-kind` contains a string
597−describing what type of ship it is. We declared `gas` on the very first line so
598−that we could add that sort of information to the subject that our Sail is
599−rendered against. The wing expression `p.bem.gas` looks for `p` within `bem`
600−within `gas`, which happens to be where the name of the ship is located.
601−
602−Note that `{what-kind}` does not have a `<>` wrapper. Why do you think this is?
603−
604−```
605− ;div; My name is {<p.bem.gas>}. I'm a {ship}.
606− ==
607−==
608−```
609−
610−The `;div;` node above is only rendered, as an alternative to the above list,
611−if `show-list` is evaluated as true. This means it won’t be shown with your
612−default code. To show this line, change the `&` on line 2 to `|` (“false”).
613−
614−### Sail Runes
615−
616−In the previous example, we used a few special runes that aren’t used in typical
617−Hoon code. But there are others that are worth learning about at this point.
618−
619−`;+` is an expression that resolves to a single node. We saw this on line 20
620−in our Sail example above: `;+ ?: show-list` resolves to the node `;ol` and
621−all of that node’s children.
622−
623−`;*` is an expression that resolves to a list of nodes. If we want to render
624−multiple nodes side-by-side, and not just the children of a single node, this
625−is the expression that we use.
626−
627−`;=` turns a tuple of nodes into a list of nodes.
628−
629−
630−To see how these runes work, let’s take a chunk of our previous code starting at
631−line 20 and modify it a bit:
632−
633−```
634− ;* ?: show-list
635− ;=
636− ;li: I am {(trip '~lodleb-ritrul')}.
637− ;li: Actually, my name is {<p.bem.gas>}.
638− ==
639− ;=
640− ;div: My name is {<p.bem.gas>}. I'm a {what-kind}.
641− ;div: No list here!
642− ==
643− ==
644−```
645−
646−We changed the conditional branches so that each contains two Sail nodes,
647−side-by-side -- notice that the `;ol` is absent from the first branch.
648−
649−We begin with the `;*` rune, which resolves to a list of nodes, instead of the
650−`;+` rune, which only resolves to a single node.
651−
652−But that’s not enough on its own. `;*` needs to resolve to a list, and a few
653−Sail nodes aren’t lists until they are explicitly made into lists. Until we wrap
654−those nodes in `;=`, the nodes treated as mere tuples. All branches must be
655−valid lists for the `;* ?: show-list` expression to resolve.
656−
657−### Further Reading
658−
659−You should now have foundational knowledge for making web pages with Sail. There
660−is, of course, more to learn.
661−
662−The [Ford manual](https://urbit.org/docs/arvo/internals/ford/runes/)
663−can show you how to access various ship resources for user in your pages. To
664−learn more about how the renderer works, take a look at the
665−`/home/ren/urb.hoon` file inside your urbit.
666−
667−## Udon: A Guide {#udon}
668−
669−Udon is a way to write content for the web. It's a minimalist
670−markup language for creating and rendering text documents, with a
671−Markdown-inspired syntax. It's integrated with our Hoon programming language,
672−allowing it to be used as standalone prose in its own file or embedded inside a
673−Hoon source file, in which case it will be parsed into a tree of HTML nodes
674−using Hoon's XML-templating syntax, Sail.
675−
676−There are quite a few similarities between Udon and the
677−CommonMark standard, but there are enough differences that you shouldn't rely on
678−existing knowledge of the latter. Udon generally supports only one
679−syntax for each type of HTML node it emits. Udon is also stricter than
680−Markdown: some syntax errors will prevent the file from being parsed at all.
681−
682−## Testing Udon
683−
684−Udon files use the `.udon` file extension, but for this entry-level guide, we
685−will use the `frontpage.hoon` method that we are already familiar with.
686−
687−To test out Udon, put a `;>` under the `^- manx` in your `frontpage.hoon` file,
688−and then put all your Udon code under that `;>`. Then run `|commit %home`
689−in the Dojo. If you've already run the `|serve` command code from the first
690−section, the new content should appear at `localhost/test`.
691−
692−## Udon Syntax
693−
694−### Front Matter
695−
696−> Note: The Front Matter section only applies to .udon files, and not the
697−frontpage.hoon testing method.
698−
699−The first thing on a `.udon` file is a chunk of code called the front matter. It
700−contains metadata about your page, such as date, title, and position relative
701−to sibling pages.
702−
703−As an example, let's look at the front matter of this very page:
704−
705−```
706−:- :~ navhome/'/docs/'
707− sort/'11'
708− title/'Udon'
709− ==
710−;>
711−```
712−
713−What's going on here?
714−
715−`:-`, the Hoon rune for creating a cell, creates a cell composed of
716−the `:~` Hoon rune for creating a list, and `;>`, which is a Sail rune
717−for Udon.
718−
719−`:~` creates a list out of the three elements: `navhome/'/docs/'`, which
720−indicates that navigating "home" will bring you to the urbit.org/docs section
721−of the website; `sort/'28',` which assigns it the 28th position of the
722−immediate section that contains it, the one you see in the sidebar;
723−and `title/'Udon'`, which gives the page its title. The `==` digraph
724−terminates the list.
725−
726−`;>` is a Sail rune that creates a node that contains everything that follows
727−it, telling the parser that that text should be interpreted as Udon.
728−It's not technically front matter, but you'll always find it following the
729−front matter, since all Udon must come after this rune.
730−
731−The categories listed in the example above -- `navhome`, `sort`, and `title` --
732−make sense to Eyre by default, but any arbitrary category can be used. The code
733−below is valid front matter.
734−
735−```
736−:- :~ date/~2018.9.12
737− author/~lodleb-ritrul
738− music/'rad'
739− ==
740−```
741−
742−Note that `~2018.9.12`, `~lodleb-ritrul`, and `'rad'` are all of of atom
743−types: `@da`(date), `@p` (ship name), and `@t` (cord), respectively. Only atom
744−types work here. Having `music/"rad"` would prevent the source file from
745−parsing.
746−
747−### Headers
748−
749−Headers in Udon begin the line with one or more `#` characters,
750−followed by a single space. After that space comes the actual text to be
751−displayed. The number of leading `#`s corresponds to the resulting HTML
752−header-size element: `#` yields an `<h1>`, `##` yields an `<h2>`, and so on,
753−through `<h6>`. The header for this section is `### Headers`.
754−
755−**Example:**
756−```
757−#### Header (h4)
758−
759−##### Header (h5)
760−```
761−**Produces:**
762−
763−#### Header (h4)
764−
765−##### Header (h5)
766−
767−### Italics and Bold
768−
769−Enclosing text with `_` will cause that text to appear italicized, using an `<i>`
770−element.
771−
772−Enclosing text with `*` will cause that text to appear bolded, using a `<b>`
773−element.
774−
775−
776−**Example:**
777−
778−```
779−To get their *attention*, you need that _je ne sais quoi_.
780−```
781−
782−**Produces:**
783−
784−To get their **attention**, you need that _je ne sais quoi_.
785−
786−### Line Break
787−
788−A blank line is interpreted as a line break, creating a distinct
789−paragraph. However, a newline on its own is merely interpreted as a space on
790−the _same line_.
791−
792−**Example:**
793−
794−```
795−Here's the first line.
796−
797−This second line is separated by two newlines, so it's a separate paragraph.
798−
799−This line looks like a distinct paragraph, but...
800−It's only separated by a single newline, so it's included in the same paragraph.
801−```
802−**Produces:**
803−
804−
805−Here's the first line.
806−
807−This second line is separated by two newlines, so it's a separate paragraph.
808−
809−This line looks like a distinct paragraph, but...
810−It's only separated by a single newline, so it's included in the same paragraph.
811−
812−#### Backslash Line Break
813−
814−A backslash at the end of a line inserts a line break (`<br>`)
815−after that line. This contrasts with the normal udon behavior of
816−converting newlines to spaces.
817−
818−**Example:**
819−```
820−I wonder how long each line
821−will be if I put backslashes\
822−at the ends of the lines.
823−```
824−**Produces:**
825−
826−I wonder how long each line
827−will be if I put backslashes\
828−at the ends of the lines.
829−
830−### Escape
831−
832−A backslash directly _before_ a word (with no spaces) will be interpreted
833−as an escape character, causing it to be rendered raw.
834−
835−**Example:**
836−
837−```
838−Here is some *bold* text.
839−Here is some \*not bold* text.
840−```
841−
842−**Produces:**
843−
844−Here is some **bold** text.
845−Here is some \*not bold* text.
846−
847−
848−### List
849−
850−A line beginning with a `-` followed by a space is interpreted as an
851−element of an **unordered list** (`<ul>`). Each line in an unordered list is
852−prepended with a bullet point.
853−
854−A line beginning with a `+` followed by a space is interpreted as an element
855−of an **ordered list** (`<ol>`). Each line in an ordered list is prepended with
856−a number corresponding to its position in that list.
857−
858−New list elements are delineated by newlines beginning with list symbols of
859−the appropriate type (`-` or `+`).
860−
861−Just as with non-list text, text on a bare newline will appear on line before,
862−separated by a space. A `\\` is used to create a line-break that isn't the list
863−itself and isn't a list. Both of these kinds of newlines must be indented by two
864−spaces, or else the page will not parse.
865−
866−Indentation is also used for creating nested sub-lists. Sub-lists of one kind
867−can be used with parent lists of the other kind. Sub-lists can't be nested
868−directly after either kind of aforementioned newline that isn't a list element;
869−only lines that are themselves list elements can nest sub-lists.
870−
871−A newline after a blank line is interpreted as a new paragraph in normal text.
872−Between to list elements, however, a blank line is semantically equivalent to
873−a bare newline. To separate two lists with blank space, create a blank line
874−followed by a `\\` on its own line.
875−
876−**Example:**
877−
878−```
879−- Eggs
880− (cage-free)
881−- Milk
882−- Butter
883−- Chicken\
884− Make sure that you get enough for the barbecue
885−- Bread
886− + Ask the baker what's fresh
887− + Buy the second-freshest batch
888−- Cereal
889−
890−\
891−+ First, separate eggs into a bowl
892−+ Then, add a splash of cream
893− - If you don't have cream, you can use milk, but cream is preferred
894− + If you don't have milk or cream, melt an eighth of a stick of butter on
895− a skillet
896− + Scramble the eggs in the bowl
897− + Pour the eggs onto the skillet before the butter browns
898−+ Heat the skillet
899−
900−+ Scramble eggs and put them into skillet
901−
902−\
903−+ Cool
904−+ Alright
905−```
906−
907−Produces
908−
909−- Eggs
910− (cage-free)
911−- Milk
912−- Butter
913−- Chicken\
914− Make sure that you get enough for the barbecue
915−- Bread
916− 1. Ask the baker what's fresh
917− 1. Buy the second-freshest batch
918−- Cereal
919−
920−\
921−1. First, separate eggs into a bowl
922−1. Then, add a splash of cream
923− - If you don't have cream, you can use milk, but cream is preferred
924− 1. If you don't have milk or cream, melt an eighth of a stick of butter on
925− a skillet
926− 1. Scramble the eggs in the bowl
927− 1. Pour the eggs onto the skillet before the butter browns
928−1. Heat the skillet
929−
930−1. Scramble eggs and put them into skillet
931−
932−\
933−1. Cool
934−1. Alright
935−
936−### Link
937−
938−There are two ways to create links, but both contain the text be hyperlinked
939−in `[]` followed by the destination in `()`.
940−
941−The first type is an inline-style link, which simply uses the full URL as its
942−destination.
943−
944−**Example:**
945−
946−```
947−[I'm an inline-style link](https://urbit.org/operations/#using-the-shell)
948−```
949−
950−**Produces:**
951−
952−[I'm an inline-style link](https://urbit.org/operations/#using-the-shell)
953−
954−The second type is a reference-style link, which uses a relative path, based on
955−the current page's location. Instead of the full url, we use `..` to fill in
956−the all of the URL that the destination has in common with the origin page.
957−
958−**Example:**
959−
960−```
961−[I'm a reference-style link](../shell)
962−```
963−
964−**Produces:**
965−
966−[I'm a reference-style link](../shell)
967−
968−If this page is located at `https://www.urbit.org/docs/reference/`, then these two
969−examples should have the same destination.
970−
971−#### Anchor Link
972−
973−A link to a section of the same page is in the style of
974−`[text to be linked](#the-destination)`.
975−
976−The destination for the anchor link is designated with the HTML element `id`,
977−so we need to use some [Sail](#sail). If there are two or more anchors with
978−the same `id` on the page, you will arrive at the earliest instance of the the
979−anchor.
980−
981−**Example:**
982−
983−```
984−Check out this [section](#here-we-are) that we want to jump to.
985−
986−Four score and seven years ago....
987−
988−It was the best of times, it was the worst of times...
989−
990−## Here we are!
991−```
992−
993−**Produces:**
994−
995−Check out this [section](#here-we-are) that we want to jump to.
996−
997−Four score and seven years ago....
998−
999−It was the best of times, it was the worst of times...
1000−
1001−## Here we are!
1002−
1003−### Double Quote
1004−
1005−Text enclosed in double quotes (`"`) will be rendered with
1006−opening and closing quotes -- that is, `“` and `”`.
1007−
1008−**Example:**
1009−```
1010−"Yes," he said. "That is the way with him."
1011−```
1012−
1013−**Produces:**
1014−
1015−“Yes,” he said. “That is the way with him.”
1016−
1017−
1018−### Code Literal
1019−
1020−There are two ways to show the literal text of code without running it: inline
1021−and block. Both highlight the contained text in another color.
1022−
1023−Note that the backslash, due to its role as the escape character, can only be
1024−displayed in a code block literal and not as inline code literal. This is a
1025−bug.
1026−
1027−```
1028−\
1029−```
1030−
1031−#### Inline Code Literal
1032−
1033−Enclosing some text in `` ` `` characters will cause it to be displayed as code,
1034−inside a `<code>` HTML element with monospace font and highlighted with a
1035−different background color.
1036−
1037−Using `` ` `` is useful when you want to designated only part of a line as code.
1038−Since this page is written in Udon, we've been using this operation
1039−throughout this guide to `format text` to distinguish code from prose.
1040−
1041−**Example:**
1042−```
1043−`*[a 2 b c] -> *[*[a b] *[a c]]` is like lisp's `apply`.
1044−```
1045−**Produces:**
1046−
1047−`*[a 2 b c] -> *[*[a b] *[a c]]` is like lisp's `apply`.
1048−
1049−Also, using the `++` prefix before a word will cause the word to be rendered as
1050−code with the `++` displayed, since that's the standard notation for an arm in
1051−Hoon.
1052−
1053−**Example:**
1054−
1055−```
1056−The ++add arm is used to sum two numbers.
1057−```
1058−
1059−**Produces:**
1060−
1061−The `++add` arm is used to sum two numbers.
1062−
1063−#### Block Code Literal
1064−
1065−By enclosing a block of text in a tick on their own lines
1066−before and after the contained text, the text will be treated as a code block.
1067−
1068−Most of our examples so far have used.
1069−
1070−**Example:**
1071−
1072−
1073− ```
1074− (def Y (fn [f]
1075− ((fn [x]
1076− (x x))
1077− (fn [x]
1078− (f (fn [y]
1079− ((x x) y)))))))
1080− ```
1081−
1082−**Produces:**
1083−
1084−```
1085−(def Y (fn [f]
1086− ((fn [x]
1087− (x x))
1088− (fn [x]
1089− (f (fn [y]
1090− ((x x) y)))))))
1091−```
1092−
1093−### Hoon Constants
1094−
1095−Hoon has several syntactic forms for literals (numbers, strings, dates, etc.)
1096−that can be used in udon as well. Udon detects such code, and so these
1097−forms will automatically appear inside a `<code>` element like inline code.
1098−
1099−Example:
1100−
1101−```
1102−~2017.8.29 \
1103−0xdead.beef \
1104−%term
1105−```
1106−
1107−produces:\
1108−
1109−`~2017.8.29` \
1110−`0xdead.beef` \
1111−`%term`
1112−
1113−
1114−### Horizontal Rule
1115−
1116−Three or more hyphens, such as `---`, on their own line produce an `<hr>`
1117−element, the 'horizontal rule'. This is rendered as a horizontal line the
1118−width of its containing paragraph.
1119−
1120−**Example:**
1121−
1122−```
1123−Above the line
1124−---
1125−Below the line
1126−-----
1127−And below this line, too
1128−```
1129−
1130−**Produces:**
1131−
1132−
1133−Above the line
1134−
1135−---
1136−
1137−Below the line
1138−
1139−-----
1140−
1141−And below this line, too
1142−
1143−### Block Quote
1144−
1145−A section of text with the first line beginning with `>` and a space,
1146−and each successive newline indented by two spaces yields a
1147−`<blockquote>` HTML element. This block quote can itself contain more Udon,
1148−including more block quotes to render nested levels of quotation.
1149−
1150−Blank newlines do not end the block quote, but a blank newline followed by an
1151−unindented line of text _will_ end the quote.
1152−
1153−**Example:**
1154−
1155−```
1156−> As Gregor Samsa awoke one morning from uneasy dreams, he
1157− found himself transformed in his bed into a *monstrous* vermin.
1158−
1159−Quote break.
1160−
1161−> _See_ the child.
1162−
1163− He is pale and thin, he wears a thin and ragged linen shirt.
1164−```
1165−
1166−**Produces:**
1167−
1168−> As Gregor Samsa awoke one morning from uneasy dreams
1169− he found himself transformed in his bed into a **monstrous** vermin.
1170−
1171−Quote break.
1172−
1173−> _See_ the child.
1174−
1175−> He is pale and thin, he wears a thin and ragged linen shirt.
1176−
1177−
1178−### Poem
1179−
1180−A poem is a section of text with meaningful newlines. Recall that,
1181−normally in Udon, newlines are treated as spaces and do not create a
1182−new line of text. If you want to embed text where newlines are retained, then
1183−indent the text in question with **eight spaces**.
1184−
1185−**Example:**
1186−
1187−```
1188− A shape with lion body and the head of a man,
1189− A gaze blank and pitiless as the sun,
1190− Is moving its slow thighs, while all about it
1191− Reel shadows of the indignant desert birds.
1192−```
1193−**Produces:**
1194−
1195− A shape with lion body and the head of a man,
1196− A gaze blank and pitiless as the sun,
1197− Is moving its slow thighs, while all about it
1198− Reel shadows of the indignant desert birds.
1199−
1200−
1201−## Sail Expressions
1202−
1203−It's possible to use Udon as an HTML templating language akin to
1204−PHP, ERB, JSP, or Handlebars templates. This facility derives
1205−in part from the support for embedding Hoon code inside the markup.
1206−
1207−
1208−Sail is a domain-specific language within Hoon for creating XML nodes,
1209−including HTML. It can be used directly within Udon to provide
1210−scripting capability with Hoon and also to provide more precise control over the
1211−resulting HTML. The [Sail guide](#sail) is a good place to learn the
1212−specifics.
1213−
1214−Example:
1215−
1216−```
1217−;=
1218− ;p
1219− ;strong: Don't panic!
1220− ;br;
1221− ;small: [reactive publishing intensifies]
1222− ==
1223−==
1224−```
1225−
1226−Produces:
1227−
1228−
1229−<p>
1230− <strong>Don't panic!</strong>
1231− <br>
1232− <small>[reactive publishing intensifies]</small>
1233−</p>
arvo/ship-troubleshooting.mddeleted−171
@@ -1,171 +0,0 @@
1−+++
2−title = "Ship Troubleshooting"
3−weight = 8
4−template = "doc.html"
5−+++
6−
7−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.
8−
9−## Table of Contents
10−
11−- [Best practices](#best-practices)
12−- [Operation issues](#operation-issues)
13−- [Connectivity issues](#connectivity-issues)
14−- [Booting issues](#booting-issues)
15−- [Crashing issues](#crashing-issues)
16−
17−## Best Practices {#best-practices}
18−
19−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.
20−
21−**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.
22−
23−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.
24−
25−**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)
26−
27−**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.
28−
29−**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.
30−
31−**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/)
32−
33−**`|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.
34−
35−**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.
36−
37−**Perform a personal breach.** {#personal-breach} 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.
38−
39−Personal breaches often fix connectivity issues, but should only be used as a last resort.
40−
41−## Operation Issues {#operation-issues}
42−
43−### My urbit is very slow
44−
45−Run `|wash-gall`. This clears caches in Gall, and may result in steep performance improvements.
46−
47−### My urbit is frozen
48−
49−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.
50−
51−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.
52−
53−### When I try to type into the Dojo, it prints `dy-noprompt`
54−
55−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).
56−
57−### My ship doesn't recognize file changes that I make in my pier
58−
59−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.
60−
61−## Connectivity Issues {#connectivity-issues}
62−
63−### I can `|hi` my sponsor star, but I cannot get syncs from it or discover peers
64−
65−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)`.
66−
67−### I can't communicate with anyone
68−
69−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).
70−
71−### I keep getting an `ames` error stack-trace
72−
73−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.
74−
75−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.
76−
77−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...
78−
79−```
80−`@ux`~sampel-palnet
81−```
82−
83−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:
84−
85−```
86−|start %eth-manage
87−:eth-manage %look-ethnode
88−```
89−
90−If they have wrong keys of yours, you need to somehow ask them to to run that same command.
91−
92−### I can talk to some ships, but I can't talk to my sponsor and some other ships
93−
94−This is the result of deleting your pier and starting your ship again. To fix this, you must perform a [personal breach](#personal-breach).
95−
96−### I have two ships, and only one can connect with the other
97−
98−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.
99−
100−1. Turn both ships off and on again. This sometimes solves this problem.
101−
102−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.
103−
104−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`.
105−
106−4. Try running `|hi ~B`. Wait a bit. Are you seeing `%blocked` or `%bad-ack` messages yet? If not, send another `|hi ~B`.
107−
108−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.
109−
110−6. If the OWC is still not resolved, try step 6.
111−
112−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.
113−
114−## Booting Issues {#booting-issues}
115−
116−### My ship won't boot and gets a `terminals database is inaccessible` message
117−
118−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.
119−
120−### My ship booted for the first time, but it turned into a comet instead of my planet or star
121−
122−You may have used the wrong arguments when booting your ship for the first time. Delete this comet and try again.
123−
124−### My development ship ("fakezod") gets a `boot: malformed` failure
125−
126−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`.
127−
128−## Crashing Issues {#crashing-issues}
129−
130−### I got a `bail` error and my ship crashed
131−
132−Try just bringing it back up; it will often start working just fine again.
133−
134−However, if you get a `bail` error again, you should perform a personal breach.
135−
136−#### Making a GitHub issue out of your `bail`
137−
138−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.
139−
140−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.
141−
142−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:
143−
144−```
145−(lldb) bt
146−* thread #1, stop reason = signal SIGSTOP
147− * frame #0: 0x000000010583d871 urbit`_box_free + 17
148− frame #1: 0x0000000105845ee6 urbit`u3j_boot + 182
149− frame #2: 0x000000010584d1f9 urbit`u3m_boot + 89
150− frame #3: 0x000000010583d15d urbit`main + 2765
151− frame #4: 0x00007fff75cb83d5 libdyld.dylib`start + 1
152−(lldb)
153−```
154−
155−Copy this stack trace and include it in your GitHub issue.
156−
157−### My ship crashed with a `bail: meme` error.
158−
159−1. Make sure you are running version to `0.8.2` if you are not already on it.
160−
161−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).
162−
163−### My ship crashed with a `bail: oops` error
164−
165−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.
166−
167−This same error might also appear with a message like `Assertion '0'`.
168−
169−### My ship crashed with an `pier: work error` error
170−
171−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 = "doc.html"
5−+++
azimuth/azimuth.mddeleted−11
@@ -1,11 +0,0 @@
1−+++
2−title = "Azimuth"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−Azimuth is a general-purpose public-key infrastructure (PKI) on the Ethereum blockchain, used as a decentralized ledger for Urbit identities that we call **points**. Having a point is necessary to use the Urbit network, which makes it important to have a neutral ledger to determine who owns what.
8−
9−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 a point is used to boot a virtual computer on the Urbit network for the first time. When that happens, the point considered **linked** to Azimuth and the point’s full powers are available for use. Once a point is linked, it cannot be unlinked.
10−
11−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/glossary.mddeleted−117
@@ -1,117 +0,0 @@
1−+++
2−title = "Azimuth Glossary"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−
8−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).
9−
10−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).
11−
12−### Azimuth identity
13−
14−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.
15−
16−#### Planet
17−
18−An Azimuth identity to be used as a personal identity. Issued by stars.
19−
20−#### Star
21−
22−An Azimuth identity meant to be used as network infrastructure. Issued by galaxies, issues planets.
23−
24−#### Galaxy
25−
26−An Azimuth identity meant to be used as top-level network infrastructure, with governance powers. Issues stars.
27−
28−### Bridge
29−
30−A tool that's the primary way to interact with Azimuth and manage your identities. It can be accessed at bridge.azimuth.network.
31−
32−### Master Ticket
33−
34−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.
35−
36−### Multipass
37−
38−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.
39−
40−#### Network Explorer
41−
42−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.
43−
44−### Ownership Address
45−
46−The Ethereum address that owns a point. As the owner, it can perform all possible operations for that point.
47−
48−### Invite Pool
49−
50−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.
51−
52−#### Pool Host
53−
54−The ship that generates the invite pool. It's most often a star.
55−
56−#### Guest List
57−
58−The names of planets invited to the same invite pool, as viewed by the pool host.
59−
60−#### Invite Cohort
61−
62−The names of planets invited to the same invite pool, as viewed by the pool's member's.
63−
64−#### Sending Invites
65−
66−The action of giving someone a planet using Bridge.
67−
68−#### Code
69−
70−Activation code from an email that allows you to claim an invite
71−
72−#### Birth Time
73−
74−When a ship is claimed from an invite
75−
76−### Passport
77−
78−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.
79−
80−### Proxy Address
81−
82−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.
83−
84−#### Management Proxy Address
85−
86−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).
87−Use cases:
88−- Keeping this handy so you can put the ownership/master ticket in a super safe place
89−- Allowing someone to manage your ship (by setting/deriving networking keys, managing sponsorship)
90−- Allowing a smart contract to manage sponsorship ops (ie star service smart contract)
91−
92−#### Network Keys
93−
94−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.
95−
96−#### Spawn Proxy Address
97−
98−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.
99−
100−Use cases:
101−- Keeping this handy so you can put the ownership/master ticket in a super safe place
102−- Allowing a smart contract to spawn on your behalf (delegated sending/invites, planet sale)
103−
104−#### Voting Proxy Address
105−An Ethereum address used for voting as a point.
106−
107−Use cases:
108−- Keeping this handy so you can put the ownership/master ticket in a super safe place
109−- Delegating your voting rights to someone else
110−
111−#### Transfer Proxy Address
112−
113−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.
114−
115−### Sponsorship
116−
117−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
@@ -0,0 +1,59 @@
1++++
2+title = "Hackathon Results"
3+date = "2020-06-11"
4+description = "We recently held an invite-only Urbit Hackathon for graduates of our Hoon School program, and the submissions really impressed us across the board. Submissions were judged on several criteria: creativity, usefulness, and code quality."
5+
6+[extra]
7+author = "Robert Mariani"
8+ship = "~lodleb-ritrul"
9+image = "https://media.urbit.org/site/posts/essays/hackathon-results-wide.png"
10++++
11+
12+![](https://media.urbit.org/site/posts/essays/hackathon-results.png)
13+
14+Results of the Urbit Hackathon
15+
16+We recently held an invite-only Urbit Hackathon for graduates of our Hoon School program, and the submissions really impressed us across the board. Submissions were judged on several criteria: creativity, usefulness, and code quality.
17+
18+Congratulations to all the participants, especially the winners—their projects are seriously impressive.
19+
20+### First Place: Eight Stars
21+
22+Jose’s `~norsyr-torryn` Canvas is a peer-to-peer, collaborative drawing app that comes in the form of a Landscape tile. It’s kind of like a multiplayer MS Paint, but better.
23+
24+Canvas uses Urbit in a way that we think it’s supposed to be used: the stuff that doesn’t require peer-to-peer or storage heavy lifting, such as the actual “drawing” component of the app, is done outside of Urbit.
25+
26+In addition to a freehand template for the classic Paint experience, you can choose from a number of templates to work with, such as a grid of fillable hexagons, or maps of parts of the world and of continents with fillable country divisions. Have you ever wanted to compare which countries you visited, color-coded for how much you liked them? Canvas has a built-in feature for sharing your work on chats in Landscape.
27+
28+Check out a video [demonstration](https://www.youtube.com/watch?v=S6DySv730Hw) of Canvas, and view [the code](https://github.com/yosoyubik/canvas).
29+
30+Jose wins eight stars, and he also wins [le internet for the day](https://news.ycombinator.com/item?id=23228058). Bravo!
31+
32+### Second Place: Four Stars Each
33+
34+Luke Champine’s (`~watter-parter`) flashcard app for Landscape, Rote, has been awarded one of two second-place prizes.
35+
36+Rote users write decks in udon, review them, and share them with other ships. His immaculate backend code-style and documentation secured his high placement in the Hackathon—his Hoon code also functions as a full-blown walkthrough. If you’re a Gall novice and you’re looking to learn, take a look at his [code](https://github.com/lukechampine/rote). Luke also kept a Notebook documenting his experience at `~watter-parter/hackathon`.
37+
38+Luke also included example decks for flashcards on Hoon runes and their irregular forms. So, all said and done, everything about Rote is an excellent resource to the eager Hoon neophyte.
39+
40+Pyry Kovanen (`~dinleb-rambep`) was also awarded second prize for his reading-list-sharing app, Books. Also a Landscape tile, and it’s pretty darn useful, with the ability to import books from Goodreads. Check out [the code](https://github.com/pkova/urbit/tree/books/pkg/interface/books) and the [video demo](https://youtu.be/Spy7FoPdfx8).
41+
42+### Third Place: Two Stars Each
43+
44+N E Davis (`~lagrev-nocfep`) brought the heavy infrastructural artillery with Roessler, and won third prize. Roessler is actually three related Hoon tools:
45+`roessler` proper, a library for solving the differential equations producing the [Roessler attractor](https://en.wikipedia.org/wiki/R%C3%B6ssler_attractor).
46+`lazytrig`, a library for transcendental functions.
47+`proj-3d`, a generator that takes the 3D coordinates produced by `Roessler`.
48+
49+The Roessler project is full of cool, novel features. You might enjoy taking a look at the [GitHub repo](https://github.com/sigilante/roessler) ...if your brain is big enough.
50+
51+John Franklin (`~dirwex-dosrev`) also secured third place for his Notes application. True to its name, it’s a Landscape tile that allows the user to create and search notes by keyword. Look at the [code](https://github.com/jfranklin9000/notes/) and the [demo video](https://www.youtube.com/watch?v=7DurNjCFOmA).
52+
53+Jon (`~ribnes-fonbex`) was awarded third prize for his Quadratic Voting project. It implements for Urbit ships a [quadratic voting system](https://en.wikipedia.org/wiki/Quadratic_voting), which is sort of like ranked-choice voting but allows people to express their stronger preferences.
54+
55+Congratulations to the winners and to everyone who submitted—nice work!
56+
57+### The Future
58+
59+We were thoroughly impressed with all of the projects from this inaugural Hackathon. Not only did this Hackathon demonstrate the talent and dedication of our community members, it’s an encouraging sign about the maturity of the Urbit system. We’re going to hold more Hackathons in the future, with one big change: they will be open to anyone who applies.
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−23

This diff is too big to show here.

hoon/cheat-sheet.mddeleted−27

This diff is too big to show here.

hoon/hoon-expressions/_index.mddeleted−27

This diff is too big to show here.

hoon/hoon-expressions/advanced.mddeleted−202

This diff is too big to show here.

hoon/hoon-expressions/basic.mddeleted−176

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−17

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

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−31

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

hoon/hoon-tutorial/caesar.mddeleted−346

This diff is too big to show here.

hoon/hoon-tutorial/conditionals.mddeleted−74

This diff is too big to show here.

hoon/hoon-tutorial/doors.mddeleted−504

This diff is too big to show here.

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

This diff is too big to show here.

hoon/hoon-tutorial/fibonacci.mddeleted−62

This diff is too big to show here.

hoon/hoon-tutorial/gall.mddeleted−80

This diff is too big to show here.

hoon/hoon-tutorial/gates.mddeleted−272

This diff is too big to show here.

hoon/hoon-tutorial/generators.mddeleted−599

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

hoon/hoon-tutorial/libraries.mddeleted−184

This diff is too big to show here.

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

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−58

This diff is too big to show here.

hoon/hoon-tutorial/nouns.mddeleted−482

This diff is too big to show here.

hoon/hoon-tutorial/recursion.mddeleted−194

This diff is too big to show here.

hoon/hoon-tutorial/setup.mddeleted−106

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

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

This diff is too big to show here.

hoon/library/1a.mddeleted−679

This diff is too big to show here.

hoon/library/1b.mddeleted−272

This diff is too big to show here.

hoon/library/1c.mddeleted−420

This diff is too big to show here.

hoon/library/2a.mddeleted−448

This diff is too big to show here.

hoon/library/2b.mddeleted−1292

This diff is too big to show here.

hoon/library/2c.mddeleted−1250

This diff is too big to show here.

hoon/library/2d.mddeleted−372

This diff is too big to show here.

hoon/library/2e.mddeleted−275

This diff is too big to show here.

hoon/library/2f.mddeleted−436

This diff is too big to show here.

hoon/library/2g.mddeleted−104

This diff is too big to show here.

hoon/library/2h.mddeleted−797

This diff is too big to show here.

hoon/library/2i.mddeleted−1058

This diff is too big to show here.

hoon/library/2j.mddeleted−271

This diff is too big to show here.

hoon/library/2k.mddeleted−398

This diff is too big to show here.

hoon/library/2l.mddeleted−110

This diff is too big to show here.

hoon/library/2m.mddeleted−307

This diff is too big to show here.

hoon/library/2n.mddeleted−426

This diff is too big to show here.

hoon/library/2o.mddeleted−186

This diff is too big to show here.

hoon/library/2p.mddeleted−241

This diff is too big to show here.

hoon/library/2q.mddeleted−374

This diff is too big to show here.

hoon/library/3a.mddeleted−857

This diff is too big to show here.

hoon/library/3b.mddeleted−5888

This diff is too big to show here.

hoon/library/3c.mddeleted−648

This diff is too big to show here.

hoon/library/3d.mddeleted−820

This diff is too big to show here.

hoon/library/3e.mddeleted−8

This diff is too big to show here.

hoon/library/3f.mddeleted−722

This diff is too big to show here.

hoon/library/3g.mddeleted−385

This diff is too big to show here.

hoon/library/4a.mddeleted−216

This diff is too big to show here.

hoon/library/4b.mddeleted−993

This diff is too big to show here.

hoon/library/4c.mddeleted−363

This diff is too big to show here.

hoon/library/4d.mddeleted−99

This diff is too big to show here.

hoon/library/4e.mddeleted−470

This diff is too big to show here.

hoon/library/4f.mddeleted−1194

This diff is too big to show here.

hoon/library/4g.mddeleted−178

This diff is too big to show here.

hoon/library/4h.mddeleted−961

This diff is too big to show here.

hoon/library/4i.mddeleted−1053

This diff is too big to show here.

hoon/library/4j.mddeleted−1655

This diff is too big to show here.

hoon/library/4k.mddeleted−275

This diff is too big to show here.

hoon/library/4l.mddeleted−607

This diff is too big to show here.

hoon/library/4m.mddeleted−433

This diff is too big to show here.

hoon/library/4n.mddeleted−446

This diff is too big to show here.

hoon/library/4o.mddeleted−781

This diff is too big to show here.

hoon/library/5a.mddeleted−6

This diff is too big to show here.

hoon/library/5b.mddeleted−6

This diff is too big to show here.

hoon/library/5c.mddeleted−6

This diff is too big to show here.

hoon/library/5d.mddeleted−6

This diff is too big to show here.

hoon/library/5e.mddeleted−6

This diff is too big to show here.

hoon/library/5f.mddeleted−175

This diff is too big to show here.

hoon/library/5g.mddeleted−6

This diff is too big to show here.

hoon/library/_index.mddeleted−1732

This diff is too big to show here.

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

This diff is too big to show here.

hoon/library/zuse.mddeleted−11

This diff is too big to show here.

hoon/style.mddeleted−474

This diff is too big to show here.

hoon/troubleshooting.mddeleted−182

This diff is too big to show here.

hoon/workbook/_index.mddeleted−16

This diff is too big to show here.

hoon/workbook/bomb.mddeleted−139

This diff is too big to show here.

hoon/workbook/digits.mddeleted−112

This diff is too big to show here.

hoon/workbook/eightball.mddeleted−157

This diff is too big to show here.

hoon/workbook/traffic-light.mddeleted−154

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−25

This diff is too big to show here.

nock/definition.mddeleted−186

This diff is too big to show here.

nock/example.mddeleted−361

This diff is too big to show here.

nock/explanation.mddeleted−599

This diff is too big to show here.

nock/implementations.mddeleted−2321

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−35

This diff is too big to show here.

vere/api.mddeleted−1039

This diff is too big to show here.

vere/c.mddeleted−113

This diff is too big to show here.

vere/jetting.mddeleted−769

This diff is too big to show here.

vere/nouns.mddeleted−476

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.