on master help sign in
1209 files changed+29052−134195
since splitsnapshots
unifiedsplit
.gitignore+5−1 .husky/.gitignore−1 .husky/pre-commit−4 .nova/Configuration.json−3 .nvmrc+1 .prettierrc+5 README.md+35−13 components/BasicPage.js+20−11 components/Contact.js+7−91 components/Container.js−8 components/ContentArea.js+23−21 components/CopyLink.js+61 components/DocsSidebar.js+32 components/EventPreview.js+56−90 components/Footer.js+3−177 components/GrantPreview.js+37−35 components/GrantProgramOverview.js+14−12 components/Header.js+70−61 components/HighlightCard.js+22 components/JoinGroup.js+2−2 components/Lorem.js−106 components/Markdown.js−61 components/MenuTray.js−104 components/Meta.js+31−8 components/NewletterSignup.js → components/NewsletterSignup.js+2−2 components/PageWithIndex.js−42 components/Pagination.js+2−4 components/PostPreview.js+15−33 components/Search.js−212 components/Section.js−21 components/Sidebar.js+3−14 components/SingleColumn.js−8 components/Snippets.js+9−5 components/TableOfContents.js−120 components/TwoUp.js−12 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/BubbleLink.js → components/index/BubbleLink.js 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+33−3 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/Bitcoin-wallet.md → content/bitcoin-wallet.md content/bitcoin.md+125 content/blog/2020-to-2021.md−4 content/blog/20200929-state-of-urbit.md−4 content/blog/20201119-models-of-society.md−12 content/blog/2021-11-18-report-from-the-field.md+2−2 content/blog/2021-11-18-the-promise-and-paradox-of-decentralization.md+8−8 content/blog/aesthetic-culture-1.md+1−5 content/blog/after-machine-war.md−6 content/blog/agency-daos.md+110 content/blog/ares.md+51 content/blog/august-2022-grants-program.md+73 content/blog/common-objections-to-urbit.md+15−15 content/blog/convivial-networks.md+27 content/blog/creating-sigils.md+8−8 content/blog/desire-lines.md+35 content/blog/eliza.md+1−5 content/blog/events-series.md−4 content/blog/first-contract.md+2−6 content/blog/first-steps-towards-urbit-org.md+1−3 content/blog/ford-fusion.md+1−5 content/blog/foss-1.md+64 content/blog/foss-2.md+59 content/blog/gifts-q3-2020.md+1−5 content/blog/hackathon-results.md+1−5 content/blog/hoon-4-lispers.md+764 content/blog/hosting-the-future.md−4 content/blog/immunology-for-the-internet-age.md+118 content/blog/infrastructural.md+2−8 content/blog/interplanetary_commerce.md+3−6 content/blog/introducing-os1.md+7−9 content/blog/introduction-to-the-combine-dao.md+46 content/blog/io-in-hoon.md+154−134 content/blog/iot.md+1−5 content/blog/layer-2-faq.md+155 content/blog/metaphase.md−4 content/blog/pin-the-face-that-launches-a-thousand-ships.md+146 content/blog/pki-maze.md+10−10 content/blog/platform-decay.md+1−3 content/blog/precepts-discussion.md+7−21 content/blog/precepts.md+7−21 content/blog/providers.md+1−5 content/blog/pseudonymous-reputation.md+64 content/blog/rollups.md+4−4 content/blog/security-audit.md−4 content/blog/simple-durable-yours.md+3−3 content/blog/smart-home-of-the-future.md+60 content/blog/the-missing-middle.md+1−5 content/blog/the-shape-of-dao-governance-to-come.md+103 content/blog/the-understanding-urbit-podcast.md+1−3 content/blog/tools-of-our-own.md+6−14 content/blog/urbit-and-bitcoin.md+1−1 content/blog/urbit-creator-daos.md+74 content/blog/urbit-for-normies.md+3−4 content/blog/urbit-is-for-communities.md+1−3 content/blog/using-urbit-in-2023.md+55 content/blog/value-of-address-space-pt1.md+4−4 content/blog/value-of-address-space-pt2.md+1−1 content/blog/value-of-address-space-pt3.md+1−3 content/blog/why-hoon.md+3−3 content/blog/your-last-computer.md+3−3 content/bounties.md+50−4 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/community/_index.md−5 content/community/community-grants.md−14 content/community/governance.md−25 content/community/hoonschool.md−15 content/community/hosting-a-meetup.md−82 content/community/meetups.md−51 content/docs/_index.md−56 content/docs/arvo/_index.md−53 content/docs/arvo/ames/_index.md−27 content/docs/arvo/ames/ames.md−466 content/docs/arvo/ames/cryptography.md−145 content/docs/arvo/ames/data-types.md−389 content/docs/arvo/ames/scry.md−126 content/docs/arvo/ames/tasks.md−193 content/docs/arvo/behn/_index.md−23 content/docs/arvo/behn/behn.md−19 content/docs/arvo/behn/examples.md−95 content/docs/arvo/behn/scry.md−46 content/docs/arvo/behn/tasks.md−155 content/docs/arvo/clay/_index.md−36 content/docs/arvo/clay/architecture.md−177 content/docs/arvo/clay/clay.md−61 content/docs/arvo/clay/data-types.md−681 content/docs/arvo/clay/examples.md−788 content/docs/arvo/clay/marks/_index.md−23 content/docs/arvo/clay/marks/examples.md−248 content/docs/arvo/clay/marks/marks.md−59 content/docs/arvo/clay/marks/using-marks.md−240 content/docs/arvo/clay/marks/writing-marks.md−333 content/docs/arvo/clay/scry.md−398 content/docs/arvo/clay/tasks.md−503 content/docs/arvo/clay/using.md−223 content/docs/arvo/concepts/_index.md−17 content/docs/arvo/concepts/scry.md−77 content/docs/arvo/concepts/subscriptions.md−162 content/docs/arvo/dill/_index.md−23 content/docs/arvo/dill/data-types.md−187 content/docs/arvo/dill/dill.md−41 content/docs/arvo/dill/scry.md−45 content/docs/arvo/dill/tasks.md−342 content/docs/arvo/eyre/_index.md−31 content/docs/arvo/eyre/data-types.md−289 content/docs/arvo/eyre/external-api-ref.md−359 content/docs/arvo/eyre/eyre.md−61 content/docs/arvo/eyre/guide.md−619 content/docs/arvo/eyre/scry.md−195 content/docs/arvo/eyre/tasks.md−213 content/docs/arvo/ford/_index.md−7 content/docs/arvo/ford/ford.md−223 content/docs/arvo/gall/_index.md−7 content/docs/arvo/gall/data-types.md−492 content/docs/arvo/gall/gall-api.md−958 content/docs/arvo/gall/gall.md−558 content/docs/arvo/iris/_index.md−23 content/docs/arvo/iris/data-types.md−54 content/docs/arvo/iris/example.md−87 content/docs/arvo/iris/iris.md−17 content/docs/arvo/iris/tasks.md−61 content/docs/arvo/jael/_index.md−27 content/docs/arvo/jael/data-types.md−243 content/docs/arvo/jael/examples.md−251 content/docs/arvo/jael/jael.md−25 content/docs/arvo/jael/scry.md−204 content/docs/arvo/jael/tasks.md−225 content/docs/arvo/overview.md−554 content/docs/arvo/reference/_index.md−11 content/docs/arvo/reference/cryptography.md−222 content/docs/arvo/reference/filesystem.md−103 content/docs/arvo/tutorials/_index.md−9 content/docs/arvo/tutorials/move-trace.md−378 content/docs/azimuth/_index.md−41 content/docs/azimuth/advanced-azimuth-tools.md−124 content/docs/azimuth/azimuth-eth.md−158 content/docs/azimuth/azimuth.md−138 content/docs/azimuth/ecliptic.md−446 content/docs/azimuth/flow.md−232 content/docs/azimuth/hd-wallet.md−137 content/docs/azimuth/l2/_index.md−35 content/docs/azimuth/l2/bytestring.md−201 content/docs/azimuth/l2/l2-actions.md−183 content/docs/azimuth/l2/layer2-api.md−14 content/docs/azimuth/l2/layer2.md−403 content/docs/azimuth/l2/roller.md−66 content/docs/azimuth/life-and-rift.md−60 content/docs/development/_index.md−33 content/docs/development/develop.md−113 content/docs/development/environment.md−327 content/docs/development/grants.md−84 content/docs/development/precepts.md−336 content/docs/development/project-repositories.md−47 content/docs/glossary/_index.md−10 content/docs/glossary/ames.md−21 content/docs/glossary/aqua.md−12 content/docs/glossary/arm.md−14 content/docs/glossary/arvo.md−44 content/docs/glossary/atom.md−20 content/docs/glossary/azimuth.md−39 content/docs/glossary/battery.md−14 content/docs/glossary/behn.md−14 content/docs/glossary/bridge.md−32 content/docs/glossary/censure.md−14 content/docs/glossary/ceremony.md−8 content/docs/glossary/chat.md−32 content/docs/glossary/claims.md−21 content/docs/glossary/clay.md−18 content/docs/glossary/comet.md−32 content/docs/glossary/core.md−14 content/docs/glossary/delegated-sending.md−9 content/docs/glossary/desk.md−15 content/docs/glossary/dill.md−22 content/docs/glossary/docvote.md−9 content/docs/glossary/dojo.md−15 content/docs/glossary/door.md−14 content/docs/glossary/ecliptic.md−12 content/docs/glossary/eventlog.md−23 content/docs/glossary/eyre.md−17 content/docs/glossary/ford.md−17 content/docs/glossary/galaxy.md−15 content/docs/glossary/gall.md−18 content/docs/glossary/gate.md−14 content/docs/glossary/hdwallet.md−18 content/docs/glossary/hoon.md−15 content/docs/glossary/invite-tree.md−9 content/docs/glossary/iris.md−11 content/docs/glossary/jael.md−11 content/docs/glossary/jaque.md−15 content/docs/glossary/keyfile.md−15 content/docs/glossary/landscape.md−11 content/docs/glossary/mark.md−17 content/docs/glossary/moon.md−34 content/docs/glossary/nock.md−17 content/docs/glossary/noun.md−15 content/docs/glossary/ota-updates.md−9 content/docs/glossary/payload.md−14 content/docs/glossary/ph.md−9 content/docs/glossary/pier.md−28 content/docs/glossary/pill.md−14 content/docs/glossary/planet.md−15 content/docs/glossary/proxies.md−34 content/docs/glossary/replay.md−13 content/docs/glossary/reset.md−32 content/docs/glossary/rollups.md−30 content/docs/glossary/sailudon.md−13 content/docs/glossary/senate.md−14 content/docs/glossary/ship.md−26 content/docs/glossary/shiparvonetwork.md−9 content/docs/glossary/star.md−17 content/docs/glossary/sync.md−16 content/docs/glossary/trap.md−14 content/docs/glossary/upgrade.md−13 content/docs/glossary/vane.md−24 content/docs/glossary/vere.md−18 content/docs/glossary/voting.md−27 content/docs/glossary/wallet-generator.md−11 content/docs/hoon/_index.md−27 content/docs/hoon/guides/_index.md−17 content/docs/hoon/guides/aqua.md−80 content/docs/hoon/guides/cli-tutorial.md−440 content/docs/hoon/guides/json-guide.md−513 content/docs/hoon/guides/parsing.md−709 content/docs/hoon/guides/strings.md−531 content/docs/hoon/hoon-school/_index.md−37 content/docs/hoon/hoon-school/ackermann.md−29 content/docs/hoon/hoon-school/arms-and-cores.md−652 content/docs/hoon/hoon-school/atoms-auras-and-simple-cell-types.md−779 content/docs/hoon/hoon-school/bank-account.md−80 content/docs/hoon/hoon-school/behn.md−110 content/docs/hoon/hoon-school/caesar.md−394 content/docs/hoon/hoon-school/conditionals.md−105 content/docs/hoon/hoon-school/doors.md−516 content/docs/hoon/hoon-school/egg-timer.md−164 content/docs/hoon/hoon-school/fibonacci.md−61 content/docs/hoon/hoon-school/gall.md−129 content/docs/hoon/hoon-school/gates.md−272 content/docs/hoon/hoon-school/generators.md−460 content/docs/hoon/hoon-school/hoon-syntax.md−356 content/docs/hoon/hoon-school/intro.md−121 content/docs/hoon/hoon-school/iron-polymorphism.md−88 content/docs/hoon/hoon-school/lead-polymorphism.md−155 content/docs/hoon/hoon-school/libraries.md−191 content/docs/hoon/hoon-school/list-of-numbers.md−132 content/docs/hoon/hoon-school/lists.md−497 content/docs/hoon/hoon-school/molds.md−98 content/docs/hoon/hoon-school/nouns.md−563 content/docs/hoon/hoon-school/recursion.md−194 content/docs/hoon/hoon-school/structures-and-complex-types.md−356 content/docs/hoon/hoon-school/the-subject-and-its-legs.md−726 content/docs/hoon/hoon-school/trees-sets-and-maps.md−321 content/docs/hoon/hoon-school/type-checking-and-type-inference.md−643 content/docs/hoon/hoon-school/type-polymorphism.md−584 content/docs/hoon/overview.md−276 content/docs/hoon/reference/_index.md−53 content/docs/hoon/reference/advanced.md−206 content/docs/hoon/reference/auras.md−98 content/docs/hoon/reference/basic.md−177 content/docs/hoon/reference/cheat-sheet.md−18 content/docs/hoon/reference/hoon-errors.md−187 content/docs/hoon/reference/irregular.md−308 content/docs/hoon/reference/limbs/_index.md−18 content/docs/hoon/reference/limbs/limb.md−71 content/docs/hoon/reference/limbs/wing.md−44 content/docs/hoon/reference/rune/_index.md−73 content/docs/hoon/reference/rune/bar.md−708 content/docs/hoon/reference/rune/buc.md−606 content/docs/hoon/reference/rune/cen.md−466 content/docs/hoon/reference/rune/col.md−245 content/docs/hoon/reference/rune/constants.md−193 content/docs/hoon/reference/rune/dot.md−224 content/docs/hoon/reference/rune/ket.md−396 content/docs/hoon/reference/rune/lus.md−230 content/docs/hoon/reference/rune/mic.md−462 content/docs/hoon/reference/rune/sig.md−452 content/docs/hoon/reference/rune/terminators.md−78 content/docs/hoon/reference/rune/tis.md−496 content/docs/hoon/reference/rune/wut.md−551 content/docs/hoon/reference/rune/zap.md−240 content/docs/hoon/reference/stdlib/1a.md−799 content/docs/hoon/reference/stdlib/1b.md−309 content/docs/hoon/reference/stdlib/1c.md−538 content/docs/hoon/reference/stdlib/2a.md−616 content/docs/hoon/reference/stdlib/2b.md−1645 content/docs/hoon/reference/stdlib/2c.md−1518 content/docs/hoon/reference/stdlib/2d.md−374 content/docs/hoon/reference/stdlib/2e.md−188 content/docs/hoon/reference/stdlib/2f.md−315 content/docs/hoon/reference/stdlib/2g.md−105 content/docs/hoon/reference/stdlib/2h.md−826 content/docs/hoon/reference/stdlib/2i.md−1417 content/docs/hoon/reference/stdlib/2j.md−397 content/docs/hoon/reference/stdlib/2k.md−456 content/docs/hoon/reference/stdlib/2l.md−110 content/docs/hoon/reference/stdlib/2m.md−316 content/docs/hoon/reference/stdlib/2n.md−450 content/docs/hoon/reference/stdlib/2o.md−200 content/docs/hoon/reference/stdlib/2p.md−248 content/docs/hoon/reference/stdlib/2q.md−586 content/docs/hoon/reference/stdlib/3a.md−881 content/docs/hoon/reference/stdlib/3b.md−6054 content/docs/hoon/reference/stdlib/3c.md−664 content/docs/hoon/reference/stdlib/3d.md−820 content/docs/hoon/reference/stdlib/3e.md−8 content/docs/hoon/reference/stdlib/3f.md−868 content/docs/hoon/reference/stdlib/3g.md−355 content/docs/hoon/reference/stdlib/4a.md−424 content/docs/hoon/reference/stdlib/4b.md−1320 content/docs/hoon/reference/stdlib/4c.md−396 content/docs/hoon/reference/stdlib/4d.md−100 content/docs/hoon/reference/stdlib/4e.md−466 content/docs/hoon/reference/stdlib/4f.md−1380 content/docs/hoon/reference/stdlib/4g.md−229 content/docs/hoon/reference/stdlib/4h.md−703 content/docs/hoon/reference/stdlib/4i.md−1086 content/docs/hoon/reference/stdlib/4j.md−1796 content/docs/hoon/reference/stdlib/4k.md−841 content/docs/hoon/reference/stdlib/4l.md−618 content/docs/hoon/reference/stdlib/4m.md−486 content/docs/hoon/reference/stdlib/4n.md−723 content/docs/hoon/reference/stdlib/4o.md−1473 content/docs/hoon/reference/stdlib/5a.md−7 content/docs/hoon/reference/stdlib/5b.md−7 content/docs/hoon/reference/stdlib/5c.md−83 content/docs/hoon/reference/stdlib/5d.md−7 content/docs/hoon/reference/stdlib/5e.md−7 content/docs/hoon/reference/stdlib/5f.md−171 content/docs/hoon/reference/stdlib/5g.md−7 content/docs/hoon/reference/stdlib/_index.md−1733 content/docs/hoon/reference/stdlib/table-of-contents.md−1934 content/docs/hoon/reference/style.md−476 content/docs/hoon/reference/zuse/2d_1-5.md−587 content/docs/hoon/reference/zuse/2d_6.md−1551 content/docs/hoon/reference/zuse/2d_7.md−1307 content/docs/hoon/reference/zuse/2e_2-3.md−67 content/docs/hoon/reference/zuse/_index.md−31 content/docs/hoon/reference/zuse/table-of-contents.md−247 content/docs/nock/_index.md−27 content/docs/nock/definition.md−186 content/docs/nock/example.md−362 content/docs/nock/explanation.md−605 content/docs/nock/implementations.md−2879 content/docs/system-overview/_index.md−77 content/docs/system-overview/arvo.md−32 content/docs/system-overview/azimuth.md−34 content/docs/system-overview/cryptography.md−124 content/docs/system-overview/hoon.md−28 content/docs/system-overview/nock.md−34 content/docs/system-overview/vere.md−45 content/docs/userspace/_index.md−29 content/docs/userspace/dist/_index.md−29 content/docs/userspace/dist/dist.md−105 content/docs/userspace/dist/docket.md−296 content/docs/userspace/dist/glob.md−102 content/docs/userspace/dist/guide.md−269 content/docs/userspace/dist/tools.md−342 content/docs/userspace/gall-guide/1-arvo.md−305 content/docs/userspace/gall-guide/10-scry.md−362 content/docs/userspace/gall-guide/11-fail.md−146 content/docs/userspace/gall-guide/12-next-steps.md−42 content/docs/userspace/gall-guide/2-agent.md−305 content/docs/userspace/gall-guide/3-imports-and-aliases.md−285 content/docs/userspace/gall-guide/4-lifecycle.md−499 content/docs/userspace/gall-guide/5-cards.md−244 content/docs/userspace/gall-guide/6-pokes.md−538 content/docs/userspace/gall-guide/7-sur-and-marks.md−408 content/docs/userspace/gall-guide/8-subscriptions.md−911 content/docs/userspace/gall-guide/9-vanes.md−284 content/docs/userspace/gall-guide/_index.md−45 content/docs/userspace/gall-guide/intro.md−83 content/docs/userspace/gall-guide/types.md−228 content/docs/userspace/graph-store/_index.md−23 content/docs/userspace/graph-store/advanced-info.md−64 content/docs/userspace/graph-store/data-structure-overview.md−359 content/docs/userspace/graph-store/graph-store-reference.md−243 content/docs/userspace/graph-store/overview.md−103 content/docs/userspace/graph-store/sample-application-overview.md−369 content/docs/userspace/graph-store/validator-walkthrough.md−476 content/docs/userspace/overview.md−24 content/docs/userspace/threads/_index.md−27 content/docs/userspace/threads/basics/_index.md−29 content/docs/userspace/threads/basics/bind.md−97 content/docs/userspace/threads/basics/fundamentals.md−168 content/docs/userspace/threads/basics/input.md−145 content/docs/userspace/threads/basics/output.md−119 content/docs/userspace/threads/basics/summary.md−81 content/docs/userspace/threads/examples/_index.md−33 content/docs/userspace/threads/examples/child-thread.md−238 content/docs/userspace/threads/examples/get-json.md−114 content/docs/userspace/threads/examples/main-loop.md−178 content/docs/userspace/threads/examples/poke-agent.md−60 content/docs/userspace/threads/examples/scry.md−70 content/docs/userspace/threads/examples/take-fact.md−65 content/docs/userspace/threads/gall/_index.md−29 content/docs/userspace/threads/gall/poke-thread.md−115 content/docs/userspace/threads/gall/start-thread.md−145 content/docs/userspace/threads/gall/stop-thread.md−152 content/docs/userspace/threads/gall/take-facts.md−184 content/docs/userspace/threads/gall/take-result.md−132 content/docs/userspace/threads/http-api.md−73 content/docs/userspace/threads/overview.md−82 content/docs/userspace/threads/reference.md−87 content/docs/vere/_index.md−42 content/docs/vere/api.md−1040 content/docs/vere/c.md−114 content/docs/vere/cryptography.md−43 content/docs/vere/jetting.md−779 content/docs/vere/nouns.md−477 content/docs/vere/runtime.md−44 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+2−2 content/events/2017-09-22-after-hours-fun-with-arvo-the-urbit-os.md+2−2 content/events/2017-10-26-after-hours-designing-robust-human-systems.md+2−2 content/events/2017-11-16-after-hours-visiting-contributors.md+2−2 content/events/2018-01-26-urbit-irl-20181.md+2−2 content/events/2018-02-23-urbit-irl-20182.md+2−2 content/events/2018-03-11-20183-hoon-school.md+2−2 content/events/2018-03-23-urbit-irl-20183.md+2−2 content/events/2018-05-25-urbit-irl-20185.md+2−2 content/events/2018-08-03-after-hours-decentralized-web-summit.md+2−2 content/events/2018-08-17-urbit-irl-20188.md+2−2 content/events/2018-09-21-urbit-irl-20189.md+2−2 content/events/2018-10-10-urbit-zcash-blockchain-week.md+2−2 content/events/2018-12-20-after-hours-its-just-a-party-man.md+2−2 content/events/2019-03-01-after-hours-ask-galen-anything.md+2−2 content/events/2019-03-08-urbit-irl-austin-tx.md+2−2 content/events/2019-04-19-urbit-irl-20194.md+2−2 content/events/2019-05-17-urbit-irl-20195.md+2−2 content/events/2019-06-21-urbit-irl-20196.md+2−2 content/events/2019-07-19-urbit-irl-20197.md+4−2 content/events/2019-08-29-urbit-austin-20198.md+4−2 content/events/2019-10-04-urbit-irl-201910.md+4−2 content/events/2019-11-15-urbit-irl-201911.md+4−2 content/events/2019-12-13-urbit-irl-201912.md+4−2 content/events/2020-01-24-urbit-irl-20201.md+4−2 content/events/2020-02-28-urbit-irl-20202.md+4−2 content/events/2020-04-03-urbit-os1-launch-party.md+8−6 content/events/2020-10-09-urbit-hosting-launch-event.md+13−8 content/events/2020-12-10-developer-call-injecting-external-services-into-urbit.md+1−2 content/events/2021-03-18-developer-call-pressure-and-protolith.md+1−1 content/events/2021-04-01-developer-call-javascript-apps-on-urbit.md+1−1 content/events/2021-04-27-bitcoin-launch.md+3−1 content/events/2021-05-13-developer-call-versioned-networking.md+1−1 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+45−47 content/getting-started/_index.md+20−124 content/getting-started/cli.md+220−126 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/planet.md−216 content/getting-started/self-host.md+33 content/grants/bitcoin-node-json-rpc-api-part-1.md → content/grants/2019/bitcoin-node-json-rpc-api-part-1.md+4−3 content/grants/bitcoin-node-json-rpc-api-part-2.md → content/grants/2019/bitcoin-node-json-rpc-api-part-2.md+4−3 content/grants/bitcoin-node-json-rpc-api-part-3.md → content/grants/2019/bitcoin-node-json-rpc-api-part-3.md+4−3 content/grants/bitcoin-node-json-rpc-api-part-4.md → content/grants/2019/bitcoin-node-json-rpc-api-part-4.md+4−3 content/grants/bitcoin-wallet-on-bridge.md → content/grants/2019/bitcoin-wallet-on-bridge.md+4−3 content/grants/escape.md → content/grants/2019/escape.md+2−2 content/grants/gall-api-documentation.md → content/grants/2019/gall-api-documentation.md+2−2 content/grants/host-two-urbit-meetups-1.md → content/grants/2019/host-two-urbit-meetups-1.md+2−2 content/grants/host-two-urbit-meetups-10.md → content/grants/2019/host-two-urbit-meetups-10.md+2−2 content/grants/host-two-urbit-meetups-2.md → content/grants/2019/host-two-urbit-meetups-2.md+2−2 content/grants/host-two-urbit-meetups-3.md → content/grants/2019/host-two-urbit-meetups-3.md+2−2 content/grants/host-two-urbit-meetups-4.md → content/grants/2019/host-two-urbit-meetups-4.md+2−2 content/grants/host-two-urbit-meetups-5.md → content/grants/2019/host-two-urbit-meetups-5.md+2−2 content/grants/host-two-urbit-meetups-6.md → content/grants/2019/host-two-urbit-meetups-6.md+2−2 content/grants/host-two-urbit-meetups-7.md → content/grants/2019/host-two-urbit-meetups-7.md+2−2 content/grants/host-two-urbit-meetups-8.md → content/grants/2019/host-two-urbit-meetups-8.md+2−2 content/grants/host-two-urbit-meetups-9.md → content/grants/2019/host-two-urbit-meetups-9.md+2−2 content/grants/ragnarok-online-on-urbit.md → content/grants/2019/ragnarok-online-on-urbit.md+2−2 content/grants/udon-syntax-highlighter.md → content/grants/2019/udon-syntax-highlighter.md+2−2 content/grants/unit-tests-for-json-parsing.md → content/grants/2019/unit-tests-for-json-parsing.md+2−2 content/grants/unit-tests-for-pure-algorithms.md → content/grants/2019/unit-tests-for-pure-algorithms.md+2−2 content/grants/unit-tests-for-sha-functions.md → content/grants/2019/unit-tests-for-sha-functions.md+2−2 content/grants/unit-tests-for-zuse-cryptographic-functions.md → content/grants/2019/unit-tests-for-zuse-cryptographic-functions.md+2−2 content/grants/a-book-about-urbit.md → content/grants/2020/a-book-about-urbit.md+2−2 content/grants/a-network-enabled-spatial-database-and-demonstration-app.md → content/grants/2020/a-network-enabled-spatial-database-and-demonstration-app.md+13−16 content/grants/antechamber.md → content/grants/2020/antechamber.md+2−2 content/grants/art-by-urbit.md → content/grants/2020/art-by-urbit.md+2−2 content/grants/bart-train-tracker-landscape-tile.md → content/grants/2020/bart-train-tracker-landscape-tile.md+2−2 content/grants/bitcoin-full-node-provider-and-wallet.md → content/grants/2020/bitcoin-full-node-provider-and-wallet.md+4−3 content/grants/bitcoin-key-derivation.md → content/grants/2020/bitcoin-key-derivation.md+4−3 content/grants/boston-t-train-tracker-landscape-tile.md → content/grants/2020/boston-t-train-tracker-landscape-tile.md+2−2 content/grants/calendar-ui.md → content/grants/2020/calendar-ui.md+2−2 content/grants/calendar.md → content/grants/2020/calendar.md+2−2 content/grants/content-saver.md → content/grants/2020/content-saver.md+3−3 content/grants/cta-train-tracker-landscape-tile.md → content/grants/2020/cta-train-tracker-landscape-tile.md+2−2 content/grants/display-eth-data.md → content/grants/2020/display-eth-data.md+2−2 content/grants/docker-image-for-cloud-container-orchestration.md → content/grants/2020/docker-image-for-cloud-container-orchestration.md+2−2 content/grants/ethereum-abi-parser.md → content/grants/2020/ethereum-abi-parser.md+2−2 content/grants/go-airlock-library.md → content/grants/2020/go-airlock-library.md+2−2 content/grants/haskell-airlock-library.md → content/grants/2020/haskell-airlock-library.md+2−2 content/grants/hoon-001-learner-efficiency-and-early-learner-resources.md → content/grants/2020/hoon-001-learner-efficiency-and-early-learner-resources.md+2−2 content/grants/host-three-college-university-urbit-meetups-1.md → content/grants/2020/host-three-college-university-urbit-meetups-1.md+2−2 content/grants/host-three-college-university-urbit-meetups-2.md → content/grants/2020/host-three-college-university-urbit-meetups-2.md+2−2 content/grants/host-three-college-university-urbit-meetups-3.md → content/grants/2020/host-three-college-university-urbit-meetups-3.md+2−2 content/grants/host-three-virtual-urbit-meetups.md → content/grants/2020/host-three-virtual-urbit-meetups.md+2−2 content/grants/links-in-urbit-reference-docs.md → content/grants/2020/links-in-urbit-reference-docs.md+2−2 content/grants/llelogram.md → content/grants/2020/llelogram.md+2−2 content/grants/matrices-in-hoon.md → content/grants/2020/matrices-in-hoon.md+2−2 content/grants/matrixriotim-bridge-bot.md → content/grants/2020/matrixriotim-bridge-bot.md+2−2 content/grants/open-street-maps-data-importation.md → content/grants/2020/open-street-maps-data-importation.md+2−2 content/grants/staff-the-urbit-help-desk-1.md → content/grants/2020/staff-the-urbit-help-desk-1.md+2−2 content/grants/staff-the-urbit-help-desk-2.md → content/grants/2020/staff-the-urbit-help-desk-2.md+2−2 content/grants/staff-the-urbit-helpdesk-west.md → content/grants/2020/staff-the-urbit-helpdesk-west.md+2−2 content/grants/the-complete-guide-to-gall-and-landscape.md → content/grants/2020/the-complete-guide-to-gall-and-landscape.md+2−2 content/grants/tor-nodes-relay-search-tile.md → content/grants/2020/tor-nodes-relay-search-tile.md+2−2 content/grants/typescript-airlock-library.md → content/grants/2020/typescript-airlock-library.md+2−2 content/grants/up-to-date-hoon-reference-card.md → content/grants/2020/up-to-date-hoon-reference-card.md+2−2 content/grants/urbian-a-customized-linux-distribution-for-urbit-appliances.md → content/grants/2020/urbian-a-customized-linux-distribution-for-urbit-appliances.md+2−2 content/grants/urbit-event-series.md → content/grants/2020/urbit-event-series.md+2−2 content/grants/urbit-explainer-video.md → content/grants/2020/urbit-explainer-video.md+2−2 content/grants/urbit-http-api-for-kotlin.md → content/grants/2020/urbit-http-api-for-kotlin.md+2−2 content/grants/urbit-http-api-for-rust.md → content/grants/2020/urbit-http-api-for-rust.md+2−2 content/grants/urbit-http-interface-java-edition.md → content/grants/2020/urbit-http-interface-java-edition.md+2−2 content/grants/urbit-http-library-for-ruby.md → content/grants/2020/urbit-http-library-for-ruby.md+3−3 content/grants/urbit-online-meetup.md → content/grants/2020/urbit-online-meetup.md+2−2 content/grants/urbit-ship-and-star-hosting-and-troubleshooting-docs.md → content/grants/2020/urbit-ship-and-star-hosting-and-troubleshooting-docs.md+2−2 content/grants/verifying-urbit-id-on-keybase.md → content/grants/2020/verifying-urbit-id-on-keybase.md+2−2 content/grants/web-scraper.md → content/grants/2020/web-scraper.md+2−2 content/grants/analytics-script.md → content/grants/2021/analytics-script.md+2−2 content/grants/authenticate-with-urbit.md → content/grants/2021/authenticate-with-urbit.md+4−4 content/grants/azimuth-cli.md → content/grants/2021/azimuth-cli.md+4−4 content/grants/bitcoin-wallet-maintenance.md → content/grants/2021/bitcoin-wallet-maintenance.md+5−3 content/grants/bridge-l2-revamp.md → content/grants/2021/bridge-l2-revamp.md+2−2 content/grants/clojure-urbit-client.md → content/grants/2021/clojure-urbit-client.md+5−3 content/grants/comprehensive-local-server-and-mum-explanation-video.md → content/grants/2021/comprehensive-local-server-and-mum-explanation-video.md+2−2 content/grants/contacts.md → content/grants/2021/contacts.md+3−3 content/grants/content-producer.md → content/grants/2021/content-producer.md+3−3 content/grants/cross-platform-desktop-urbit-app.md → content/grants/2021/cross-platform-desktop-urbit-app.md+2−2 content/grants/cypherscope-bot.md → content/grants/2021/cypherscope-bot.md+4−4 content/grants/educational-guide-todomvc-urbit-edition.md → content/grants/2021/educational-guide-todomvc-urbit-edition.md+2−2 content/grants/feed-aggregator.md → content/grants/2021/feed-aggregator.md+4−4 content/grants/graph-store-documentation-guide.md → content/grants/2021/graph-store-documentation-guide.md+2−2 content/grants/guide-to-s3.md → content/grants/2021/guide-to-s3.md+2−2 content/grants/host-two-urbit-meetups-11.md → content/grants/2021/host-two-urbit-meetups-11.md+2−2 content/grants/host-two-urbit-meetups-12.md → content/grants/2021/host-two-urbit-meetups-12.md+3−3 content/grants/host-two-urbit-meetups-13.md → content/grants/2021/host-two-urbit-meetups-13.md+3−3 content/grants/host-two-urbit-meetups-14.md → content/grants/2021/host-two-urbit-meetups-14.md+3−3 content/grants/host-two-urbit-meetups-15.md → content/grants/2021/host-two-urbit-meetups-15.md+2−2 content/grants/host-two-urbit-meetups-16.md → content/grants/2021/host-two-urbit-meetups-16.md+2−2 content/grants/json-jet.md → content/grants/2021/json-jet.md+4−4 content/grants/login-with-urbit.md → content/grants/2021/login-with-urbit.md+2−3 content/grants/machine-learning.md → content/grants/2021/machine-learning.md+4−4 content/grants/market-interface.md → content/grants/2021/market-interface.md+3−2 content/grants/meetup-bom.md → content/grants/2021/meetup-bom.md+4−4 content/grants/minimal-urbit-os.md → content/grants/2021/minimal-urbit-os.md+2−2 content/grants/native-urbit.md → content/grants/2021/native-urbit.md+3−3 content/grants/network-explorer-data-pipeline-http-api.md → content/grants/2021/network-explorer-data-pipeline-http-api.md+2−2 content/grants/nuck-jet.md → content/grants/2021/nuck-jet.md+3−3 content/grants/overhaul-the-urbitorg-website.md → content/grants/2021/overhaul-the-urbitorg-website.md+2−2 content/grants/planet-sales.md → content/grants/2021/planet-sales.md+4−4 content/grants/pokur.md → content/grants/2021/pokur.md+3−3 content/grants/ra-debugging-tools.md → content/grants/2021/ra-debugging-tools.md+5−5 content/grants/ra-page-tracking.md → content/grants/2021/ra-page-tracking.md+3−3 content/grants/ra-segfaults.md → content/grants/2021/ra-segfaults.md+3−3 content/grants/ra-stack-overflow.md → content/grants/2021/ra-stack-overflow.md+3−3 content/grants/search-in-groups.md → content/grants/2021/search-in-groups.md+2−2 content/grants/send-emails-to-a-mailing-list.md → content/grants/2021/send-emails-to-a-mailing-list.md+3−3 content/grants/smol-future-sustained-knowledge-sharing-and-marketing.md → content/grants/2021/smol-future-sustained-knowledge-sharing-and-marketing.md+2−2 content/grants/speech-recognition.md → content/grants/2021/speech-recognition.md+3−3 content/grants/staff-the-urbit-helpdesk-east.md → content/grants/2021/staff-the-urbit-helpdesk-east.md+2−2 content/grants/static-site-generation.md → content/grants/2021/static-site-generation.md+3−3 content/grants/thread-documentation.md → content/grants/2021/thread-documentation.md+2−2 content/grants/translate-key-parts-of-urbitorg-into-german.md → content/grants/2021/translate-key-parts-of-urbitorg-into-german.md+2−2 content/grants/translate-key-parts-of-urbitorg-into-korean.md → content/grants/2021/translate-key-parts-of-urbitorg-into-korean.md+3−3 content/grants/translate-key-parts-of-urbitorg-into-norwegian.md → content/grants/2021/translate-key-parts-of-urbitorg-into-norwegian.md+2−2 content/grants/translate-key-parts-of-urbitorg-into-spanish.md → content/grants/2021/translate-key-parts-of-urbitorg-into-spanish.md+2−2 content/grants/try-urbit-website.md → content/grants/2021/try-urbit-website.md+2−2 content/grants/twitter-uv-extension.md → content/grants/2021/twitter-uv-extension.md+3−3 content/grants/ua-collaborative-text-editor.md → content/grants/2021/ua-collaborative-text-editor.md+3−3 content/grants/ua-filesharer.md → content/grants/2021/ua-filesharer.md+3−3 content/grants/ua-heads-up-poker.md → content/grants/2021/ua-heads-up-poker.md+3−3 content/grants/ua-invoice-system.md → content/grants/2021/ua-invoice-system.md+3−3 content/grants/ua-marketplace.md → content/grants/2021/ua-marketplace.md+6−4 content/grants/ucal-google-and-outlook-integration.md → content/grants/2021/ucal-google-and-outlook-integration.md+2−2 content/grants/urbit-api-for-elixir.md → content/grants/2021/urbit-api-for-elixir.md+2−2 content/grants/urbit-community-concierge-east-coast-2q2021.md → content/grants/2021/urbit-community-concierge-east-coast-2q2021.md+2−2 content/grants/urbit-community-concierge-east-coast.md → content/grants/2021/urbit-community-concierge-east-coast.md+2−2 content/grants/urbit-community-concierge-west-coast-2q2021.md → content/grants/2021/urbit-community-concierge-west-coast-2q2021.md+2−2 content/grants/urbit-community-concierge-west-coast.md → content/grants/2021/urbit-community-concierge-west-coast.md+2−2 content/grants/urbit-http-api-for-emacs-elisp.md → content/grants/2021/urbit-http-api-for-emacs-elisp.md+2−2 content/grants/urbit-http-api-for-python.md → content/grants/2021/urbit-http-api-for-python.md+3−3 content/grants/urbit-irc-bridge.md → content/grants/2021/urbit-irc-bridge.md+2−2 content/grants/urbit-lfs-filehosting.md → content/grants/2021/urbit-lfs-filehosting.md+2−2 content/grants/urbit-notes.md → content/grants/2021/urbit-notes.md+4−4 content/grants/urbit-react-cookbook.md → content/grants/2021/urbit-react-cookbook.md+2−2 content/grants/uturn.md → content/grants/2021/uturn.md+9−8 content/grants/uv-extension-library.md → content/grants/2021/uv-extension-library.md+4−4 content/grants/video-content-manager.md → content/grants/2021/video-content-manager.md+2−2 content/grants/volt-lightning-on-urbit.md → content/grants/2021/volt-lightning-on-urbit.md+4−3 content/grants/webrtc-gall-agent-and-external-app.md → content/grants/2021/webrtc-gall-agent-and-external-app.md+2−2 content/grants/~home-urbit.md → content/grants/2021/~home-urbit.md+3−2 content/grants/2022/abacus.md+56 content/grants/2022/app-engram.md+117 content/grants/app-openbsd.md → content/grants/2022/app-openbsd.md+9−4 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/slaw-scot-jets.md → content/grants/2022/slaw-scot-jets.md+6−5 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/media/blockchannel-episode-19-virtual-land-in-the-clouds-with-urbit.md−14 content/media/blueprint-2017-galen-wolfe-pauly-on-the-distributed-web.md−15 content/media/epicenter-episode-205-urbit-a-digital-republic-reinventing-the-internet.md−15 content/media/governing-the-future-e09-urbit-a-user-owned-internet-on-top-of-the-internet.md−16 content/media/lambdaconf-2016-curtis-yarvin-urbit-a-clean-slate-functional-operating-stack.md−15 content/media/lambdaconf-2018-ted-blackman-ford-urbits-build-system.md−15 content/media/on-the-brink-castle-island.md−14 content/media/the-ether-review-46-curtis-yarvin-and-galen-wolfe-pauly-on-urbit.md−15 content/media/urbit-and-the-not-so-dark-future-of-the-internet.md−11 content/media/what-is-urbit.md−10 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/understanding-urbit/_index.md → content/overview/_index.md+20−24 content/overview/interface.md+42 content/overview/people-history.md+73 content/understanding-urbit/urbit-id.md → content/overview/urbit-id.md+13−18 content/understanding-urbit/urbit-os.md → content/overview/urbit-os.md+7−20 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+5−4 content/proposals.md+25−45 content/reset.md−109 content/rfps.md+40 content/terms-of-use.md → content/terms-of-service.md+1−1 content/understanding-urbit/interface.md−68 content/understanding-urbit/people-history.md−101 content/understanding-urbit/roadmap.md−97 content/updates/2018-7-30-update.md+1−1 content/updates/2019-2-11-update.md+1−1 content/updates/2020-07-27-update.md−2 content/using/_index.md−33 content/using/id/_index.md−59 content/using/id/bridge-troubleshooting.md−37 content/using/id/creating-an-invite-pool.md−106 content/using/id/guide-to-resets.md−93 content/using/id/hd-wallet.md−164 content/using/id/l2-star.md−41 content/using/id/overview.md−203 content/using/id/proxies.md−55 content/using/id/using-bridge.md−111 content/using/os/_index.md−36 content/using/os/basics.md−236 content/using/os/dist-faq.md−162 content/using/os/filesystem.md−379 content/using/os/messaging.md−254 content/using/os/s3.md−38 content/using/os/shell.md−343 content/using/os/ship-troubleshooting.md−225 content/using/os/stars-and-galaxies.md−38 content/using/running/_index.md−24 content/using/running/hosting.md−202 content/using/running/minio.md−141 content/using/running/port.md−157 content/voting-instructions.md+1−1 gnosis-safe.md+48 images/favicon.ico lib/buildGlossary.js+59 lib/buildPageTree.js+111 lib/cache.js+25−8 lib/constants.js+65 lib/glossary.js−7720 lib/hooks.js+12 lib/lib.js+153−261 lib/rss.js+1−1 next.config.js+11−48 package-lock.json+4242−4878 package.json+35−31 pages/404.js+7−3 pages/[slug].js+48 pages/_app.js+11−8 pages/api/dev-search.js+8 pages/api/ops-search.js+8 pages/api/roadmap-search.js+8 pages/api/search.js+39−4 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/audits.js−17 pages/bitcoin-wallet.js−21 pages/bitcoin.js+98 pages/blog.js+82−44 pages/blog/[slug].js+25−32 pages/campus/[[...slug]].js+312 pages/communities/[slug].js+87 pages/community/[[...slug]].js−130 pages/decentralized-discord.js+291 pages/docs/[[...slug]].js−234 pages/ecosystem/index.js+416 pages/ecosystem/spotlight/[slug].js+69 pages/events.js+113−53 pages/events/[slug].js+15−26 pages/faq.js−17 pages/getinvolved.js+58 pages/getting-started/[[...slug]].js+240−79 pages/grants.js+254−345 pages/grants/[slug].js+190−39 pages/grants/apprenticeships.js+3−18 pages/grants/bounties.js+2−18 pages/grants/proposals.js+2−17 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+307−242 pages/marketplaces/[slug].js+84 pages/media.js−109 pages/media/[slug].js−115 pages/organizations/[slug].js+179 pages/overview/[[...slug]].js+147 pages/podcasts/[slug].js+84 pages/privacy.js−17 pages/terms-of-service.js−21 pages/trial-over.js+35 pages/trial.js+129 pages/understanding-urbit/[[...slug]].js−211 pages/updates.js+17−10 pages/updates/[slug].js+21−30 pages/using/[[...slug]].js−163 pages/voting-instructions.js−21 public/images/android-chrome-192x192.png public/images/android-chrome-512x512.png public/images/apple-touch-icon.png public/images/developers-guide-logo.png public/images/favicon-16x16.png public/images/favicon-32x32.png public/images/favicon.ico public/images/network-explorer-logo.png public/images/operators-guide-logo.png public/images/planet-l2-claim.gif public/images/planet-l2-migration.gif public/images/planet-l2-transactions.png public/images/sound.svg+5 public/images/star-market-logo.png public/rss.xml−17770 styles/globals.css−212 styles/markdown.css−185 styles/prism.css−170 tailwind.config.js+14−64 vercel.json+112−683
.gitignore+5−1
@@ -39,4 +39,8 @@ yarn-error.log*
3939# editors
4040/.nova/
4141
42−yarn.lock
42+# rss
43+public/rss.xml
44+
45+yarn.lock
46+
.husky/.gitignoredeleted−1
@@ -1 +0,0 @@
1−_
.husky/pre-commitdeleted−4
@@ -1,4 +0,0 @@
1−#!/bin/sh
2−. "$(dirname "$0")/_/husky.sh"
3−
4−npx pretty-quick --staged
.nova/Configuration.jsondeleted−3
@@ -1,3 +0,0 @@
1−{
2− "workspace.name": "urbit.org"
3−}
.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.md+35−13
@@ -1,20 +1,42 @@
1−The website for Urbit.
1+The website for Urbit is maintained by the Urbit Foundation and the Urbit community. Issues and contributions are welcome.
22
33## Getting Started
44
5−```bash
6−npm install
7−```
5+1. Fork the [Urbit site repository](https://github.com/urbit/urbit.org).
86
9−Run the development server:
7+2. [Create a local clone](https://help.github.com/articles/cloning-a-repository/) of your fork.
108
11−```bash
12−npm run dev
13−# or
14−yarn dev
15−```
9+3. Navigate to the `urbit.org` directory and install Node 14 using [nvm](https://github.com/nvm-sh/nvm):
1610
17−Finally, open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
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).
1840
1941## Framework and Library Documentation
2042
@@ -29,8 +51,8 @@ To learn more about Tailwind CSS, take a look at the docs:
2951
3052## Deployment
3153
32−WIP
54+We deploy using Vercel. All pull requests will show a deployment preview via the same.
3355
3456## Upgrades
3557
36−The `/scripts` contains scripts used to programmatically upgrade site content data.
58+The `/scripts` contains scripts used to programmatically upgrade site content data.
components/BasicPage.js+20−11
@@ -2,14 +2,19 @@ import { useRouter } from "next/router";
22import Head from "next/head";
33import Meta from "../components/Meta";
44import ErrorPage from "../pages/404";
5−import Container from "./Container";
5+import {
6+ Container,
7+ SingleColumn,
8+ Section,
9+ Markdown,
10+ IntraNav,
11+ TableOfContents,
12+} from "@urbit/foundation-design-system";
613import Header from "./Header";
714import Footer from "./Footer";
8−import SingleColumn from "./SingleColumn";
9−import Section from "./Section";
10−import { decode } from "html-entities";
15+import classNames from "classnames";
1116
12−export default function BasicPage({ post, markdown, search }) {
17+export default function BasicPage({ post, markdown, search, index = false }) {
1318 const router = useRouter();
1419 if (!router.isFallback && !post?.slug) {
1520 return <ErrorPage />;
@@ -17,18 +22,22 @@ export default function BasicPage({ post, markdown, search }) {
1722 return (
1823 <Container>
1924 <Head>
20− <title>Urbit • {post.title}</title>
25+ <title>{post.title}</title>
2126 {Meta(post)}
2227 </Head>
28+ <IntraNav ourSite="https://urbit.org" search={search} />
2329 <SingleColumn>
2430 <Header search={search} />
25− <Section narrow>
31+ <Section>
2632 <h1>{post.title}</h1>
2733 </Section>
28− <Section narrow className="markdown">
29− <article
30− dangerouslySetInnerHTML={{ __html: decode(markdown) }}
31− ></article>
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>
3241 </Section>
3342 </SingleColumn>
3443 <Footer />
components/Contact.js+7−91
@@ -1,100 +1,16 @@
1−import NewsletterSignup from "./NewletterSignup";
2−import { name, contact } from "../lib/constants";
3−import { useCopyToClipboard } from "../lib/hooks";
4−
5−export default function Contact({ emphasize }) {
6− const [copyStatus, copy] = useCopyToClipboard(contact.urbitCommunity);
1+import NewsletterSignup from "./NewsletterSignup";
72
3+export default function Contact({
4+ emphasize,
5+ ecosystem = false,
6+ className = "",
7+}) {
88 const linkText = emphasize ? "text-green-400" : "text-wall-600";
99 const border = emphasize ? "border-green-400" : "border-wall-600";
10− const washedBg = emphasize ? "bg-green-100" : "bg-wall-100";
11− const iconColor = emphasize ? "#00B171" : "#24221E";
12−
13− const buttonIcon =
14− copyStatus === "inactive" ? (
15− <svg
16− width="16"
17− height="16"
18− viewBox="0 0 16 16"
19− fill="none"
20− xmlns="http://www.w3.org/2000/svg"
21− >
22− <path
23− fillRule="evenodd"
24− clipRule="evenodd"
25− 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"
26− fill={iconColor}
27− />
28− </svg>
29− ) : copyStatus === "copied" ? (
30− <svg
31− width="16"
32− height="16"
33− viewBox="0 0 16 16"
34− fill="none"
35− xmlns="http://www.w3.org/2000/svg"
36− >
37− <path
38− fillRule="evenodd"
39− clipRule="evenodd"
40− 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"
41− fill={iconColor}
42− />
43− </svg>
44− ) : (
45− <svg
46− width="16"
47− height="16"
48− viewBox="0 0 16 16"
49− fill="none"
50− xmlns="http://www.w3.org/2000/svg"
51− >
52− <path
53− fillRule="evenodd"
54− clipRule="evenodd"
55− 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"
56− fill={iconColor}
57− />
58− </svg>
59− );
6010
6111 return (
62− <div>
63− <div className="measure">
64− <h4 className="pb-6">
65− If you’d like to follow our progress, we send monthly updates via
66− email:
67− </h4>
68− </div>
12+ <div className={className}>
6913 <NewsletterSignup color={border} />
70− <h4 className="mt-12 text-wall-500">
71− Follow us on{" "}
72− <a className={linkText} href={contact.twitter}>
73− Twitter
74− </a>
75− </h4>
76− <h4 className="mt-6 text-wall-500">
77− Explore code on{" "}
78− <a className={linkText} href={contact.github}>
79− Github
80− </a>
81− </h4>
82− <h4 className="mt-4 text-wall-500 flex items-baseline flex-wrap">
83− Boot Urbit and join{" "}
84− <div className="md:ml-2 rounded-lg flex items-stretch">
85− <code
86− className={`rounded-l-lg px-2 md:px-4 py-2 ${washedBg} flex items-center h-full ${linkText}`}
87− >
88− {contact.urbitCommunity}
89− </code>
90− <button
91− className={`rounded-r-lg px-4 ml-0.5 flex-1 flex justify-center items-center ${washedBg}`}
92− onClick={() => copy()}
93− >
94− {buttonIcon}
95− </button>
96− </div>
97− </h4>
9814 </div>
9915 );
10016}
components/Container.jsdeleted−8
@@ -1,8 +0,0 @@
1−// Ensures the root container is always 100vw, min 100vh, and centers all children along the y-axis
2−export default function Container({ children }) {
3− return (
4− <div className="flex flex-col min-h-screen w-screen items-center">
5− {children}
6− </div>
7− );
8−}
components/ContentArea.js+23−21
@@ -1,7 +1,6 @@
1−import Section from "./Section";
21import { useState, useEffect, useRef } from "react";
32import { useRouter } from "next/router";
4−import { TableOfContents } from "./TableOfContents";
3+import { TableOfContents } from "@urbit/foundation-design-system";
54
65export default function ContentArea(props) {
76 const [shortcut, setShortcut] = useState("");
@@ -41,13 +40,15 @@ export default function ContentArea(props) {
4140 }, []);
4241
4342 return (
44− <div className="w-full min-w-0 flex flex-col items-center">
43+ <div className="w-full min-w-0 flex flex-col items-center bg-white">
4544 <div
4645 ref={scrollBox}
47− className="px-4 md:px-12 lg:px-24 pb-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"
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"
4847 >
49− <div className="flex justify-between w-full items-center flex-shrink-0">
50− <div className="type-ui text-wall-500">{props.breadcrumbs}</div>
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>
5152 <div className="hidden md:block">
5253 <button
5354 onClick={(e) => {
@@ -60,23 +61,24 @@ export default function ContentArea(props) {
6061 </button>
6162 </div>
6263 </div>
63− <div className="w-full flex justify-center">
64− {props.narrow ? (
65− <Section narrow className={""}>
66− <h2 className="mb-16 mt-24">{props.title}</h2>
67− {props.children}
68− <div className="pb-32" />
69− </Section>
70− ) : (
71− <div className="min-w-0">
72− <h2 className="mb-16 mt-24">{props.title}</h2>
73− {props.children}
74− <div className="pb-32" />
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+ )}
7573 </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+ />
7681 )}
77− <TableOfContents
78− key={props.params.slug?.join("/") || Math.random()}
79− />
8082 </div>
8183 </div>
8284 </div>
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.js+56−90
@@ -1,60 +1,18 @@
11import Link from "next/link";
22import { DateTime } from "luxon";
3−import {
4− ShowOrHide,
5− ReadableList,
6− Person,
7− Name,
8− DateRange,
9−} from "../components/Snippets";
3+import { DateRange } from "../components/Snippets";
104import {
115 generateDisplayDate,
126 generateRealtimeDate,
13− formatDate,
14− formatTime,
15− formatTimeZone,
16−} from "../lib/lib";
17−
18−// JAL(2021.9.13) Couldn't quite get this to work properly. There's a trailing
19−// "and"
20−//
21−// function GuestList({ guests, textClass }) {
22−
23−// const renderGuests = guests?.length > 2 ? guests?.slice(0,2) : guests;
24−// const noRenderGuestsCount = guests?.slice(2).length;
25−
26−// return (
27−// <p className={textClass + " type-sub"}>
28−// <b>
29−// {renderGuests?.length > 1 ? "With guests " : "With guest "}
30−// </b>
31−// <ReadableList>
32−// {renderGuests?.map((guest, index) => (
33−// <>
34−// <Person
35−// key={`${guest.name}-${guest.patp}`}
36−// nameClassNames={textClass}
37−// patpClassNames={textClass}
38−// name={guest.name}
39−// patp={guest.patp}
40−// />
41−// {renderGuests?.length > 1 ? <span>, </span> : <></>}
42−// </>
43−// ))}
44−// {noRenderGuestsCount > 1 ?
45−// <Name>{noRenderGuestsCount} more </Name>
46−// :
47−// <></>
48−// }
49−// </ReadableList>
50−// </p>
51−// );
52−// }
7+} from "@urbit/foundation-design-system";
8+import classNames from "classnames";
539
5410export default function EventPreview({ event, className, big }) {
5511 // Event tiles have a 'dark mode' used when their background images are dark and white text is needed for legibility.
56− const grayText = event?.dark ? "text-washedWhite" : "text-wall-400";
57− const blackText = event?.dark ? "text-white" : "text-wall-600";
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";
5816
5917 const starts = generateDisplayDate(event.starts, event.timezone);
6018 const ends = generateDisplayDate(event.ends, event.timezone);
@@ -65,59 +23,67 @@ export default function EventPreview({ event, className, big }) {
6523 generateRealtimeDate(event.starts) > DateTime.now() && !inFuture;
6624
6725 return (
68− <div
69− className={`cursor-pointer aspect-w-4 aspect-h-5 md:aspect-w-5 md:aspect-h-4 ${className}`}
70− >
26+ <div className={`cursor-pointer h-full ${className}`}>
7127 <div
7228 key={event.slug}
73− className={`bg-wall-100 rounded-xl bg-cover bg-center bg-no-repeat `}
29+ className={`bg-wall-100 min-h-[320px] h-full flex flex-col rounded-xl bg-cover bg-center bg-no-repeat `}
7430 style={{ backgroundImage: `url(${event.image})` || "" }}
7531 >
7632 <Link href={`/events/${event.slug}`}>
7733 <div
78− className={`flex flex-col p-6 justify-between items-between h-full relative`}
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+ )}
7942 >
8043 <div
81− className={`flex-grow-1 flex ${
82− big ? "justify-center" : ""
83− } flex-col h-full`}
44+ className={`grow-1 flex ${big ? "justify-center" : ""
45+ } flex-col h-full`}
8446 >
85− <h3 className={`${blackText} mb-2`}>{event.title}</h3>
86− <p className={blackText + ""}>{event.description}</p>
47+ <h3 className={`${blackText} mb-2`} id={event.title}>{event.title}</h3>
48+ <p className={blackText + " truncate text-sm"}>
49+ {event.description}
50+ </p>
8751 </div>
8852
89− <div className="absolute p-6 left-0 bottom-0 w-full pr-32">
90− <p className={`${blackText} type-sub mb-1`}>{event.location}</p>
91− <DateRange
92− starts={starts}
93− ends={ends}
94− className={`${grayText} type-sub`}
95− />
96− </div>
97−
98− {inFuture && event.registration_url ? (
99− <div className="absolute right-0 bottom-0 p-6">
100− <a
101− className="button-sm bg-green-400 text-white"
102− href={event.registration_url}
103− onClick={(e) => e.stopPropagation()}
104− target="_blank"
105− >
106− RSVP
107− </a>
108− </div>
109− ) : event.youtube ? (
110− <div className="absolute right-0 bottom-0 p-6">
111− <a
112− className="button-sm bg-wall-600 text-white"
113− href={`https://www.youtube.com/watch?v=${event.youtube}`}
114− onClick={(e) => e.stopPropagation()}
115− target="_blank"
116− >
117− ▶ Watch
118− </a>
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+ />
11961 </div>
120− ) : null}
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>
12187 </div>
12288 </Link>
12389 </div>
components/Footer.js+3−177
@@ -1,180 +1,6 @@
1−import Link from "next/link";
2−import SingleColumn from "./SingleColumn";
3−import Section from "./Section";
4−import { contact } from "../lib/constants";
1+import { Footer as FooterComponent } from "@urbit/foundation-design-system";
2+import { footerData } from "../lib/constants";
53
64export default function Footer() {
7− return (
8− <footer className="bg-wall-100 mt-20 w-full flex justify-center">
9− <SingleColumn>
10− <Section short className="flex flex-row flex-wrap">
11− <div className="w-1/2 md:w-1/3 flex flex-col flex-shrink">
12− <h4 className="mt-16 mb-8">Use Urbit</h4>
13− <Link href="/getting-started">
14− <div>
15− <a className="type-bold text-wall-500">Getting Started</a>
16− </div>
17− </Link>
18− <Link href="/using">
19− <div>
20− <a className="type-bold text-wall-500">User's Manual</a>
21− </div>
22− </Link>
23− <Link href="https://github.com/urbit/port/releases">
24− <div>
25− <a className="type-bold text-wall-500">Urbit Client</a>
26− </div>
27− </Link>
28− <Link href="https://github.com/urbit/urbit/releases">
29− <div>
30− <a className="mt-2 type-bold text-wall-500">Urbit Binaries</a>
31− </div>
32− </Link>
33− {
34− // <Link href="">
35− // <div>
36− // <a className="mt-2 type-bold text-wall-500">Urbit Apps</a>
37− // </div>
38− // </Link>
39− }
40− <Link href="/getting-started/planet/#hosting-providers">
41− <div>
42− <a className="mt-2 type-bold text-wall-500">
43− Hosting Providers
44− </a>
45− </div>
46− </Link>
47− </div>
48− <div className="w-1/2 md:w-1/3 flex flex-col flex-shrink">
49− <h4 className="mt-16 mb-8">About</h4>
50− <Link href="/understanding-urbit">
51− <div>
52− <a className="type-bold text-wall-500">What's Urbit?</a>
53− </div>
54− </Link>
55− <Link href="/understanding-urbit/urbit-id">
56− <div>
57− <a className="mt-2 type-bold text-wall-500">Urbit ID</a>
58− </div>
59− </Link>
60− <Link href="/understanding-urbit/urbit-os">
61− <div>
62− <a className="mt-2 type-bold text-wall-500">Urbit OS</a>
63− </div>
64− </Link>
65− <Link href="/audits">
66− <div>
67− <a className="mt-2 type-bold text-wall-500">Security Audits</a>
68− </div>
69− </Link>
70− <Link href="/faq">
71− <div>
72− <a className="mt-2 type-bold text-wall-500">FAQ</a>
73− </div>
74− </Link>
75− <Link href="//media.urbit.org/whitepaper.pdf">
76− <div>
77− <a className="mt-2 type-bold text-wall-500">Whitepaper</a>
78− </div>
79− </Link>
80− </div>
81− <div className="w-1/2 md:w-1/3 flex flex-col flex-shrink">
82− <h4 className="mt-16 mb-8">News</h4>
83− <Link href="/blog">
84− <div>
85− <a className="type-bold text-wall-500">Blog</a>
86− </div>
87− </Link>
88− <Link href="/events">
89− <div>
90− <a className="mt-2 type-bold text-wall-500">Events</a>
91− </div>
92− </Link>
93− <Link href="/updates">
94− <div>
95− <a className="mt-2 type-bold text-wall-500">Updates</a>
96− </div>
97− </Link>
98− </div>
99−
100− <div className="w-1/2 md:w-1/3 flex flex-col">
101− <h4 className="mt-16 mb-8">Develop</h4>
102− <Link href="/docs">
103− <div>
104− <a className="type-bold text-wall-500">Documentation</a>
105− </div>
106− </Link>
107− <Link href="https://github.com/urbit">
108− <div>
109− <a className="mt-2 type-bold text-wall-500">Github</a>
110− </div>
111− </Link>
112− <Link href="https://github.com/urbit/awesome-urbit#http-apis-airlock">
113− <div>
114− <a className="mt-2 type-bold text-wall-500">Airlock APIs</a>
115− </div>
116− </Link>
117− </div>
118− <div className="w-1/2 md:w-1/3 flex flex-col">
119− <h4 className="mt-16 mb-8">Contribute</h4>
120− <Link href="https://github.com/urbit/urbit/issues">
121− <div>
122− <a className="type-bold text-wall-500">Issue Tracker</a>
123− </div>
124− </Link>
125− <Link href="/grants">
126− <div>
127− <a className="mt-2 type-bold text-wall-500">Urbit Grants</a>
128− </div>
129− </Link>
130− </div>
131−
132− <div className="w-1/2 md:w-1/3 flex flex-col">
133− <h4 className="mt-16 mb-8">Community</h4>
134− <Link href="https://groups.google.com/a/urbit.org/g/dev?pli=1">
135− <div>
136− <a className="type-bold text-wall-500">Dev Mailing List</a>
137− </div>
138− </Link>
139− <Link href="https://github.com/urbit/azimuth">
140− <div>
141− <a className="mt-2 type-bold text-wall-500">Governance</a>
142− </div>
143− </Link>
144− <Link href="https://twitter.com/urbit">
145− <div>
146− <a className="mt-2 type-bold text-wall-500">Twitter</a>
147− </div>
148− </Link>
149− </div>
150− </Section>
151− <Section className="flex flex-col md:flex-row">
152− <div className="md:w-1/3">
153− <Link href="/privacy">
154− <div>
155− <a className="type-bold text-wall-500">Privacy Policy</a>
156− </div>
157− </Link>
158− </div>
159− <div className="md:w-1/3">
160− <Link href="/terms-of-service">
161− <div>
162− <a className="type-bold text-wall-500">Terms of Service</a>
163− </div>
164− </Link>
165− </div>
166− <div className="md:w-1/3">
167− <div>
168− <a
169− href={"mailto:" + contact.email}
170− className="type-bold text-wall-500"
171− >
172− {contact.email}
173− </a>
174− </div>
175− </div>
176− </Section>
177− </SingleColumn>
178− </footer>
179− );
5+ return <FooterComponent data={footerData} />;
1806}
components/GrantPreview.js+37−35
@@ -3,12 +3,12 @@ import Link from "next/link";
33
44export default function GrantPreview({ grant }) {
55 const isCompleted = grant.extra.completed;
6− const isOpen = !isCompleted && grant.extra.assignee === "";
6+ const isOpen = !isCompleted && grant.extra.assignee?.[0] === "";
77 const type = grant.taxonomies.grant_type;
88
99 const className = classnames({
1010 "bg-lightBlue": type.includes("Proposal") && isOpen,
11− "bg-green-200": type.includes("Apprenticeship") && isOpen,
11+ "bg-purple-200": type.includes("RFP") && isOpen,
1212 "bg-yellow-100": type.includes("Bounty") && isOpen,
1313 });
1414
@@ -17,44 +17,46 @@ export default function GrantPreview({ grant }) {
1717 key={grant.slug}
1818 className={`mb-4 cursor-pointer bg-wall-100 rounded-lg ${className}`}
1919 >
20− <Link href={`/grants/${grant.slug}`}>
21− <div className="p-8">
22− <div className="flex items-center mb-4">
23− <h3 className="type-ui" id={grant.slug}>
24− {grant.title}
25− </h3>
26− <div className={`bg-wall-500 text-wall-100 badge-sm ml-2`}>
27− {!isCompleted ? (isOpen ? "Open" : "In Progress") : "Completed"}
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>
2830 </div>
29− </div>
30− <p className="mb-4">{grant.extra.description}</p>
31− <div className="flex w-full flex-col md:flex-row md:items-center justify-between">
32− <p className="text-wall-500">
33− <strong>Reward: </strong>
34− {grant.extra.reward} star
35− {grant.extra.reward === 1 ? "" : "s"}
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-green-400 text-white": category === "Apprenticeship",
42− "bg-yellow-300": category === "Bounty",
43− });
44− return (
45− <div className={`${className} badge-sm mr-1 my-1`}>
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">
4653 {category}
4754 </div>
48− );
49− })}
50− {grant.taxonomies.grant_category.map((category) => (
51− <div className="bg-wall-500 text-wall-100 badge-sm mr-1 my-1">
52− {category}
53− </div>
54− ))}
55+ ))}
56+ </div>
5557 </div>
5658 </div>
57− </div>
59+ </a>
5860 </Link>
5961 </div>
6062 );
components/GrantProgramOverview.js+14−12
@@ -1,15 +1,18 @@
11import { useRouter } from "next/router";
2−import { formatDate } from "../lib/lib";
32import Link from "next/link";
43import Head from "next/head";
54import Meta from "../components/Meta";
65import ErrorPage from "../pages/404";
7−import Container from "./Container";
6+import {
7+ Container,
8+ Section,
9+ SingleColumn,
10+ Markdown,
11+ IntraNav,
12+ formatDate,
13+} from "@urbit/foundation-design-system";
814import Header from "./Header";
915import Footer from "./Footer";
10−import SingleColumn from "./SingleColumn";
11−import Section from "./Section";
12−import { decode } from "html-entities";
1316import { DateTime } from "luxon";
1417
1518export default function GrantProgramOverview({
@@ -29,9 +32,10 @@ export default function GrantProgramOverview({
2932 return (
3033 <Container>
3134 <Head>
32− <title>{title} • Grants • urbit.org</title>
35+ <title>{title} • Grants</title>
3336 {Meta(post)}
3437 </Head>
38+ <IntraNav ourSite="https://urbit.org" search={search} />
3539 <SingleColumn>
3640 <Header search={search} />
3741 <Section narrow short>
@@ -39,16 +43,14 @@ export default function GrantProgramOverview({
3943 <div className="type-ui text-wall-500 mt-4 md:mt-8 lg:mt-10">
4044 Last Revision: {formatDate(DateTime.fromISO(post.date))}
4145 </div>
42− <Link href={actionLink}>
43− <button className="button-sm bg-green-400 text-white mt-8">
46+ <Link href={actionLink} passHref>
47+ <a className="button-sm bg-green-400 text-white mt-8 max-w-fit">
4448 {actionText}
45− </button>
49+ </a>
4650 </Link>
4751 </Section>
4852 <Section narrow short className="markdown">
49− <article
50− dangerouslySetInnerHTML={{ __html: decode(markdown) }}
51− ></article>
53+ <Markdown.render content={JSON.parse(markdown)} />
5254 </Section>
5355 </SingleColumn>
5456 <Footer />
components/Header.js+70−61
@@ -1,22 +1,19 @@
11import Link from "next/link";
22import { useRouter } from "next/router";
3−import { useState, useEffect } from "react";
3+import { useState } from "react";
44import classnames from "classnames";
5−import path from "path";
6−import MenuTray from "../components/MenuTray";
7−import Section from "../components/Section";
8−import { capitalize } from "../lib/lib";
5+import { capitalize, MenuTray } from "@urbit/foundation-design-system";
96
107function ActiveLink({ children, href, className, currentPath }) {
118 const firstCrumb = currentPath.split("/")[1];
129
1310 const activeClassName = classnames({
14− "text-wall-600": "/" + firstCrumb === href,
11+ "text-wall-900": "/" + firstCrumb === href,
1512 "text-wall-500": "/" + firstCrumb !== href,
1613 });
1714
1815 return (
19− <Link href={href}>
16+ <Link href={href} passHref>
2017 <a className={`${className} ${activeClassName}`}>{children}</a>
2118 </Link>
2219 );
@@ -24,7 +21,6 @@ function ActiveLink({ children, href, className, currentPath }) {
2421
2522export default function Header(props) {
2623 const [isOpen, setTray] = useState(false);
27− const [shortcut, setShortcut] = useState("");
2824
2925 const currentPath = useRouter().asPath;
3026
@@ -32,29 +28,14 @@ export default function Header(props) {
3228
3329 const firstCrumb = currentPath.split("/")[1];
3430
35− const detectOS = () => {
36− const agent = window.navigator.appVersion;
37− if (agent.includes("Win")) {
38− return "Ctrl+K";
39− } else if (agent.includes("Mac")) {
40− return "⌘K";
41− } else if (agent.includes("Linux")) {
42− return "Ctrl+K";
43− }
44− };
45−
46− useEffect(() => {
47− setShortcut(detectOS());
48− }, []);
49−
5031 return (
5132 <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">
5233 <div>
53− <Link href="/">
54− <a className="type-ui">Urbit</a>
34+ <Link href="/" passHref>
35+ <a className="font-semibold text-lg">Urbit</a>
5536 </Link>
5637 {routeDepth > 2 ? (
57− <Link href={`/${firstCrumb}`}>
38+ <Link href={`/${firstCrumb}`} passHref>
5839 <a className="inline md:hidden type-ui text-wall-500 ml-2">
5940 {capitalize(firstCrumb)}
6041 </a>
@@ -68,92 +49,120 @@ export default function Header(props) {
6849 <ActiveLink
6950 currentPath={currentPath}
7051 className="mr-5 type-ui"
71− href="/docs"
52+ href="/getting-started"
7253 >
73− Docs
54+ Get Started
7455 </ActiveLink>
56+
7557 <ActiveLink
7658 currentPath={currentPath}
7759 className="mr-5 type-ui"
78− href="/using"
60+ href="/overview"
7961 >
80− Manual
62+ Overview
8163 </ActiveLink>
64+
8265 <ActiveLink
8366 currentPath={currentPath}
8467 className="mr-5 type-ui"
85− href="/blog"
68+ href="/ecosystem"
8669 >
87− Blog
70+ Ecosystem
8871 </ActiveLink>
72+
8973 <ActiveLink
9074 currentPath={currentPath}
9175 className="mr-5 type-ui"
92− href="/events"
76+ href="/grants"
9377 >
94− Events
78+ Grants
9579 </ActiveLink>
80+
9681 <ActiveLink
9782 currentPath={currentPath}
98− className="mr-5 text-green-400 type-ui button-text"
99− href="/getting-started"
83+ className="mr-5 type-ui"
84+ href="/events"
10085 >
101− Get Started
86+ Events
10287 </ActiveLink>
88+
10389 <ActiveLink
10490 currentPath={currentPath}
10591 className="mr-5 type-ui"
106− href="/faq"
92+ href="/blog"
10793 >
108− FAQ
94+ Blog
10995 </ActiveLink>
110− <button
111− onClick={(e) => {
112− e.stopPropagation();
113− props.search.toggleSearch(e);
114− }}
115− className="bg-wall-100 text-wall-500 flex px-4 py-1 rounded-lg type-ui"
116− >
117− <div>Search</div>
118− <div className="ml-4 text-wall-400">{shortcut}</div>
119− </button>
12096 </nav>
12197
12298 {
12399 // Small screen header
124100 }
125101 <MenuTray isOpen={isOpen} setTray={setTray} search={props.search}>
126− <Link href="/">
127− <a className="type-ui mb-12">Urbit</a>
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>
128113 </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+
129119 <ActiveLink
130120 currentPath={currentPath}
131− className="mr-5 mb-4 type-h3"
132− href="/docs"
121+ className="mr-5 mt-4 mb-4 text-green-400"
122+ href="/getting-started"
133123 >
134− Docs
124+ Get Started
135125 </ActiveLink>
126+
136127 <ActiveLink
137128 currentPath={currentPath}
138− className="mr-5 mb-4 type-h3"
139− href="/blog"
129+ className="mr-5 mb-4"
130+ href="/overview"
140131 >
141− Blog
132+ Overview
142133 </ActiveLink>
134+
143135 <ActiveLink
144136 currentPath={currentPath}
145− className="mr-5 mb-4 type-h3"
146− href="/events"
137+ className="mr-5 mb-4"
138+ href="/ecosystem"
147139 >
148− Events
140+ Ecosystem
149141 </ActiveLink>
142+
150143 <ActiveLink
151144 currentPath={currentPath}
152− className="mr-5 mb-4 type-h3"
145+ className="mr-5 mb-4"
153146 href="/grants"
154147 >
155148 Grants
156149 </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>
157166 </MenuTray>
158167 </header>
159168 );
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.js+2−2
@@ -58,9 +58,9 @@ export default function Contact({ emphasize, groupName, label, className }) {
5858
5959 return (
6060 <div className={className}>
61− <h4 className="mt-4 text-wall-500 flex items-baseline flex-wrap">
61+ <h4 className="text-wall-500 flex items-baseline flex-wrap">
6262 {label ? label + " " : ""}
63− <div className="md:ml-2 rounded-lg flex items-stretch">
63+ <div className="rounded-lg flex items-stretch">
6464 <code
6565 className={`rounded-l-lg px-2 md:px-4 py-2 ${washedBg} flex items-center h-full ${linkText}`}
6666 >
components/Lorem.jsdeleted−106
@@ -1,106 +0,0 @@
1−// Giant lorem ipsum for tests
2−export default function Lorem(props) {
3− return (
4− <div className={props.className || ''}>
5− Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus sagittis posuere purus vitae auctor. Duis consequat commodo metus vel pellentesque. Nulla massa neque, commodo sed placerat vel, mattis sed felis. Proin et felis auctor, tristique ante at, mollis nisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; In tempus blandit volutpat. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
6−
7− Praesent egestas at metus ac pharetra. Pellentesque tempus elit ex, vel scelerisque magna ornare ac. Vestibulum vitae est nibh. Nullam posuere, libero ac aliquet congue, urna tortor faucibus leo, eu bibendum quam nulla id metus. Vivamus eget feugiat ex. Sed purus nulla, ultricies eget dui fermentum, pellentesque posuere lectus. Maecenas vel orci dignissim ligula luctus varius. Quisque convallis massa in lectus aliquet, varius varius risus scelerisque. Suspendisse et interdum turpis. Sed ac fermentum nulla. Donec nunc est, tincidunt ac fermentum luctus, auctor vel dui. Vivamus hendrerit, libero sed pellentesque viverra, est massa pretium tellus, vel ultrices turpis ante at orci.
8−
9− Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer sit amet dui sed purus accumsan tempor. Aenean posuere lacus mollis mattis maximus. Integer hendrerit pulvinar tempus. Nam aliquet ipsum et arcu convallis placerat. Donec facilisis odio sed dolor ultricies, nec rhoncus lacus fringilla. Cras luctus odio ipsum, in pretium eros volutpat sit amet. Integer fringilla ipsum at bibendum imperdiet. Maecenas auctor magna non arcu varius rhoncus. Nunc dictum elementum suscipit. Proin rhoncus lacus in massa eleifend blandit.
10−
11− Maecenas eu tellus dignissim, venenatis turpis eu, tempus odio. Praesent viverra vitae neque in dapibus. Donec fermentum neque at augue volutpat bibendum. Integer blandit tristique sodales. Vestibulum ultrices nulla ac est vulputate imperdiet. Vivamus venenatis cursus tellus quis faucibus. Curabitur non fringilla felis. Sed blandit tellus quis dictum cursus. In quam ex, euismod at ipsum quis, porta tempor nisl. In id scelerisque diam, quis gravida mi.
12−
13− Nullam lacinia quis nibh vitae fermentum. Sed in libero vitae massa pulvinar feugiat nec non sem. Donec tristique ac felis vel feugiat. Suspendisse tempus ante metus, non porttitor arcu tincidunt nec. Vestibulum iaculis dolor ut quam lobortis, quis mollis purus imperdiet. Vivamus faucibus interdum nibh vel lacinia. Pellentesque at tempus mi. In hac habitasse platea dictumst. Phasellus ultricies tincidunt elementum. Mauris mollis mollis auctor.
14−
15− Suspendisse potenti. Pellentesque egestas leo ut arcu imperdiet vehicula. Fusce dapibus volutpat leo, tempus sodales risus ultricies et. Nullam gravida massa ac aliquam egestas. In facilisis vitae eros vitae posuere. Duis enim enim, commodo vel dapibus et, consequat sed purus. Morbi ornare vitae tellus nec ultricies. Curabitur egestas lacus ut dictum laoreet. Praesent bibendum cursus pellentesque. Maecenas fringilla tempor lacus id feugiat. Praesent non imperdiet velit. Nulla facilisi. Vestibulum elementum, velit sed ultricies porta, odio eros porta libero, a tempor turpis arcu malesuada ipsum. Phasellus eu mauris elit.
16−
17− Curabitur id justo a eros tristique semper sodales non ipsum. Mauris aliquam felis sed orci pretium, at placerat urna posuere. Suspendisse potenti. In ac ipsum lorem. Maecenas in semper tortor, ac consectetur enim. Nullam sit amet nulla ante. Aliquam viverra risus et mauris suscipit, at gravida risus dignissim. Proin tincidunt metus eros. Donec tempus finibus nulla quis ullamcorper. Etiam ut nulla nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus lacinia ornare mauris ac fringilla. Maecenas ac faucibus ipsum.
18−
19− Nulla finibus fringilla lacus, id venenatis dolor pulvinar vitae. Vestibulum vulputate luctus eros, sed commodo justo consectetur fermentum. Suspendisse potenti. Morbi ex diam, dapibus vel faucibus id, mattis et felis. Ut a interdum augue, euismod fringilla ex. Nullam fermentum, eros sed congue vestibulum, tortor neque tempus sapien, in ultricies erat nulla in eros. Aliquam non velit semper, ullamcorper augue nec, auctor purus. Duis enim felis, viverra nec nisi vel, sodales bibendum ante. Etiam sollicitudin ornare cursus.
20−
21− Donec iaculis bibendum viverra. Mauris mattis consectetur suscipit. Proin at cursus risus. Vivamus eu felis condimentum, tempus enim id, vestibulum odio. Praesent pretium massa vitae turpis aliquet posuere. Nunc egestas, libero eu vestibulum iaculis, leo sapien consequat dolor, ut feugiat nisl metus vel eros. Suspendisse faucibus felis a est porta tincidunt. Sed diam orci, sodales non orci nec, pharetra dapibus ipsum.
22−
23− Quisque rutrum, urna non vehicula porta, tellus dolor maximus quam, et pharetra justo diam quis neque. Suspendisse at lorem rhoncus, maximus tortor nec, sodales leo. Vivamus eu condimentum mauris. Pellentesque varius, velit nec maximus volutpat, dui purus porta lorem, eu dapibus metus risus non sem. Vestibulum id libero tellus. Quisque tortor turpis, laoreet eu est et, mollis volutpat elit. Nunc posuere enim sit amet vulputate fringilla. Curabitur pretium arcu in sem mattis pellentesque. Quisque vulputate ex leo, at accumsan tellus fermentum sit amet. Fusce ac velit vel dolor lacinia gravida. Proin ac faucibus felis.
24−
25− Aliquam semper massa et cursus laoreet. Praesent nec ante auctor, dapibus sem id, pellentesque justo. Maecenas iaculis ex sapien, in tempor erat dapibus a. Vivamus varius ut turpis eget vehicula. Sed condimentum enim non consectetur sagittis. Donec eu ipsum eros. Pellentesque convallis tellus id finibus rutrum. Fusce et facilisis metus. Proin quis orci iaculis enim iaculis ultrices a et ipsum. Vivamus blandit a diam at condimentum.
26−
27− Donec et vestibulum purus. Ut at est pulvinar mauris ultrices facilisis. Duis lacus quam, euismod maximus venenatis at, consectetur id nunc. Suspendisse elementum risus vitae eros laoreet gravida. Fusce aliquam, justo eu auctor iaculis, purus justo molestie metus, in tincidunt metus magna nec orci. Proin lacus libero, maximus eu laoreet nec, egestas et lorem. Nunc condimentum, arcu ac elementum facilisis, purus ligula maximus est, sit amet hendrerit dui ante eu elit. Aenean tempor rutrum massa eget efficitur. Donec tempor metus diam, in gravida nunc lobortis at. Nam elementum sollicitudin aliquam. Proin sit amet quam eros. Vivamus ut ante nisi. Pellentesque vitae felis consectetur erat ultrices ultrices ut a ante. Duis interdum, ante id accumsan maximus, nisi sem euismod sem, vitae facilisis ex nunc a quam. Pellentesque libero sem, tempus sit amet blandit sed, interdum sed ante. Maecenas vitae rhoncus augue, eu molestie erat.
28−
29− Nullam bibendum, lacus vel tincidunt tristique, ligula sapien interdum velit, non pretium dolor tortor sollicitudin leo. Aliquam vel lorem ut ligula mattis auctor. Proin ullamcorper molestie augue, eget pulvinar justo placerat eu. Sed euismod vehicula enim. In semper faucibus consectetur. Pellentesque interdum varius varius. Cras laoreet felis vitae eros iaculis sollicitudin. Aenean eu mattis felis. Proin mattis nunc sodales hendrerit fringilla. Aliquam velit mauris, feugiat eu felis a, ullamcorper tempus velit. Fusce non pulvinar quam, commodo imperdiet mi. Nam rhoncus turpis neque, in eleifend purus cursus vel. Quisque lobortis, nulla ut auctor finibus, ex nunc tristique nisl, in tincidunt est massa ut sem.
30−
31− Vestibulum eu urna elit. Aliquam tempor cursus faucibus. Praesent scelerisque dui eu lorem auctor, eu lacinia nibh porttitor. Ut et eros eget felis tristique volutpat a ac tortor. Praesent quis lorem a mauris ultrices imperdiet quis a odio. In cursus maximus orci sed dignissim. Donec semper, orci id consectetur pulvinar, turpis lorem eleifend quam, eu fringilla libero mauris vel ante. Nunc id tellus elit. Etiam facilisis vitae lorem vel fermentum.
32−
33− Sed bibendum maximus nulla a egestas. Cras commodo ipsum quis magna viverra, quis tempus eros gravida. Donec et dictum dui. Etiam vel orci quis mi molestie eleifend. Vivamus vel tincidunt augue. Fusce vel tortor sagittis, viverra velit nec, consequat elit. Maecenas sem metus, dignissim non mauris ac, elementum tempor lectus. Suspendisse vel sapien tincidunt elit posuere mattis vel id mauris. Nam vitae imperdiet orci. Sed bibendum justo eu bibendum consequat. Mauris mauris sapien, blandit eget semper nec, pulvinar at lorem.
34−
35− Pellentesque vitae nunc sed nibh condimentum tempor eget sed est. Quisque bibendum eu odio vitae pharetra. Cras ut condimentum purus. Nullam ipsum dui, efficitur tempus tincidunt et, condimentum a ipsum. Curabitur malesuada nibh id massa imperdiet porttitor. Duis quis lobortis dui. Mauris aliquam lectus arcu, vel euismod ante dignissim quis.
36−
37− In ut vulputate nisi. Vivamus felis est, vestibulum vitae scelerisque non, blandit sit amet purus. Nullam dictum, turpis sed rutrum lacinia, sapien enim dictum lectus, ut molestie lorem enim id mi. Donec vestibulum dui urna, ut viverra purus mattis sit amet. In maximus metus ipsum. Sed bibendum scelerisque mattis. Nunc sed dolor at metus euismod semper. Cras libero purus, porttitor nec sapien eu, pellentesque malesuada magna. Etiam euismod purus ut leo pharetra, sollicitudin hendrerit nibh dignissim. Nam accumsan lacus in velit commodo, non mollis urna ornare. Vivamus ligula metus, ultrices a iaculis quis, venenatis pellentesque nisl. Proin vestibulum pellentesque tortor vel tempor.
38−
39− Pellentesque id orci tincidunt, egestas erat eu, fermentum ipsum. Nunc efficitur nulla vitae nunc feugiat porttitor. Fusce risus est, dignissim in fermentum vel, finibus eu sapien. Maecenas mollis lorem nec dolor ornare, vel vestibulum nunc fringilla. Quisque at ante nunc. Nam blandit nisi quis blandit auctor. Cras ac sem lorem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Fusce nulla tellus, porttitor id aliquet iaculis, auctor a quam. Aenean sodales pulvinar vehicula.
40−
41− Etiam non diam tortor. Ut posuere dolor id placerat posuere. Aliquam erat volutpat. Morbi tempor volutpat venenatis. Sed id iaculis mi, in commodo dui. Aliquam eleifend urna sagittis lorem porta malesuada. Praesent placerat justo sed luctus finibus. Vivamus commodo porttitor metus, vulputate sagittis ipsum finibus non. Vestibulum porttitor varius metus eu fermentum. Morbi eleifend augue sit amet velit aliquam facilisis.
42−
43− Donec et lorem lectus. Integer ex neque, lobortis vitae posuere eu, tincidunt id enim. Vivamus consectetur elit porttitor mi viverra, in sodales velit finibus. Fusce auctor felis a ipsum mollis, nec ornare metus tempus. Fusce nulla felis, semper vitae lorem non, tincidunt feugiat tellus. Vivamus eu pulvinar elit. Proin leo odio, laoreet eu purus ut, luctus laoreet ante. Ut commodo lacus odio, in scelerisque tortor pharetra in. Aenean rhoncus augue non egestas condimentum. Donec maximus placerat facilisis. Praesent aliquam augue non purus volutpat blandit. Pellentesque id mollis enim.
44−
45− In ut eros posuere, imperdiet sapien a, dapibus velit. Nam at blandit neque. Nam euismod leo et venenatis mattis. Praesent consectetur, risus consequat condimentum tincidunt, ante nibh aliquam ligula, condimentum egestas augue tortor non risus. Nulla accumsan diam a sapien tempus hendrerit. Fusce fringilla mi quis blandit sodales. Quisque finibus mi vel nisi efficitur imperdiet. Cras luctus dapibus mauris non feugiat. Aliquam eu rutrum ipsum. Aliquam elementum luctus molestie. Maecenas molestie nisi molestie, sollicitudin arcu vel, condimentum diam. Mauris eu quam ac lacus accumsan vestibulum. Etiam et mi imperdiet sem convallis dapibus vel eget nisl. In vel faucibus risus. Curabitur luctus pellentesque eros, ac condimentum tellus placerat nec. Nam gravida consequat tincidunt.
46−
47− Vestibulum consectetur vitae erat non ultrices. Nullam eu diam dictum ante vehicula tempor sit amet et est. Donec ipsum justo, facilisis lobortis vehicula eleifend, viverra a leo. Donec hendrerit, lorem et congue dictum, ipsum nunc facilisis nunc, non ornare nulla augue eu nibh. Ut condimentum in mauris eget blandit. Donec sed est mi. Nunc gravida sodales vestibulum. In hac habitasse platea dictumst.
48−
49− Aliquam interdum mauris turpis, a efficitur eros molestie suscipit. Donec elementum ultrices augue, in facilisis sapien vestibulum ac. Sed sit amet dictum augue. Nullam posuere ante sit amet cursus molestie. Praesent odio dolor, molestie ac eleifend vitae, tempor quis ligula. Cras a volutpat sem, a varius sapien. Curabitur finibus nisl quis porttitor luctus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque dignissim lacus a neque ultricies blandit. Donec a imperdiet est. Phasellus a tristique lectus. Mauris in augue in metus euismod fringilla.
50−
51− Praesent congue tincidunt hendrerit. Vivamus efficitur neque est, vel ultricies lectus tempor et. Fusce sit amet lorem sit amet enim eleifend faucibus. Pellentesque mattis malesuada scelerisque. Aliquam quam elit, commodo a commodo nec, vestibulum eget neque. Suspendisse et nibh vestibulum massa placerat maximus rutrum non felis. Donec non nisi rhoncus ipsum luctus ultrices sit amet vel ligula.
52−
53− In dictum vitae neque vehicula faucibus. Curabitur elementum nibh turpis, a pellentesque nunc viverra eu. Morbi dapibus justo dolor, nec fringilla turpis condimentum eu. Donec nec nibh eu erat tincidunt semper a ut erat. Duis accumsan mattis convallis. Aenean lacus elit, ultrices vitae nibh sit amet, consectetur vulputate risus. Morbi blandit lacus et condimentum mollis. Maecenas id massa ut massa interdum viverra a nec nisl. Pellentesque ullamcorper fringilla eros et volutpat.
54−
55− Suspendisse egestas, purus sit amet condimentum tincidunt, nunc nibh pulvinar turpis, vel eleifend lacus elit nec ligula. In viverra et ipsum a faucibus. In dictum turpis nec lectus hendrerit, vitae imperdiet orci tincidunt. Aliquam felis risus, aliquam vel ornare vel, molestie vehicula tortor. Etiam ullamcorper sit amet tellus in mollis. Proin ut rhoncus enim. In sit amet blandit est. Quisque ultricies tortor a felis ultricies, in auctor ex feugiat. Integer tempus auctor nunc id molestie. Praesent eget placerat odio. Maecenas feugiat justo a odio blandit venenatis.
56−
57− Nunc sit amet justo eu sapien efficitur porta. Pellentesque aliquet elementum odio. Donec est diam, vehicula quis scelerisque eget, gravida non arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Ut vehicula vestibulum commodo. Integer sed nunc sit amet augue hendrerit aliquam id quis elit. Donec congue risus non mauris condimentum luctus.
58−
59− Sed dapibus nulla id feugiat eleifend. Vestibulum cursus malesuada nunc quis porta. Curabitur sodales justo augue, ac semper arcu gravida in. Nunc eu ex rutrum, viverra ipsum in, interdum leo. Nunc erat leo, consectetur vitae magna eget, lacinia auctor dolor. Etiam consequat eros sit amet lorem mollis malesuada. Suspendisse sit amet aliquet libero. Cras ut nisl aliquet, pulvinar odio nec, porttitor nisl. Aenean feugiat diam eget sapien rhoncus placerat. Etiam tincidunt blandit dui at venenatis. Nullam viverra tincidunt diam eget lacinia. Fusce hendrerit arcu nisi, euismod tincidunt eros blandit non. Fusce vehicula est a lorem ornare, id ultrices metus tempor. Aenean in sollicitudin felis.
60−
61− Nunc euismod dolor erat, sit amet maximus quam blandit nec. Sed mollis placerat facilisis. Donec placerat eget lectus non egestas. In hac habitasse platea dictumst. Nullam vitae molestie justo, vitae convallis massa. Pellentesque quis magna sit amet est consequat vestibulum sed vestibulum tellus. Cras pharetra mi efficitur libero rutrum blandit. Vivamus eu orci ut diam pellentesque scelerisque. In dignissim malesuada risus. Phasellus eu scelerisque justo. Morbi nunc mi, tempus eu tempor sit amet, feugiat quis elit.
62−
63− Nunc iaculis consectetur lectus, non placerat eros. Praesent sed tellus magna. Fusce in dui mattis, auctor turpis ut, condimentum metus. Duis nibh elit, euismod nec tellus quis, pulvinar consectetur nisl. Quisque laoreet, urna ut pharetra vehicula, erat dolor molestie lorem, ornare porta enim lacus ac massa. Donec volutpat dignissim mi. Nam in imperdiet lectus. Morbi quis varius risus. In ut fermentum elit. In hac habitasse platea dictumst. Duis gravida, nisl at consectetur hendrerit, risus diam porta nisi, dignissim gravida libero urna sit amet diam. Nunc orci felis, tincidunt in turpis quis, varius molestie ex. Praesent dapibus ipsum quis velit cursus, a vehicula orci mattis. In bibendum convallis lorem nec maximus. Praesent erat libero, accumsan vitae semper at, ultrices ornare urna. Sed interdum ex vitae lectus tempus, sit amet imperdiet elit blandit.
64−
65− Nulla rhoncus dolor in ex porttitor, sit amet scelerisque risus sollicitudin. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed a orci quis diam vehicula pellentesque at molestie risus. Vivamus sollicitudin urna ex, at porta elit blandit sed. Pellentesque malesuada hendrerit diam porttitor ultricies. Suspendisse lobortis, diam non dapibus pulvinar, dui mi sodales quam, in vulputate nibh urna sit amet felis. Mauris sit amet tempor tortor. Ut viverra varius erat, pretium efficitur enim tempor vel.
66−
67− Sed et mi at neque ornare aliquet ac id risus. Pellentesque auctor varius hendrerit. Vestibulum rhoncus, magna id dapibus dapibus, eros nisl blandit lacus, id suscipit odio leo eget lorem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas mauris mi, volutpat id felis sit amet, condimentum venenatis ligula. Vivamus vitae ligula aliquet diam viverra dignissim eget vitae dolor. Fusce gravida tincidunt volutpat. Nulla hendrerit lectus in justo tincidunt, ac scelerisque lorem ultricies. Sed varius iaculis ipsum at maximus.
68−
69− Nulla facilisi. Curabitur et ullamcorper turpis, vitae venenatis tortor. Fusce elementum in nulla vitae tempus. Nam malesuada, nulla quis molestie fermentum, quam sapien vestibulum neque, nec posuere metus nisl semper turpis. Vestibulum semper euismod pretium. Aenean mattis scelerisque pulvinar. Duis pharetra ex ut sem pretium, ut tempus ipsum bibendum. Ut id ligula eu neque suscipit accumsan et non libero. Nulla non ante ligula. Vivamus a posuere justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec ut sollicitudin lectus, in finibus libero. Morbi tempor turpis at metus porta pulvinar.
70−
71− Donec sollicitudin posuere turpis, sagittis finibus sapien vestibulum finibus. Suspendisse gravida, quam non faucibus dictum, risus ex vulputate nunc, non viverra ipsum leo ut orci. Pellentesque pellentesque vehicula vulputate. Nullam sagittis quis justo et dignissim. Nulla sodales erat nec malesuada malesuada. Phasellus tincidunt tincidunt tincidunt. Nunc malesuada sem ut lectus elementum, non pulvinar augue porta. Proin ultrices sem ut maximus ultricies.
72−
73− Sed id luctus massa. Ut elementum erat sed sem euismod viverra. Aenean a libero suscipit, facilisis tellus vitae, egestas lectus. Nunc eget maximus purus, vel varius leo. Suspendisse dui felis, aliquet ut ullamcorper sed, ultrices at purus. Pellentesque luctus odio feugiat hendrerit consectetur. Quisque auctor lobortis sem. Sed arcu odio, fringilla sit amet ipsum et, dapibus maximus risus. Aenean malesuada turpis nec aliquet commodo. Morbi mauris nisi, porttitor et sapien vitae, interdum sollicitudin purus. Aliquam at magna ac quam viverra venenatis sit amet ut velit. Aenean accumsan lorem vel nisi tempor condimentum. Nunc elementum ligula ac placerat viverra. Cras et quam in ligula vestibulum finibus sed nec purus. In a accumsan dui. Donec urna neque, venenatis nec nibh mattis, semper convallis orci.
74−
75− Maecenas luctus pretium ultrices. Donec rutrum nisi vel augue placerat, vitae laoreet velit vehicula. Suspendisse potenti. Quisque posuere congue metus eu viverra. Etiam lacus ante, ullamcorper vitae consectetur sit amet, elementum sit amet risus. Nulla tempus nisi in arcu eleifend rhoncus. Proin elit risus, ultrices eu dui sit amet, dictum finibus dolor. Nunc faucibus sagittis est, eget tempor dui congue ac. Mauris dictum mollis dolor eget gravida. Duis pharetra sed quam non tempor. Ut elementum nisl vel commodo dictum. Quisque velit urna, eleifend sit amet interdum at, interdum in ante. Duis sed elit mauris. In finibus ipsum nec aliquam venenatis. Sed enim mi, gravida et fringilla vel, viverra ut mi. Maecenas est leo, viverra ut interdum ac, viverra ut est.
76−
77− Cras faucibus tempor consequat. Donec bibendum magna augue, sed faucibus ex semper vel. Nullam sit amet sem enim. Nunc tincidunt, lectus nec blandit rutrum, mi dui mattis ligula, et interdum massa libero in urna. Curabitur in elit viverra, hendrerit enim quis, finibus turpis. Ut euismod efficitur iaculis. Nunc mauris metus, condimentum ac posuere ac, vehicula eget est. Maecenas tincidunt eget leo vel tempus.
78−
79− Nam porta nulla et sapien ultricies facilisis. Fusce sed rutrum ligula, scelerisque interdum mauris. Sed feugiat venenatis nibh, vitae interdum purus sodales pharetra. Praesent commodo ultricies laoreet. Donec efficitur porta massa sit amet ullamcorper. Nulla consequat ante nec consequat aliquet. Ut vel rutrum turpis, eu mattis lacus. Donec dapibus fringilla nunc, dictum porttitor risus scelerisque et. Vivamus vitae lorem commodo, laoreet risus a, cursus diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
80−
81− Vivamus consequat libero venenatis, aliquet felis nec, gravida arcu. Donec iaculis elit massa, in mattis leo lobortis quis. Nunc id tellus egestas, posuere felis nec, dapibus massa. Integer sagittis sem et nulla sagittis, non dapibus odio aliquam. Proin vitae dolor lacus. Maecenas porttitor nisl ut leo eleifend, sed fermentum lorem iaculis. Donec diam lectus, aliquam in commodo et, sodales nec nunc. Vivamus imperdiet ante non porttitor ullamcorper. Donec vestibulum velit ut sapien pharetra porta.
82−
83− Ut tempus, enim vel aliquet convallis, eros magna interdum nisi, vel fermentum sem lorem eget magna. Nulla eu sapien id augue ornare vestibulum. Curabitur a mollis turpis, eu fringilla quam. Cras congue lorem eget mauris finibus cursus eu sit amet nisi. Sed ante tellus, molestie id velit ut, congue aliquam lacus. Mauris ultrices leo a enim porttitor, ut rutrum mauris feugiat. Vivamus volutpat, quam eget accumsan cursus, diam ante luctus nibh, ut aliquet nisl mauris at enim. Phasellus purus ex, scelerisque vel quam in, facilisis sollicitudin augue.
84−
85− Morbi faucibus ut nisi eu facilisis. Donec congue sapien eget felis interdum fringilla. Duis eget magna hendrerit, varius velit eu, accumsan augue. Vestibulum massa nibh, pulvinar ac facilisis a, ultrices ac arcu. Suspendisse fermentum et lorem et euismod. Sed auctor purus justo, id malesuada lacus vehicula nec. Phasellus venenatis nulla eu lacus finibus, sed auctor dolor dapibus. Mauris sollicitudin augue mi, sed viverra dolor imperdiet sed. Nulla facilisi. Pellentesque placerat aliquet erat nec pellentesque. Curabitur accumsan ultricies pharetra.
86−
87− Aliquam eget lobortis velit, a sollicitudin urna. Etiam eget nunc fermentum, pellentesque velit non, commodo nulla. Cras ultrices sapien purus, ut sagittis orci viverra at. Nulla sed auctor neque, quis pulvinar leo. Nulla ut tempus nunc, in condimentum justo. Morbi pretium fermentum quam ac luctus. Duis eu faucibus enim. Duis imperdiet eleifend ante, nec egestas elit posuere vel. Morbi varius porttitor urna quis ullamcorper. In sapien velit, sagittis eu vestibulum sed, faucibus a elit. Praesent eros mi, vestibulum vel est eget, egestas luctus mauris. Morbi fringilla sapien ut purus auctor laoreet.
88−
89− Mauris dapibus nisl lacus, sit amet malesuada enim molestie non. Pellentesque feugiat tempor nisi vel vehicula. Sed congue ultrices condimentum. Nulla eget urna laoreet, dictum mauris ac, consequat nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur tempus ante et ex elementum vestibulum. In sit amet nunc quis dui gravida auctor congue non dui. Vestibulum varius vehicula risus sit amet posuere. Morbi a urna volutpat, varius augue sed, sollicitudin diam. In pulvinar felis quis tellus scelerisque, ut dictum turpis placerat. Nunc nunc ligula, cursus a sagittis at, tristique vel ligula. Ut lorem arcu, fringilla vitae molestie nec, dignissim et elit. Praesent commodo, nibh ut semper dapibus, ligula velit maximus lorem, at dapibus ante turpis viverra felis. Etiam mollis mi enim, ac cursus tortor feugiat eu. Phasellus ut augue sit amet nunc vehicula varius.
90−
91− Ut purus libero, tempor in diam quis, fringilla euismod dolor. Nullam vitae leo magna. Donec elementum eget ex non vestibulum. Praesent vitae consequat urna. Aenean sit amet vehicula lorem. Aliquam malesuada auctor suscipit. Phasellus rhoncus auctor erat. Nam cursus consectetur lacus.
92−
93− Morbi velit nulla, maximus ac urna ut, finibus tincidunt orci. Sed blandit, nisi sit amet eleifend ultricies, sem justo rhoncus ipsum, eget lobortis enim sem a ante. Vestibulum faucibus sapien magna, nec eleifend eros fermentum sed. Praesent ante lacus, ornare non elementum egestas, porta eget mi. Aenean sit amet luctus erat. Sed dapibus, tortor feugiat viverra luctus, enim sem vestibulum quam, quis elementum nunc velit a nunc. Morbi faucibus pulvinar placerat. Cras vehicula tempor lobortis. Nulla sagittis lorem quis odio eleifend, nec ultricies odio rhoncus. Nunc euismod interdum leo in dignissim. Nullam a metus erat. Phasellus commodo tellus lacus, aliquet faucibus mi accumsan sed. Mauris ultrices sit amet libero in rhoncus. Duis at lectus non est blandit finibus eu id libero.
94−
95− Donec iaculis ante ut neque dictum, id malesuada orci iaculis. Nunc semper venenatis arcu non consequat. Etiam consectetur arcu ac felis gravida elementum. Suspendisse potenti. Curabitur tortor libero, aliquam nec sem eu, maximus rhoncus augue. Phasellus placerat rhoncus ex, cursus tristique ex efficitur et. Mauris sagittis convallis mollis. Duis tristique vulputate felis, vel accumsan tellus hendrerit vel. Quisque sit amet justo vitae dui pellentesque ullamcorper. Morbi consectetur elit dolor, quis consequat tortor fringilla sit amet.
96−
97− Praesent molestie ligula non euismod congue. Maecenas semper orci turpis, consectetur varius nisi fringilla a. Donec eget iaculis est, in fermentum augue. Nulla facilisi. In dapibus, nulla non aliquam placerat, tellus nulla commodo neque, eu fermentum augue nulla et magna. Proin auctor nunc fringilla ultricies efficitur. Suspendisse et eros a dolor pharetra semper. Donec sed elit vel odio sollicitudin dapibus vitae at felis. Aliquam sit amet aliquet elit.
98−
99− Aliquam id quam id felis gravida facilisis quis et velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nullam ultricies mauris ut erat sodales dignissim. Vivamus molestie justo et ante congue interdum. Pellentesque id dolor sagittis ex sollicitudin interdum. Donec dictum, quam in tristique volutpat, libero nibh commodo erat, id porttitor diam ante vitae nunc. Donec ut finibus turpis, a luctus lorem.
100−
101− Donec et elit ut lorem tincidunt maximus id porttitor arcu. Mauris pharetra lacinia dignissim. Aliquam vel rutrum libero. Nam vehicula, nibh et ullamcorper pulvinar, leo nunc dapibus quam, et mattis purus lorem id diam. In ut venenatis felis. Suspendisse et tempor nulla. Sed finibus pretium nisi quis molestie. In hac habitasse platea dictumst. Nunc accumsan egestas dui, nec suscipit turpis efficitur sed. Mauris dapibus nisl nec eros maximus sollicitudin. Curabitur eget tincidunt ligula. Vivamus in maximus odio.
102−
103− Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam erat volutpat. Donec et auctor ante. Fusce et ullamcorper risus, nec ullamcorper risus. Vestibulum id iaculis tellus. Quisque a ultricies neque, id viverra quam. Ut est nunc, finibus id leo sed, sodales viverra magna. Proin sit amet purus tellus. Nullam at viverra massa, in gravida justo. In hac habitasse platea dictumst. Mauris orci ligula, porta sit amet est vel, faucibus ullamcorper magna. Nunc eget convallis dui, et faucibus mi. Aliquam erat volutpat. Maecenas mattis mollis mauris in dictum. Suspendisse potenti.
104− </div>
105− )
106−}
components/Markdown.jsdeleted−61
@@ -1,61 +0,0 @@
1−import remark from "remark";
2−import gfm from "remark-gfm";
3−import slug from "remark-slug";
4−import heading from "remark-heading-id";
5−import remarkprism from "remark-prism";
6−import normalize from "mdurl/encode";
7−import merge from "deepmerge";
8−import github from "hast-util-sanitize/lib/github";
9−import remarkParse from "remark-parse";
10−import remarkRehype from "remark-rehype";
11−import rehypeStringify from "rehype-stringify";
12−import rehypeRaw from "rehype-raw";
13−
14−// img is wrapped in figure so that images can be extra wide in the blog posts
15−function Img(h, node) {
16− var props = { src: normalize(node.url), alt: node.alt };
17− if (node.title !== null && node.title !== undefined) {
18− props.title = node.title;
19− }
20− return {
21− type: "element",
22− tagName: "figure",
23− properties: {},
24− children: [
25− {
26− type: "element",
27− tagName: "img",
28− properties: props,
29− },
30− ],
31− };
32−}
33−
34−const options = {
35− handlers: {
36− image: Img,
37− },
38− sanitize: merge(github, {
39− // remove user-content from github.json to remark-slug work as expected
40− clobberPrefix: "",
41− attributes: { "*": ["className"] },
42− }),
43−};
44−
45−// Converts markdown strings into markdown HTML/React components
46−export default async function Markdown({ post }) {
47− const result = await remark()
48− .use(remarkParse, options)
49− .use(remarkprism, {
50− plugins: ["show-invisibles"],
51− })
52− .use(gfm)
53− .use(slug)
54− .use(heading)
55− .use(remarkRehype, { allowDangerousHtml: true })
56− .use(rehypeRaw)
57− .use(rehypeStringify)
58− .process(post.content);
59−
60− return result.toString();
61−}
components/MenuTray.jsdeleted−104
@@ -1,104 +0,0 @@
1−import classnames from "classnames";
2−import { useSwipeable } from "react-swipeable";
3−
4−export default function MenuTray({ isOpen, setTray, search, children }) {
5− // Locks document scrolling when menu is open
6− if (typeof document !== "undefined") {
7− if (isOpen) {
8− document.body.style.overflow = "hidden";
9− } else {
10− document.body.style.overflow = "visible";
11− }
12− }
13−
14− const handlers = useSwipeable({
15− onSwipedLeft: (e) => setTray(false),
16− });
17−
18− // Slides the tray in or out from the left
19− const trayClasses = classnames({
20− "tray-menu-open": isOpen,
21− "tray-menu-closed": !isOpen,
22− });
23−
24− // Fades the background overlay in or out
25− const overlayClasses = classnames({
26− "tray-overlay-open": isOpen,
27− "tray-overlay-closed": !isOpen,
28− });
29−
30− // Hides or shows the menu
31− const menuClasses = classnames({
32− "menu-open": isOpen,
33− "menu-closed": !isOpen,
34− });
35−
36− return (
37− <>
38− <nav
39− {...handlers}
40− className={`z-10 w-screen h-screen top-0 left-0 fixed block md:hidden ${menuClasses}`}
41− >
42− <div
43− onClick={() => setTray(!isOpen)}
44− className={`bg-washedWhite w-screen h-screen ${overlayClasses}`}
45− />
46− <div
47− className={`absolute bg-wall-100 h-screen top-0 left-0 tray-menu-width overflow-y-scroll mb-24 ${trayClasses}`}
48− >
49− <div
50− {...handlers}
51− className="flex flex-col px-4 md:px-8 pt-8 md:pt-10 lg:pt-12"
52− >
53− {children}
54− </div>
55− </div>
56−
57− <button
58− onClick={(e) => {
59− e.stopPropagation();
60− search.toggleSearch(e);
61− }}
62− className={`z-10 fixed px-4 items-center justify-center type-ui rounded-xl h-16 bg-white text-wall-500 left-4 right-4 bottom-4 mobile-search-button-width ${
63− isOpen ? "flex" : "hidden"
64− }`}
65− >
66− Search
67− </button>
68− </nav>
69− <button
70− onClick={() => setTray(!isOpen)}
71− className="z-10 fixed bottom-4 right-4 w-16 h-16 bg-wall-600 flex items-center justify-center rounded-full md:hidden"
72− >
73− {isOpen ? (
74− <svg
75− width="16"
76− height="16"
77− viewBox="0 0 16 16"
78− fill="none"
79− xmlns="http://www.w3.org/2000/svg"
80− >
81− <path
82− fillRule="evenodd"
83− clipRule="evenodd"
84− d="M0.39382 13.7045C-0.131273 14.2296 -0.131274 15.081 0.39382 15.6061C0.918913 16.1312 1.77026 16.1312 2.29535 15.6061L7.99999 9.90142L13.7047 15.6061C14.2297 16.1312 15.0811 16.1312 15.6062 15.6061C16.1313 15.081 16.1313 14.2296 15.6062 13.7046L9.90152 7.99989L15.6061 2.29535C16.1312 1.77026 16.1312 0.918913 15.6061 0.39382C15.081 -0.131273 14.2296 -0.131273 13.7045 0.39382L7.99999 6.09836L2.29548 0.393844C1.77038 -0.131249 0.919038 -0.13125 0.393945 0.393844C-0.131148 0.918937 -0.131148 1.77028 0.393945 2.29537L6.09846 7.99989L0.39382 13.7045Z"
85− fill="white"
86− />
87− </svg>
88− ) : (
89− <svg
90− width="16"
91− height="16"
92− viewBox="0 0 16 17"
93− fill="none"
94− xmlns="http://www.w3.org/2000/svg"
95− >
96− <rect width="16" height="3" rx="1.5" fill="white" />
97− <rect y="7" width="16" height="3" rx="1.5" fill="white" />
98− <rect y="14" width="16" height="3" rx="1.5" fill="white" />
99− </svg>
100− )}
101− </button>
102− </>
103− );
104−}
components/Meta.js+31−8
@@ -1,25 +1,48 @@
1−export default function Meta(post) {
2− const author = post?.extra?.author || "Urbit";
3− const title = post?.title ? `${post.title} - ` : "";
1+export default function Meta(post, disableImage, large = false) {
2+ const author = post?.extra?.author || "urbit.org";
3+ const title = post?.title ? post.title : "";
44 const description =
5− post?.description || "Urbit is a personal server built from scratch.";
5+ post?.description || "Urbit is a new kind of computer that you can own completely in ways that matter: networking, identity, & data.";
66 const image =
7− post?.extra?.image || "https://media.urbit.org/logo/urbit-logo-card.png";
7+ post?.extra?.image ||
8+ post?.image ||
9+ "https://storage.googleapis.com/media.urbit.org/site/opengraph/sig-white.png";
810 return (
911 <>
1012 <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+
1132 <meta
1233 name="twitter:card"
13− content="summary_large_image"
34+ content={large ? "summary_large_image" : "summary"}
1435 key="twitter-card"
1536 />
1637 <meta name="twitter:site" content="@urbit" key="twitter-site" />
1738 <meta name="twitter:creator" content="@urbit" key="twitter-creator" />
18− <meta name="og:title" content={`${title}urbit.org`} key="title" />
39+ <meta name="og:title" content={title} key="title" />
1940 <meta name="og:description" content={description} key="description" />
2041 <meta name="description" content={description} />
2142 <meta name="author" content={author} key="author" />
22− <meta name="twitter:image" content={image} key="image" />
43+ {!disableImage && (
44+ <meta name="twitter:image" content={image} key="image" />
45+ )}
2346 <link
2447 rel="alternative"
2548 type="application/rss+xml"
components/NewletterSignup.js → components/NewsletterSignup.jsrenamed+2−2
@@ -12,7 +12,7 @@ export default function NewsletterSignup(props) {
1212 <div className="input-group" id="mc_embed_signup_scroll">
1313 <div className="mc-field-group w-full relative">
1414 <input
15− className={`appearance-none outline-none text-wall-500 type-ui black ${
15+ className={`appearance-none outline-none text-wall-500 type-ui bg-white black ${
1616 props.color || "border-wall-600"
1717 } border-4 px-3 w-full mb-2 h-16 rounded-xl`}
1818 type="email"
@@ -23,7 +23,7 @@ export default function NewsletterSignup(props) {
2323 <div className="flex h-16 items-center justify-center absolute top-0 right-6">
2424 <button
2525 id="mc-embedded-subscribe"
26− className="type-ui text-wall-500 bg-transparent"
26+ className="type-ui dark:text-green-400 text-wall-500 bg-transparent"
2727 type="submit"
2828 name="subscribe"
2929 >
components/PageWithIndex.jsdeleted−42
@@ -1,42 +0,0 @@
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 Container from "./Container";
6−import Header from "./Header";
7−import Footer from "./Footer";
8−import SingleColumn from "./SingleColumn";
9−import Section from "./Section";
10−import { decode } from "html-entities";
11−import { TableOfContents } from "./TableOfContents";
12−
13−export default function PageWithIndex({ post, markdown, search }) {
14− const router = useRouter();
15− if (!router.isFallback && !post?.slug) {
16− return <ErrorPage />;
17− }
18− return (
19− <Container>
20− <Head>
21− <title>Urbit • {post.title}</title>
22− {Meta(post)}
23− </Head>
24− <SingleColumn>
25− <Header search={search} />
26− <Section narrow>
27− <h1>{post.title}</h1>
28− </Section>
29− <Section narrow>
30− <div className="flex sidebar">
31− <article
32− className={"markdown pr-0 lg:pr-16"}
33− dangerouslySetInnerHTML={{ __html: decode(markdown) }}
34− ></article>
35− <TableOfContents />
36− </div>
37− </Section>
38− </SingleColumn>
39− <Footer />
40− </Container>
41− );
42−}
components/Pagination.js+2−4
@@ -1,6 +1,4 @@
11import Link from "next/link";
2−import { formatDate } from "../lib/lib";
3−
42export default function Pagination(props) {
53 return (
64 <Link
@@ -11,9 +9,9 @@ export default function Pagination(props) {
119 className="bg-wall-100 cursor-pointer font-semibold p-2 px-4 rounded-xl flex"
1210 style={{ maxWidth: "45%" }}
1311 >
14− <p className="flex-shrink-0 pr-1">{props.previous ? "<- " : ""}</p>
12+ <p className="shrink-0 pr-1">{props.previous ? "<- " : ""}</p>
1513 <p className="text-wall-600 truncate">{props.post.title}</p>
16− <p className="flex-shrink-0 pl-1">{props.next ? " ->" : ""}</p>
14+ <p className="shrink-0 pl-1">{props.next ? " ->" : ""}</p>
1715 </div>
1816 </Link>
1917 );
components/PostPreview.js+15−33
@@ -1,42 +1,24 @@
1−import Link from "next/link";
2−import BackgroundImage from "./BackgroundImage";
3−import { formatDate, generateDisplayDate } from "../lib/lib";
1+import {
2+ Card,
3+ formatDate,
4+ generateDisplayDate,
5+} from "@urbit/foundation-design-system";
46
57export default function PostPreview(props) {
68 const section = props?.section ? props.section : "blog";
79
810 const date = generateDisplayDate(props.post.date);
911 return (
10− <div className={`cursor-pointer ${props.className}`}>
11− {props.title ? <h3 className="mb-2">{props.title}</h3> : null}
12−
13− <Link
14− href={`/${section}/${props.post.slug}`}
15− key={`post-${props.post.slug}`}
16− >
17− <div>
18− <BackgroundImage
19− className="aspect-w-5 aspect-h-4 rounded-lg"
20− src={props.post.extra.image || ""}
21− />
22−
23− <h4 className="mt-2">{props.post.title}</h4>
24− <div className="flex items-baseline mt-1">
25− {props.post.extra.author ? (
26− <div className="type-sub-bold mr-2">
27− {props.post.extra.author}
28− </div>
29− ) : null}
30− {props.post.extra.ship ? (
31− <div className="type-sub-bold text-wall-500 font-mono">
32− {props.post.extra.ship}
33− </div>
34− ) : null}
35− </div>
36− <div className="text-wall-500 type-sub mt-1">{formatDate(date)}</div>
37− </div>
38− </Link>
39− </div>
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+ />
4022 );
4123}
4224
components/Search.jsdeleted−212
@@ -1,212 +0,0 @@
1−import { Component, createRef } from "react";
2−import { glossary } from "../lib/glossary";
3−import { withRouter } from "next/router";
4−import Downshift from "downshift";
5−
6−class Search extends Component {
7− constructor(props) {
8− super(props);
9− this.state = {
10− results: [],
11− };
12− this.searchEndpoint = this.searchEndpoint.bind(this);
13− this.onInputValueChange = this.onInputValueChange.bind(this);
14− this.onSelect = this.onSelect.bind(this);
15− this.glossarySearch = this.glossarySearch.bind(this);
16− }
17−
18− searchEndpoint(query) {
19− return `/api/search?q=${query}`;
20− }
21−
22− glossarySearch(query) {
23− return glossary.filter((entry) => {
24− return query.toLowerCase() === entry.name || entry.symbol === query;
25− });
26− }
27−
28− onSelect(item) {
29− if (item.slug) {
30− this.props.router.push(item.slug);
31− }
32−
33− this.setState({
34− query: "",
35− results: [],
36− });
37−
38− this.props.closeSearch();
39− }
40−
41− onInputValueChange(query) {
42− if (query.length) {
43− fetch(this.searchEndpoint(query))
44− .then((res) => res.json())
45− .then((res) => {
46− // Wrap results in an object which will tell React what component to use to render results.
47− const results = res.results.map((item) => ({
48− type: "RESULT",
49− content: item,
50− }));
51−
52− const glossaryResults = this.glossarySearch(query).map((item) => ({
53− type: "GLOSSARY_RESULT",
54− content: item,
55− }));
56−
57− const list = [...glossaryResults, ...results];
58−
59− this.setState({ results: list });
60− });
61− } else {
62− this.setState({ results: [] });
63− }
64− }
65−
66− render() {
67− const { state, props } = this;
68−
69− if (props.showSearch) {
70− return (
71− <Downshift
72− onSelect={(selection) => this.onSelect(selection)}
73− onInputValueChange={(event) => this.onInputValueChange(event)}
74− itemToString={(item) => (item ? item.slug : "")}
75− defaultHighlightedIndex={0}
76− >
77− {({
78− getInputProps,
79− getItemProps,
80− getLabelProps,
81− getMenuProps,
82− isOpen,
83− inputValue,
84− highlightedIndex,
85− selectedItem,
86− getRootProps,
87− }) => (
88− <div className="fixed w-screen h-screen z-50 flex flex-col items-center p-4">
89− <div
90− onClick={(event) => props.closeSearch(event)}
91− className="top-0 left-0 fixed w-screen h-screen bg-washedWall"
92− />
93− <div className="relative flex flex-col max-w-screen-lg md:my-32 w-full md:w-10/12 lg:w-8/12 xl:w-6/12 rounded-xl bg-white min-h-0 overflow-hidden">
94− <div
95− style={{ display: "inline-block" }}
96− {...getRootProps({}, { suppressRefError: true })}
97− >
98− <input
99− autoFocus
100− className="text-lg md:text-xl lg:text-2xl font-medium text-green-400 bg-transparent py-2 px-4 outline-none relative w-full"
101− placeholder="Search..."
102− type="text"
103− onClick={(e) => e.stopPropagation()}
104− {...getInputProps({
105− onKeyDown: (event) => {
106− if (event.key === "Escape") {
107− // Prevent Downshift's default 'Escape' behavior.
108− event.nativeEvent.preventDownshiftDefault = true;
109− this.props.closeSearch(event);
110− }
111− },
112− })}
113− />
114− </div>
115− <ul {...getMenuProps()} className="overflow-y-scroll">
116− {isOpen
117− ? state.results.map((item, index) => {
118− const selected = highlightedIndex === index;
119− if (item.type === "GLOSSARY_RESULT") {
120− return (
121− <li
122− className={`cursor-pointer flex text-left w-full ${
123− selected ? "bg-green-400" : ""
124− }`}
125− {...getItemProps({
126− key: item.content.slug + "-" + index,
127− index,
128− item: item.content,
129− selected: highlightedIndex === index,
130− })}
131− >
132− <div className="font-semibold p-3">
133− <p
134− className={`text-base ${
135− selected ? "text-white" : "text-wall-600"
136− }`}
137− >
138− {item.content.symbol.length > 0 && (
139− <code
140− className={`mr-1 rounded px-1 py-0.5 ${
141− selected
142− ? "bg-washedWhite"
143− : "bg-wall-100"
144− }`}
145− >
146− {item.content.symbol}
147− </code>
148− )}
149− {item.content.name}
150− </p>
151− <p
152− className={`font-normal text-base mt-1 ${
153− selected ? "text-white" : "text-wall-600"
154− }`}
155− >
156− {item.content.desc}
157− </p>
158− </div>
159− </li>
160− );
161− }
162− if (item.type === "RESULT") {
163− return (
164− <li
165− className={`cursor-pointer flex text-left w-full ${
166− selected ? "bg-green-400" : ""
167− }`}
168− {...getItemProps({
169− key: item.content.link + "-" + index,
170− index,
171− item: item.content,
172− selected,
173− })}
174− >
175− <div className="p-3">
176− <p
177− className={`font-medium text-base ${
178− selected ? "text-white" : "text-wall-600"
179− }`}
180− >
181− {item.content.parent !== "Content"
182− ? `${item.content.parent} /`
183− : ""}{" "}
184− {item.content.title}
185− </p>
186− <p
187− className={`text-base font-regular text-small ${
188− selected ? "text-midWhite" : "text-wall-500"
189− }`}
190− >
191− {item.content.content}
192− </p>
193− </div>
194− </li>
195− );
196− }
197− return null;
198− })
199− : null}
200− </ul>
201− </div>
202− </div>
203− )}
204− </Downshift>
205− );
206− } else {
207− return null;
208− }
209− }
210−}
211−
212−export default withRouter(Search);
components/Section.jsdeleted−21
@@ -1,21 +0,0 @@
1−import classnames from "classnames";
2−
3−// Provides a flexible layout building block
4−export default function Section({
5− children,
6− className = "",
7− short = false,
8− narrow = false,
9−}) {
10− const spacing = classnames({
11− "py-8": short,
12− "py-20": !short,
13− "layout-narrow": narrow,
14− layout: !narrow,
15− });
16− return (
17− <section className={`w-full px-4 md:px-8 ${spacing} ${className}`}>
18− {children}
19− </section>
20− );
21−}
components/Sidebar.js+3−14
@@ -1,29 +1,18 @@
1−import Link from "next/link";
21import { useState } from "react";
3−import MenuTray from "./MenuTray";
2+import { MenuTray } from '@urbit/foundation-design-system';
43
54export default function Sidebar(props) {
65 const [isOpen, setTray] = useState(false);
76 return (
87 <>
9− <div className="hidden md:flex flex-col w-96 bg-wall-100 max-h-screen h-screen">
10− <header className="flex flex-shrink-0 justify-between items-center pl-6 pt-12 mt-5 pb-8">
11− <Link href="/">
12− <a className="type-ui text-wall-500">Urbit</a>
13− </Link>
14− </header>
15− <div className="overflow-y-auto p-6 pt-16">
8+ <div className="hidden md:flex flex-col h-full sticky top-8">
9+ <div className="overflow-y-auto">
1610 {props.children}
1711 <div className="pb-32" />
1812 </div>
1913 </div>
2014
2115 <MenuTray isOpen={isOpen} setTray={setTray} search={props.search}>
22− <header className="flex flex-shrink-0 justify-between items-center pb-8">
23− <Link href="/">
24− <a className="type-ui text-wall-500">Urbit</a>
25− </Link>
26− </header>
2716 {props.children}
2817 <div className="pt-64" />
2918 </MenuTray>
components/SingleColumn.jsdeleted−8
@@ -1,8 +0,0 @@
1−// Provides a limited-width column with all children center-aligned along the vertical axis
2−export default function SingleColumn({ children }) {
3− return (
4− <div className="flex flex-col w-full items-center max-w-screen-2xl">
5− {children}
6− </div>
7− );
8−}
components/Snippets.js+9−5
@@ -1,18 +1,22 @@
1+import Link from "next/link";
12import {
2− getAllEvents,
3− generateDisplayDate,
4− generateRealtimeDate,
53 formatDate,
64 formatTime,
75 formatTimeZone,
8−} from "../lib/lib";
6+} from "@urbit/foundation-design-system";
97
108export function Name({ children, className }) {
119 return <b className={`font-normal ${className || ""}`}>{children}</b>;
1210}
1311
1412export function Patp({ children, className }) {
15− return <code className={`font-mono ${className || ""}`}>{children}</code>;
13+ return (
14+ <Link href={`/ids/${children}`} passHref>
15+ <a>
16+ <code className={`font-mono ${className || ""}`}>{children}</code>
17+ </a>
18+ </Link>
19+ );
1620}
1721
1822// Used to render a human name alongside their @p
components/TableOfContents.jsdeleted−120
@@ -1,120 +0,0 @@
1−import { useState, useEffect, useRef } from "react";
2−
3−export const TableOfContents = ({ staticPosition, noh3s }) => {
4− const { nestedHeadings } = useHeadingsData(noh3s);
5− const [activeId, setActiveId] = useState();
6− useIntersectionObserver(setActiveId);
7− return (
8− <nav
9− className={
10− (staticPosition ? "static" : "sticky") +
11− " min-h-0 overflow-y-auto w-52 flex-shrink-0 pb-24 hidden lg:block pl-4"
12− }
13− style={{ top: "8rem", height: "calc(100vh - 16rem)" }}
14− >
15− <Headings headings={nestedHeadings} activeId={activeId} />
16− </nav>
17− );
18−};
19−
20−const getNestedHeadings = (headingElements) => {
21− const nestedHeadings = [];
22−
23− headingElements.forEach((heading, index) => {
24− const { innerText: title, id } = heading;
25−
26− if (heading.nodeName === "H2") {
27− nestedHeadings.push({ id, title, items: [] });
28− } else if (heading.nodeName === "H3" && nestedHeadings.length > 0) {
29− nestedHeadings[nestedHeadings.length - 1].items.push({
30− id,
31− title,
32− });
33− }
34− });
35−
36− return nestedHeadings;
37−};
38−
39−const useHeadingsData = (noh3s) => {
40− const [nestedHeadings, setNestedHeadings] = useState([]);
41−
42− const query = noh3s ? "h2" : "h2, h3";
43− useEffect(() => {
44− const headingElements = Array.from(document.querySelectorAll(query));
45−
46− const newNestedHeadings = getNestedHeadings(headingElements);
47− setNestedHeadings(newNestedHeadings);
48− }, []);
49−
50− return { nestedHeadings };
51−};
52−
53−const Headings = ({ headings, activeId }) => (
54− <ul>
55− {headings.map((heading, index) => (
56− <li key={heading.id}>
57− <a
58− className={index === 0 ? "font-bold" : "font-medium"}
59− href={`#${heading.id}`}
60− >
61− {heading.title}
62− </a>
63− {heading.items.length > 0 && (
64− <ul className="pl-2">
65− {heading.items.map((child) => (
66− <li
67− key={child.id}
68− className={
69− child.id === activeId ? "text-green-400" : "text-wall-500"
70− }
71− >
72− <a href={`#${child.id}`}>{child.title}</a>
73− </li>
74− ))}
75− </ul>
76− )}
77− </li>
78− ))}
79− </ul>
80−);
81−
82−const useIntersectionObserver = (setActiveId) => {
83− const headingElementsRef = useRef({});
84− useEffect(() => {
85− const callback = (headings) => {
86− headingElementsRef.current = headings.reduce((map, headingElement) => {
87− map[headingElement.target.id] = headingElement;
88− return map;
89− }, headingElementsRef.current);
90−
91− const visibleHeadings = [];
92− Object.keys(headingElementsRef.current).forEach((key) => {
93− const headingElement = headingElementsRef.current[key];
94− if (headingElement.isIntersecting) visibleHeadings.push(headingElement);
95− });
96−
97− const getIndexFromId = (id) =>
98− headingElements.findIndex((heading) => heading.id === id);
99−
100− if (visibleHeadings.length === 1) {
101− setActiveId(visibleHeadings[0].target.id);
102− } else if (visibleHeadings.length > 1) {
103− const sortedVisibleHeadings = visibleHeadings.sort(
104− (a, b) => getIndexFromId(a.target.id) > getIndexFromId(b.target.id)
105− );
106− setActiveId(sortedVisibleHeadings[0].target.id);
107− }
108− };
109−
110− const observer = new IntersectionObserver(callback, {
111− rootMargin: "0px 0px -50% 0px",
112− });
113−
114− const headingElements = Array.from(document.querySelectorAll("h2, h3"));
115−
116− headingElements.forEach((element) => observer.observe(element));
117−
118− return () => observer.disconnect();
119− }, [setActiveId]);
120−};
components/TwoUp.jsdeleted−12
@@ -1,12 +0,0 @@
1−export default function TwoUp({ children, className = "" }) {
2− return (
3− <div className={`flex flex-wrap w-full ${className}`}>
4− <div className="w-full md:w-1/2 pr-0 pb-8 md:pr-4">
5− {children[0] || null}
6− </div>
7− <div className="w-full md:w-1/2 pl-0 pb-8 md:pl-4">
8− {children[1] || null}
9− </div>
10− </div>
11− );
12−}
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/BubbleLink.js → components/index/BubbleLink.jsrenamed

The content is the same.

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.md+33−3
@@ -1,8 +1,38 @@
11+++
2−title = "Apply for an Apprenticeship"
3−date = "2021-11-25"
2+title = "Become an Apprentice"
3+date = "2023-01-04"
44weight = 1
55description = "Everything you need to know about applying for an apprenticeship"
66+++
77
8−WIP
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/Bitcoin-wallet.md → content/bitcoin-wallet.mdrenamed

The content is the same.

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/2020-to-2021.md−4
@@ -9,12 +9,8 @@ ship = "~wolref-podlex"
99image = "https://media.urbit.org/site/posts/essays/arch-sunrise-2.jpeg"
1010+++
1111
12−<br>
13−
1412![arch](https://media.urbit.org/site/posts/essays/arch-sunrise-2.jpeg)
1513
16−<br>
17−
1814In 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.
1915
2016## 2020
content/blog/20200929-state-of-urbit.md−4
@@ -9,12 +9,8 @@ ship = "~ravmel-ropdyl"
99image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/state-of-urbit-1.jpg"
1010+++
1111
12−<br>
13−
1412![Grassy Knoll](https://storage.googleapis.com/media.urbit.org/site/posts/essays/state-of-urbit-1.jpg)
1513
16−<br>
17−
1814When 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.
1915
2016We’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.
content/blog/20201119-models-of-society.md−12
@@ -17,12 +17,8 @@ All people like to talk. Society is built by talking. In this&mdash;the year of
1717
1818## Modes of Messaging
1919
20−<br>
21−
2220![Ludovic Maclellan Mann examining the Cochno Stone](https://media.urbit.org/site/posts/essays/cochno-stone.png)
2321
24−<br>
25−
2622In 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.
2723
2824Consider 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.
@@ -44,12 +40,8 @@ Having an indistinct sense of place makes the form of conversation ambiguous and
4440
4541## People in Places
4642
47−<br>
48−
4943![Halle Saale Marktplatz](https://media.urbit.org/site/posts/essays/halle-saale-marktplatz.jpg)
5044
51−<br>
52−
5345As 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.
5446
5547The 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.
@@ -60,12 +52,8 @@ In theory, we would have a digital city with unique regions, public fora, and so
6052
6153## Urbis ec Bit
6254
63−<br>
64−
6555![View of Florence from San Miniato](https://media.urbit.org/site/posts/essays/view-of-florence.jpg)
6656
67−<br>
68−
6957Urbit 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.
7058
7159In 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.
content/blog/2021-11-18-report-from-the-field.md+2−2
@@ -26,7 +26,7 @@ I’ll try to abide by the Chatham rule in this post which is why no one is name
2626
2727New world energy -
2828
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 <em>ready to build</em>.
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*.
3030
3131When 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.
3232
@@ -34,7 +34,7 @@ We didn’t have much scheduled during Assembly. Most of the time was unstructur
3434
3535I 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.
3636
37−Where did these people come from? All over the place. They have this incredible <em>new world energy</em>. 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.
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.
3838
3939This 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.
4040
content/blog/2021-11-18-the-promise-and-paradox-of-decentralization.md+8−8
@@ -12,19 +12,19 @@ image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/ux-cen
1212
1313Every 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?
1414
15−There are, to varying extents, efforts to do all of the above. But what's worth considering is that <em>all of these bans happen through centralized actors running on decentralized systems</em>. 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.
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.
1616
1717And yet all of these originally decentralized systems end up facing some degree of centralization.
1818
1919The 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:
2020
21−- The first downside to "Anyone can build anything" is that "anyone" means <em>anyone</em>, 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.
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.
2222
2323- 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.
2424
25−- The caveat is that, to quote a [<em>Diff</em> 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
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
2626
27−An open, decentralized system is <em>sparse</em>: 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.
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.
2828
2929This privatization proceeds in three different ways:
3030
@@ -32,9 +32,9 @@ This privatization proceeds in three different ways:
3232
3333- 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.
3434
35−- Facebook—the product, not the company—is a third example. It essentially implemented a missing element to the protocol: <em>identity matters</em>. 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.
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.
3636
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 <em>that</em>, and a series of closed systems built on top of that, which are the only ones the average person interacts with?
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?
3838
3939One 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.
4040
@@ -50,6 +50,6 @@ One possibility for the successor to the current Internet is that it will end up
5050
5151Norms 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.
5252
53−(Disclosure: I'm long decentralization by way of Bitcoin and Urbit. If you're on Urbit and would like to discuss <em>The Diff</em>, go to ~lableg-tadrex/the-diff.)
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.)
5454
55−<sup>1.</sup> 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) ($, <em>Economist</em>). 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.
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/aesthetic-culture-1.md+1−5
@@ -5,17 +5,13 @@ date = "2020-11-11"
55
66[extra]
77description = "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 = "Nikolai Mallett"
8+author = "~nartes-fasrum"
99ship = "~nartes-fasrum"
1010image = "https://media.urbit.org/site/posts/essays/help-the-environment.jpg"
1111+++
1212
13−<br>
14−
1513![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)
1614
17−<br>
18−
1915_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_
2016
2117One 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.
content/blog/after-machine-war.md−6
@@ -9,12 +9,8 @@ ship = "~bacbec-lormur"
99image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/berlin-wall.jpeg"
1010+++
1111
12−<br>
13−
1412![berlin-wall](https://storage.googleapis.com/media.urbit.org/site/posts/essays/berlin-wall.jpeg)
1513
16−<br>
17−
1814> 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.
1915>
2016> Really the only notable thing about it is that it was written on Urbit. And that, perhaps, has made all the difference.
@@ -25,8 +21,6 @@ image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/berlin
2521>
2622> 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.
2723
28−<br>
29−
3024The 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.
3125
3226But 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?
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/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/common-objections-to-urbit.md+15−15
@@ -40,7 +40,7 @@ Here's our list right now:
4040_"We choose to go to the moon, not because it is easy, but because it is hard."_
4141— [John F. Kennedy](https://www.youtube.com/watch?v=g25G1M4EXrQ)
4242
43−## <a name="prime"></a>Urbit is not ready for prime time.
43+## Urbit is not ready for prime time. {% #prime %}
4444
4545_TLDR_: we agree.
4646
@@ -68,7 +68,7 @@ maintained or stabilized by a mad auteur. Our primary goal today
6868is expanding the number of people who understand Urbit, and we
6969expect these pioneers to participate in technical governance.
7070
71−## <a name="jets"></a>Nock jets are a total hoax.
71+## Nock jets are a total hoax. {% #jets %}
7272
7373_TLDR_: all of computing is a hoax. You can't compare a hoax
7474to nothing. You can only compare it to all the other hoaxes.
@@ -149,7 +149,7 @@ state. The way to resolve this conflict is for the current state
149149to win, and the event history to be discarded -- not abnormal
150150anyway. See the next question.
151151
152−## <a name="log"></a>Urbit needs an infinitely extending packet/event.
152+## Urbit needs an infinitely extending packet/event. {% #log %}
153153
154154_TLDR_: no, it doesn't. Urbit can prune the log.
155155
@@ -166,7 +166,7 @@ checkpoint. Our present implementation doesn't provide a way to
166166prune the event log. But that's just a missing feature. We have
167167one or two of those!
168168
169−## <a name="scam"></a>Urbit is a total scamcoin. It's 100% premined.
169+## Urbit is a total scamcoin. It's 100% premined. {% #scam %}
170170
171171_TLDR_: yeah. But at least it's not the DAO.
172172
@@ -241,7 +241,7 @@ seem to have unexpected centripetal qualities, producing
241241unanticipated concentrations of centralized hashpower. See the
242242next objection.
243243
244−## <a name="gov"></a>Urbit isn't even really decentralized! It has a government!
244+## Urbit isn't even really decentralized! It has a government! {% #gov %}
245245
246246_TLDR_: it's technically impossible for Urbit to be
247247decentralized at this stage of its life. Urbit is designed to
@@ -317,7 +317,7 @@ at best, and a hoax at worst. And of course, no one can DAO us
317317Among other things, we check it into GitHub. GitHub is not a
318318blockchain -- but still, good luck with that.
319319
320−## <a name="sand"></a>Sandstorm/IPFS/Ethereum is way ahead of Urbit.
320+## Sandstorm/IPFS/Ethereum is way ahead of Urbit. {% #sand %}
321321
322322In general, web3 (next distributed web) solutions don't compete
323323with each other. They support each other. Concretely, they are
@@ -362,7 +362,7 @@ expressive power; but identity is optimal for the UI of the
362362common case. We'd need to see the Powerbox, Sandstorm's UI, more
363363fully fleshed out to understand its UI approach better.
364364
365−## <a name="planet"></a>Urbit doesn't have enough planets for every human
365+## Urbit doesn't have enough planets for every human {% #planet %}
366366
367367A 32-bit planet is a tool, not a toy. Like a car, it's a device
368368for a responsible and independent adult. There aren't 4 billion
@@ -388,7 +388,7 @@ social network social.
388388There is always a tradeoff between free speech and free beer.
389389Urbit will always choose free speech.
390390
391−## <a name="pwned"></a>Cloud computing is inherently non-private.
391+## Cloud computing is inherently non-private. {% #pwned %}
392392
393393_TLDR_: a general-purpose cloud computer is much, much more
394394private than a special-purpose cloud computer. In general, a
@@ -430,7 +430,7 @@ course, since Urbit is formally specified, it's trivially
430430portable. In fact, one strategy against sovereign adversaries
431431may be continuous rotation between hosts, like an MX missile.
432432
433−## <a name="code"></a>Urbit will never be able to call any existing code.
433+## Urbit will never be able to call any existing code. {% #code %}
434434
435435_TLDR_: neither will Javascript. And dear Unix, the browser
436436does not miss interacting with your `$LD_LIBRARY_PATH` at all.
@@ -444,7 +444,7 @@ When in doubt, remember that Urbit is "the browser for the server
444444side." It plays by the same general rules. Isolation means
445445isolation.
446446
447−## <a name="weird"></a>There's no way Urbit will ever be adopted. It's too weird.
447+## There's no way Urbit will ever be adopted. It's too weird. {% #weird %}
448448
449449_TLDR_: Urbit adoption is designed to be driven by ordinary end
450450users. Urbit isn't ready for ordinary end users yet. We're
@@ -484,7 +484,7 @@ Urbit only gets adopted if it's useful as a personal server for
484484human beings -- most of whom won't be Hoon programmers, or
485485programmers at all.
486486
487−## <a name="program"></a>Hoon is too weird. No one will be able to program in it.
487+## Hoon is too weird. No one will be able to program in it. {% #program %}
488488
489489_TLDR_: Hoon is ridiculously simple. Our documentation and
490490tooling are just immature.
@@ -523,7 +523,7 @@ Yes, we know: Hoon remains quite hard to learn. Again, we have
523523no reason to think this problem isn't solvable. Public
524524enlightenment remains our main priority.
525525
526−## <a name="stuck"></a>Urbit programmers are stuck with Hoon.
526+## Urbit programmers are stuck with Hoon. {% #stuck %}
527527
528528_TLDR_: patience, grasshopper.
529529
@@ -534,7 +534,7 @@ write an interpreter for that language in Hoon. Second, jet that intepreter func
534534It is not clear that Javascript is _quite_ well-defined enough
535535for this treatment. But Lua probably is.
536536
537−## <a name="user"></a>Ordinary users will never be able to manage an Urbit server.
537+## Ordinary users will never be able to manage an Urbit server. {% #user %}
538538
539539_TLDR_: Urbit's technical simplicity has always been designed
540540to drive human usability. But the polish is the last thing that
@@ -581,7 +581,7 @@ a general-purpose computer. Computing isn't scary or dangerous.
581581Unix and the Internet are scary and dangerous. That's fine for
582582an industrial tool, but not a personal tool.
583583
584−## <a name="killer"></a>Urbit has no killer app.
584+## Urbit has no killer app. {% #killer %}
585585
586586_TLDR_: the killer app is personal API aggregation.
587587
@@ -646,7 +646,7 @@ Stateful, self-updating, generic API aggregators with FUSE
646646integration, also integrated with a reactive web server, are
647647rarer.
648648
649−## <a name="horse"></a> Urbit is sniffed at by Houyhnhyms.
649+## Urbit is sniffed at by Houyhnhyms. {% #horse %}
650650
651651It's difficult to categorize [this awesome
652652essay](http://ngnghm.github.io/blog/2016/06/11/chapter-10-houyhnhnms-vs-martians/)
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.md+8−8
@@ -21,7 +21,7 @@ From a design standpoint, some of this is accomplished simply by having a system
2121
2222While 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.
2323
24−There are 2<sup>32</sup> 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.
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.
2525
2626Regardless, we set out to tackle this problem. By the end of this process, every Urbit ID got its very own ‘sigil.’
2727
@@ -33,37 +33,37 @@ What are the basic primitives of a visual language? There aren’t any completel
3333
3434So we started by collecting influences.
3535
36−<iframe class="arena-iframe" width="100%" src="https://www.are.na/tlon/seal-zp3irwad52y/embed"></iframe>
36+{% iframe src="https://www.are.na/tlon/seal-zp3irwad52y/embed" className="arena-iframe" width="100%" /%}
3737
3838The ‘chop’ or [seal](<https://en.wikipedia.org/wiki/Seal_(East_Asia)>) is conceptually pretty close to what we wanted to get to.
3939
4040<br /><br />
4141
42−<iframe class="arena-iframe" width="100%" src="https://www.are.na/tlon/kamon/embed"></iframe>
42+{% iframe className="arena-iframe" src="https://www.are.na/tlon/kamon/embed" width="100%" /%}
4343
4444[Kamon](<https://en.wikipedia.org/wiki/Mon_(emblem)>) are even closer — especially since they have very little visual complexity.
4545
4646<br /><br />
4747
48−<iframe class="arena-iframe" width="100%" src="https://www.are.na/tlon/grids-jd_xbmspxkm/embed"></iframe>
48+{% iframe className="arena-iframe" src="https://www.are.na/tlon/grids-jd_xbmspxkm/embed" width="100%" /%}
4949
5050We 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.
5151
5252<br /><br />
5353
54−<iframe class="arena-iframe" width="100%" src="https://www.are.na/tlon/stella-xfroicotm_4/embed"></iframe>
54+{% iframe className="arena-iframe" src="https://www.are.na/tlon/stella-xfroicotm_4/embed" width="100%" /%}
5555
5656Frank 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.
5757
5858<br /><br />
5959
60−<iframe class="arena-iframe" width="100%" src="https://www.are.na/tlon/ledoux-palladio/embed"></iframe>
60+{% iframe className="arena-iframe" src="https://www.are.na/tlon/ledoux-palladio/embed" width="100%" /%}
6161
6262The 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.
6363
6464<br /><br />
6565
66−<iframe class="arena-iframe" width="100%" src="https://www.are.na/tlon/flags-k9moxiayuvq/embed"></iframe>
66+{% iframe className="arena-iframe" src="https://www.are.na/tlon/flags-k9moxiayuvq/embed" width="100%" /%}
6767
6868Another 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.
6969
@@ -75,7 +75,7 @@ Ultimately, we didn’t specifically draw on any of these influences very consci
7575
7676> _“Lev’s sigil appeared, strobing, as Netherton was getting out of the cab in Henrietta Street. “Yes?” Netherton asked.”_
7777>
78−> <cite>— William Gibson, The Peripheral</cite>
78+> **— William Gibson, The Peripheral**
7979
8080Before we get to how we worked through the problem of actually designing these things, let’s talk about the problem of naming.
8181
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.md+1−5
@@ -9,12 +9,8 @@ ship = "~pindet-timmut"
99image = "https://media.urbit.org/site/posts/essays/valleys.jpg"
1010+++
1111
12−<br>
13−
1412![valleys](https://media.urbit.org/site/posts/essays/valleys.jpg)
1513
16−<br>
17−
1814## The Storm before the Calm
1915
2016Building 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.
@@ -27,7 +23,7 @@ Hang on. An AI? Harvesting my data? Spying on me? Flooding me with spam? This is
2723
2824> Replicants are like any other machine - they're either a benefit or a hazard. If they're a benefit, it's not my problem.
2925>
30−> <cite>Rick Deckard</cite>
26+> **Rick Deckard**
3127
3228Let'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.
3329
content/blog/events-series.md−4
@@ -10,12 +10,8 @@ ship = "~naplet-hildec"
1010image = "https://media.urbit.org/site/posts/essays/bau.jpg"
1111+++
1212
13−<br>
14−
1513![people gathered](https://media.urbit.org/site/posts/essays/bau.jpg)
1614
17−<br>
18−
1915_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._
2016
2117--
content/blog/first-contract.md+2−6
@@ -9,12 +9,8 @@ ship = "~datnut-pollen and ~palfun-foslup"
99image = "https://media.urbit.org/site/posts/essays/land3.jpg"
1010+++
1111
12−<br>
13−
1412![milestone](https://media.urbit.org/site/posts/essays/land3.jpg)
1513
16−<br>
17−
1814Recently, the [first upgrade](https://github.com/urbit/azimuth/pull/35) to the
1915[Azimuth](/docs/glossary/azimuth) smart contracts which make up Urbit ID was
2016put up to an [upgrade proposal vote](/docs/glossary/upgrade) by the
@@ -40,7 +36,7 @@ time, and how sponsorship works. Put another way, the data and database format
4036must remain the same, but the rules by which we interact with it may change
4137according to the governance rules we [detail below](#senate).
4238
43−## Changelist {#changelist}
39+## Changelist {% #changelist %}
4440
4541The Galactic Senate is voting on the following changes to Ecliptic:
4642
@@ -106,7 +102,7 @@ yourself), its configured proxies, networking keys and claims are cleared during
106102transfer. As such, Ecliptic will need to know about the address of the new
107103Claims contract.
108104
109−## Urbit Governance {#senate}
105+## Urbit Governance {% #senate %}
110106
111107![geology](https://media.urbit.org/site/posts/essays/b1.jpg)
112108
content/blog/first-steps-towards-urbit-org.md+1−3
@@ -9,9 +9,7 @@ ship = "~wolref-podlex"
99image = "https://media.urbit.org/site/posts/essays/first-steps.png"
1010+++
1111
12−<br>
13−
14−<img src="https://media.urbit.org/site/posts/essays/first-steps.png">
12+![](https://media.urbit.org/site/posts/essays/first-steps.png)
1513
1614## Summary
1715
content/blog/ford-fusion.md+1−5
@@ -9,11 +9,7 @@ ship = "~rovnys-ricfer"
99image = "https://media.urbit.org/site/posts/essays/ford-fusion.png"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/ford-fusion.png">
15−
16−<br>
12+![](https://media.urbit.org/site/posts/essays/ford-fusion.png)
1713
1814## Overview and Rationale
1915
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.md+1−5
@@ -13,11 +13,7 @@ ship = "~wolref-podlex"
1313image = "https://media.urbit.org/site/posts/essays/gifts.png"
1414+++
1515
16−<br>
17−
18−<img class="ba" src="https://media.urbit.org/site/posts/essays/gifts.png">
19−
20−<br>
16+![](https://media.urbit.org/site/posts/essays/gifts.png)
2117
2218Twice 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.
2319
content/blog/hackathon-results.md+1−5
@@ -9,11 +9,7 @@ ship = "~lodleb-ritrul"
99image = "https://media.urbit.org/site/posts/essays/hackathon-results-wide.png"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/hackathon-results.png">
15−
16−<br>
12+![](https://media.urbit.org/site/posts/essays/hackathon-results.png)
1713
1814Results of the Urbit Hackathon
1915
content/blog/hoon-4-lispers.mdnew file+764
@@ -0,0 +1,764 @@
1++++
2+title = "A Perspective on Lisp and Hoon"
3+date = "2023-06-15"
4+description = "Lisp is an éminence grise of programming. How does Hoon compare?"
5+
6+[extra]
7+author = "N E Davis"
8+ship = "~lagrev-nocfep"
9+image = "https://engineering.stanford.edu/sites/default/files/styles/card_1900x950/public/images/news/john_mccarthy.jpeg?h=3751da6c&itok=6tPSih53"
10++++
11+
12+![John McCarthy, inventor of Lisp, at Stanford.](https://engineering.stanford.edu/sites/default/files/styles/card_1900x950/public/images/news/john_mccarthy.jpeg?h=3751da6c&itok=6tPSih53)
13+
14+> In the beginning, von Neumann created the machine. And the machine was with rigorous form and code, and no compiler yet moved upon the face of the tubes. And the evening and the morning were the first day.
15+>
16+> And John Backus said, Let there be FORTRAN, and there was Fortran. And Fortran ruled over the assembly.
17+>
18+> And John McCarthy saw the lambda calculus, that it was very good. And McCarthy made the LISP and divided the programmers who were for the array from the programmers who were for the list.
19+>
20+> And the Fortran and the Lisp were the second day. And God set them in the firmament to give light upon the earth.
21+
22+Two great temperaments of programming language design span these poles: Fortran as the engineer of assembler-first hard-nosed array coding and Lisp as the math professor running down to the machine room waving papers. While they have ceded some to the practicalities of the other over time, each is a trope of a particular computing paradigm. In this article, we will examine the Lisp pole in light of Urbit's development language, Hoon.
23+
24+Hoon is a statically typed functional programming language that is designed to be safe, efficient, and expressive. Hoon has a unique syntax relying heavily on symbolic expressions (using “runes”) rather than traditional keywords and operators. Hoon's underlying execution language, Nock, has been described as a “pico-Lisp“, making reference to its nature as a cell-based combinator calculus. Both languages (Nock and Hoon) follow very much in the philosophical steps of Lisp but seek to improve the genre.
25+
26+Lisp is known for its powerful macro system, which allows developers to write code that generates more code at compile time, and for its powerful `eval` function; while Hoon provides a flexible metaprogramming system that allows developers to manipulate code at compile time and hot-swap code at runtime.
27+
28+This article will contrast classical Lisp syntax and assumptions with Hoon's design. As Lisp is a family of languages rather than a single implementation, I will strive to make generally applicable statements or qualify the discussion—I welcome nuance in your responses about the different major Lisp dialects.
29+
30+Hoon's characteristic structure has arisen from these overarching design principles:
31+
32+1. Hoon must compile to Nock, and benefits from reflecting Nock's calculational worldview.
33+2. Hoon must be capable of live upgrades; that is, conscious brain surgery on itself.
34+3. Hoon should grow organically based on actual developer usage patterns.
35+
36+Our investigation of Lisp and Hoon will compare their syntax, their metaprogramming affordances, and their underlying philosophies.
37+
38+
39+## Syntax
40+
41+Hoon has many commonalities with Lisp and its most common calling convention is sugared to appear like Lisp. The conventions of Nock differ—e.g. using `[]` brackets instead of `()` parentheses—and Nock does not have non-numeric tokens or names. Hoon serves as a more human-friendly syntax which mediates common expressions and structures much as C overlays assembly language. For practical purposes, we never need to write Nock code by hand, and so while Nock informs Hoon's design choices, we don't need to understand any Nock to talk about Hoon.
42+
43+Both Lisp and Hoon are homoiconic, meaning that code and data are directly represented the same way: Lisp code is represented as Lisp data structures, and Hoon code is represented as Hoon data structures. Homoiconicity means that code can be manipulated and transformed as data at runtime. While the most compelling investigation in this article focuses on metaprogramming, we need to start with a comparative syntax and grammar so we understand how code and data are represented.
44+
45+Before all of that, let us compare a simple program implemented in both Lisp and Hoon. Both programming languages are species of functional languages for which expressions result in values, but they handle side effects differently: in Hoon side effects are strictly impossible (although a runtime workaround permits I/O and necessary effects), while in Lisp side effects are permitted (although opinions on their use vary). We will therefore not use a trivial “Hello World” example. Instead we will calculate the arithmetic mean of a set of numbers of known size.
46+
47+```scheme
48+(define (mean a)
49+ (if (null? a)
50+ 0
51+ (/ (apply + a) (length a))))
52+```
53+
54+```hoon
55+:: Common (sugared) form
56+++ mean
57+ |= a=(list @ud)
58+ ?~ a 0
59+ (div (roll a add) (lent a))
60+
61+:: Rune (unsugared) form
62+++ mean
63+ |= a=(list @ud)
64+ ?~ a 0
65+ %+ div
66+ %- roll [a add]
67+ %- lent a
68+```
69+
70+The Scheme code has the advantage that it reads almost English-like as one works through the logic, but implicitly relies on familiarity with the `if`/`then`/`else` structure and function application using `()` (on which more soon).
71+
72+The Hoon code uses the `%` function application runes (differentiated by number of arguments) to apply the function calls. With syntactic sugar, this looks similar to the Lisp call, with `++roll` instead of `apply` and `++lent` instead of `length`.
73+
74+Throughout I will use code examples for Lisp taken from [Rosetta Code](https://rosettacode.org/wiki/Category:Scheme). I will select or compose Hoon examples to be structurally similar to the Lisp code in order to facilitate comparison. I will also avoid sugar syntax that would obscure the structure of the Hoon code; in some cases this will make it slightly less readable than its equivalent in practice.
75+
76+### Syntax in Lisp
77+
78+#### Types
79+
80+Lisp types are dynamic, checked at runtime rather than on compilation. Since everything is an object, some assumptions can be made about manipulation and behavior. Most Lisp dialects share these types:
81+
82+- Numbers, including integers and floating-point numbers.
83+- Characters.
84+- Strings, as a sequence of characters.
85+- Lists, as a sequence of objects (including lists).
86+- Symbols, names used to refer to a function, variable, or other object.
87+- Arrays, a fixed-size multidimensional indexed object collection.
88+
89+Lisp code, being dynamically typed, is inclined to try a value and see if it works in a given context. However, some restrictions can be made, such as an argument type declaration on a function:
90+
91+```lisp
92+(defun add-two-integers (x y)
93+ (declare (type integer x y))
94+ (+ x y))
95+```
96+
97+Lisp types are to some extent (justly) influenced by the underlying platform architecture: Lisp is generally compiled directly to machine code (like a C program), with the notable exception of [Clojure](https://clojure.org/reference/lisps) which runs on the Java Virtual Machine.
98+
99+#### Operators, Functions, Macros, and Thunks
100+
101+Lisp syntax is characterized by its use of nested lists, called S-expressions (symbolic expressions), which consist of parentheses enclosing atoms or other S-expressions. The basic structure of an S-expression is an operator (or function) followed by its arguments, all enclosed in parentheses. For example, the following S-expression performs a simple arithmetic operation:
102+
103+```lisp
104+(+ 1 2 3)
105+```
106+
107+Lisp uses prefix notation, where the operator comes before the operands, and parentheses are used to group expressions. The S-expression is evaluated from left to right (in most Lisps save Scheme), with the operator being applied to its arguments.
108+
109+Operators in Lisp operate on values of different basic types. Lisp dialects vary in their particular base types, but typically include numbers, strings, booleans, and so forth. The core data type is the list, of course (LISP is for LISt Processing). Since Lisp biases towards list processing, many operators are comfortable receiving an arbitrary number of values as inputs, as in the code sample above.
110+
111+In Lisp, [`cons`](https://en.wikipedia.org/wiki/Cons) describes the procedure to construct a pair of objects. This seemingly modest capability is fundamental to how Lisp builds lists—and since everything is a list, `cons` has consequences. One fundamental convention is the `cons` cell, which consists of two other Lisp objects and is how lists are actually constructed.
112+
113+![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Cons-cells.svg/450px-Cons-cells.svg.png)
114+
115+Lisp operations are built either as functions or as macros. Functions produce results directly from their inputs. Macros by contrast are basically function-building functions, and produce expressions that can be evaluated with inputs to get a result.
116+
117+A Lisp function is created using `defun`:
118+
119+```lisp
120+> (defun square (x) (* x x))
121+SQUARE
122+
123+> (square 2)
124+4
125+```
126+
127+(Lisp dialects tend to not be case-sensitive.)
128+
129+Lisp functions are first-class objects and can be manipulated and passed like values of basic types as well.
130+
131+Before we can look at macros, we need to consider Lisp's notion of evaluation and in particular deferred evaluation. For Lisp, an expression can be marked as a literal value rather than evaluated to produce a result. The quote `'` symbol is used to mark expressions for prevented evaluation:
132+
133+```lisp
134+'(1 2 3) ; evaluates to the list (1 2 3)
135+'foo ; evaluates to the symbol FOO
136+(1 5) ; evaluates to the list (1 5)
137+'(1 (+ 2 3)) ; evaluates to the list (1 (+ 2 3))
138+```
139+
140+Backtic or backquote `` ` `` allows you to switch an expression in and out of evaluation mode, along with `,` to mark evaluated components for splicing back into the unevaluated expression.
141+
142+```lisp
143+`(1 2 3) ; evaluates to the list (1 2 3)
144+`foo ; evaluates to the symbol FOO
145+`(1 ,(+ 2 3)) ; evaluates to the list (1 5)
146+```
147+
148+A Lisp macro is essentially a compile-time function.
149+
150+```lisp
151+> (defmacro square (x)
152+ "Returns the square of the input value."
153+ `(* ,x ,x))
154+
155+> (square 2)
156+4
157+```
158+
159+(The `` ` `` notation constructs the expression with values spliced in by `,`.)
160+
161+A deferred evaluation, called a thunk, is a closure that inherits its lexical environment but is deferred for later computation. Thunks enable lazy code evaluation and separate the computation’s definition from its execution.
162+
163+```lisp
164+(defun create-thunk (function &rest arguments)
165+ (lambda () (apply function arguments)))
166+
167+(defun invoke-thunk (thunk)
168+ (funcall thunk))
169+
170+;; Creating a thunk that calculates the factorial of a number
171+(defvar factorial-thunk (create-thunk #'(lambda () (factorial 5))))
172+
173+;; Invoking the thunk to get the result
174+(print (invoke-thunk factorial-thunk)) ; Output: 120
175+```
176+
177+In this code example, `create-thunk` accepts a function and returns a thunk created using a lambda function to encapsulate the computation. `invoke-thunk` is used to invoke the thunk to get the actual result. The actual application creates a deferred factorial implementation and then finally invokes it. Without the last line, the actual calculation would never be executed.
178+
179+As Paul Graham wrote, “The unusual thing about Lisp-- in fact, the defining quality of Lisp-- is that it can be written in itself.” A Lisp program is an S-expression, and in principle we can run the equation the other way: certain S-expressions are valid Lisp programs. Although uncommon in practice due to code safety issues, the `eval` function is illustrative of Lisps’ ability to evaluate a Lisp expression that is represented as a data structure. It takes a single argument, which is a Lisp expression, and returns the value of that expression. Lisp programs can in principle generate new code—or modify existing code—and evaluate it on the fly, since code is data.
180+
181+```lisp
182+(defvar x 10)
183+(defvar y 20)
184+(defvar z '(+ x y))
185+
186+(eval z)
187+```
188+
189+Besides explicitly named functions and macros, Lisp frequently employs lambda expressions to produce functions on demand at the point of use.
190+
191+```lisp
192+> ((lambda (x y) (+ x y)) 5 10)
193+15
194+```
195+
196+Naturally, we have not covered all of Lisp, but the above should motivate how Hoon differs from Lisp. Furthermore, Lisp is really a family of languages, so there is a fair amount of variation in specifics.
197+
198+- [Paul Graham, _On Lisp_](http://www.paulgraham.com/onlisptext.html)
199+
200+### Syntax in Hoon
201+
202+#### Types
203+
204+Hoon compiles to Nock and runs on a Nock virtual machine interpreter. Nock knows only about nouns, that is to say either simple unsigned integers or pairs of other nouns.
205+
206+> To be exact, a noun is an S-expression, except that classic S-expressions have multiple atom types ("S" is for "symbol"). Since Nock is designed to be used with a higher-level type system (such as Hoon's), it does not need low-level types. An atom is just an unsigned integer of any size.
207+
208+
209+One of the biggest differences between Hoon and Lisp lies in their respective type systems: Hoon is statically typed while Lisp is dynamically typed. Furthermore, since Hoon compiles to Nock, ultimately every value, expression, and program in Hoon results in a noun (an atom or unsigned integer, or a cell or pair of nouns). (The compiler may make this process slightly opaque, but it is deterministic.) Types, if values are known, must match or nest properly at compile time.
210+
211+Hoon implements types as a metadata layer over bare Nock numbers and atoms. (The implementation details do not concern us but can be seen using the `!,` zapcom rune, which produces the abstract syntax tree of an expression.) Hoon atom types include various numeric types (signed and unsigned, hexadecimal, binary, etc.); address space identifiers (such as ~zod); IP addresses; UTF-8 text; and floating-point values, [among many others](https://developers.urbit.org/blog/literals). As these are interpretations laid over the bare integer, it is trivial to convert among them, a convenience like C affords.
212+
213+```hoon
214+:: raw unsigned decimal integer
215+> 123
216+123
217+
218+:: hexadecimal integer
219+> `@ux`123
220+0x7b
221+
222+:: UTF-8 text
223+> `@t`123
224+'{'
225+
226+:: relative datetime (a small fraction of a second)
227+> `@dr`123
228+~s0..0000.0000.0000.007b
229+
230+:: address mnemonic (ship name)
231+> `@p`123
232+~rux
233+
234+:: IPv4 address
235+> `@if`123
236+.0.0.0.123
237+
238+:: IPv6 address
239+> `@is`123
240+.0.0.0.0.0.0.0.7b
241+```
242+
243+A cell is a pair of two nouns, and of course many compound types exist, including lists (a null-terminated series of cells). A file path in Urbit is, for instance, a list of resource names (a `path`). A manipulable text string is a list of single bytes for characters (a `tape`). Maps (associative arrays), sets, and other containers round out the basic data structure types, but more complex types such as HTTP headers and app metadata are available. Even app actions have an associated type so that the set of actions is enumerable and validated. Here, for instance, are some cryptographic types from the standard library:
244+
245+```hoon
246++$ jacobian [x=@ y=@ z=@] :: jacobian point
247++$ point [x=@ y=@] :: curve point
248++$ domain
249+ $: p=@ :: prime modulo
250+ a=@ :: y^2=x^3+ax+b
251+ b=@ ::
252+ g=point :: base point
253+ n=@ :: prime order of g
254+ ==
255+```
256+
257+Hoon expressions are ultimately binary trees of cells and atoms—Hoon is homoiconic and so code is directly represented as a data structure which can be interpreted as a value as well. This facilitates Hoon's ability to upgrade itself in place, as we will see.
258+
259+Hoon commonly implements types structurally via _molds_, or functions which coerce to type or crash. A mold is a way of asserting known type information over a value, typically at compile time, in a way that allows for data transformation and data validation. This leads to some interesting cases such as the difference between a null-terminated tuple and a true list, which some functions require.
260+
261+```hoon
262+> ~[1 2 3]
263+[1 2 3 ~]
264+
265+> `(list @)`~[1 2 3]
266+~[1 2 3]
267+
268+> (snag 2 ~[1 2 3])
269+mull-grow
270+-need.[i=@ud t=%~]
271+-have.%~
272+nest-fail
273+dojo: hoon expression failed
274+
275+> (snag 2 `(list @)`~[1 2 3])
276+3
277+```
278+
279+Hoon implements a unique character literal syntax for every single atom type, allowing any value to be unambiguously interpreted by the parser per the developer's intent. You can see this somewhat in evidence in this comparison chart:
280+
281+| Type | Lisp Type | Hoon Type |
282+| --- | --- | --- |
283+| (Unsigned) integer | `1` | `1` |
284+| Signed integer | `-1`, `1` | `-1`, `--1` |
285+| Symbol | `x` | `%x` |
286+| Real/FP | `1.5` | `.1.5` |
287+| Character | `#\c` | `'c'` |
288+| Text | `"Hello"` | `'Hello'` (as atom); `"Hello"` (as list) |
289+| Rational | `2/3` | (no Hoon equivalent) |
290+| Address | (no Lisp equivalent) | `~sampel-palnet` |
291+
292+Much of Hoon's practical power derives from how it represents and manipulates nouns as data and as code.
293+
294+> The type of type is just a normal datatype in Hoon, and a lot of the system manipulates types. In particular, the `!>` rune, when applied to a piece of data, uses compile-time type reflection to produce something called a "vase": a pair of type and data, similar to a `Data.Dynamic` in Haskell, or a limited form of a dependent pair. Since the Arvo kernel does a lot of dynamic compilation, it uses vases to implement something akin to a dynamically typed language using Hoon. This allows for type-safe dynamic program loading, program execution, and data migration. (Ted Blackman ~rovnys-ricfer, [“Why Hoon”](https://urbit.org/blog/why-hoon))
295+
296+A `vase` in Hoon is a cell of type and value. Typically `vase`s are produced with the `!>` zapgar rune. We use `vase`s to carry type information where otherwise it may be lost, such as in transmission over the wire to another Urbit instance.
297+
298+```hoon
299+> !>('hello')
300+[#t/@t q=478.560.413.032]
301+
302+> !>([5 10])
303+[#t/[@ud @ud] q=[5 10]]
304+
305+> !>(`(list @)`~[1 2 3])
306+[#t/it(@) q=[1 2 3 0]]
307+
308+> !>(`(list @)`~)
309+[#t/it(@) q=0]
310+```
311+
312+A `vase` can be used at runtime to resolve a value from a dynamic context into an executable Hoon expression, and this is commonly done with web-based input, for instance, where insufficient information will be available at compile time to resolve the type correctly.
313+
314+#### Expressions
315+
316+Nock explicitly consists of binary trees, since any Nock structure or program consists entirely of atoms (bare values) and cells (pairs of nouns).
317+
318+![](https://storage.googleapis.com/media.urbit.org/docs/userspace/hoon-school/binary-tree.png)
319+
320+Expressions are oriented around runes, which act as operators to join or manipulate expressions. To construct a cell of two values like `1` and `2`, one uses the `:-` cencol rune. (Hoon cells implement what we call an “implicit `cons`”, meaning that two nouns composed together are simply unified in a shared binary tree.)
321+
322+```
323+ :-
324+ / \
325+1 2
326+```
327+
328+To invoke a function named `add`, one can provide a `%-` cenhep rune with the function name and the arguments.
329+
330+```
331+ %-
332+ / \
333+add :-
334+ / \
335+ 1 2
336+```
337+
338+We write this Hoon expression one of two ways, either separated by whitespace or using parentheses:
339+
340+```
341+> %- add :- 1 2
342+3
343+
344+> %-(add :-(1 2))
345+3
346+```
347+
348+Hoon employs “sugar syntax” for many common code patterns to make them easier to write and (sometimes) to read. Since Hoon had the advantage of knowing about Lisp's syntax beforehand, the standard invocation syntax in Hoon (formally a `%` rune) uses the irregular `()`-based syntax like Lisp. In this case, we could instead write the Lisp-like expression:
349+
350+```hoon
351+> (add 1 2)
352+3
353+```
354+
355+which results in basically the same expression once the parser is done.
356+
357+(Although Hoon ultimately compiles to Nock, it is more natural in some ways to approach the syntax of a program as an array of $n$-ary trees, where each “slot” in an expression can have zero, one, or many children. Zero children refers to a tree address containing a terminal value like a symbol or an integer.)
358+
359+Rune syntax is Hoon's answer to the Lisp proliferation of parentheses—by restricting expressions to a definite number of children, Hoon avoids needing to explicitly terminate most expressions. In some ways, runes are an ASCII-based equivalent of APL's symbolic character operators.
360+
361+```apl
362+life ← {⊃1 ⍵ ∨.∧ 3 4 = +/ +⌿ ¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂⍵}
363+```
364+
365+Rather than permit polymorphic language statements, Hoon requires each rune to be extremely tightly defined. While many statements may be functionally equivalent to an `if` or a `cond` statement, for instance, Hoon allows the developer to select a particular expressive rune if desired.
366+
367+- `?:` typical `if`/`then`/`else` branch
368+- `?=` branch on type
369+- `?@` branch if atom
370+- `?^` branch if cell
371+- `?+` switch on type with default
372+- `?-` switch on type without default
373+- `?~` branch if null
374+
375+The next examples explore an interesting difference between Lisp `cond` and Hoon `?+` wutlus swtich statements: Hoon switches over _types_ not _values_, and `term` symbols as constants are instances of self-matching types.)
376+
377+```scheme
378+(define (weather f)
379+ (cond ((> f 80) 'too-hot)
380+ ((> f 60) 'nice)
381+ ((< f 35) 'too-cold)
382+ (else 'typical-midwest)))
383+```
384+
385+```hoon
386+|%
387+++ weather
388+ |= f=@ud
389+ ?: (gth f 80) %too-hot
390+ ?: (gth f 60) %nice
391+ ?: (lth f 35) %too-cold
392+ %typical-midwest
393+++ symbol-to-message
394+ |= msg=term
395+ ?+ msg 'Typical Midwest'
396+ %too-hot
397+ 'Too hot outside'
398+ %nice
399+ 'Nice outside'
400+ %too-cold
401+ 'Too cold here'
402+ ==
403+--
404+```
405+
406+Lisp expects a program to be a running series of expressions, naturally composed together as a list. Hoon, in contrast, expects everything to be an evaluable expression (no implicit `progn`, for instance): thus, series of expressions must be composed together, e.g. using `=>` tisgar to concatenate two expressions.
407+
408+This code example defines an expression and immediately evaluates another expression against it:
409+
410+```hoon
411+=> [a=1 b=2 c=3]
412+::
413+b
414+```
415+
416+Hoon code is compiled to Nock, but it is not a simple macro over Nock—multiple Hoon expressions could result in an identical Nock expression, and the same Hoon expression evaluated against different subjects could result in different Nock expressions. Hoon code is parsed to an abstract syntax tree first, which includes type metadata, then compiled into the appropriate Nock statement. Here we use the `!,` zapcom rune to turn a Hoon expression into its AST, then `!=` zaptis to compile a Hoon expression to Nock.
417+
418+```hoon
419+> !,(*hoon `@ux`+(1))
420+[ %ktls
421+ p=[%sand p=%ux q=0]
422+ q=[%ktls p=[%sand p=%$ q=0] q=[%dtls p=[%sand p=%ud q=1]]]
423+]
424+
425+> !=(`@ux`+(1))
426+[4 1 1]
427+```
428+
429+Hoon has much more syntactic sugar than Lisp. Not only is the Lisp-like `()` execution convention sugar for `%:` cencol to invoke a function, there are in fact many ways to evaluate code expressions. Consider, for instance:
430+
431+| Rune | Usage |
432+|---|---|
433+| `%-` | Evaluate a function against a single noun. |
434+| `%+` | Evaluate a function against a cell (pair of nouns). |
435+| `%^` | Evaluate a function against a trio of nouns. |
436+| `%:` | Evaluate a function with many arguments ($n$-ary, unspecified number of nouns). |
437+| `%~` | Evaluate a higher-order function to produce a function. |
438+
439+This gives a Hoon developer an extreme amount of flexibility in constructing and laying out code expressions. In fact, many Hoon programs read as a hybrid of imperative code and functional code, since the ability to lay out intent line-by-line feels rather like C.
440+
441+Hoon conventions and sugar syntax have evolved organically as core developers discovered or invented useful design patterns and appropriately concise syntax.
442+
443+#### Functions (Gates) and Cores
444+
445+The most important structural concept in Hoon is the core, which organizes code into a binary tree of `[code data]`, or as we call it in Hoon, `[battery payload]`. Since cores have a standard structure, this means that many kinds of direct manipulations (metaprogramming) are possible, such as altering the input arguments to a function or manipulating the code variance model. Cores play a role in Hoon similar to that of objects in many other languages.
446+
447+Any function (“gate” in Hoon parlance) is a core, whose `battery` is the compiled Nock code and whose `payload` includes its view of the system, including the standard library, and its input arguments. The `|=` bartis rune is most commonly used to make a gate:
448+
449+```hoon
450+:: Select the larger of two values ("max").
451+|= [a=@ b=@]
452+?: (gth a b)
453+ a
454+b
455+```
456+
457+The gate definition rune `|=` bartis has two children, a specification of the expected input and the expression. When invoked, the values of the specification (or "sample") are provided to the expression, which then evaluates to return a noun.
458+
459+One quirk of Hoon is that since everything is an address (or “axis”) in a binary tree, you can access anything in your scope (“subject”) through its axis. Most commonly you attach a face to a value (like a gate), but you don't have to. At any point, to refer to the previous statement, you can invoke the head of the tree, `-`; to wit,
460+
461+```hoon
462+> =/ a 5
463+ -
464+a=5
465+```
466+
467+The name `a` is also attached to the value and can be used to identify the value. (To the Hoon parser there is no real difference; this is a programmer quality-of-life affordance.)
468+
469+```hoon
470+> =/ a 5
471+ a
472+5
473+```
474+
475+Thus faces (names) are attached to gates (functions) within a particular scope or context, such as a `|%` core. Each core defines a collection of values and gates (collectively termed “arms”) which occupy a shared scope. For example, the following library demonstrates a few floating-point operations in Hoon. Each function can see the parent subject (including `hoon.hoon` and some other cores) as well as its neighboring arms (such as `++pow-n` called by `++exp`).
476+
477+```hoon
478+|%
479+:: Factorial, x!
480+++ factorial
481+ |= x=@rs
482+ =/ t=@rs .1
483+ |- ^- @rs
484+ ?: =(x .1) t
485+ $(x (sub:rs x .1), t (mul:rs t x))
486+:: Absolute value, |x|
487+++ absolute
488+ |= x=@rs
489+ ?: (gth:rs x .0) x
490+ (sub:rs .0 x)
491+:: Exponential function, exp(x)
492+++ exp
493+ |= x=@rs
494+ =/ rtol .1e-5
495+ =/ p .1
496+ =/ po .-1
497+ =/ i .1
498+ |- ^- @rs
499+ ?: (lth:rs (absolute (sub:rs po p)) rtol) p
500+ $(i (add:rs i .1), p (add:rs p (div:rs (pow-n x i) (factorial i))), po p)
501+:: Power, restricted to integeres only, x**n
502+++ pow-n
503+ |= [x=@rs n=@rs]
504+ ?: =(n .0) .1
505+ =/ p x
506+ |- ^- @rs
507+ ?: (lth:rs n .2) p
508+ $(n (sub:rs n .1), p (mul:rs p x))
509+--
510+```
511+
512+Ultimately, however, the faces resolve back to an axis and the code is composed by the compiler into a Hoon syntax tree and thence to Nock for the runtime interpreter.
513+
514+The nature of cores derives from Nock and is key to understanding how Hoon works. All nontrivial structures in Hoon are cores. For instance, even a gate is a regular `|%` core, with `|=` expanding to `|%`. The following code snippets are identical to the Hoon compiler after parsing.
515+
516+```hoon
517+:: increment a number by two
518+|= p=@ud
519++(+(p))
520+```
521+
522+```hoon
523+:: increment a number by two
524+=+ ^~(*p=@ud)
525+|%
526+++ $
527+ +(+(p))
528+--
529+```
530+
531+Although Lisp's `'` quoting has no direct equivalent in Hoon, there are a couple of structures that can provide a similar effect. The most important of these is the `|.` trap, which defines an expression to be evaluated at a later time—Hoon’s equivalent of Lisp’s thunk. For instance, traps are used when testing code that _should_ fail, as the expression can be defined and deferred until the test framework is ready to process it.
532+
533+```hoon
534+> =foo |.((add 1 41))
535+
536+> -:foo
537+[8 [9 36 0 2.047] 9 2 10 [6 [7 [0 3] 1 1] 7 [0 3] 1 41] 0 2]
538+
539+> (foo)
540+42
541+```
542+
543+(To understand the second entry, recall that code is the in head of the core—here, we see the Nock code for the operation defined in the `|.` trap.)
544+
545+[Wet gates](https://developers.urbit.org/guides/core/hoon-school/R-metals) present the most macro-like feature in Hoon. A regular function, or “dry gate” (as above), receives an argument (the sample); the type system tries to cast the sample to the type specified by the gate, and fails if not possible. Wet gates instead defer type evaluation and instead attempt to use the sample (or arguments) directly in the expression. This produces a parametric polymorphism. (This comes close to dynamic typing, but type is still checked at compile time.) Wet gates are commonly used as gate-building gates, such as mold-producing gates like `++list`.
546+
547+Consider a function like `++turn` which transforms each element of a list.
548+
549+```hoon
550+> `tape`(turn ~[77 97 114 115] @t)
551+"Mars"
552+```
553+
554+To use `++turn`, we need a list and a transformation function. The type of the list we produce depends on the type of the list and the type of the transformation function. The actual gate `++turn` should work to transform each element of the list for on any function and any list, so long as the function's argument is the list item.
555+
556+Wet gates are therefore used when incoming type information is not well known and needs to be preserved. This includes parsing, building, and structuring arbitrary nouns. (Beyond Lisp analogues, you can think of C++'s templates and operator overloading, and Haskell's typeclasses.)
557+
558+This example compares the Lisp deferred factorial thunk with an equivalent Hoon trap. (Hoon includes `++factorial` since it is not part of the standard library.)
559+
560+```scheme
561+(defun create-thunk (function &rest arguments)
562+ (lambda () (apply function arguments)))
563+
564+(defun invoke-thunk (thunk)
565+ (funcall thunk))
566+
567+;; Creating a thunk that calculates the factorial of a number
568+(defvar factorial-thunk (create-thunk #'(lambda () (factorial 5))))
569+
570+;; Invoking the thunk to get the result
571+(print (invoke-thunk factorial-thunk)) ; Output: 120
572+```
573+
574+```hoon
575+=>
576+|%
577+++ factorial
578+ |= n=@ud
579+ |-
580+ ?: =(n 1) 1
581+ %+ mul n
582+ %= $
583+ n (dec n)
584+ ==
585+++ factorial-5
586+ |. (factorial 5)
587+--
588+(factorial-5)
589+```
590+
591+### Subject-Oriented Programming
592+
593+Urbit programming employs a paradigm deriving from the nature of Nock (_a fortiori_ Hoon), subject-oriented programming. Every expression of Hoon is evaluated relative to its subject, a piece of data that represents the environment, or the context, of an expression.
594+
595+The subject refers to the parent binary tree of an expression, more or less, and serves as state, lexical scope, environment, and function argument. (We can be precise about the definition in all cases—e.g. the subject of a gate in a core is the core itself—but don't need to for this essay.) Lisp supports variable scope and global variables, such that any part of the program can access a particular binding. Hoon's subject-oriented programming model naturally provides its equivalent of scope: all code is evaluated against a subject and name bindings proceed by depth-first match (with permitted skips to prevent unwanted masking).
596+
597+> Subject orientation in Nock and Hoon stems partly from minimalism (there's just one subject, which serves as state, lexical scope, environment, and function argument), partly from a desire to simplify compilation (the type of the subject is a full specification of the compile-time environment for a source file), and partly in order to give the language a more imperative feel.
598+>
599+> Everything about a scope, including name bindings, aliases, and docstrings, is stored in the subject's type. This allows Hoon's compilation discipline to be similarly minimal: the compiler is a function from subject type and Hoon source to product type and compiled Nock. Running this Nock against a value of the subject type produces a vase of the result. It's hard to imagine a more streamlined formalism for compilation. (Ted Blackman ~rovnys-ricfer, [“Why Hoon”](https://urbit.org/blog/why-hoon))
600+
601+The subject is typically the core in which an expression is evaluated, but can be more narrowly defined; consider, for instance, our example from above:
602+
603+```hoon
604+=> [a=1 b=2 c=3]
605+::
606+b
607+```
608+
609+A slightly different program fails:
610+
611+```hoon
612+=> [a=1 b=2 c=3]
613+::
614+(add a b)
615+```
616+
617+because the `++add` gate is not defined in the subject against which the expression is evaluated, the first statement.
618+
619+### Comparative Examples
620+
621+#### Find in List
622+
623+```scheme
624+(define index-of
625+ (lambda (needle haystack)
626+ (let ((tail (member needle haystack)))
627+ (if tail
628+ (- (length haystack) (length tail))
629+ (throw 'needle-missing)))))
630+```
631+
632+```hoon
633+:: Produces the index of the first occurrence of nedl in hstk
634+:: as the unit of an atom.
635+++ find
636+ |= [nedl=(list) hstk=(list)]
637+ =| i=@ud
638+ |- ^- (unit @ud)
639+ =+ [n=nedl h=hstk]
640+ |-
641+ ?: |(?=(~ n) ?=(~ h))
642+ ~
643+ ?: =(i.n i.h)
644+ ?~ t.n
645+ `i
646+ $(n t.n, h t.h)
647+ ^$(i +(i), hstk +.hstk)
648+```
649+
650+#### Filter a List
651+
652+```scheme
653+(define filter
654+ (lambda (fn lst)
655+ (let iter ((lst lst) (result '()))
656+ (if (null? lst)
657+ (reverse result)
658+ (let ((item (car lst))
659+ (rest (cdr lst)))
660+ (if (fn item)
661+ (iter rest (cons item result))
662+ (iter rest result)))))))
663+```
664+
665+```hoon
666+:: Cycle through the members of a list a, passing them to a gate b
667+:: and produce a list of all of the members that produce TRUE.
668+++ skim
669+ |* [a=(list) b=$-(* ?)]
670+ |-
671+ ^+ a
672+ ?~ a ~
673+ ?:((b i.a) [i.a $(a t.a)] $(a t.a))
674+```
675+
676+- Several examples in the above section were drawn from [UW's CSE 341 course notes](https://courses.cs.washington.edu/courses/cse341/03wi/scheme/basics.html) and from [Rosetta Code](https://rosettacode.org/).
677+
678+
679+## Metaprogramming
680+
681+A Lisp program is really a list, or a list of lists (nested as much as necessary). While this can be interpreted as an $n$-ary tree, tree structure is not the preferred structural metaphor. A Hoon program is a noun, or equivalently a binary tree. Every component of it is directly addressable and thus in principle reflective. Both languages are homoiconic, with code and data representations being the same. What are the consequences of homoiconicity?
682+
683+### Metaprogramming in Lisp
684+
685+Metaprogramming is the practice of writing code that manipulates other code at either compile-time or runtime. In Lisp, metaprogramming is a core feature of the language, and it allows developers to create programs that are incredibly powerful and flexible. Lisp's metaprogramming capabilities are primarily built on two features: macros and syntax manipulation.
686+
687+Macros in Lisp are a way to define new language constructs that are more expressive and more powerful than those provided by the language itself. When a Lisp program is compiled or interpreted, macros are expanded into regular Lisp code, allowing the macro to generate new code based on its input arguments. Since Lisp code is represented as data, it can be manipulated using the same functions and operators used to manipulate other data structures.
688+
689+For instance, Lisp macros could allow you flexibility in expressing a common operation. Imagine you're working on a project that requires a lot of complex math calculations. Rather than writing out each calculation manually, you could define a macro that takes an expression in infix notation (e.g. `2 + 3 * 4`), and transforms it into a Lisp expression that can be evaluated directly. Thus you could compose math expressions in a more human-natural way without having to worry about details of Lisp syntax.
690+
691+Lisp can also manipulate its own syntax. This is sometimes done through the use of reader macros, which operate at the level of the Lisp reader, which is responsible for converting textual input into Lisp expressions. Reader macros can be used to extend the syntax of Lisp, allowing developers to define new conventions or domain-specific languages for specific types of data or operations. Beyond reader macros, Lisp can permit the developer to change the parser (and as long as the result is a Lisp expression, the interpreter or compiler will be fine with this). Top-level functions can be replaced or modified (“advised”). Symbol macros can change source code.
692+
693+Lisp's `'` quote and the `eval` statement allow single expressions to be inhibited or evaluated at will, which is incredibly useful when dealing with symbols that may not be defined yet or in the composition of macros.
694+
695+In addition to macros and syntax manipulation, Lisp dialects typically provide a number of other features that make metaprogramming easier, such as the ability to inspect and modify the runtime environment, and the ability to create or redefine functions and classes at runtime.
696+
697+### Metaprogramming in Hoon
698+
699+While Hoon explicitly avoids macros and domain-specific language specializations, there are many aspects of Hoon which allow or exploit code reflection and manipulation.
700+
701+In practice, Hoon is intended as a systems programming language for the Urbit Nock VM. Hoon's metaprogramming has as a consequence mainly focused on aspects of core manipulation (such as code building and wet gates) and on live code upgrades (what I'll call hot-swapping code). Hoon eschews macros and in particular has a philosophical stance against domain-specific languages (DSLs). (There are some exceptions, notably Sail, Hoon's XML/HTML syntax; and JSON reparsing.)
702+
703+Hoon has the ability to parse arbitrary text strings (typically files) into executable ASTs and Nock. Symbols can be directly converted to and from regular text strings.
704+
705+As the programming language for a “hundred-year computer”, Hoon needs the ability to hot-swap code at runtime. Elements of cores can be removed or replaced. (Really, Hoon code is immutable: the system is actually making a copy with a specified change.) Every app and even the OS itself can define a state transition function and upgrade along a deterministic pathway.
706+
707+Hoon is in principle extremely reflective as it simply compiles to a Nock noun. Since everything is a stationary tree, it is straightforward to manipulate any object. There are no magic binary blobs or opaque data types: if you have a file handle or an Ethereum block or a websocket connection object, it is a tree and you can work with it directly. (Cf. [“Why Hoon”](https://urbit.org/blog/why-hoon).) Obtaining—or changing—details about gate sample or core behavior becomes a routine part of the Hoon developer’s toolkit. Given such regularity, it would be desirable to expose further capabilities of code reflection and introspection explicitly for the interpreter and IDE.
708+
709+One of the most common design patterns in Hoon is that of the higher-order function, or what Hoon calls “gate-building gates”. These are gates (functions) that produce gates (functions). For instance, as Hoon is statically typed a list must have an associated element type at compile time. `++list` is a gate builder that produces a type gate, which can then be applied to the actual values:
710+
711+```hoon
712+list :: gate builder
713+(list cord) :: gate for list of cords (strings)
714+`(list cord)`~['a' 'b' 'c'] :: list type applied to value
715+```
716+
717+Hoon represents a “hyperlambda” with respect to anonymous function creation: one very often defines gates at their point of use, particularly when operating on each member of a list or set. Similar to Lisp's frequent use of `lambda`, the one-time-use function is available at the point of call as an anonymous gate. (More generally, every gate is anonymous and we have to attach a name to it as a search path, but that's a bit out of scope here.)
718+
719+```scheme
720+((lambda (x1 x2)
721+ (* (- x1 x2) (- x1 x2)))
722+ 2 -5)
723+```
724+
725+```hoon
726+%- |= [x1=@ x2=@]
727+ (pro:si (dif:si x1 x2) (dif:si x1 x2))
728+[--2 -5]
729+```
730+
731+Like Lisp, Hoon yields a lot of power to the user–developer. One could implement a fairly regular Lisp on top of Hoon with very few changes—and perhaps even implement a pure-Hoon discipline yielding a statically-typed Lisp à la TypeScript from JavaScript.
732+
733+- [~tacryt-socryp, “Hick, a more traditional Lisp than Hoon”](https://gist.github.com/tacryt-socryp/b08dc66b7bcc760e914c4db5c9fd7ba7)
734+
735+
736+## Philosophy
737+
738+Hoon's focus on atoms, static typing, and symbolic expressions make it a highly expressive and efficient language for building applications on the Urbit platform, while Lisp's flexible syntax and macro system make it a popular choice for a wide range of programming tasks.
739+
740+Lisp has evolved greatly since John McCarthy's founding. Like Unix, a complicated family tree has finally settled down into a few strong contenders: Scheme, Common Lisp, Clojure, Racket.
741+
742+Lisp has tended to be fractious: as many have noted, and [Mark Tarver eloquently expressed](http://web.archive.org/web/20080803193859/http://www.lambdassociates.org/blog/bipolar.htm), the Lisp platform appeals to idiosyncratic visions for completist platforms. There's a looseness in the community's coherence as a result.
743+
744+For a few reasons, the Urbit community has managed to avoid such splintering (the [Urbit Classic joke](http://urbit-classic.org/) aside). With a single sponsoring organization, first Tlon Corporation and since 2022 the Urbit Foundation, to steward the ecosystem and a philosophical commitment to protocol-as-platform, Urbit should avoid partition into competing bazaars.
745+
746+Urbit's governing philosophy as a technical program is laid out in the [Precepts](https://urbit.org/blog/precepts). A sampling:
747+
748+> A.13. If you don't completely understand your code and the semantics of all the code it depends on, your code is wrong.
749+
750+> A.16. Explicit state is better than implicit state.
751+
752+> A.20. One hundred lines of simplicity is better than twenty lines of complexity.
753+
754+> D.3. Not being qualified to solve a problem is no reason not to solve it.
755+
756+There is significant overlap here with the ideals of the Lisp developer community present. Scheme like Hoon aims at minimalism and ample use of lambda expressions. [Clojure](https://www.clojure.org/about/rationale) aims at strengthening Lisp by building it on a modern platform (the JVM); it would agree with Urbit's disdain for nondeterminism: “pervasive, unmoderated mutation simply has to go”. Racket was designed for production systems and to some extent with a hope to unify parts of the developer stack.
757+
758+In many ways, Hoon is more Lisp-y than Lisp: that is, it represents a point more polar towards the telos of Lisp than any extant Lisp. By shedding the skin of lists and focusing on binary trees, Urbit achieves a deeper conceptual unification within itself. Hoon doesn't properly supersede Lisp—it requires running on a particular VM architecture, for instance—but Hoon's focus on typing, the nature of Hoon's binary-tree homoiconicity, and its employment of pure functional concepts make it a strong new tool for those to whom Lisp already appeals.
759+
760+Hoon goes farther than Lisp, however. Hoon is an accessible and practical, if unconventional, tool for simplifying the developer stack, ultimately to a single language. Ultimately, Urbit is a technical project to encode human digital freedom into the very protocol we use—with Hoon its nose-to-tail _lingua franca_. Hoon carries the torch that Lisp kindled into a new user-oriented future.
761+
762+To close, I quote Urbit Foundation CTO Ted Blackman on why Urbit follows its particular design discipline:
763+
764+> The promise of Urbit lies in its reimagination of the digital world using components that are as constrained and limited as possible. By adhering firmly to principle and doubling down on minimalism at every turn, we get an OS that provides far stronger guarantees than Unix with a thousand times less code. Given the complexity of modern software, this is what's required to put personal computing back into the hands of people. (Ted Blackman ~rovnys-ricfer, [“Why Hoon”](https://urbit.org/blog/why-hoon))
content/blog/hosting-the-future.md−4
@@ -9,12 +9,8 @@ ship = "~simfur-ritwed"
99image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/200930-hosting-by-tlon.jpg"
1010+++
1111
12−<br>
13−
1412![Ocean](https://storage.googleapis.com/media.urbit.org/site/posts/essays/200930-hosting-by-tlon.jpg)
1513
16−<br>
17−
1814Urbit users tend to be interesting, creative, and capable people; we’re genuinely impressed with the communities that have formed on the network, and with the quality of discourse there. But for the number of communities to continue to grow, getting on the network has to become dramatically easier. It’s not realistic to expect most people to configure their own Urbit OS node in the command line.
1915
2016At the moment, the biggest lever we have here is to help ordinary users get online, so they can participate in communities inside Urbit, and eventually form their own. This means hosting their Urbit nodes and showing them around the network when they first arrive. There are already several businesses overlapping with this space to varying degrees: [planet.market](https://planet.market/), [urth.systems](https://urth.systems/), and [geturbitid](https://www.geturbitid.com/). Now, Tlon is releasing its own hosting offering. For the uninitiated, “Hosting” just means that we run your urbit ship for you, making it easier for you to get onto the network. We’ve been testing our hosting service with friends and family for the past few months, and now we’re ready to bring it to the rest of the world.
content/blog/immunology-for-the-internet-age.mdnew file+118
@@ -0,0 +1,118 @@
1++++
2+title = "Immunology for the Internet Age"
3+date = "2022-04-07"
4+description = "A consideration of the history of the Internet motivates introspection on the nature and causes of social dysfunction in a globally shared space. Centralized solutions fail to yield satisfactory outcomes for human freedom and thriving. Decentralized autonomous organizations and their technological apparatus together represent the evolution of an immune system against a corporatized Internet."
5+[extra]
6+author = ""
7+ship = "~lagrev-nocfep"
8+image = "https://live.staticflickr.com/4322/35891780782_4179f476f9_k.jpg"
9++++
10+
11+_A version of the following was presented by ~lagrev-nocfep at the [MTAConf 2022 conference on “The Decentralization of Power”](https://www.mtaconf.org/)._
12+
13+**✿**
14+
15+IN THE BEGINNING, _God created the prokaryotes. And the prokaryotes were without nucleus and organelle; and structural simplicity was upon the face of the deep. And chemotaxis moved it upon the face of the waters._
16+
17+A single-celled organism possesses many advantages, notably simplicity of form. Being largely indistinguishable, they have no differentiation or specialization. Prokaryotes often form large colonies, such as the cyanobacteria. Some prokaryotes discovered early on that it paid better to consume resources that had already been processed into usable form by another cell, rather than to process those resources oneself. Thus predator and prey were born, and they have always exemplified divergent competitive evolutionary strategies. The resulting arms race meant that predators were continually adapting to better extract resources from prey, while prey were evolving to evade, resist, fight, or poison predators. Selection pressures applied at individual, species, and clade levels, lead to speciation across deep time.
18+
19+More complex forms seemed better able to evade predators, and thus simple symbiotic alliances between differentiated prokaryotes evolved into the eukaryotes (yielding specialized features such as the nucleus and mitochondria) and multicellular life forms. Simpler forms also abounded, including the liminal virus. Viruses are forms of near-life so simple that they simply exploit cells to reproduce. They are entirely predatory or at best symbiotic with other life. Evasion of pathogenic disease, or disequilibrated colonization by simpler forms of life, has been a---if not the---primary driver towards increasing complexity in multicellular life.[^1]
20+
21+**✿**
22+
23+The Internet began in the late 1960s, born of scientific alliance between the Cold War Department of Defense and the academic research community.[^2] This community had a signal advantage over many subsequent communities: it was dominated by strong norms of discourse which shaped the professionalism of the community. This is not to discount the significance of courtly intrigue, of course, which deftly exploited tensions between competing systems.[^3].
24+
25+Throughout this era, though, the Internet generally functioned as a real-name high-trust environment---if not exactly of peers, at least of colleagues.
26+
27+The Internet evolved as a coordination mechanism---literally a nervous system incarnate in copper and silicon---particularly through the Usenet days of the 1980s. In our days of heightened online tension and mediated preference cascades, it is rather quaint to go back and look at what qualified as email flame wars at the time (e.g. Torvalds/Tanenbaum). One hallmark of the Usenet era, however, is a gradually eroding social trust: spam was invented[^6] and Internet-based scams started to spin up.
28+
29+Pseudonymity gained in popularity as a countermeasure to both of these as well as restrictions on discourse. The revelation that persistent digital records could cost someone's job further fueled a cyberpunk-like obsession with identity control and hacking.[^7]
30+
31+Computer viruses could propagate for the first time: it never made much sense to build a computer virus until systems were connected. Although John von Neumann and others early explored the possibility of mathematical or code structures which could self-replicate, it was not until the Creeper virus in the 1970s that self-replicating code was observed in the wild. And like a bacillus in an immune system-free host, code-based computer viruses began to spread from the 1980s onwards.
32+
33+The crisis arrived in the form of the World Wide Web. Founded initially on a belief in the democratization of information, the Web rapidly became dominated by a handful of large corporations (henceforth "megacorps"). User experience became the predominant driver of adoption, leading to rapid preference cascades as new platforms became available. Any child of the 90s or earlier can recite the lived litany: Ebay, MySpace, Friendster. Initially these served as proofs-of-concept, then became the only significant player (until the next killer app came along). Search engines drove discovery, then focused attention asymmetrically. The "walled garden" approach of AOL, then Apple and Facebook, led to concentrations of users which tipped the balance from single webpage hosts presenting their own idiosyncratic views to corporate-approved genericity and ultimately censorship.[^8]
34+
35+**✿**
36+
37+When was the first time you did something in the physical world because of something you read or encountered online? For generations born after the advent of the Web, they may not recall such a time when meatspace existence wasn't driven by life online. As Internet data sources have overwhelmed traditional media, publishing, and distribution services, the resulting tsunami of information and informatization has swept into every corner of lived human experience in technological societies. The psychological (memetic) virus problem is much greater than actual code viruses. The ongoing universal exposure to alien and internally incoherent value systems has undergirded the well-documented crisis of credibility (collapse of meaning) that all Western institutions are experiencing today. The World Wide Web and its technological predecessors acted as a cultural petri dish of clean agar, which grew every spore and germ which fell upon it. We live in the midst of a memetic epidemic because of the World Wide Web, and the dominant strain is corporate, approved by a marketing department and run through a search-engine optimization algorithm.
38+
39+The turn towards a low-trust then zero-trust environment was inevitable if anything like an analogy with prokaryotic evolution holds true. The megacorp platforms are in a way worse than a purely zero-trust environment, because they don't advertise that the world is zero-trust. Thereby they lure the unwary into transgressing arbitrary global norms and courting the wrath of social media mobs and the concomitant loss of access to their data held in "trust." To mix a metaphor, megacorps are apex predators---at best, sheepdogs with a strong strain of wolfishness; at worst, tar pits manned by various bad-faith actors. The pre-Web cypherpunks were right: "Privacy is the power to selectively reveal oneself to the world."[^9]
40+
41+If anything, they were too narrow; not only their valued "open society" (polyvalent crypto-anarchy) but _any_ non-megacorp society at all requires true privacy.
42+
43+What cyberspace (and human culture writ broadly) needed was an immune system---and in good Darwinian form, such an immune system has been evolving before our eyes. An immune system formally consists of layers with increasing specificity: first surface barriers, then the innate immune system, and finally the adaptive immune system. The objective of the immune system is to protect the organism: in this case, human sociality and agency.
44+
45+First, what is human sociality? Human culture has been the means of participating in the Great Discussion which ranges from the earliest days of oral culture to the birth of literacy and libraries down to our day. High culture and low culture have both articulated and preserved valuable insights and forms of human flourishing. However, throughout the 20^th^ century and particularly by the means of the consumer revolution, our lives have been thoroughly colonized by capital and commercial instruments. So-called "economies of scale" have disrupted smallholders, artisans, and shopkeepers to the extent that these have been virtually eradicated from the modern landscape in favor of the plastic and polluting "dark Satanic mills." Although small-scale "provident living" has supported gardening, canning, and home production, none of this has survived across a large enough cultural segment to matter macroscopically, and it has unfortunately been tarred with the "prepper" brush that delegitimizes economic downsizing as antisocial because anticapitalist. The siren call of cheap consumer goods has ushered in a generational collapse in self-sufficiency and resulted in the complete colonization of entertainment, food consumption, and self-care by massive corporate brands. Not only have physical goods entered a post-consumer phase, but only certain classes of ideas, attitudes, political stances, regional accents, and sensibilities enjoy the sanction of megacorp sociality. There is essentially no native culture left, only that forged in the enterprise brand management office.[^10]
46+
47+In an immune system, _surface barriers_ are designed to make it hard for exogenous agents to enter a cell or organism; in our analogy, the primary surface barrier was the match of physical separation to psychological separation. Surface barriers were rendered finally obsolete by the launch of the World Wide Web and its subsequent infiltration of every aspect of human culture. To the extent they exist today, it is a matter of ignorance, self-discipline, or happy accident.
48+
49+The _innate immune system_ responds non-specifically to pathogens. Any immune system must have a way of deciding what is _me_ and what is _not-me_. Framed as an identity problem in a zero-trust environment, users have evolved several ways to uniquely identify agents without reference to legacy systems. Chief among these means is the blockchain, introduced by Bitcoin for control and transaction of digital assets and since much exploited beyond its design intent. Ethereum-based ERC tokens represent tweaks of this identity concept, as do many other blockchain platforms.
50+
51+Identity is still fluid and polysemous, but in certain key instances it is indelibly demonstrable.[^11]
52+
53+The individual actor has the capability to express itself with many public faces or none; one of these typically enjoys government sanction and liability, but it is no more _real_ than the others, only more legible to regulation and taxation.[^12]
54+
55+Another aspect of the innate immune system is the public visibility of code. Open source has developed an ethic of transparency on epistemological grounds (i.e. you have a right to know what code you are running) and practical grounds. (Linus's law: "given enough eyeballs, all bugs are shallow."[^13])
56+
57+The _adaptive immune system_ responds to specific pathogenic incursions. Particular conditions arise, whether through social, regulatory, military, or other requirements, which must be met with specialized forms that are thereafter in evolutionary competition with the external factor. For instance, one megacorp solution to what it perceives as a threat, i.e. unsanctioned memes, is to attempt to mandate the ultimate traceability of any image's provenance.[^14]
58+
59+The Internet immune system thus evolves to further obfuscate legibility and enhance individual control and self-determination by shifting to less-traceable technologies such as the InterPlanetary File System (IPFS). The point is not whether or not a salient technology such as deepfakes, 3D-printed firearms, deviant scientific or political thought, or even the DRM-free sharing of copyrighted material can be contained.
60+
61+The experience with export-grade cryptography has already shown that regulatory attempts ultimately fail.[^17]
62+
63+The philosophical question is what kind of world will evolve (a _fait accompli_ driven by factors beyond any individual or office) and the practical question is how any particular group of actors can preserve their own agency, autonomy, and ambit of action.
64+
65+The first decentralized autonomous organization, "The DAO" (Đ) itself[^18], was created in 2016 as a way of distributing ownership and stake in a joint venture capital fund. Đ was a new form of organization in that it was essentially a mathematical entity, a set of smart contracts on the blockchain to which anyone had access. Đ lived up at least to "decentralized" and "autonomous." No money was held centrally, with token-based authentication yielding the right to vote on projects. Having set the criteria for membership and investment, Đ then operated in truly democratic fashion until an exploit of imperfectly written smart contract code led to theft, crisis, and the reorganization of the Ethereum blockchain itself.
66+
67+While the heirs of Đ serve a role in the current Internet immune system, the original was formed in response to exogenous regulatory concerns, notably ongoing governmental insistence on restricting investment to the already-wealthy. The U.S. Securities and Exchange Commission and other agencies have in place arbitrary investor requirements which would make little sense even if pegged to something like inflation or index rather than the rapidly-devaluing petrodollar. Nominally put in place to protect the naïve from getting scammed, these restrictions have had the pernicious effect of pulling up the ladder behind the _actuel riche_.
68+
69+DAOs have rapidly evolved as a way of distributing ownership and stake in a purely democratic way. (As an aside, the word "democracy" has been much abused, but here I use it in a sense much like the Greek original: the holders of an immutable and indelible token cast their secured votes to govern their society.) DAOs represent a resurgence of the sovereign city-state in new guise. Will this be enough to evade "imperial" aggregates which dominate today's Web?
70+
71+Decentralized autonomous organizations, zero-knowledge cryptographic proofs, cryptocurrencies, proof-of-identity systems, and their as-yet-unborn kin represent the evolution of an immune system on top of the Darwinian churn of the legacy Internet. The stakes are necessarily high: possession is _de facto_ ownership, the other end of the stick from "not your keys, not your coins" (the old cryptocurrency chestnut). The focus is currently on ownership of money, non-fungible tokens, and similar assets, but broadly speaking such systems allow the authenticated ownership of all data and assets one holds, from chat messages to market shares to physical real estate. There may be good reasons to retain the legacy system for some classes of physical or legal artifacts, but at minimum these will be in competition with purely autonomous constructs. (As an aside, I am of the philosophical opinion that legal recognition should not be sought generally for new forms of organization, as any legibility to legacy systems opens new attack surfaces in an immunological sense.) "Code is law."[^19]
72+
73+A decentralized autonomous organization seems to be at least the first two. Having set the criteria for membership, the organization can act as the (distributed, possibly unknown in the zero-knowledge proof sense) stakeholders direct.
74+
75+This form is still somewhat "yeasty" in that like cyanobacteria it acts as an undifferentiated mass. We should expect further innovations in DAO-like entities.[^21] The most salient epithet of a DAO is "decentralized"; one can imagine hierarchical, concentric, or role-specialized DAOs as well as other taxonomically related forms, just as one can imagine progressively less organized instances in a chaos-happy Internet.
76+
77+Like the first mutant with a new gene, Đ itself failed. Many lessons can be drawn from that failure, including the criticality of getting smart contract code absolutely correct ("code is law"), and how to administer a blockchain in the presence of massive fraud. And indeed, what has happened to the blockchain world of decentralized finance? Millisecond differentials in responsiveness lead to huge swings in profitability of transactions. Frontrunner bots watch algorithmically for transactions they can complete faster than the original source, thereby making money on asymmetric knowledge.[^22] Zero-day exploits of code abound, heralding a need for more thorough vetting and more expressive and secure smart contract languages.
78+
79+Blockchains (and thus DAOs via Ethereum) operate as proof-of-work, proof-of-stake, etc. This provides node operators with a way of verifying consensus reality and thereby cementing a record of digital transactions. Future innovations hold forth the possibility of secure proof-of-identity blockchains (such as the Uqbar Layer 1 smart contract blockchain on Urbit[^23]), wherein each node which can provide concrete cryptographic evidence of its identity gets a vote on the consensus.
80+
81+We must consider modern systems to necessarily interact at the pinnacle intensity of competence and competition: any differential advantage that can be exploited to outcompete an adversary not only can be exploited but _should_ be. Illegibility, redundancy, and apposite complexity are allies in the immune fight to maintain identity and ownership in the modern Internet.[^24] Any system which does not have an operational DAO-like layer is immuno­compromised. All tools for the individual and collective need to be architected around a zero-trust adversarial world. They also need to guard the embers of community and enable new growth.
82+
83+In a nutshell, the early Internet was a cocktail party. By the age of Usenet and into the World Wide Web era, the Internet evolved into a player-versus-player defect--defect equilibrium in which brigading, spamming, and anonymity are rational adaptive behaviors. Indeed, anonymity is barely a protection given the lengths to which governments and megacorps go to prevent truly untraceable usage. This approach is adaptive for agencies which have given up on any other model of reality, fundamentally lacking a vision of humans as other than atomized individual krill for the megacorp apex predators: consumers for the consumers. The legacy megacorp Internet has become a crab bucket, always drawing everything back into itself in a dysfunctional and frankly satanic way.
84+
85+Communities built on decentralized Web3 platforms such as Mastodon, Fediverse, and Urbit[^25] have stepped back from the purely PvP world of the globally-namespaced social media Internet. These today have more of a block party feel, wherein one can wander from house to house or room to room and encounter some of the same faces in the same or new guise. Conversations can drop and resume anew in very different locales with largely the same composition. Marrying the underlying cryptographic identity requirements of DAOs to communication tools and databases yields a strong stable solution to the problem of retaining a foothold of personal identity from which to coordinate one's multifaceted digital life. IPFS, Sovrin Foundation, Tim Berners-Lee's Solid, and Urbit all offer their take on this requirement. Even a Signal chat group running its own server is a kind of token-free DAO.
86+
87+Since the Renaissance, essentially all theology has been humanist in nature, concerning itself with how man should live to flourish in this world and inherit in the next. Even secularized descendants enjoin an ethos of ritual behaviors and practices. The social and cultural "stack" (in software parlance) upon which we build provides for a variety, broad or narrow, of human cultural forms. Lately, the variety of forms has been diminishing both by cutting off older forms from the modern world and by cultivating only certain state-legible apex predators[^26] and their preferred ovine repast.
88+
89+Contra this monoculture, the _telos_ of social computing is to recreate the village green, not the penitentiary. Revisiting a thesis from above: "All tools for the individual and collective need to be architected around _using cryptographic proofs to create stable high-trust havens in an otherwise_ zero-trust adversarial world." The village is a stable, long-term tribe well below Dunbar's limit which shares values and assets in common, from which a member occasionally ventures out into the broader social web but always has a home. Every village will grow its own culture, perhaps even its own _cultus_, enabled by decentralized technologies to protect their assets and precious peculiarities. The World Wide Web has been an extinction-level event for many forms of life, livelihood, and culture. For others, it has offered strange forms of life support and even thriving. With a new immune system evolved and now operational, human endeavor stands on the cusp of a Cambrian explosion, unconstrainable by a rent-seeking boardroom-and-bureaucracy world that never comprehended the light shining in its darkness.
90+
91+_The header image is [Volvox sp. microscopic algae](https://www.flickr.com/photos/picksfromoutthere/35891780782/in/photolist-WFCKYA-XPdGLq-2k9Cew6-ViCgrB-23QUBQR-21rF362-CCSE2n-23AwZ7m-CbKedu-gznqa-2dHUv3k-EE8eoq-gznq9-i5zqqk-WYSwcf-XWVgQk-WabAAG-gLjRj-gDcLp-4VvECm-259cDCS-i5zqRk-25cV246-i5yNvM-gupiMJ-PXLbhr-LUACZ7-ihvxSH-ihvvVg-ihwjbF-ihvxDX-i5yQDd-ihzQwK-fWwpxb-rarKrm-8LWTQf-qVar5j-ihzAPA-JNrgyK-ihzBrC-ca6Ex9-2kCTSrj-ihz67k-qfJsYd-248ePDL-ihztbm-ihzuyS-LQYZQq-2kCTRxL-ihvWPA) by Picturepest on Flickr._
92+
93+[^1]: Kaufman, Jim. (2010) ["Evolution and immunity"](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2913256/). _Immunology 130_, iss. 4, pp. 459--462.
94+[^2]: President Eisenhower's original coinage was likely "the military-industrial-academic complex."
95+[^3]: E.g., Richard Bellman of the RAND Corporation on the origin of "dynamic programming," a mathematical discipline: in dealing with a recalcitrant secretary of defense who hated the word "research," Bellman instead chose the word "dynamic" arbitrarily because "it's impossible to use the word 'dynamic' in a pejorative sense. ...It was something not even a Congressman could object to. So I used it as an umbrella for my activities." (Bellman, Richard. (1984) [_Eye of the Hurricane_](https://books.google.ch/books?id=4FwGCwAAQBAJ&lpg=PA159&dq=#v=onepage&q=).)
96+[^4]: The nuclear triad doctrine, joining the Air Force's Strategic Air Command bombers, the Navy's nuclear submarines, and the Army's ICBMs and other assorted nuclear warheads, was based less on strategic considerations than on appeasing constituent departments of the military. Strategists developed a formal justification decades later in a magnificent demonstration of motivated reasoning. (Woolf, Amy. (2016) "U.S. Strategic Nuclear Forces: Background, Developments, and Issues". [CRS 7-5700](https://digital.library.unt.edu/ark:/67531/metadc847627/m2/1/high_res_d/RL33640_2016Mar10.pdf).)
97+[^5]: The Air Force early commissioned the RAND Corporation on contract with Douglas Aircraft Company as the first "think tank"; RAND soon upended the traditional role of passive reception of studies by making its own recommendations and showing their analytical chops. Other service branches followed suit, such as the U.S. Navy's Center for Naval Analyses and the Battelle Memorial Institute for various federal contracting agencies; compare also the role of the national laboratory system, e.g. Los Alamos, Sandia, Livermore, etc. for the Department of Energy and Department of Defense. (Rich, Michael. (2003) "RAND: How Think Tanks Interact with the Military". [RP-1050](https://www.rand.org/pubs/reprints/RP1050.html).)
98+[^6]: "On January 18, 1994, the first large-scale deliberate USENET spam occurred. A message with the subject "Global Alert for All: Jesus is Coming Soon" was cross-posted to every available newsgroup." ([Wikipedia, "History of email spam"](https://en.wikipedia.org/wiki/History_of_email_spam))
99+[^7]: The first instance which seems to have brough this to general public awareness was the submission of Judge Robert Bork's video rental history as evidence in his Supreme Court hearings before the U.S. Senate. The resulting Video Privacy Protection Act was delightfully naïve. Besides relying on "video rental" narrowly construed, users have effectively no leverage against unilaterally-imposed terms of service and end-user license agreements. (See, e.g., [Electronic Privacy Information Center, "Video Privacy Protection Act"](https://archive.epic.org/privacy/vppa/).)
100+[^8]: E.g. Tumblr and OnlyFans and adult content; Twitter and right-wing content; Youtube and Facebook and unsanctioned medical content, etc. Note that this is regardless of the viability of a given view or the necessity of vigorous debate within a field, but focuses on the palatibility of politics to the megacorp entity providing the platform, even if the content drives platform usage.
101+[^9]: Hughes, Eric. (1993) [_A Cypherpunk's Manifesto_](https://nakamotoinstitute.org/cypherpunk-manifesto/).
102+[^10]: The mass shift to remote work from March 2020 onwards due to the COVID-19 pandemic has accelerated the trend of corporate colonization of private spaces. At first, this was occasionally humorous, as when a child ran into the background of a Zoom call, or underwear or private materials were inadvertently left in view of the remote audience. In the end, it demanded that individuals reconfigure their homes to accommodate mass corporate preferences, thus another invasion of private space by the megacorp panopticon. I note as well an invasive doctrine demanding "truth in communication" under names like ["radical transparency"](https://www.bridgewater.com/principles-and-culture) and ["radical candor"](https://third-bit.com/2018/11/24/afraid-of-change/) put forward by partisans of power over against vulnerable employees, clients, and customers, who may be disproportionately affected by a megacorp demand for one-sided transparency.
103+[^11]: Several have pointed to the failure of Craig S. Wright to demonstrate cryptographically that he is Satoshi Nakamoto, the pseudonymous inventor of Bitcoin. (C.f. Khaosan, Venzen. (2016) ["Craig Wright is Not Satoshi Nakamoto---The Technical Proof"](https://www.ccn.com/technical-proof-craig-wright-not-satoshi-nakamoto/).)
104+[^12]: Davidson, Dale, and Rees-Mogg, William. (1999) _The Sovereign Individual: Mastering the Transition to the Information Age_.
105+[^13]: Raymond, Eric. (1999) [_The Cathedral and the Bazaar_](http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html).
106+[^14]: The [Coalition for Content Provenance and Authenticity](https://c2pa.org/) "addresses the prevalence of misleading information online through the development of technical standards for certifying the source and history (or provenance) of media content."
107+[^15]: Cf. Walker, Shawn, et al. (2019) ["The disinformation landscape and the lockdown of social platforms."](https://www.tandfonline.com/doi/full/10.1080/1369118X.2019.1648536) _Information, Communication & Society 22_, pp. 1531--43. Walker et al. lament that "highly ephemeral mis/disinformation campaigns" are not susceptible of study due to closed platform APIs. "Social media platforms \[attempt\] to rekindle trust by appearing to reinforce individual privacy within a newly secured user community, a set of measures that also locked academic and non-profit researchers out from studying social platforms while preserving corporate and business access to social media users' data." They fail to address the tension between community self-determination and academic exploitation.
108+[^16]: "If in fact you can't crack \[the encryption\] at all, government can't get in, then everybody is walking around with a Swiss bank account in their pocket -- right? So there has to be some concession to the need to be able to get into that information somehow." ([Barack Obama in March 2016 at SXSW](https://www.businessinsider.com/obama-comments-on-encryption-at-sxsw-2016-3))
109+[^17]: Heninger, Nadia. (2016) ["The Legacy of Export-Grade Cryptography in the 21^st^ Century"](https://publish.illinois.edu/science-of-security-lablet/files/2016/08/10062016-Heninger-Slides.pdf).
110+[^18]: Chohan, Usman. (2017) ["The Decentralized Autonomous Organization and Governance Issues"](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3082055). Discussion Paper Series: _Notes on the 21^st^ Century_.
111+[^19]: Lessig, Lawrence. (1999) _Code and Other Laws of Cyberspace_.
112+[^20]: Hobart, Byrne `~lableg-tadrex`. (Nov 17, 2021) ["The Promise and Paradox of Decentralization"](https://urbit.org/blog/2021-11-18-the-promise-and-paradox-of-decentralization). _The Diff_.
113+[^21]: See, e.g., the Governor Alpha smart contract protocols. Solari, R. (2021) ["The case for Governor Alpha".](https://medium.com/tally-blog/the-case-for-governor-alpha-15c1362d49eb)
114+[^22]: Robinson, D. (2020) ["Ethereum is a dark forest"](https://www.paradigm.xyz/2020/08/ethereum-is-a-dark-forest). Paradigm blog.
115+[^23]: [Uqbar Network](https://uqbar.network/); ["Introducing Uqbar Network"](https://uqbarnetwork.substack.com/p/introducing-uqbar-network); \~hocwyn-tipwex/uqbar-event-horizon (Urbit group)
116+[^24]: This is not to deny the benefits of system-legibility, in particular legal protections. As common law develops around DAOs, I hope for similar affordances where they must interact with the legacy legal system.
117+[^25]: Originally this list included Discord, as there has been substantial growth in stable goal-oriented communities thereon. However, more recently the company [adopted a user policy](https://discord.com/blog/addressing-harmful-off-platform-behavior) which subjects use of their product to judgment calls about "off-platform behavior"---a clear violation of a cypherpunk ethos which Discord likely never espoused anyway.
118+[^26]: E.g., Auerbach, David. (Mar 3, 2022) ["The metaverse will steal your identity"](https://unherd.com/2022/03/the-metaverse-will-steal-your-identity/). _UnHerd_. Auerbach correctly recognizes and decries the looming "monetisation of identity" which will allow any platform controller to incentivize prosocial or antisocial behaviors at will.
content/blog/infrastructural.md+2−8
@@ -9,9 +9,7 @@ ship = "~fabled-faster"
99image = "https://media.urbit.org/site/posts/essays/infrastructural-2.jpg"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/infrastructural-1.jpg">
12+![](https://media.urbit.org/site/posts/essays/infrastructural-1.jpg)
1513
1614## Seasons
1715
@@ -53,11 +51,7 @@ We deeply hope that Urbit can form a support structure for you and your communit
5351
5452These self-evident statements underlie the core problems we sought to address in designing a userspace for OS 1: How do we design an _actually_ personal digital infrastructure? What does infrastructure look like when shared with immediate friends? With a cooperative organization? How can we impress upon Urbit's earliest adopters that once they've obtained an Urbit ID, their computer is at that moment _literally_ entirely theirs?
5553
56−<br>
57−
58−<br>
59−
60−<img class="ba" src="https://media.urbit.org/site/posts/essays/infrastructural-2.jpg">
54+![](https://media.urbit.org/site/posts/essays/infrastructural-2.jpg)
6155
6256## Expressing Infrastructure
6357
content/blog/interplanetary_commerce.md+3−6
@@ -2,6 +2,7 @@
22title = "Interplanetary Commerce"
33date = "2021-04-08"
44description = "OS-level commercial primitives."
5+tags = ["bitcoin"]
56
67[extra]
78author = "Christian Langalis"
@@ -9,12 +10,8 @@ ship = "~pindet-timmut"
910image = "https://media.urbit.org/site/posts/essays/ocean.jpeg"
1011+++
1112
12−<br>
13−
1413![ocean](https://media.urbit.org/site/posts/essays/ocean.jpeg)
1514
16−<br>
17−
1815## Paying
1916
2017A year ago, we started [integrating](https://urbit.org/blog/urbit-and-bitcoin/) Bitcoin into Urbit to be an OS-level primitive for money. Our initial objective: build a payments wallet, equally sovereign and ergonomic. The first public version, releasing this month, will have a broad set of capabilities including ship-to-ship payments, hardware wallet support, and full node integration. We’ll be unveiling this wallet on [April 27th](https://www.meetup.com/urbit-sf/events/276741426/). Do join us.
@@ -25,7 +22,7 @@ Things only accelerate from here. Our next objective, to integrate Lightning Net
2522
2623> And there is all the difference in the world between paying and being paid. The act of paying is perhaps the most uncomfortable infliction that the two orchard thieves entailed upon us. But being paid,—what will compare with it?
2724>
28−> <cite>Herman Melville</cite>
25+> **Herman Melville**
2926
3027However, a good wallet is only half the equation for a holistic P2P commercial experience. Interfaces for selling goods and services is the other half. While we don’t part with our Bitcoin [easily](https://nakamotoinstitute.org/mempool/everyones-a-scammer/), two initial markets appear logical and attractive: content and Urbit-native services.
3128
@@ -37,4 +34,4 @@ The Urbit Foundation is soliciting contributors to this project through Urbit Gr
3734
3835## An Ocean
3936
40−After honing our commercial tools on these use-cases, we’ll sail into a blue ocean. On the horizon: beautiful products, deployable at scale, built with the robust primitives of Urbit OS. Extensibility is Urbit’s promise to middle-men: every Web2.0 service they use to scalp us will find its P2P analog on Urbit. We invite developers and entrepreneurs of all stripes to join in the feeding frenzy. Ideas are constantly nucleating in <a href="web+urbitgraph://group/~pindet-timmut/urbitcoin-cash">Urbitcoiners</a> and <a href="web+urbitgraph://group/~bitbet-bolbel/urbit-community/graph/~darrux-landes/business-building-on-urbit">Urbit Community</a>.
37+After honing our commercial tools on these use-cases, we’ll sail into a blue ocean. On the horizon: beautiful products, deployable at scale, built with the robust primitives of Urbit OS. Extensibility is Urbit’s promise to middle-men: every Web2.0 service they use to scalp us will find its P2P analog on Urbit. We invite developers and entrepreneurs of all stripes to join in the feeding frenzy. Ideas are constantly nucleating in [Urbitcoiners](web+urbitgraph://group/~pindet-timmut/urbitcoiners) and [Urbit Community](web+urbitgraph://group/~bitbet-bolbel/urbit-community/graph/~darrux-landes/business-building-on-urbit).
content/blog/introducing-os1.md+7−9
@@ -9,8 +9,6 @@ ship = "~ravmel-ropdyl"
99image = "https://media.urbit.org/site/posts/essays/intro-os1-landscape.png"
1010+++
1111
12−<br>
13−
1412<video class="ba w-100" autoplay loop src="https://media.urbit.org/site/posts/essays/intro-os1.mov"></video>
1513
1614## Introducing OS 1
@@ -39,7 +37,7 @@ Let’s walk through the features of OS 1 one by one to see what it’s like.
3937
4038### Groups
4139
42−<img class="ba" src="https://media.urbit.org/site/posts/essays/intro-os1-groups.png">
40+![](https://media.urbit.org/site/posts/essays/intro-os1-groups.png)
4341
4442The group is the main building block in OS 1. A group is simply a list of people that share a set of chat, links, and publish channels. A group is sort of like a super powerful group chat.
4543
@@ -51,7 +49,7 @@ Let’s walk through each module and talk about what they can do.
5149
5250### Chat
5351
54−<img class="ba" src="https://media.urbit.org/site/posts/essays/intro-os1-chat.png">
52+![](https://media.urbit.org/site/posts/essays/intro-os1-chat.png)
5553
5654Chat is chat: a sequential list of messages meant for synchronous communication. There are already a million ways to chat — but Urbit chat differs in a few important ways.
5755
@@ -69,7 +67,7 @@ Anyway, not everything can happen in a chat. Let’s keep moving.
6967
7068### Links
7169
72−<img class="ba" src="https://media.urbit.org/site/posts/essays/intro-os1-links.png">
70+![](https://media.urbit.org/site/posts/essays/intro-os1-links.png)
7371
7472Links is a bit like Hacker News or Reddit. It’s just a collection of links with comments. There’s no upvoting or sorting. We decided that with a small group it’s more about collecting references than deciding what’s most exciting — but permutations of Links could be a great area for contributors to experiment with.
7573
@@ -79,7 +77,7 @@ We originally imagined links as evolving into more of a general-purpose ‘colle
7977
8078### Publishing
8179
82−<img class="ba" src="https://media.urbit.org/site/posts/essays/intro-os1-publish1.png">
80+![](https://media.urbit.org/site/posts/essays/intro-os1-publish1.png)
8381
8482Publishing is somewhere between a blog and a note-taking system. A Publish notebook is a list of markdown files with optional comments. A private Publish notebook is like a journal, a group notebook can be like a forum (with comments on) or a collaborative blog.
8583
@@ -89,7 +87,7 @@ Publish, like all our other modules, is an interface to a generalized protocol f
8987
9088### Modules
9189
92−<img class="ba" src="https://media.urbit.org/site/posts/essays/intro-os1-home.png">
90+![](https://media.urbit.org/site/posts/essays/intro-os1-home.png)
9391
9492You’ll find a few other things on the home screen: a clock, the weather, and a simple command-line that we call the Dojo. These are system-wide utilities that aren’t group-specific.
9593
@@ -97,7 +95,7 @@ The clock and weather tiles are simple indications of the state of the outside w
9795
9896### Dojo
9997
100−<img class="ba" src="https://media.urbit.org/site/posts/essays/intro-os1-dojo.png">
98+![](https://media.urbit.org/site/posts/essays/intro-os1-dojo.png)
10199
102100The Dojo gives you a quick way to see that, under the hood, Urbit OS is a powerful general-purpose system. The system hasn’t evolved to the point that our libraries, frameworks, and modules are polished to our standards. Since it’s still early, we can’t claim that it’s easy to develop on top of this platform. But we want it to become much easier.
103101
@@ -133,7 +131,7 @@ As we expand the affordances of the system and add modules over the course of OS
133131
134132### Becoming a homesteader
135133
136−<img class="ba" src="https://media.urbit.org/site/posts/essays/intro-os1-landscape.png">
134+![](https://media.urbit.org/site/posts/essays/intro-os1-landscape.png)
137135
138136As a distributed team trying to stay connected, we like using OS 1 from day to day. We’d really like to hand-onboard a small group of like-minded groups of people who want to experiment with living on the fringe of the digital world. Toward this end, we started the community grants program.
139137
content/blog/introduction-to-the-combine-dao.mdnew file+46
@@ -0,0 +1,46 @@
1++++
2+title = "Introduction to the Combine DAO"
3+date = "2022-07-01"
4+description = "Inside the mind of the Combine"
5+
6+[extra]
7+author = "Anthony Arroyo"
8+ship = "~poldec-tonteg"
9+image = "https://media.urbit.org/blog/cortina-ampezzo.jpg"
10++++
11+
12+![Cortina-D'Ampezzo-1200x1200px.jpg](https://media.urbit.org/blog/cortina-ampezzo.jpg)
13+
14+_This is cross-posted from [The Combine DAO Blog](https://blog.the-combine.org). If you'd like to comment, join the public [Urbit group](https://urbit.org/groups/~famreb-todmec/the-combine-public)_
15+
16+Until a couple of weeks ago, The Combine was a subdivision of the Urbit Foundation with a budget earmarked to invest in new projects. As of Urbit NYC that all changed. Now we’re an honest-to-goodness DAO built on Urbit—by Urbit maximalists, for Urbit maximalists. We pool assets to invest in teams building new tools, products and services for the Urbit Universe. Our members are investors, engineers, founders and galactic senators.
17+
18+In this post we'll talk about what we're aiming to do and why we’re in the best position to do it. In a future post, we'll dive into technical and strategic insights drawn from building a DAO on Urbit.
19+
20+## Our Objective
21+
22+Our objective is simple: support organizations in building high-value projects on Urbit. Urbit address space has intrinsic, tradeable value, as is the case with many crypto assets. But, unlike most crypto, that’s just the tip of the Urbit iceberg. Where most crypto assets are built to be owned and exchanged, Urbit is built to be owned and used. It has the potential to replace virtually every centralized part of Web2 you use (but don’t own) today.
23+
24+The Combine DAO invests in teams working on projects that generate and capture value beyond Urbit address space. The price of address space reflects confidence in Urbit's user growth, but every increase in utility to an Urbit user — that is, every time a user can do more with their Urbit — creates additional value. The Combine takes advantage of this upside.
25+
26+For example, one of our portfolio companies, [Uqbar](https://uqbar.network), is building a smart contract platform on Urbit. The Uqbar network will use Urbit ships as nodes in their network, as ZK provers and sequencers, creating an ZK Rollup L2 with the full power of general compute and identity. While their use of the Urbit network as part of their infrastructure will drive demand for planets, stars and galaxies, the value of Uqbar is potentially much greater than that demand.
27+
28+So, members of The Combine DAO should believe at least one of two things:
29+
30+- That products built on Urbit can outpace the value of address space alone, and that The Combine is in the best position to capture that value.
31+- That successful projects built on Urbit will enhance the value of Urbit address space.
32+
33+## Our Pipeline
34+
35+The Combine works hand-in-hand with the Urbit Foundation, meaning we have unparalleled visibility into the development of new projects and teams on Urbit. The Foundation has been working hard to shore up Urbit's developer pipeline, with Hoon School constantly bringing in new developers. The last cohort had 61 finishers, seven of whom had no previous programming experience. The Foundation’s [Grants](https://urbit.org/grants) program is active with over 40 active grants. The Combine and The Foundation continue to work together to identify, nurture and launch projects in need of funding.
36+
37+## Our Membership
38+
39+Startups are risky by nature. Add Urbit’s novel technology and you’ve got more than your share of pitfalls. The Combine mitigates these risks through its membership. Combine members are long-time supporters of the project who have run startups, exchanges and have invested in successful technology on Urbit and beyond. The membership can help lead teams past challenges inherent to all new ventures. We're familiar with the technical and product landscape of Urbit and its adjacent technologies. All of us have experience building technology, on Urbit and outside it, which enables us to provide valuable coaching and due diligence.
40+
41+Another of our portfolio companies, [Holium](https://holium.com), is building unified tooling for DAOs. They started with an application that the Combine DAO uses internally: a voting app called “Ballot.” Holium’s founder has been working on a unified environment for DAOs for some time, but it wasn’t until he came to Assembly 2021 that the pieces finally clicked and he realized that Urbit was the correct stack for Holium’s projects. As he built Ballot on Urbit, The Combine provided product feedback, investor intros, and access to experienced contractors and personnel. Now we’re actively dogfooding Ballot as a core element in The Combine stack.
42+
43+In the coming weeks we’ll dive into the details of why we think Urbit is the natural home for DAOs. For now, we’ll just say that Urbit’s unified stack opens up a unique level of ownership and customizability to DAO builders. The Combine, as a DAO built on Urbit, to support Urbit, is test driving this use case. What we learn here will feed back into diligence, outreach and development priorities for the Foundation.
44+
45+In the next post, we’ll share technical insights for DAOs gleaned from our own experiences building The Combine DAO on Urbit.
46+
content/blog/io-in-hoon.md+154−134
@@ -9,12 +9,8 @@ ship = "~wicdev-wisryt"
99image = "https://media.urbit.org/site/posts/essays/zion-canyon-1.jpg"
1010+++
1111
12−<br>
13−
1412![canyon](https://media.urbit.org/site/posts/essays/zion-canyon-1.jpg)
1513
16−<br>
17−
1814Let's talk about IO in Urbit. I won't say much about how events and effects are processed by the runtime; it suffices to note that the runtime is a normal Unix program which (1) listens for various events, (2) passes them to Arvo (Urbit OS), and (3) processes the effects produced by Arvo. Instead, I’ll focus on how IO works from the perspective of Hoon programs, like Arvo or apps running on Arvo. But first, let's review IO paradigms in other languages.
1915
2016All examples are in a made-up language, since it's useful to understand this information even before you're comfortable in Hoon. If you're learning Hoon and want a challenge, try translating them!
@@ -29,7 +25,9 @@ Imperative languages (such as C and Python) perform IO by calling a function in
2925
3026In this example and others to follow, the task will be to read a filename from the command line, read a URL out of that file, and fetch the contents at that URL.
3127
32− output = fetchUrl(stripWhitespace(readFile(cliInput())))
28+```
29+output = fetchUrl(stripWhitespace(readFile(cliInput())))
30+```
3331
3432For readability, intermediate variables would be a good idea, but nothing stops you from nesting IO this way.
3533
@@ -37,9 +35,11 @@ For readability, intermediate variables would be a good idea, but nothing stops
3735
3836Languages that use explicit monads for IO (such as Haskell) perform IO by running IO behind a bind operation, which I'll notate with `<-`. Thus, while you can't put IO _anywhere_, the general structure is a sequence of IO operations.
3937
40− fileName <- cliInput()
41− url <- readFile(fileName)
42− output <- fetchUrl(stripWhitespace(url))
38+```
39+fileName <- cliInput()
40+url <- readFile(fileName)
41+output <- fetchUrl(stripWhitespace(url))
42+```
4343
4444[Tackling the Awkward Squad](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/mark.pdf) is the canonical description of monadic IO, and does a great job of explaining how the Haskell community decided to use this as their primary IO style.
4545
@@ -47,22 +47,24 @@ Languages that use explicit monads for IO (such as Haskell) perform IO by runnin
4747
4848Languages that use explicit state machines for IO (such as Elm) perform IO by accepting events and producing a list of effects.
4949
50− event :: Initialize
51− | CLIInput text
52− | FileInput text
53− | HTTPResponse body
54− effect :: CLIInput
55− | ReadFile fileName
56− | FetchUrl url
57− | Print text
58− main(event) {
59− switch event {
60− Initialize -> [CLIInput ~]
61− CLIinput fileName -> [ReadFile fileName]
62− FileInput url -> [FetchUrl stripWhitespace(url)]
63− HTTPResponse body -> [Print body]
64− }
65− }
50+```
51+event :: Initialize
52+ | CLIInput text
53+ | FileInput text
54+ | HTTPResponse body
55+effect :: CLIInput
56+ | ReadFile fileName
57+ | FetchUrl url
58+ | Print text
59+main(event) {
60+ switch event {
61+ Initialize -> [CLIInput ~]
62+ CLIinput fileName -> [ReadFile fileName]
63+ FileInput url -> [FetchUrl stripWhitespace(url)]
64+ HTTPResponse body -> [Print body]
65+ }
66+}
67+```
6668
6769The effects produced are not functions but data.
6870
@@ -74,39 +76,45 @@ Let's look at another type of program: a simple HTTP server that you can give te
7476
7577Imperative:
7678
77− text = "no text entered yet"
78− while (true)
79− cli = readCli()
80− if (cli != Null)
81− text = cli
82− request = readHttp()
83− if (request != Null)
84− respond(request,text)
79+```
80+text = "no text entered yet"
81+while (true)
82+ cli = readCli()
83+ if (cli != Null)
84+ text = cli
85+ request = readHttp()
86+ if (request != Null)
87+ respond(request,text)
88+```
8589
8690Monadic:
8791
88− loop("no text entered yet")
92+```
93+loop("no text entered yet")
8994
90− where:
95+where:
9196
92− loop :: text -> IO Null
93− loop =
94− input <- readInput()
95− switch input
96− CLIInput newText -> loop(newText)
97− HTTPRequest request ->
98− _ <- respond(request,text)
99− loop(text)
97+loop :: text -> IO Null
98+loop =
99+ input <- readInput()
100+ switch input
101+ CLIInput newText -> loop(newText)
102+ HTTPRequest request ->
103+ _ <- respond(request,text)
104+ loop(text)
105+```
100106
101107State machine:
102108
103− text = "no text entered yet"
104− main(text,event) {
105− switch event {
106− CLIInput newText -> [newText, Null]
107− HTTPRequest request -> [text, HTTPResponse text]
108− }
109− }
109+```
110+text = "no text entered yet"
111+main(text,event) {
112+ switch event {
113+ CLIInput newText -> [newText, Null]
114+ HTTPRequest request -> [text, HTTPResponse text]
115+ }
116+}
117+```
110118
111119Again, note the response in the state machine is data, not a function.
112120
@@ -124,9 +132,9 @@ When inventing a new system, you should consider which of these you intend to su
124132
125133So much for exploring the space of IO solutions. In terms of deployed code on Earth, the split is about 90% imperative, 5% monadic, and 5% state machine. In Urbit, the split is about 90% state machine and 10% monadic. This is what I intend to explain and defend.
126134
127−Urbit's OS is called Arvo; it has several "kernel modules" called vanes, and it has userspace applications. Colloquially these are called "apps," but when speaking about them abstractly, it's helpful to use their more specific name: ["agents"](https://urbit.org/docs/tutorials/arvo/gall/#agents). Arvo, the vanes, and agents are all structured as explicit state machines.
135+Urbit's OS is called Arvo; it has several "kernel modules" called vanes, and it has userspace applications. Colloquially these are called "apps," but when speaking about them abstractly, it's helpful to use their more specific name: ["agents"](https://developers.urbit.org/reference/glossary/agent). Arvo, the vanes, and agents are all structured as explicit state machines.
128136
129−In addition, there are ["threads"](https://urbit.org/docs/tutorials/arvo/gall/#threads), which are structured as monadic IO. Note there's only a superficial resemblance to Unix threads: they are not executed in parallel and they don't share memory, or at least not any more than agents do. They're simply a computation that takes an argument and produces a result, possibly after doing some IO, structured monadically.
137+In addition, there are ["threads"](https://developers.urbit.org/reference/glossary/thread), which are structured as monadic IO. Note there's only a superficial resemblance to Unix threads: they are not executed in parallel and they don't share memory, or at least not any more than agents do. They're simply a computation that takes an argument and produces a result, possibly after doing some IO, structured monadically.
130138
131139As you can see, all the lowest levels of Arvo are explicit state machines, and only the highest layer supports monadic IO. To see why this is the case, let's list advantages and disadvantages to each type. Note that, while I'm speaking specifically of agents and threads in the context of Urbit, these are fundamental properties of monadic and state machine IO.
132140
@@ -158,16 +166,18 @@ However, Arvo is a single-level store — all of its state is permanent. This is
158166
159167Further, Arvo and the vanes rarely perform long sequences of IO. Generally, they do one thing and emit some effects, similar to the HTTP server example above. Sometimes they "pass through" a request. For example, the Eyre vane passes HTTP requests to userspace agents or threads. In this case, there is a sequence of IO, which in monadic code would be:
160168
161− loop()
169+```
170+loop()
162171
163− where:
172+where:
164173
165− loop =
166− request <- receiveRequest()
167− agent = lookupAgent(request)
168− response <- callAgent(agent, request)
169− _ <- sendResponse(request, response)
170− loop()
174+loop =
175+ request <- receiveRequest()
176+ agent = lookupAgent(request)
177+ response <- callAgent(agent, request)
178+ _ <- sendResponse(request, response)
179+ loop()
180+```
171181
172182This is clear code to read, but it leaves open the question of how to respond during the callAgent() function. If another request comes in, can we handle it in parallel? If we need to upgrade ourselves before the agent responds, can we make sure to properly handle the response?
173183
@@ -175,16 +185,18 @@ The naive solution in monadic code is to say that you can only handle one reques
175185
176186In a state machine, the naive solution is:
177187
178− state :: (map request agent)
179− main(state, event) {
180− switch event {
181− HTTPRequest request ->
182− agent = lookupAgent(request)
183− [put(state, request, agent), CallAgent agent request]
184− AgentResponse request response ->
185− [del(state, request), HTTPRespond request response]
186− }
187− }
188+```
189+state :: (map request agent)
190+main(state, event) {
191+ switch event {
192+ HTTPRequest request ->
193+ agent = lookupAgent(request)
194+ [put(state, request, agent), CallAgent agent request]
195+ AgentResponse request response ->
196+ [del(state, request), HTTPRespond request response]
197+ }
198+}
199+```
188200
189201Upgrading this is trivial, since the state (map of requests to outstanding calls to agents) is explicit. It also trivially handles concurrent requests.
190202
@@ -200,59 +212,63 @@ However, userspace sometimes needs to perform long sequences of IO. Let's look a
200212
201213Monadic:
202214
203− topStories <- fetch(topStoriesUrl)
204− loop(topStories)
215+```
216+topStories <- fetch(topStoriesUrl)
217+loop(topStories)
205218
206− where:
219+where:
207220
208− loop :: topStories -> IO Null
209− if topStories is Null
210− return Null
211− comments <- retryLoop(5,head(topStories))
212− otherComments <- loop(tail(topStories))
213− append(comments,otherComments)
221+loop :: topStories -> IO Null
222+ if topStories is Null
223+ return Null
224+ comments <- retryLoop(5,head(topStories))
225+ otherComments <- loop(tail(topStories))
226+ append(comments,otherComments)
214227
215− retryLoop :: [n story] -> IO Comments
216− comments <- fetchComments(story)
217− if comments is HTTPError:
218− if n == 0:
219− bail
220− else:
221− retryLoop(n-1, story)
228+retryLoop :: [n story] -> IO Comments
229+ comments <- fetchComments(story)
230+ if comments is HTTPError:
231+ if n == 0:
232+ bail
233+ else:
234+ retryLoop(n-1, story)
235+```
222236
223237State machine:
224238
225− state :: Initial
226− | FetchingTop
227− | FetchingStory comments stories retries
228− | Done comments
229−
230− main(state, event) {
231− switch event {
232− Initialize ->
233− assert state == Initial
234− [FetchingTop, Fetch topStoriesUrl]
235− HttpResponse response ->
236− switch state {
237− FetchingTop ->
238− [FetchingStory Null stories 5, FetchComments head(stories)]
239− FetchingStory comments stories retries ->
240− if response is HTTPError:
241− if retries == 0:
242− [Initial, Null]
243− else:
244− [FetchingStory comments stories retries-1,
245− FetchComments head(stories)]
246− else:
247− comments = append(response,comments)
248− if tail(stories) is Null:
249− [Done comments, Null]
250− else:
251− [FetchingStory append(comments,response) tail(stories) 5,
252− FetchComments head(tail(stories))]
253− }
239+```
240+state :: Initial
241+ | FetchingTop
242+ | FetchingStory comments stories retries
243+ | Done comments
244+
245+main(state, event) {
246+ switch event {
247+ Initialize ->
248+ assert state == Initial
249+ [FetchingTop, Fetch topStoriesUrl]
250+ HttpResponse response ->
251+ switch state {
252+ FetchingTop ->
253+ [FetchingStory Null stories 5, FetchComments head(stories)]
254+ FetchingStory comments stories retries ->
255+ if response is HTTPError:
256+ if retries == 0:
257+ [Initial, Null]
258+ else:
259+ [FetchingStory comments stories retries-1,
260+ FetchComments head(stories)]
261+ else:
262+ comments = append(response,comments)
263+ if tail(stories) is Null:
264+ [Done comments, Null]
265+ else:
266+ [FetchingStory append(comments,response) tail(stories) 5,
267+ FetchComments head(tail(stories))]
254268 }
255− }
269+ }
270+}
271+```
256272
257273With practice, the state machine version of this can be written correctly. However, (1) it's verbose, (2) the control flow jumps all over the place, and (3) in practice it's challenging to get exactly right. This is still a small example, and it gets much worse as the length and complexity of the IO sequence grows.
258274
@@ -280,30 +296,34 @@ We're in a bit of a bind, though: Jael has to be a state machine. The solution i
280296
281297This thread has a definite purpose: given the most recent block number we already know about, fetch all the PKI transactions since then. The function signature is:
282298
283− syncEthereum oldBlockNumber -> IO [newBlockNumber, newTxs]
299+```
300+syncEthereum oldBlockNumber -> IO [newBlockNumber, newTxs]
301+```
284302
285303Jael runs this thread every five minutes and, if it succeeds, then we update our block number and PKI state. If the thread fails, gets stuck, or we need to upgrade it, we just kill the old thread and start a new one. Again, a few extra HTTP requests don’t matter.
286304
287305From Jael's perspective, it looks something like:
288306
289− state :: State block txs outstandingThread
290− main(state,event) {
291− switch event {
292− Initialize -> [State 0 Null Null, StartTimer (now + five minutes)]
293− TimerFired ->
294− effects = If outstandingThread is Null
295− then Null
296− else [Kill outstandingThread]
297− newId = newThreadId()
298− [State txs newId,
299− append(effects,
300− StartThread newId syncEthereum(block),
301− StartTimer (now + five minutes))]
302− ThreadFinished Failure -> [State block txs Null, Null]
303− ThreadFinished Success newBlockNumber newTxs ->
304− [State newBlockNumber append(txs,newTxs) Null, Null]
305− }
306− }
307+```
308+state :: State block txs outstandingThread
309+main(state,event) {
310+ switch event {
311+ Initialize -> [State 0 Null Null, StartTimer (now + five minutes)]
312+ TimerFired ->
313+ effects = If outstandingThread is Null
314+ then Null
315+ else [Kill outstandingThread]
316+ newId = newThreadId()
317+ [State txs newId,
318+ append(effects,
319+ StartThread newId syncEthereum(block),
320+ StartTimer (now + five minutes))]
321+ ThreadFinished Failure -> [State block txs Null, Null]
322+ ThreadFinished Success newBlockNumber newTxs ->
323+ [State newBlockNumber append(txs,newTxs) Null, Null]
324+ }
325+}
326+```
307327
308328In other words, from Jael's perspective, it's just a single IO event that encapsulates arbitrarily complex IO in the thread. A single IO event is easy enough, and we can maintain all our permanency and robustness guarantees, because we know the thread will have one of three results: success, failure, or it hangs. If we set a timeout, hang becomes failure, so there's only two possible results: success or failure. If we handle both of those correctly, we've handled all the possible IO errors that could have occurred.
309329
content/blog/iot.md+1−5
@@ -9,12 +9,8 @@ ship = "~datnut-pollen"
99image = "https://media.urbit.org/site/posts/essays/phobos.jpeg"
1010+++
1111
12−<br>
13−
1412![phobos](https://media.urbit.org/site/posts/essays/phobos.jpeg)
1513
16−<br>
17−
1814Each of the ~4B 32-or-fewer-bit or [Azimuth](/docs/glossary/azimuth)
1915identities, namely [planets](/docs/glossary/planet),
2016[stars](/docs/glossary/star), and [galaxies](/docs/glossary/galaxy), may
@@ -302,7 +298,7 @@ So let us focus on the additional meritorious aspects of Urbit (or more
302298generally, solid state interpreter networks) that make it not merely a band-aid
303299to the broken IoT system but a permanent and sound replacement.
304300
305−#### Solid state interpreter networks {#ssi}
301+#### Solid state interpreter networks {% #ssi %}
306302
307303![cubesats](https://media.urbit.org/site/posts/essays/cubesats.jpg)
308304
content/blog/layer-2-faq.mdnew file+155
@@ -0,0 +1,155 @@
1++++
2+title = "Layer 2 FAQ"
3+date = "2022-03-01"
4+description = "Answers to all your lingering L2 questions."
5+[extra]
6+image = "https://media.urbit.org/site/posts/essays/l2-faq-artwork.jpg"
7++++
8+
9+The launch of our [Layer 2](https://urbit.org/blog/layer-2-guides) was met with
10+a lot of excitement and a few questions. Don’t fret, we have answers. Below is a
11+selection of the most frequently asked questions and our responses.
12+
13+If you're still stumped, head to `~bitbet-bolbel/urbit-community` or give us a
14+shout online.
15+
16+### Questions:
17+
18+#### Planet Booting, Buying, Custody
19+
20+1. [Do I need ETH to boot my planet?](#1-do-i-need-eth-to-boot-my-planet)
21+2. [Do I have full custody of my L2 planet?](#2-is-there-anything-i-need-to-do-to-ensure-full-custody-of-my-planet)
22+3. [Where can I buy a planet?](#3-are-there-any-platforms-where-i-can-buy-a-planet-for-btc-or-usd)
23+4. [How do I get a hosted planet?](#4-how-do-i-get-a-cloud-hosted-planet)
24+
25+#### Layer 2 Architecture & Migration
26+
27+5. [Why did you decide to build your own Layer 2 rollup?](#5-there-are-plenty-of-organizations-dedicated-to-customizable-rollup-solutions-why-did-you-decide-to-build-your-own)
28+6. [Should I migrate my L1 planet to L2?](#6-if-i-currently-have-an-l1-planet-are-there-any-advantages-to-migrating)
29+7. [Where did the old Bridge go? Can I still use it?](#7-is-it-possible-to-use-the-old-bridge-for-l1-operations)
30+8. [Why is the cost reduction so significant?](#8-why-is-the-cost-reduction-so-significant)
31+9. [What exactly is the mechanism for the “naive” consensus?](#9-what-exactly-is-the-mechanism-for-the-naive-consensus)
32+10. [When I spawn L2 planets via Metamask, I'm prompted to sign every transaction. Do you have plans to remedy this?](#10-when-i-spawn-l2-planets-via-metamask-im-prompted-to-sign-every-transaction-do-you-have-plans-to-remedy-this)
33+
34+#### 1. Do I need ETH to boot my planet?
35+
36+If you were invited to claim a L2 planet, you **do not** need ETH to claim
37+that Urbit ID. Anyone can get on Urbit without ETH or a crypto wallet via L2.
38+Inviting your mom to Urbit just got a lot easier.
39+
40+If you have a L1 planet, you **do** need ETH to claim that Urbit ID.
41+
42+Once you have claimed your Urbit ID and have recorded your master ticket,
43+you **do not** need ETH to boot Urbit. That Urbit ID is now yours, forever.
44+
45+Unsure whether you have been invited to claim a L2 or L1 planet? The quickest
46+way to identify a L2 planet is if you used the below flow to claim.
47+
48+![](/images/planet-l2-claim.gif)
49+
50+For those with L1 planets, you can avoid future transaction fees by migrating
51+your L1 planet to L2. Read the migration instructions
52+[here](https://urbit.org/getting-started/layer-2-for-planets).
53+
54+#### 2. Is there anything I need to do to ensure full custody of my planet?
55+
56+If you were sent a direct link to claim an L2 planet (see above), it’s
57+in your full custody by design. Bridge generates your master ticket, which you
58+downloaded during the claiming process.
59+
60+#### 3. Are there any platforms where I can buy a planet for BTC or USD?
61+
62+There are a few ways to procure a planet, including some platforms that offer
63+BTC and USD payment options.
64+
65+To purchase a L2 planet, we direct you to:
66+
67+- [Networked Subject](https://subject.network/buy/) for payment in BTC.
68+ Brought to you by `~sitful-hatred`.
69+- [planets.lanlyd.net](https://planets.lanlyd.net) and
70+ [tomdys.gumroad.com](https://tomdys.gumroad.com) for payment in USD.
71+
72+To purchase a L1 planet with ETH, there are a number of platforms dedicated
73+exclusively to Urbit ID. These include:
74+
75+- [urbit.live](https://urbit.live/buy)
76+- [urbitex.io](https://urbitex.io)
77+- [urbit.me](https://urbit.me)
78+
79+You can also acquire L1 Urbit IDs with ETH on [OpenSea](https://opensea.io/collection/urbit-id).
80+
81+Once you purchase a planet, the easiest way to manage your cryptographic asset
82+is through [Bridge](https://bridge.urbit.org/), which is our Urbit ID management
83+interface, wallet navigator, and governance portal.
84+
85+You can use Bridge to perform any desired
86+[Azimuth](https://urbit.org/docs/glossary/azimuth) interactions or download your
87+planet’s keyfile. As an alternative, [Metamask](https://metamask.io) is an
88+easy-to-use Ethereum wallet with a browser extension that integrates easily with
89+Bridge.
90+
91+#### 4. How do I get a cloud-hosted planet?
92+
93+There are a number of ways to host a planet in the cloud. Your options:
94+
95+- DIY:
96+ The most cost-effective method is [setting it up
97+ yourself](https://urbit.org/using/running/hosting), though this route requires
98+ some system administration, and troubleshooting if any issues arise.
99+
100+- Via a Hosting Provider:
101+ The more “headache-free” option is paying for a
102+ hosting provider to take care of all these processes for you, plus support. The
103+ following service providers offer hosting (some include a free planet):
104+ [Tlon](https://urbit.typeform.com/to/zQ9QOV3Z?typeform-source=tlon.io#source=tlon_io),
105+ [UrbitHost](https://urbithost.com/landing), [Get Urbit
106+ ID](https://www.geturbitid.com), [Escape Pod
107+ Store](https://www.escapepod.store), [Nodestead](https://www.nodestead.dev), and
108+ [ThirdEarth](https://third.earth/en/).
109+
110+#### 5. There are plenty of organizations dedicated to customizable rollup solutions. Why did you decide to build your own?
111+
112+Simply put, we designed and engineered our own rollup because we can’t depend
113+on the success or longevity of another organization. As they currently exist,
114+outsourced rollups are too immature and compromised in ways that undermine the
115+integrity of our technical principles. We also can’t restrict the aggregators to
116+a waitlist, another issue which might eventually be resolved, but one that we
117+can’t count on to be resolved soon.
118+
119+#### 6. If I currently have an L1 planet, are there any advantages to migrating?
120+
121+One of the most significant advantages to migrating is the reduced cost of
122+Azimuth-event related transactions. On L2, you can change sponsors or reset your
123+network keys for free with our roller. An important note: migration is currently
124+one-way. If you want to hold onto your L1 planet as a novelty, migration isn't
125+recommended.
126+
127+#### 7. Is it possible to use the old Bridge for L1 operations?
128+
129+The old version of Bridge will remain live, but unmaintained and eventually
130+decommissioned. You can access it at
131+[bridge-sunset.urbit.org](https://bridge-sunset.urbit.org). If you run into
132+something you can only do with the older version of Bridge,
133+[let us know on Github](https://github.com/urbit/bridge/issues/new?assignees=&labels=bridge&template=bridge-bug-report.md&title=).
134+
135+#### 8. Why is the cost reduction so significant?
136+
137+On L1, every operation is an Ethereum transaction, with logic and state, etc.
138+On L2, these operations are reduced and simplified into a
139+no-logic-involved Ethereum transaction. This is what makes L2 transactions
140+cost-efficient: multiple transactions happen simultaneously to share the cost of
141+just one L1 transaction.
142+
143+#### 9. What exactly is the mechanism for the “naive” consensus?
144+
145+Our engineering team has written extensively about the technical features of
146+our L2 rollup. To learn about its intricacies, we encourage you to read
147+`~datnut-pollen`’s comprehensive
148+[overview](https://urbit.org/blog/rollups#technical) and `~wicdev-wisryt`’s
149+original
150+[proposal](https://groups.google.com/a/urbit.org/g/dev/c/p6rP_WsxLS0/m/hQBX0modAwAJ?pli=1)
151+on the Urbit developer mailing list.
152+
153+#### 10. When I spawn L2 planets via Metamask, I'm prompted to sign every transaction. Do you have plans to remedy this?
154+
155+We realize this UX headache and are taking active steps to devise a more efficient transaction scheme. The new method will reduce the number of manual signatures needed for each spawned L2 planet. At the time of this FAQ's publication, we haven't publicized the release timing for the improvement. A provisional solution: set the star's spawn proxy to a custodied L2 planet secured via Master ticket and log in to Bridge as that planet to spawn invites.
content/blog/metaphase.md−4
@@ -9,12 +9,8 @@ ship = "~haddef-sigwen"
99image = "https://media.urbit.org/site/posts/essays/metaphase.jpg"
1010+++
1111
12−<br>
13−
1412![mitosis](https://media.urbit.org/site/posts/essays/metaphase.jpg)
1513
16−<br>
17−
1814_Previous versions of this essay specified the stream deploy date as December 11, 2020; then December 18, 2020. This has been amended to the actual date of release, with our sincere apologies. For new readers, you can opt into the dev stream by running:_
1915
2016```
content/blog/pin-the-face-that-launches-a-thousand-ships.mdnew file+146
@@ -0,0 +1,146 @@
1++++
2+title = "Pin the Face that Launches a Thousand Ships"
3+date = "2023-04-07"
4+description = "A guest post by ~nospex-larsut"
5+[extra]
6+image = "https://storage.googleapis.com/media.urbit.org/blog/6a0120a85dcdae970b016766c94c14970b-800wi.jpg"
7+author = ""
8+ship = "~nospex-larsut"
9++++
10+_The original article can be found [here](https://nospex-larsut.arvo.network/blog/whyhoon) using [%blog](https://urbit.org/applications/~hanrut-sillet-dachus-tiprel/blog)._
11+
12+![](https://storage.googleapis.com/media.urbit.org/blog/6a0120a85dcdae970b016766c94c14970b-800wi.jpg)
13+
14+## Pin the Face that Launches a Thousand Ships[^1] ##
15+_A short piece addressing some of the standard hesitations to learning Hoon, considered in light of all of the recent exciting network activity._
16+
17+### Setting The Table ###
18+One can draw many distinctions between the Urbit apps that were available this time last year and those released thus far in 2023, but the most important of these may be that the former were apps noticed and used almost exclusively by users already on Urbit, where the latter - notably Pongo, Realm, Tirell Studio, Groups 2, Portal, etc - are apps that are _creating Urbit users_.
19+
20+Prior to the start of 2023, the superficial, yet incomplete, take was something to the effect that much of Urbit’s appeal was largely an affinity with the ideas and principles surrounding the project.
21+
22+People who found their way to Urbit latched on to philosophical entry points, among them values such as calm computing, decentralized/privacy/data-ownership maximalism, or aspirations of replacing a generations-deep legacy computing system that entrenched an ethos of doing things fundamentally inefficiently & incorrectly, in ways that not only hobbled the potential of the internet, but resulted in outright harm to its users through establishing platform models and incentives that consciously sought to manipulate the behavior of those users in countless subtle and not-so-subtle ways.
23+
24+Urbit was a nexus, collecting people from disparate backgrounds & disciplines to something like a spiritual oasis, yes, though one seemingly situated a million miles from anywhere familiar to the outside world; its appeal was more a function of the shared ethos of the community and a shared sense of its potential rather than the existence of new & immediately useful alternatives for day-to-day compute tasks.
25+
26+The energy of Assembly '22 was palpaple; it almost seemed that widespread adoption was around the corner. Inevitably, some of the post-Assembly ‘22 buzz seemed to fizzle as the ensuing months went by; many ships launched during that time went dormant, wondering if the potential hinted at would materialize; the shallow criticisn/meme for getting on to Urbit became, “I’m here… um, now what.”
27+
28+This whole time though, the project was simultaneously also an incredibly busy construction site.
29+
30+Remarkably short-lived, “I’m here… um, now what?’ is unraveling with the realization that this universe has always been accelerating, and this new wave of apps establishes a very visible & powerful reference point for truly appreciating that acceleration and the distance traveled; after what seemed like a brief post-Assembly fizzle, the network is again kinetic and crackling with energy, but in reality it was never slowing down.
31+
32+The latest generation of apps marks an important shift in the trajectory of Urbit adoption. Much of this is possible thanks to the proliferation of hosting options - whether [Native Planet’s](https://nativeplanet.io/) self-hosted solutions or through turnkey models - which collectively have vastly streamlined the Urbit onboarding process such that getting on the network is no longer the equivalent of scaling a forbidding & remote mountain peak, arriving at the threshold of a silent monastery, heaving its heavy door ajar to find it seemingly abandoned only a thin sliver of light to illuminate your path, nobody there to acknowledge your arrival much less offer a tour. The thrill of having finally gotten there dampened by the increasing sense that all of its life is subterranean and the real journey is just beginning.[^2]
33+
34+Single-click onboarding and preloaded apps & groups may not seem like a lot for newcomers, but these things have increased tremendously the ability to get on Urbit compared to just six months ago.
35+
36+And just as a selection of competing hosting providers expanded the number of possible onramps, this new crop of Urbit apps likewise provides a complimentary function as entry points - hidden doors to Urbit embedded in the Apple/Android app stores - in ways that Urbit apps never enjoyed previously, all helping to further reduce the friction of onboarding by orders of magnitude. A user searching for a Telegram alternative stumbles across Pongo; new eyes find Urbit without ever intentionally seeking it out.
37+
38+The animating ideas behind the project, I think, remain as alive as ever - Urbit does not need to jockey to become the ‘current thing’ if it can much more efficiently become the undercurrent thing; without having to waste a single breath converting users at the margin on the necessity or virtue of recreating the web in a decentralized & privacy-oriented manner, new users are able to become advocates for apps that provide practical utility for day-to-day compute, creative, and communication needs - but that also happen to be built on such infrastructure. The yew tree doesn’t propagate itself by trying to convince the bird that it is desirable that there be more yew trees in the world, it just wraps its seed in a tasty & nutritious berry and lets the bird carry it off.
39+
40+Compelling apps, built on continually-improving and innovative infrastructure & development tooling is one piece of the adoption curve. These things bring users, who bring perspectives, feedback, ideas, wants, and needs. It brings their attention to earn it. If they are spending time on Urbit apps, they will also be exposed to whatever else is being shared on Urbit through those apps – what will catch their attention that maybe they are not seeing elsewhere? Suffice to say this is all basically network effects 101, so on to the question of learning Hoon.
41+
42+### Some Grains of Salt ###
43+Perhaps that was a lot of table-setting to get to the original inspiration of this piece, in which I wish to present some arguments to the standard objections or concerns that seem to arise for people thinking of learning Hoon. My aim is not to twist any arms or legs, but only to offer some considerations for those on the fence. Hopefully the preceding bit of history at least reveals some shred of the potential opportunities for Hooners (and other creatives - we absolutely need those as well).
44+
45+But first the grain of salt with which you should take the following:
46+I currently Hoon at something approximating a tenth-grade level. I am by no means a natural born developer, nor am I moving towards a dynamic career switch to full-time Urbit dev. Not by any stretch of the imagination. While I am interested in continuing to learn Hoon for a variety of reasons, none are likely to reverberate very far beyond my own ship.
47+
48+My Hoon education began in the summer/fall ’22 cohort of Hoon School Live. In my early 40’s, I walked into it slightly intimidated by its reputation, and with a personal technical background not much deeper than writing Excel formulas, a little Python, and building simple websites (like, 20 years ago). At the moment, I am much better at reading it than writing it, but thanks to HSL & ASL (and everyone involved with those efforts), it does make sense to me.
49+
50+So despite not exactly practicing what all I am about to preach, the foregoing, combined with having talked to enough people on the fence about learning Hoon, I feel somewhat qualified to at least offer some perspective for those considering the question.
51+
52+### The Standard Hesitations ###
53+The following hesitancies seem to be the recurring ones, and we’ll take them one at a time, although they share a significant degree of overlap.
54+<ol>
55+<li> But I already know languages x, y, z, etc and can build things with them now.</li>
56+<li> I hear Hoon is very difficult / weird / etc.</li>
57+<li> Urbit’s future is uncertain; investing in learning Hoon seems risky.</li>
58+<li> I don’t see many immediate jobs for Hoon devs.</li>
59+</ol>
60+
61+__Hesitancy 1: But I _already know_ languages x, y, z, etc and can build things with them _now_.__
62+
63+A valid contention in that one has invested in skills they are eager to put to use or continue to use. But can you build what you want to build - and where you want to build it? And what is the cost in terms of personal satisfaction to working on something which doesn’t truly excite you?
64+
65+There is something of the sunk-cost fallacy is at work here. It is not always a bad impulse, and opportunity costs are very real. But if there is something compelling about Urbit - and the fact that one is at least seriously considering learning Hoon suggests this is the case - and one is willing to view their existing proficiency in some other language as a demonstration of their capability to learn any programming language, then existing knowledge should not act as a barrier to pursuing new knowledge, particularly if there is a suspicion that working on Urbit may afford more intellectually stimulating and enjoyable opportunities.
66+
67+Consider also that a person working on things that truly animate them, despite maybe being relatively less experienced in the language, nonetheless has much more room to grow in a smaller pool where they may create closer connections, have more access to the perspectives of experienced devs, and get noticed for their contributions faster than those that may exist for a person working on things they are decidedly less passionate about amidst a pool of thousands.
68+
69+Yet another upside of working in Urbit is the sheer amount of projects yet to be built (not all require Hoon, btw); projects that may be intriguing to a developer but which already exist in some other language/product have yet to be built on here, and there is a need for them. The amount of still low-hanging fruit and infrastructure work remaining to be done, let alone potential app and utilities, is substantial, and this is a community that generally speaking, respects anybody who can come in and start contributing with minimal direction or permission.
70+
71+And is time spent learning Hoon really time spent not building things? Are you not building skills, reputation, friendships, problem-solving skills, camaraderie - building a better self - throughout the learning process? One can easily present the argument that the cost in this regard is much less than it may seem at first glance.
72+
73+Since one can only try to subjectively weigh the opportunities open to them with their current skills against the nebulous costs of _not_ pursuing something that has piqued their interest, the dilemma often cannot but remain unanswered until one takes the steps to find out; until then, it remains a persistent, nagging 'what if'?. It may take several months to feel really comfortable writing Hoon, but there is a relatively low cost to spending a few weeks to dive in and see if one has an aptitude or affinity for it.
74+
75+__Hesitancy 2: Hoon is difficult and/or weird.__
76+
77+Recognizing that there are a lot of runes, and that Hoon is odd compared to other languages,
78+
79+- learning just a handful[^3] of them along with the basic families (create cores with | runes, call functions with % runes, conditionals statements are built with ? runes, etc) will get one well on their way. </li>
80+- if Hoon is not your first language, you have already demonstrated a capacity for becoming comfortable working within a framework of structure and syntax that was, relative to your previous inexperience, alien and weird. And while there are additional wrinkles in dealing with a functional language, the majority of CS concepts remain relevant and are transferable.
81+
82+And if Hoon is your first language, it is all uncharted territory anyway and not having anything to compare it to means one is essentially in the same situation as in learning any new language, and in that respect it mirrors almost any endeavor to grasp new modes of problem-solving under a unique set of conditions and constraints. Even if you do not stick with Hoon, the new perspectives in problem-solving experience are valuable, and most of the fundamental concepts will be transferable to other languages.
83+
84+You might also consider how to use Hoon’s reputation for difficulty to your advantage from the standpoint that, if you are firmly convinced that it is or will be unduly difficult, then that should yield a much deeper satisfaction after proving you are in fact capable of learning it.
85+
86+And from a more opportunistic standpoint, realize that others who allow this reputation to dissuade them create outsized opportunities for those who are willing to learn it. One can very usefully calibrate expectations here to use the reputation to provide some cover - if it really is that hard, iit is ok to not get it at first, and you can succeed where others gave up or failed to even try.
87+
88+Speaking from my own experience, the sheer amount of terminology was somewhat overwhelming at first, and this was true of both HSL & ASL (more so the latter, IMO). Many of the names seem arbitrary, but like anything, making it familiar is largely a function of effort.
89+
90+Recognize that Hoon's unique syntax and functional paradigm are integral to its design and purpose. Instead of trying to force parallels between Hoon and other languages or concepts you already know, just immerse yourself in it with an open mind and willingness to grasp its distinct features and the reasoning behind them.
91+
92+<div class="polaroid">
93+ <img src="https://storage.googleapis.com/media.urbit.org/docs/userspace/hoon-school/binary-tree-bottom-row-full.png" alt="Tree">
94+ <div class="container">
95+
96+ <p>See - it's easy!</p>
97+ </div>
98+</div>
99+
100+__Hesitancy 3: Urbit’s future is uncertain; investing in learning Hoon seems risky.__
101+
102+Much of the table-setting for this piece was an attempt to frame the potential opportunity for devs of any level. Keeping things in perspective, Urbit is just about to hit [3,000 active ships](https://twitter.com/urbitfoundation/status/1637931937351491584). There are several reasons why recent activity may be much more indicative of even greater future growth than one might assume from looking at the chart:
103+<ul>
104+<li>a. Maybe very obviously, the growth of the last three months is not simply a 1:1 reflection of the work of the last three months, but of the many preceding years of core development that made a significant increase in percentage terms within a very short interval possible. The stage is set for much faster growth.</li>
105+<li>b. Previously mentioned, but all these threads are interconnected in that, the more eyes on Urbit, the more ideas, talent and additional users will be introduced to, and recognize the depth, of the opportunity here. A steadily stabilizing building environment (thanks to a)) that attracts and can support more users should continue to build momentum. </li>
106+</ul>
107+
108+Remaining sober about reality, 3,000 users is not exactly a ton in web 2 terms; for Urbit, it is simultaneously very many and very little. But with better apps providing more reasons to be on Urbit, working in unison with better UX and onboarding, those users have more reason to stay engaged with Urbit once they are on, which means anything an aspiring Hooner or creator can think of to give them compelling reasons to make them even more engaged is an opportunity.
109+
110+Deliberately twisting the fomo screws a little, it is as true for learning Hoon as it is of anything else that the more widely adopted a platform or language becomes, the safer a bet it will be in terms of stability and longevity. With the accretion of that stability however, the window for realizing the benefits of gaining early experience and exposure in a less-crowded space diminishes accordingly as the sense of perceived riskiness in staking ground there decreases. Like any investment, uncertaintly about the future carries the gift of a difficult to quantity but very real species of camaraderie, credibility, and respect that is only available to those willing to get involved at early stages, and which is lost as the project starts to look increasingly like a 'sure thing.' Hard to value, but weigh that aspect when considering if one should begin learning now or wait until things look ‘slightly more certain’ - what is the bar for this certainty? What is ‘certain enough’?
111+
112+Urbit, by (beautiful) design, is a very low-time preference project in some respects, but it is growing quickly. And the longer you’ve been watching Urbit grow, the more perspective you have of how much can happen in a very short time.
113+
114+When there are 10,000, 100,000 active ships it will be a trip in itself to remember that you started learning Hoon back when there were "only" 3,000, and contributed in maybe some non-trivial way to attract some quantity of new ones by building something you were excited about building.
115+
116+__Hesitancy 4: I don’t see many immediate jobs for Hoon devs.__
117+
118+_Not yet you don’t_. Much of the response to Objection 3 is also relevant here.
119+
120+The pool of Urbit companies is not fixed. It is not an insurmountable obstacle to start up a small-scale dev shop with a handful of talented devs.
121+Money flowing into Urbit is being reported with increasing frequency, and this is only the incoming money that you _hear about_. As Urbit grows, money will chase money, bringing more jobs and more opportunities. For better, or worse, of course, money changes things - more money will necessarily mean more discipline, more focus on shipping product, etc. But not having money changes things too. Money comes here in no small part because it sees the energy and intensity with which this community has been building out Urbit - regardless of whether money was flowing in or out of it - it attracted devs because the project itself was an ambitious worthwhile good in itself.
122+
123+There is much opportunity here for bright, motivated developers willing to make the effort to learn. One only has to bump the total current dev headcounts up against the growing momentum of the project to see the opportunity, whether it be in core projects, apps, or novel pairings with creators to determine ways to distribute and produce content on Urbit. The speed of deployment on Urbit compared to other projects and relative exposure to other platforms affords a significant advantage to motivated, talented people in terms of visibility - when an app gets published on Urbit, everyone sees it.
124+
125+### Wrapping Up ###
126+Hopefully the above provides some perspetive on reframing some of the standard hesitancies. None of them are irrational. However, if none of the above sways you, ask what projects or features might materialize on Urbit that would make you wish you started learning Hoon a year ago (which, in the grand scheme, would make you a reasonably well-experienced Hooner) and then consider that you could wait for that thing to materialize, or play an active part in making it a reality that will attract many other users to the network, along with making others feel like they should have started learning Hoon a year ago.
127+
128+And if the Hoon question is indeed a recurrent & nagging one, attempt to replace it with the question, “two months from now (approximately the duration of an HSL cohort), would I rather have tried learning Hoon and discovered that I don’t like it and be done with the question, or still be sitting here wondering if I should learn Hoon?”
129+
130+The resources for learning Hoon are growing:<br>
131+● [Hoon School Live](https://developers.urbit.org/courses/hsl)<br>
132+● [App School Live](https://developers.urbit.org/courses/asl) <br>
133+● [App Workshop Live](https://developers.urbit.org/courses/awl) <br>
134+● An upcoming [Core Dev course](https://developers.urbit.org/courses/csl)<br>
135+● The growing corpus of [documentation](https://developers.urbit.org/reference/hoon/overview)<br>
136+● And of course the most valuable resource of all is all the people on the network who are willing to answer questions and help one learn. Find them in the Hacker House.
137+<p>
138+
139+If something about Urbit is drawing you toward it, if the project resonates with you in a way that other things in tech do not - if you are truly intrigued by it and want to be here - it is reasonable to assert that the process of learning Hoon is not simply a tax with questionable upside, but a productive process in and of itself; that the very process of learning it will embed you deeper into a space you want to be in.
140+
141+So learn Hoon. Not only is it fun, but as an Urbiter, it is something of a cultural heritage, and the conduit between reality and whatever your endless imagination conceives Urbit’s potential to be - space here is wide open, and any of today’s aspiring Hooners has the potential to pin the face that launches a thousand ships.
142+
143+----------------
144+[^1]: To 'pin a face' is to declare a variable in Hoon.
145+[^2]: Maybe some slight dramatization; this aspect also made it fun for those not in need of immediate gratification.
146+[^3]: [See 'Rune Utilization in Hoon'](https://developers.urbit.org/blog/rune-frequency-202212)
content/blog/pki-maze.md+10−10
@@ -27,7 +27,7 @@ This is our first stop in the idea maze. We call this sort of name a "comet". A
2727
2828However, Urbit is yours and it's forever. You shouldn't have to change your name every time you change your keys. So, we go back and take the other choice: you must be able to change your keys.
2929
30−To change keys, you must sign a message with the old keys revoking them and supplying the new ones[^0]. The question is what happens if the old keys also sign a second set of new keys. This could happen if an attacker obtained your old keys after the fact. This is important because one of the reasons to be able to change your keys is to invalidate the old ones so that they have no power.
30+To change keys, you must sign a message with the old keys revoking them and supplying the new ones[^1]. The question is what happens if the old keys also sign a second set of new keys. This could happen if an attacker obtained your old keys after the fact. This is important because one of the reasons to be able to change your keys is to invalidate the old ones so that they have no power.
3131
3232We have two options again: the PKI may be globally consistent or not. To be globally consistent means that if you believe a name is bound to a set of keys, then nobody on the network will disagree.
3333
@@ -37,13 +37,13 @@ For a globally consistent PKI that allows you to revoke keys, you need to be abl
3737
3838However, the problem of proving one message was sent before any later ones inverts the problem. You can solve this with newspapers by placing the message in the text of the newspaper. However, while reading a newspaper requires no central party, writing one does. For a long time, this sort of message was always handled by a central party. SSL revocations are managed by a few central parties. When you buy property, it's not sufficient to have the previous owner sign the title — this must be entered into a central land registry. Otherwise, the owner may sell their property to multiple people and there would be no way to determine who is the new owner. With the land registry, all you need to do is ask the registry which sale happened first, and that's the one that counts.
3939
40−However, Urbit is yours and it's forever. Trusting central registries jeopardizes both. The keen reader will notice that the problem of determining which key rotation happened first is exactly the double-spend problem that Satoshi solved with his proof of work algorithm for Bitcoin. His first block famously includes a newspaper headline to prove he didn't mine the block before that date. In a beautiful duality, his own algorithm proves that he didn't mine it after that date.[^1]
40+However, Urbit is yours and it's forever. Trusting central registries jeopardizes both. The keen reader will notice that the problem of determining which key rotation happened first is exactly the double-spend problem that Satoshi solved with his proof of work algorithm for Bitcoin. His first block famously includes a newspaper headline to prove he didn't mine the block before that date. In a beautiful duality, his own algorithm proves that he didn't mine it after that date.[^2]
4141
4242Some argue that blockchain is only good for money. This is myopic and is generally based on the experience that its most valuable application so far has been money. However, blockchain is a cryptographic primitive to do what was previously impossible: prove that one message was signed before another without a central party. Blockchain was discovered by someone trying to create digital money, and he needed that primitive, but that doesn't mean that's all it's good for.
4343
44−Thus, we store our PKI data on a blockchain for our second kind of name: planets. A planet is a 32-bit address which has key information stored on the blockchain.[^2] The owner of a planet may broadcast new PKI data by adding it to the blockchain. Any later messages by the old keys will be rejected, and everyone on the network will listen to the blockchain for key data. Thus, we have global consistency, permanence, and self sovereignty. We know of no other solution that can provide these properties.
44+Thus, we store our PKI data on a blockchain for our second kind of name: planets. A planet is a 32-bit address which has key information stored on the blockchain.[^3] The owner of a planet may broadcast new PKI data by adding it to the blockchain. Any later messages by the old keys will be rejected, and everyone on the network will listen to the blockchain for key data. Thus, we have global consistency, permanence, and self sovereignty. We know of no other solution that can provide these properties.
4545
46−However, while small individually, the aggregate PKI data for all nodes on the network may become very large. This is not an issue for comets because nobody needs to store comet keys except for those which they're talking with, and even those can be garbage-collected and re-requested and verified. For planets, there is a canonical set of keys, and somebody must store that. There are about 2<sup>32</sup>, or 4 billion planets. If the PKI data is about 100 bytes for each planet, this is about 400 GB of data. This may be more than most users wish to store, but it's small enough that it would be very cheap for someone to host this data for many users[^3].
46+However, while small individually, the aggregate PKI data for all nodes on the network may become very large. This is not an issue for comets because nobody needs to store comet keys except for those which they're talking with, and even those can be garbage-collected and re-requested and verified. For planets, there is a canonical set of keys, and somebody must store that. There are about 2^32^, or 4 billion planets. If the PKI data is about 100 bytes for each planet, this is about 400 GB of data. This may be more than most users wish to store, but it's small enough that it would be very cheap for someone to host this data for many users[^4].
4747
4848This information is currently stored directly on the Ethereum 1.0 blockchain, but as is well understood in blockchain circles this approach will not scale beyond a certain point. Many chains are pursing designs that allow the users of the smart contracts to store locally the data associated with the contracts they care about and only commit hashes to the chain. We expect there to be several viable options for this by the time our scaling needs exceed what's provided by Ethereum 1.0. This will free us from the cost of hosting the PKI data on all Ethereum nodes, but the data must still be stored somewhere. Any service that could handle such a large amount of data would inherently centralize the network.
4949
@@ -61,10 +61,10 @@ To create a sane network, we require global consistency for all our names. There
6161
6262- Moons are permanent, not self sovereign, and plentiful.
6363
64−Fancifully, comets are wayward celestial bodies that are great for testing and miscellaneous low-value things that won't last for long. Planets are where you can build a home and shape it into anything you want it to be. People can always find your planet; it's not going anywhere. Moons are useful for special purposes, like storage, heavy industry, and anything else you might want to do off-planet.[^4]
64+Fancifully, comets are wayward celestial bodies that are great for testing and miscellaneous low-value things that won't last for long. Planets are where you can build a home and shape it into anything you want it to be. People can always find your planet; it's not going anywhere. Moons are useful for special purposes, like storage, heavy industry, and anything else you might want to do off-planet.[^5]
6565
66−[^0]: Or the equivalent with a hierarchical key structure. In practice, you want to have a master key which signs a junior key for everyday use. You use the master key to rotate the junior key.
67−[^1]: More strictly: it proves that he didn't mine it after the other blocks currently on the Bitcoin blockchain. It only gives an ordering within the chain, not a literal timestamp.
68−[^2]: In addition to planets, there are stars and galaxies. From a PKI perspective they're treated exactly like planets, but on the network they provide infrastructure services like routing.
69−[^3]: In practice, this will likely be an included service by your sponsoring star. It could be a separate service, but it will be very cheap because it's a commodity and the "cost of production" is very cheap. At any rate, it should never rise above the capital cost of a 400GB hard drive.
70−[^4]: To extend the metaphor, stars are a neighborhood to live in -- they're easier for other planets to see, so when they want to send you a message they look for your star first. If they don't even know where your star is, they can certainly find your star's galaxy, and that will be enough to locate the star. Of course, if your star is not providing satisfactory service, you can take your planet and move to another star.
66+[^1]: Or the equivalent with a hierarchical key structure. In practice, you want to have a master key which signs a junior key for everyday use. You use the master key to rotate the junior key.
67+[^2]: More strictly: it proves that he didn't mine it after the other blocks currently on the Bitcoin blockchain. It only gives an ordering within the chain, not a literal timestamp.
68+[^3]: In addition to planets, there are stars and galaxies. From a PKI perspective they're treated exactly like planets, but on the network they provide infrastructure services like routing.
69+[^4]: In practice, this will likely be an included service by your sponsoring star. It could be a separate service, but it will be very cheap because it's a commodity and the "cost of production" is very cheap. At any rate, it should never rise above the capital cost of a 400GB hard drive.
70+[^5]: To extend the metaphor, stars are a neighborhood to live in -- they're easier for other planets to see, so when they want to send you a message they look for your star first. If they don't even know where your star is, they can certainly find your star's galaxy, and that will be enough to locate the star. Of course, if your star is not providing satisfactory service, you can take your planet and move to another star.
content/blog/platform-decay.md+1−3
@@ -9,9 +9,7 @@ ship = "~simfur-ritwed"
99image = "https://media.urbit.org/site/posts/essays/platform-decay-preview.png"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/platform-decay.png">
12+![](https://media.urbit.org/site/posts/essays/platform-decay.png)
1513
1614## Platform decay, decentralized marketplaces, and Urbit
1715
content/blog/precepts-discussion.md+7−21
@@ -9,9 +9,7 @@ ship = "~wicdev-wisryt"
99image = "https://media.urbit.org/site/posts/essays/discuss-01.jpg"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/discuss-01.jpg">
12+![](https://media.urbit.org/site/posts/essays/discuss-01.jpg)
1513
1614The precepts aren’t arguments. We will discuss and justify them here. We don't expect to convince you this is exactly the right set of precepts, but we hope to convince you that this is a coherent set of precepts that might lead to something very interesting.
1715
@@ -36,9 +34,7 @@ We will address these in the same categories presented above:
3634- F: Real Software. Not all software matters. Any software which
3735 wouldn't exist on Mars isn't real.
3836
39−<br>
40−
41−<img class="ba" src="https://media.urbit.org/site/posts/essays/discuss-02.jpg">
37+![](https://media.urbit.org/site/posts/essays/discuss-02.jpg)
4238
4339### A: General Design
4440
@@ -355,9 +351,7 @@ An example of the second is "security through obscurity is ineffective". Securit
355351
356352However, it's important for whoever's coming up with the cliches to understand the specifics of how they're untruthful. Some of these very precepts may fall under the category of "literally untrue but more useful than the truth".
357353
358−<br>
359−
360−<img class="ba" src="https://media.urbit.org/site/posts/essays/discuss-03.jpg">
354+![](https://media.urbit.org/site/posts/essays/discuss-03.jpg)
361355
362356## B: Specific Design
363357
@@ -415,9 +409,7 @@ Memory access restrictions are blunt tools. Blunt tools are nice in simple syste
415409
416410Better to define rules in a more powerful language. This allows you to follow A6 and A8. It also lets you use all the correctness tools, like type systems, that you've developed for the rest of your code.
417411
418−<br>
419−
420−<img class="ba" src="https://media.urbit.org/site/posts/essays/discuss-04.jpg">
412+![](https://media.urbit.org/site/posts/essays/discuss-04.jpg)
421413
422414### C: Attitude
423415
@@ -468,9 +460,7 @@ of your own mind.
468460This is also one of the best ways to build stuff correctly. Very often, you will be tempted to cut a corner, and someone will point out that it should be done correctly. You should consider why you immediately rejected it. Was it because you were afraid of the relevant piece of code? If so, you should learn more about that code to determine if it's actually a good idea. Did you reject it because you felt it would distract you from working on what you thought was more important?
469461Consider carefully whether this particular piece of technical debt is worth taking on. It's worth 60 seconds of thinking about how you could solve it correctly right now — often it would be quite easy to do correctly and you'd be paying interest on the incorrectness for a long time.
470462
471−<br>
472−
473−<img class="ba" src="https://media.urbit.org/site/posts/essays/discuss-05.jpg">
463+![](https://media.urbit.org/site/posts/essays/discuss-05.jpg)
474464
475465### D: Theory
476466
@@ -511,9 +501,7 @@ objective properties and your subjective judgment of the quality of the system.
511501
512502However, that explanatory power is indeed powerful, and the exploratory suggestions are often able to break you out of a rut (attractor basin). Respect the tension.
513503
514−<img class="ba" src="https://media.urbit.org/site/posts/essays/discuss-06.jpg">
515−
516−<br>
504+![](https://media.urbit.org/site/posts/essays/discuss-06.jpg)
517505
518506### E: Text Style
519507
@@ -615,9 +603,7 @@ We're really good at memorizing sets of things, like runes. We're also good at i
615603
616604So don't be afraid to use new names for new concepts. If concepts are siblings, they needn't necessarily have a direct connection in their name, but if they're hierarchical, then something should suggest that. This can be syntactic or semantic.
617605
618−<br>
619−
620−<img class="ba" src="https://media.urbit.org/site/posts/essays/discuss-07.jpg">
606+![](https://media.urbit.org/site/posts/essays/discuss-07.jpg)
621607
622608### F: Real Software
623609
content/blog/precepts.md+7−21
@@ -9,9 +9,7 @@ ship = "~wicdev-wisryt"
99image = "https://media.urbit.org/site/posts/essays/pre-01.jpg"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/pre-01.jpg">
12+![](https://media.urbit.org/site/posts/essays/pre-01.jpg)
1513
1614Urbit is a principled approach to system design and programming, but it's often not obvious what those principles are. We have many specific terms for the different parts of the project: Arvo is the OS, Hoon is the language, Tlon is the company, Azimuth is the identity system, Ames is the network. But the word most associated with the project is "Urbit", and it's not clear what technically it refers to. It's only a small stretch to say that "Urbit" _is_ this set of principles, and that if anybody follows these principles strictly they will create a system that is isomorphic to the Urbit.
1715
@@ -19,9 +17,7 @@ Some of these are commonly held among many software projects, and some are not.
1917
2018We’ll start with a brief description of many principles, then we’ll go into a long-form justification.
2119
22−<br>
23−
24−<img class="ba" src="https://media.urbit.org/site/posts/essays/pre-02.jpg">
20+![](https://media.urbit.org/site/posts/essays/pre-02.jpg)
2521
2622### A: General Design
2723
@@ -138,9 +134,7 @@ We’ll start with a brief description of many principles, then we’ll go into
13813423. Some cliches are repeated because they are true; others must be
139135 repeated because they are not.
140136
141−<br>
142−
143−<img class="ba" src="https://media.urbit.org/site/posts/essays/pre-03.jpg">
137+![](https://media.urbit.org/site/posts/essays/pre-03.jpg)
144138
145139### B: Specific Design
146140
@@ -170,9 +164,7 @@ We’ll start with a brief description of many principles, then we’ll go into
170164 A compiler can use type safety as an effective tool to enforce
171165 some classes of security guarantees.
172166
173−<br>
174−
175−<img class="ba" src="https://media.urbit.org/site/posts/essays/pre-04.jpg">
167+![](https://media.urbit.org/site/posts/essays/pre-04.jpg)
176168
177169### C: Attitude
178170
@@ -203,9 +195,7 @@ We’ll start with a brief description of many principles, then we’ll go into
203195 responding take a full 60 seconds to envision how you would implement
204196 it and what the effects would be.
205197
206−<br>
207−
208−<img class="ba" src="https://media.urbit.org/site/posts/essays/pre-05.jpg">
198+![](https://media.urbit.org/site/posts/essays/pre-05.jpg)
209199
210200### D: Theory
211201
@@ -250,9 +240,7 @@ We’ll start with a brief description of many principles, then we’ll go into
250240 use theory to fix the bad, add the missing, and remove the
251241 unnecessary. Repeat.
252242
253−<br>
254−
255−<img class="ba" src="https://media.urbit.org/site/posts/essays/pre-06.jpg">
243+![](https://media.urbit.org/site/posts/essays/pre-06.jpg)
256244
257245### E: Text Style
258246
@@ -285,9 +273,7 @@ We’ll start with a brief description of many principles, then we’ll go into
285273
2862748. Abbreviations aren't worth it.
287275
288−<br>
289−
290−<img class="ba" src="https://media.urbit.org/site/posts/essays/pre-07.jpg">
276+![](https://media.urbit.org/site/posts/essays/pre-07.jpg)
291277
292278### F: Real Software
293279
content/blog/providers.md+1−5
@@ -9,11 +9,7 @@ ship = "~ravmel-ropdyl"
99image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/providers.png"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://storage.googleapis.com/media.urbit.org/site/posts/essays/providers.png">
15−
16−<br>
12+![](https://storage.googleapis.com/media.urbit.org/site/posts/essays/providers.png)
1713
1814We look forward to a future where your Urbit is an always-on, always-available service. You should be able to pick up any device and conjure up your whole digital life immediately.
1915
content/blog/pseudonymous-reputation.mdnew file+64
@@ -0,0 +1,64 @@
1++++
2+title = "Building Your DAO with Pseudonymous Reputation on Urbit"
3+date = "2022-07-19"
4+description = "Using Urbit ID’s pseudonymous reputation model, DAO participants know Urbit ID holders’ past behavior before relying on them, and without sacrificing anonymity."
5+
6+[extra]
7+author = "Anthony Arroyo"
8+ship = "~poldec-tonteg"
9+image = "https://storage.googleapis.com/media.urbit.org/blog/2022.7.14..19.19.05-image.jpg"
10++++
11+
12+![](https://storage.googleapis.com/media.urbit.org/blog/2022.7.14..19.19.05-image.jpg)
13+
14+_This is cross-posted from [The Combine DAO Blog](https://blog.the-combine.org). If you'd like to comment, join the public [Urbit group](https://urbit.org/groups/~famreb-todmec/the-combine-public)._
15+
16+[The Combine DAO](https://blog.the-combine.org/introduction-to-the-combine-dao) is a DAO built on Urbit to invest in promising projects on the network. While building the DAO, we did a survey of the existing identity solutions and found our solution close to home: Urbit ID provided the best balance of trust and anonymity due to the Urbit networks’ pseudonymous reputation. In this post, we’ll discuss the challenges facing DAOs and discuss why Urbit ID presents advantages over current approaches like token gated DAOs.
17+
18+## Trust, Anonymity and Pseudonymous Reputation
19+
20+Anonymity is a core feature of most DAOs. It’s great in theory. No one wants to trust that the humans operating Robinhood will execute trades how and when they say they will (much less know their names.) We’d all prefer if a smart contract handled it for them.
21+
22+The problem is that trust and anonymity don’t mix, and trust is essential to the practical operation of any organization. This is why existing DAOs take shortcuts to establish trust hierarchies—things like delegating multi-sigs to small groups of trusted leaders, or trusted leaders establishing authority via exclusive Discord channels.
23+
24+Put simply, if there’s no human to trust, there’s no human to hold accountable. Lack of accountability is a major hurdle for any organization.
25+
26+We were aware of this fundamental flaw when building Combine DAO on Urbit, and we’ve found a solution in Urbit ID. Urbit ID is the decentralized identity system at the core of the Urbit project. Urbit IDs are the “decentralized IDs” that [DAO builders yearn](https://thmueller.medium.com/decentralized-identity-3-ways-to-build-trust-in-your-dao-4871491903c8) for. They’re endowed with what we call pseudonymous reputations that unlock the ability to run DAOs in ways that more closely resemble successful IRL organizations, while maintaining the automation that makes them so attractive.
27+
28+## What is Urbit ID?
29+
30+Why is your Urbit ID so different from every other online identity you’ve ever had? The substantive answer is simple: it’s a lot more like your IRL identity. It’s permanent and owned by you. And because it’s the same throughout the Urbit network, it can accrue a reputation.
31+
32+You’ve probably seen Urbit IDs like `~ravmel-ropdyl` or `~mogmet-tadnem` in Twitter profiles. Each is a unique NFT that can be transferred and sold like any other cryptographic asset. Your Urbit ID is your username, network address and crypto wallet all in one.
33+
34+Like wallet addresses, Urbit IDs are anonymous. Like Discord, Twitter, or Notion accounts, they are also pseudonymous. Pseudonymity is the kind of anonymity you find in most online communities: a common username that people recognize even if it’s not your “real” name.
35+
36+Your Urbit ID is to your urbit ship what your deed is to your house or your keys to your car. It encrypts all of your ship’s communications and provides access to your online communities, which in this instance are DAOs.
37+
38+Using Urbit ID’s pseudonymous reputation model, DAO participants know Urbit ID holders’ past behavior before relying on them, and without sacrificing anonymity. Why do reputations stick to Urbit IDs? Because, like your physical person, every action you take with your Urbit ID affects your reputation. Urbit maximalists often ask “How high of a ransom would you pay if your Urbit ID were ‘kidnapped?’” That’s because the reputation of your Urbit ID is the result of years of labor. Imagine every social account you’ve ever had in one immutable chain tied to one immutable pseudonym.
39+
40+Thus, unlike an anonymous wallet address, Twitter handles or Discord accounts, there are high incentives for keeping your Urbit ID’s reputation squeaky clean.
41+
42+## Urbit ID for DAOs
43+
44+Many DAOs gate their membership on the ownership of a cryptographic asset like an ERC-721 or an ERC-20 token. Token gating is used to create a flat, anonymous membership. This was initially seen as a good thing. “One member, one voice.” All decisions made anonymously via multi-sigs and voting apps secured via smart contract.
45+
46+Token gating also adds utility to NFTs; it unlocks access to perks like special releases or events apart from the core asset. To get into the Milady Rave you need to buy a Milady NFT. It doesn’t matter who you are, what you’ve done, or how capable you are of participating in the community’s goals, if you buy a Milady, you’re in. You have the same rights and privileges as everyone else.
47+
48+In reality, many DAOs move inexorably back towards a more conventional model of “human trust” simply because organization requires it. That’s why DAO builders have long sought “decentralized IDs” for members. “One member, one voice” doesn’t work for complex, efficient decision making; it risks chaos and endless discussion. It creates the need for offchain governance executed by smaller groups, which is cumbersome, requires a patchwork of Web2 apps (i.e. Google and Notion), and undermines the “trustless” nature of the DAO.
49+
50+To return to a prior example, imagine Robinhood was a DAO of its members. If it was run like DAOs today—e.g. those not built on Urbit—a group of Robinhood “elites” make and execute trade decisions via private Discord channels. DAO members vote to approve, but participation is low. Some DAOs even cold-call members to garner participation. Not only is participation low, it’s also low quality: banter about the issues of the day.
51+
52+Urbit ID mitigates membership participation issues by adding permanent, pseudonymous reputations to the mix. As in: Who are you letting into your DAO? And whose DAO are you joining?
53+
54+As a leader of an organization, you want high quality members. You want to avoid Dumb Money: people passively investing in your DAO because it’s cool, but without the ability to add value. You also want to avoid oversubscription/underparticipation: a dropoff in engagement from most members as they become interested in newer, shinier things.
55+
56+When it came time to recruit members for Combine DAO, we didn’t have to leave Urbit. We only considered those with strong pseudonymous reputations on the network, many of whom were anonymous outside of Urbit. Some of the Urbit IDs in Combine DAO like `~bitmep-faswyn` have been on the network for years. Some like `~timluc-miptev` have created valuable groups and built companies on Urbit. Selection blindness was both unneeded and unnecessary—members were selected not in spite of “who” they were on Urbit, but because of it.
57+
58+Pseudonymous reputations also allow prospective DAO members to better evaluate leaders. Urbit ID reputations subsume the need for patchworks of authority. You know exactly “who” `~mogmet-tadnem` is. You don’t need to google his Twitter handle and figure out, oh maybe he’s also the guy behind this or that DAO or NFT release. Leaders benefit from the past and are held accountable for future actions.
59+
60+Now, the organizing forces behind Combine DAO are `~poldec-tonteg` and `~wolref-podlex`. In this case, their real world identities are known to many, but they needn’t be: their actions on the network speak for themselves. `~poldec-tonteg` is the former CPO of Tlon and `~wolref-podlex` is the Executive Director of the Urbit Foundation. Prospective members of Combine DAO know who they are aligning themselves with.
61+
62+To sum it up, Urbit ID is a solution for the reputational problems faced by DAOs in their current form. While good in theory, the trustless nature of DAOs leads to practical issues around organization, leadership, membership, voting, and participation. This is why DAO builders need ways to give their membership durable reputations that can travel with the members as they participate.
63+
64+Urbit offers just such cryptographic identities with portable reputations in the form of Urbit IDs. We put pseudonymous reputations to the test in building Combine DAO, and discovered they enhanced leadership formation and membership curation, eliminating some of the organizational problems that DAOs struggle with today.
content/blog/rollups.md+4−4
@@ -121,7 +121,7 @@ And that's it! If you'd like to know how things will be changing for
121121[stars](#stars), what goes into [setting up a roller](#rollers), and additional
122122[technical details](#technical), read on.
123123
124−### Changes to stars {#stars}
124+### Changes to stars {% #stars %}
125125
126126Both planets and stars will be able to move to layer 2.
127127[Galaxies](/docs/glossary/galaxy) must remain on layer 1 for technical
@@ -148,7 +148,7 @@ moving ownership to layer 2, this will be a one-way journey for now. Planets
148148spawned before moving the spawn proxy to layer 2 will remain on layer 1, but
149149from then on, all planets spawned by that star will live on layer 2. Finally, stars in this second mode may transition to the first mode, but not vice versa.
150150
151−### Creating a roller {#rollers}
151+### Creating a roller {% #rollers %}
152152
153153![gasprices](https://media.urbit.org/site/posts/essays/gasprices.jpeg)
154154
@@ -182,7 +182,7 @@ making a couple minor alterations:
182182- Galaxies and their proxies cannot be deposited to layer 2.
183183 Some other minor details are yet to be worked out, but again, nothing will change for those who wish to remain on layer 1.
184184
185−### Technical details {#technical}
185+### Technical details {% #technical %}
186186
187187What's really going on behind the scenes here? Briefly, only the data of the Urbit ID transactions will be posted on-chain, while computation and state storage will now happen on your ship.
188188
@@ -203,7 +203,7 @@ blockchain, rather than the EVM.
203203Since [Urbit OS](/docs/glossary/arvo) is deterministic, and Hoon has some nice formal
204204properties, it turns out to be a great language for writing smart contracts. Thus we are effectively swapping the Ethereum smart contract with a “Hoon smart contract” run locally on your ship.
205205
206−#### Further Resources {#resources}
206+#### Further Resources {% #resources %}
207207
208208We want to keep this post brief and non-technical, so that's all we'll say about
209209it for now. To find out more, you have a few directions to go on. We held a
content/blog/security-audit.md−4
@@ -9,12 +9,8 @@ ship = "~rovnys-ricfer + ~poldec-tonteg"
99image = "https://storage.googleapis.com/media.urbit.org/site/posts/essays/20201218-audit.png"
1010+++
1111
12−<br>
13−
1412![audit](https://storage.googleapis.com/media.urbit.org/site/posts/essays/20201218-audit.png)
1513
16−<br>
17−
1814The security firm Leviathan has now finished their initial audit of the security of Urbit's Ames network protocol. In addition to their review of Ames, we also asked them to identify any other issues in order to help guide further development.
1915
2016I'm pleased to report they confirmed the cryptographic soundness of the protocol, namely that "a ship must have possession of their own valid Urbit key in order to authenticate as that ship and to send valid Ames messages. Additionally, no other ship except the two communicating may be able to decrypt or modify messages during transport."
content/blog/simple-durable-yours.md+3−3
@@ -9,13 +9,13 @@ We live in a world dense with digital services. We see the world through them, w
99
1010But computers are a mess.
1111
12−<img class="ba mv5 w-100" src="https://media.urbit.org/site/understanding-urbit/simple-durable-yours/simple-durable-yours-notifications.svg">
12+![](https://media.urbit.org/site/understanding-urbit/simple-durable-yours/simple-durable-yours-notifications.svg)
1313
1414We spend all our time switching between services, juggling logins and different interfaces. And once we’re logged in, the services we use harvest our data, spy on us, and often shut down with little warning.
1515
1616If computers are going to be a part of our lives for generations to come, we need a sound foundation for them. We need a _system_, not a grab bag of apps and services. Urbit is that system.
1717
18−<img class="ba mv5 w-100" src="https://media.urbit.org/site/understanding-urbit/simple-durable-yours/simple-durable-yours-rock%402x.png">
18+![](https://media.urbit.org/site/understanding-urbit/simple-durable-yours/simple-durable-yours-rock%402x.png)
1919
2020We built Urbit from scratch to be a system that’s simple, durable, and yours. Everything that computing today is not — but should be.
2121
@@ -39,7 +39,7 @@ Your Urbit is designed to be durable: both to store your data across generations
3939
4040Finally, your Urbit belongs to you in every possible way. You own it with a private key, control it completely, and can inspect its source code. We want your Urbit to be your digital home. A home you don’t own is just a hotel room.
4141
42−<img class="ba mv5 w-100" src="https://media.urbit.org/site/understanding-urbit/simple-durable-yours/simple-durable-yours-evolution.svg">
42+![](https://media.urbit.org/site/understanding-urbit/simple-durable-yours/simple-durable-yours-evolution.svg)
4343
4444Urbit began as a sketch, driven from a basic intuition that a better platform could be built. Today, Urbit is two components: Urbit ID, an identity system that’s already live on Ethereum; and Urbit OS, a decentralized network and OS stack that’s young but working well.
4545
content/blog/smart-home-of-the-future.mdnew file+60
@@ -0,0 +1,60 @@
1++++
2+title = "The Smart Home of the Future"
3+date = "2022-08-04"
4+description = "Homes are getting smarter. A smart home is no longer just a collection of smart devices but a superorganism of data-collecting objects. These people and devices who use and inhabit these homes form a complex socio-technical system. What is the future of the smart home and how will Urbit fit into it?"
5+[extra]
6+author = ""
7+ship = "~pilwyc-fastec"
8+image = "https://storage.googleapis.com/media.urbit.org/blog/484f30d6e2d5aa86840a662a8b57bdd5.jpg"
9++++
10+
11+![The Smart Home of the Future](https://storage.googleapis.com/media.urbit.org/blog/484f30d6e2d5aa86840a662a8b57bdd5.jpg)
12+
13+During the last couple months I’ve worked on learning what makes smart homes tick for Urbit users through a [grant by the Urbit Foundation](https://urbit.org/grants/communal-computing). What I’ve found (and [published in the final whitepaper](https://pilwyc-fastec-public.s3.us-west-2.amazonaws.com/Communal-Computing-for-Urbit-whitepaper.pdf)) is that people have a complicated relationship with the technologies in their homes while the number of devices are continuously increasing.
14+
15+It is further complexified by the fact that for every additional person in the household there is an expanding total number of interactions because of connections individuals form as groups. For example, I may generate one type of data sitting in a room by myself listening to music and a very different set of data sitting with my whole household watching a video together (while also browsing our own personal devices).
16+
17+The relationships you have with everyone that lives and visits your home (even the people that are not supposed to be there) are how we start to define our identity inside those spaces.
18+
19+During the study, I also learned about some important distinctions of Urbit's identity and (current lack of) digital reputation compared to other computing platforms.
20+
21+[Lunar Urbit and the Internet of Things](https://urbit.org/blog/iot) brings up key questions about the perfect paradigm for computing in the Urbit smart home. In that post [~datnut-pollen](https://urbit.org/ids/~datnut-pollen) articulates a problem with smart home devices:
22+
23+
24+> The Internet of Things is much maligned by technologists as a privacy, security, and maintenance nightmare. These products usually depend on phoning home to perform their service, which is inevitably a funnel by which personal data is harvested, an attack surface for hackers to gain access to your home network, and a single point of failure which may render the device useless, all in one!
25+
26+There are a range of needs and preferences regarding a person’s identity, the data they create in the home, and how data would be used. About half of the people thought of themselves as a singular online identity and had fewer concerns with sharing their data with 3rd parties. The other half of people that saw themselves segmented into different identities (e.g. home vs. work vs. online) were concerned with all of the data being sent to 3rd parties from their smart home.
27+
28+This is likely because people’s identities are split based on the relationships they have in their lives. This is related to how they consider what is a violation of privacy based on how their information is used. A framework in the practice of privacy is [Contextual Integrity](https://en.wikipedia.org/wiki/Contextual_integrity) first proposed by Helen Nissenbaum in [Privacy In Context: Technology, Policy, and the Integrity of Social Life](https://www.amazon.com/Privacy-Context-Technology-Policy-Integrity/dp/0804752370). It outlines a model that is based on norms and expectations by people of how they control the flow of their data rather than a false dichotomy of private vs. public. Mismatches between where a person expects their data to go and where it actually goes causes privacy violations. For more ways this is linked to the Urbit privacy models see the [white paper](https://pilwyc-fastec-public.s3.us-west-2.amazonaws.com/Communal-Computing-for-Urbit-whitepaper.pdf).
29+
30+Through these interviews I also found that Urbit’s identity doesn’t, by default, include strong reputational considerations for people. It started in an early conversation I had with [~wolref-podlex](https://urbit.org/ids/~wolref-podlex) about how communal computing would make sense in the Urbit world of strong identity and was confirmed through the discussions we had. The only information that shows up in Urbit communities today are your ID and sigil. Your reputation is then built in every human’s head based on the interactions they have with you through the community. This is a departure from what many technology platforms do today by encoding reputation in stars, likes, and other reputational markers.
31+
32+Lack of reputation legibility is valuable because “snapping to” a set of reputations doesn’t account for all of the different identities that form through the relationships you have. This is especially true for households where there are multiple people or multiple generations. It isn’t so much that they need to be illegible but that having anything other than a human decide what is appropriate will lead to incorrect assessments.
33+
34+In a recent post [Soulbinding Like a State](https://subconscious.substack.com/p/soulbinding-like-a-state), Gordon Brander makes some important points on how the requirement to be legible with identity systems is hazardous for people, especially at the scale of the internet. Client-server models that have proliferated with smart home technologies require that identities need to be legible to the 3rd party services. This is because we are mistaking the need for access with evaluations of those people. Confusing those creates circumstances that will overconstrain the possibilities of a people with the needs of the system.
35+
36+An Urbit smart home could deliver a more realistic identity model, communal experiences, and match the expectations of privacy by letting people relate as humans rather than identities or accounts. It doesn’t stop with only people physically in the household. Households can be joined across space and time. Think about those households intermediated by technology like a shared photo stream that shows up in two different household’s picture frames.
37+
38+For Urbit to be a better part of the home it needs to continue to focus on access through its peer-to-peer network rather than creating complex schemes for the person’s reputation. The reputation within a household is through the interpretations of those that are there in the household. There are many different relational identities like being a parent, a spouse, part of a parent-teacher association, table-top gaming group, and a backyard BBQ crew which is all part of your identity. The norms of how people deal with each other in the home will evolve over time including what should be shared within that context. Who is allowed in a room or not is something set by the expectations of norms that are negotiated between people. This includes photos that should be shown (or not) on the shared picture frame.
39+
40+[Stewart Brand](https://en.wikipedia.org/wiki/Stewart_Brand)’s book [How Buildings Learn](https://en.wikipedia.org/wiki/How_Buildings_Learn) points to how building are in a constant state of flux:
41+
42+> A building is not something you finish. A building is something you start.
43+
44+We should assume that when we add technologies to the household with connected devices this isn’t any different. How we build these devices to respect the privacy, identity, and relationships of people will be key.
45+
46+The next step is to take this work forward and show how the Urbit platform could be used for smart home control. Due to the way the most smart home devices are built today we won’t be able to completely stop the sharing of data in the home with 3rd parties but we can somewhat obfuscate a person’s identity behind their Urbit identity that the device maker won’t understand. In my next [grant proposal](https://pilwyc-fastec-public.s3.us-west-2.amazonaws.com/Communal-Computing-for-Urbit-whitepaper.pdf#page=11&zoom=100,96,96) we will be looking to build a prototype of Gall app to control the most commonly used smart home device: the smart light bulb.
47+
48+The future of Urbit in the smart home will depend on its ability to integrate with many different device manufacturers. As these devices are installed, upgraded, and generally maintained they need to persist the identities of people in the home and configuration over time whereas most today require a relogin. The people in the home should maintain control over the systems automatically and perpetually rather than having to keep reasserting it through password resets. When they decide to leave the home they should be able to easily transfer that ownership to the next occupant like they would a set of keys.
49+
50+Another quote by Stewart Brand on buildings:
51+
52+> All buildings are predictions. All predictions are wrong.
53+
54+Our guesses as to what the people in a smart home of the future needs will be incorrect. What we can do is start to build around the doctrine of Urbit focused on personal data ownership, simplified identity, and leaving reputation to humans.
55+
56+The future of computing in the home will be one that is ubiquitous, contextual, and communal. Urbit needs to embrace the strong identity it already has without forcing legible reputational systems that are meant to be all-encompassing. The ownership over data and what happens to an Urbit ship will be a huge benefit when considering the growing distrust in 3rd party, client-server architectures. Urbit has a real opportunity to provide the home of the future with a platform for computing that let’s people be themselves and feel their home’s data, like their home, is really theirs.
57+
58+–
59+
60+*[~pilwyc-fastec](https://urbit.org/ids/~pilwyc-fastec) is a smart home pragmatist and Urbit enthusiast. While he enjoys the chaos of children using smart home devices he wishes it didn’t wreck his music recommendations so much. He can be found in the [Communal Computing for Urbit community](https://pilwyc-fastec.tlon.network/apps/landscape/~landscape/ship/~pilwyc-fastec/communal-computing-for-urbit/resource/chat/ship/~pilwyc-fastec/discussion-7484) if you want to get in touch.*
content/blog/the-missing-middle.md+1−5
@@ -9,11 +9,7 @@ ship = "~simfur-ritwed"
99image = "https://media.urbit.org/site/posts/essays/missing-middle.png"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/missing-middle.png">
15−
16−<br>
12+![](https://media.urbit.org/site/posts/essays/missing-middle.png)
1713
1814The promise of social technology is that we can discover more friends; _specifically, people more similar to us_ than we previously had access to. The means by which we do so, the methods of collaboration, the quality of connected experiences; these factors matter, but they are marginal considerations compared to the basic offering of an expanded choice of connections.
1915
content/blog/the-shape-of-dao-governance-to-come.mdnew file+103
@@ -0,0 +1,103 @@
1++++
2+title = "The Shape of DAO Governance to Come"
3+date = "2022-08-17"
4+description = "When building the Combine DAO, we conducted a survey of DAO governance and tooling and came to the conclusion that the many theoretical approaches to the problem of governance were tied to the implementation details of the DAO stack. Since we were building everything on Urbit—as opposed to through the typical combination of Solidity contracts, Web2 tools and Snapshot—we realized that we’d have to do some rethinking. A new approach for a new stack."
5+
6+[extra]
7+author = "Anthony Arroyo"
8+ship = "~poldec-tonteg"
9+image = "https://storage.googleapis.com/media.urbit.org/blog/2022.7.29..17.14.22-image.jpg"
10++++
11+
12+![Image](https://storage.googleapis.com/media.urbit.org/blog/2022.7.29..17.14.22-image.jpg)
13+
14+On Urbit, the risk of a governance attack is reduced because the Combine DAO’s founding team was selected based on their on-Urbit track records. All participants had skin in the game. This allowed us to focus on workaday consensus building, which forms the bulk of any organization’s activities. We use Holium’s Ballot app, which integrates with all aspects of Urbit OS and gives complete flexibility for automating the execution of a winning proposal via [Custom Actions](https://docs.holium.com/ballot/custom-actions/intro).
15+
16+Let’s walk through the thought process that led us to adopt an Urbit-centric approach to DAO governance.
17+
18+## Reputation’s Effect on DAO Governance
19+
20+In our last blog, we discussed how Urbit’s pseudonymous reputation model frees DAOs from the constraints of “trustless” systems. Urbit IDs also mitigate the inflexibility that plagues DAO governance. Here’s what we mean.
21+
22+One of the primary objectives of DAO governance systems is to prevent governance attacks. A governance attack occurs when one or more actors changes the internal processes to benefit themselves, for example transfering the entire treasury to himself.
23+
24+The risk of governance attacks means DAO governance is either 1) very rigid or 2) vulnerable. The vast majority of DAOs, Moloch for example, opt for the former. Thus the rules around upgrading smart contracts are constrained. Once systems are in place, they can’t be changed. On-chain activity is limited. Voting procedures are either distilled or taken off-chain (and usually onto Web2.) This leaves DAOs inflexible.
25+
26+Here’s an example of said inflexibility gone wrong. In March of this year, the DAO that runs the Ethereum Name Service [held a vote](https://www.coindesk.com/layer2/2022/03/07/ens-and-the-limitations-of-dao-governance/) to oust its director Brantly Millegan. Brantly had recently been canceled for 2016 tweets dug up by an anonymous DAO member, fired from his role as director of operations at ENS’ non-DAO corporate parent True Names Limited. ENS iself, however, was governed by a typical 1 share: 1 vote system (plus delegates). Unsurprisingly, Millegan owned or controlled a large block of votes, and was able to overcome the ouster vote 1.6 million tokens to 1.4 million, with holders of roughly one third of the tokens abstaining or not participating.
27+
28+Now, this is indeed a DAO working as it should, a democratic decision unswayed by the influence of insiders or elites. At the same time, the natural functioning of the DAO was derailed by mass distraction. Instead of focusing on ENS, for nearly a year the DAO’s function was to address a controversy raised by an anonymous member who, if we’re being honest, most likely intended to disrupt its active functioning from the start.
29+
30+We arrive back again at the inflexibility inherent to anonymity—if just anyone can buy a token, bad actors will buy them. Yet currently most DAOs intentionally eschew reputation. The incentives for good behaviors are thus only economic.
31+
32+[Pseudonymous reputation](https://urbit.org/blog/pseudonymous-reputation) changes this calculus, adding incentives beyond money for both security and participation. This means when built on Urbit, DAOs are less susceptible to governance attacks, and more flexible. Having a baseline of trust allows DAOs to experiment with different governance tools and structures.
33+
34+In order to understand how DAOs are more free to experiment on Urbit and what they can experiment with, it’s first important to understand the history of DAO governance, why it developed the way they did, and where it’s at currently.
35+
36+
37+## A Little DAO Governance History Lesson
38+
39+The first DAO, The DAO, was also the most disastrous. A recursive calls flaw in the governance code led to the only hack-related hard fork in Ethereum History.
40+
41+Recursive call weaknesses in DAO code are somewhat like endlessly automated micro-pyramid schemes. An attacker can call a transaction, mark its benefit, then initiate another transaction before the original transaction is completed, over and over until the block limit is reached. Bernie Madoff paid off old investments with new investments while marking fake gains, took out fees, then reinvested before the prior investments could be properly marked. Both schemes work when automated governance fails.
42+
43+While The DAO’s shoddy governance was its downfall, it was Ethereum’s good governance that saved ETH. Ethereum leadership proposed a hard fork and 97% of holders voted in favor. The transaction was undone. Money returned. Ethereum Classic was born.
44+
45+While The DAO failed, its happy ending paved the way for the DAO boom of today. DAO creators learned the security lesson: there hasn’t been a major DAO hack since 2016. They built better governance—a combination of visionary leadership, trustless voting, and vigorous participation—that steered the ETH ship to calmer waters.
46+
47+
48+## Birth of the Ragequit
49+
50+Moloch DAO was born in the shadow of The DAO fiasco; its governance was expressly designed in response to it. Unlike The DAO, Moloch is a charity; it exists only to give money away to Ethereum infrastructure projects. Its on-chain governance is extremely_ _simple. Members can do only one of two things.
51+
52+The first thing is submitting and voting on proposals for new members. Votes are majority rule with one vote per Moloch share. Only an existing member can propose a new member, so prospective members must convince an existing one to nominate them.
53+
54+New member proposals double as funding proposals, a clever wrinkle which demonstrates just how much can be done on-chain with a single function. Every proposal must include a fundable ETH infrastructure project and a fundee to execute it. If approved, Moloch accepts the fundee as a new member and grants them a number of Moloch shares exchangeable 1:1 for ETH.
55+
56+![Moloch DAO](https://storage.googleapis.com/media.urbit.org/blog/moloch-dao.png)
57+
58+How the fundee exchanges the shares for ETH brings us to the second thing Moloch members can do: ragequitting.
59+
60+Ragequitting is a smart contract function that allows members to rescind their shares—and thus their membership—during a seven day waiting period between approval of new members and disbursement of their funds. Its primary purpose is to allow members to opt out of the DAO if they don’t like a new member or proposal. If they ragequit, they automatically receive ETH equal to their shares.
61+
62+Ragequitting thus provides a major safeguard against the kinds of attack that took down The DAO. Members can simply ragequit en masse to invalidate any harmful action, thereby looting their own DAO and stopping bad actors in their tracks. Ragequitting is Moloch’s “ultimate safety net for malicious attacks.”
63+
64+Like member voting, ragequitting also has a dual purpose. In order to receive their funding, new fundees must ragequit, discharging their shares, receiving ETH, and thereby immediately becoming non-members. Thus, the only time someone becomes a permanent member is if they are granted more shares than they ragequit, which usually happens for non-fundee members, i.e. philanthropic members, not fundees.
65+
66+This is all to say that Moloch, a very successful DAO, has reduced its governance to the simplest imaginable framework. Members can take one of two actions—that’s it. While it makes for a functional secure on-chain charity, the ragequit process isn’t exactly dynamic governance. It’s too low-res for the vast majority of organizations.
67+
68+## Ouroboros
69+
70+In a way, ragequitting uses pyramid scheme logic to its advantage. The only thing members can do is add other members or quit; and it’s through these cyclical actions that the DAO gains members, disburses funds, and maintains security. But it also opens up new problems. For example, what happens if a disgruntled member intentionally votes yes on a harmful proposal, only to ragequit their shares just after the proposal passes? You might call it a murder suicide problem.
71+
72+DAOs supposedly solve the Principal Agent Dilemma; an ancient problem faced by all resource-distributing organizations where an agent’s self-interest inevitably runs counter to principles’ assets. The most common example is a non-shareholding manager of a company (agent) versus its shareholders (principal). The manager is in charge of spending shareholders’ money, but doesn’t suffer the financial consequences from her decisions. Theoretically, DAO principles and DAO agents are indistinguishable—everyone is both investor and employee—which solves the dilemma.
73+
74+But anonymous shareholders often act badly, or they don’t act at all. Even the [DAOs with the highest participation](https://www.businessofbusiness.com/articles/ranking-daos-we-computed-their-net-community-score-to-see-how-they-stack-up/) top out around 75%, and that’s rare. A DAO with low voter participation can become either paralyzed, if a quorum is required, or oligarchical if one isn’t. On-chain voting requires high gas fees and time spend, prohibitively high when it comes to the many technical decisions that need to be made. This is why every successful DAO has naturally developed sets of working groups who make decisions off-chain with the blessing of the body politic. The vast majority of these “governance forums” use a patchwork of Web2 apps.
75+
76+For the bigger decisions, avoiding high gas fees and low participation can mean voting with literal Discord emojis, then having small groups of trusted “delegates” enter on-chain decisions via multi-sigs. This is both sloppy and defeats the purpose of the DAO.
77+
78+More serious solutions make up the primary class L2 products. “Dynamic governance” adds granularity to voting systems, allowing for more complex on-chain voting with different rights for different member classes. “Holographic consensus” gamifies participation by appending a prediction market to every vote. Some are even trying “[Meta Governance](https://indexcoop.com/blog/early-2022-survey-of-metagovernance)”—DAOs governing DAOs. L2 decisions are even further analyzed by deep risk analyzers like Gauntlet that stress test decisions via simulated protocols before they’re executed on-chain.
79+
80+The simple solution is conducting votes using decentralized apps that verify shareholder status. Snapshot is an IPFS voting app that holds votes off-chain, weighing and verifying member votes by reading members’ wallets. It’s a quick and secure way to stage off-chain votes, but it’s still pretty limited. Snapshot is called that because all it really does is take a picture of the result of a vote. All the activity resulting from said vote must still be manually undertaken by DAO operators.
81+
82+Traditional DAOs suffer from what we like to call the Self-Enforcement Problem. Smart contracts enforce themselves, a stark difference from traditional corporations where bylaws and operating rules are met by employees using the best tools for the job. With DAOs, the bylaws and the tools that enforce them are one and the same. This adds up to yet another layer on inflexibility: traditional orgs can adopt new tools for old problems, DAOs cannot.
83+
84+
85+## The Right Tool for the Job
86+
87+This all brings us finally back to Urbit. In the Urbit OS using Urbit IDs, DAOs can integrate every governance solution discussed above without touching Web2. Tailor DAO governance to your own precise needs. Download someone else’s voting app, or spin up your own. Using Urbit blurs the boundaries between on-chain and off-chain actions, eliminating the need for ad hoc fixes then fixes to fix those fixes. It all occurs in one landscape, and can pivot with new information
88+
89+One Urbit app is called Ballot. Ballot most closely resembles Snapshot. It’s like a decentralized version of Snapshot that works without the need for Discord—everything is on the Urbit OS—that can also be modified to execute custom off-chain actions after a vote is held.
90+
91+![Ballot](https://storage.googleapis.com/media.urbit.org/site/ecosystem/applications/ballot.png)
92+
93+Ballot allows for this sort of dynamic governance enhancement, or what we call Custom Actions. In a way, Custom Actions make the dream of smart contracts a reality: instead of being constrained to ragequitting or not ragequitting, you can create automated granular responses to Ballot votes. In other words, smart contracts that are actually smart. One action could be “tweet something” or “ping someone” once a vote is recorded in Ballot. You can write any if-then you want on the outcomes of a vote. For example, instead of relegating membership to simplistic on-chain democracy, a la ragequitting, Ballot has a function for inviting or kicking members via Urbit native logic. Imagine if Snapshot could both conduct a Moloch-style membership vote, and then automatically add or kick the member depending on the result. That’s Ballot.
94+
95+What about the small technical decisions, like the ones that took down The DAO, like booting someone from a chat or paying a contractor through treasury? All of those actions are programmatic, irreversible, and immutable on Urbit, eliminating concerns about gas fees and participation.
96+
97+If Ballot doesn’t suit your DAO’s needs, it’s easy to use Urbit’s primitives to write a custom voting application. Since Urbit has ring signature support built in, you can build a simple, anonymous voting app in just 15 minutes, following [this tutorial](https://developers.urbit.org/guides/quickstart/voting-guide). The combination of cryptographic identity and an append-only event log means that you are free to experiment with different tools to support whatever governance process your DAO adheres to.
98+
99+The Combine DAO uses Ballot for voting on proposals as it integrates cleanly with Urbit ID and provides flexibility for setting different quora for votes and Custom Actions to automate outcomes. There is thus no need to distinguish between the tool used for a “real vote” such as deploying Stars in exchange for tokens and the tool used for a “fun vote” like choosing a date for a meetup.This flexibility and interoperability is a hallmark to the burgeoning supply of [applications](https://urbit.org/ecosystem?type=applications) being built for Urbit.
100+
101+—
102+
103+*Anthony Arroyo is the Director of [The Combine DAO](https://blog.the-combine.org/introduction-to-the-combine-dao)*
content/blog/the-understanding-urbit-podcast.md+1−3
@@ -9,9 +9,7 @@ ship = "~satsyt-sogleb"
99image = "https://media.urbit.org/site/posts/essays/uu-podcast.png"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/uu-podcast.png">
12+![](https://media.urbit.org/site/posts/essays/uu-podcast.png)
1513
1614At the end of January, the team at Tlon invited me to spend some time at their San Francisco office and to create a podcast series about Urbit. The idea was to produce an interview-based series about the project told in the words of those working on it. In this modest goal, I think we were very successful. Beyond a transactional description, however, we captured a range of perspectives of the flaws in our current computing landscape and visions for how Urbit will alter it.
1715
content/blog/tools-of-our-own.md+6−14
@@ -9,15 +9,11 @@ ship = "~haddef-sigwen"
99image = "https://media.urbit.org/site/posts/essays/tools-of-our-own-1.png"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/tools-of-our-own-1.png">
15−
16−<br>
12+![](https://media.urbit.org/site/posts/essays/tools-of-our-own-1.png)
1713
1814> People need only not to obtain things, they need above all the freedom to make things among which they can live, or give shape to them according to their own tastes, and to put them to use in caring for and about others.
1915>
20−> <cite>Ivan Illich, <em>Tools for Conviviality</em></cite>
16+> **Ivan Illich, *Tools for Conviviality***
2117
2218One of the recent ways we've come to describe the mission of the Urbit project is to give communities [the power to shape, or evolve, their digital environments](https://urbit.org/blog/urbit-is-for-communities/). Of course, like many of our definitions, it requires some background to really contextualize the claim. When I describe this particular statement to people, they often ask, "What does that _mean_, though? What is a digital environment, and why would I need Urbit to do it?"
2319
@@ -27,15 +23,13 @@ The [Rube Goldberg machine](https://en.wikipedia.org/wiki/Rube_Goldberg_machine)
2723
2824And it's nobody's distinct fault that the experience of aligning all these disparate services into a workflow is a skill in itself. It's a collective restriction that comes from the systems beneath.
2925
30−<br>
31−
32−<img class="ba" src="https://media.urbit.org/site/posts/essays/tools-of-our-own-2.png">
26+![](https://media.urbit.org/site/posts/essays/tools-of-our-own-2.png)
3327
3428### Systems as masters
3529
3630> If you don't understand a system you're using, you don't control it. If nobody understands the system, the system is in control.
3731>
38−> <cite>Philip Monk, <a href="https://urbit.org/blog/precepts/">Precepts</a></cite>
32+> **Philip Monk, [Precepts](https://urbit.org/blog/precepts/)**
3933
4034If you asked any of the creators of the social tools we use today what their mission was, it would seem neutral, a public good. To "bring the world closer," to "make a more open and connected world," to "easily see what's happening in the world." Ignore the fact that the net effects of their products are far more mixed than their mission suggests: for many users, the tools themselves come second to the power the tools have in capturing their social graph.
4135
@@ -53,15 +47,13 @@ And for productivity tools—for the personal activities we do every day—the s
5347
5448This is why hybrid products are born _and_ why massive enterprises are shifting toward subscription models for office software. With the [clearnet](<https://en.wikipedia.org/wiki/Clearnet_(networking)>), using our own computers for everyday tasks that extend outside themselves is not easy. It's way easier to sign into an enterprise's server farm for your persistent data storage and manipulation. In 2020, the prefab parts for the exoskeleton only come in "left arm, right leg" pairs, or you can just give up and plug straight into SkyNet.
5549
56−<br>
57−
58−<img class="ba" src="https://media.urbit.org/site/posts/essays/tools-of-our-own-3.png">
50+![](https://media.urbit.org/site/posts/essays/tools-of-our-own-3.png)
5951
6052### The collective body
6153
6254> “Autonomy” means that we make the **worlds that we are** grow.
6355>
64−> <cite>Tiqqun, <em>The Cybernetic Hypothesis</em>
56+> **Tiqqun, *The Cybernetic Hypothesis*
6557
6658So why does this matter for us? Me and you and everyone we know? We put up with the cost all the time. But the limitations of our tools—on the vulnerable side of a power dynamic that, unbeknownst to everyone involved, functions as a catalyzed and increasingly accelerated system bringing out the worst in all of us—range from the everyday annoyances to a pervasive alienation, an information malaise.
6759
content/blog/urbit-and-bitcoin.md+1−1
@@ -2,7 +2,7 @@
22title = "Urbit and Bitcoin"
33description = "A sound money deserves a sound computer."
44date = "2019-10-16"
5−
5+tags = ["bitcoin"]
66[extra]
77author = "Christian Langalis"
88ship = "~pindet-timmut"
content/blog/urbit-creator-daos.mdnew file+74
@@ -0,0 +1,74 @@
1++++
2+title = "Urbit + Creator DAOs with Justin Murphy"
3+date = "2022-10-05"
4+description = "Creator DAOs are blank slates, new foundational cryptographic patterns just beginning to take shape. Justin Murphy thinks Urbit is the most obvious place to start building one."
5+
6+[extra]
7+author = "Isaac Simpson"
8+ship = "~mogmet-tadnem"
9+image = "https://storage.googleapis.com/media.urbit.org/blog/creatordao-3.jpg"
10++++
11+
12+![Image](https://storage.googleapis.com/media.urbit.org/blog/creatordao-3.jpg)
13+<div style="font-size:13px; text-align: center; color: #999">Photo by <a href="https://unsplash.com/@nathynmasters
14+">Nathyn Masters</a></div>
15+
16+# Other Life: Proto Creator DAO
17+
18+Justin Murphy runs a creator network. As a thinker, writer, and podcaster, he works to grow value within this network in order to stay independent. No ads. No branded content. Just varying degrees of membership, with members enjoying private channels and cohort-based courses all under the header “Philosophy and technology for the ungovernable.”
19+
20+Murphy’s “personal media company,” called Other Life, is composed of a newsletter, podcast, Youtube channel. It also extends to Urbit; [Other Life](https://urbit.org/groups/~hatryx-lastud/other-life) is one of the largest groups on the network. Followers and friends of Other Life create and share their own work within the network, aided by a catalog of courses. Murphy’s next logical step is building what we’re calling a Creator DAO: all the same stuff, but instead of a la carte memberships you secure your spot via ERC-20 tokens. In exchange, you get access to all levels of his community and content and attain the rights and responsibilities inherent to any DAO member.
21+
22+![Image](https://storage.googleapis.com/media.urbit.org/blog/otherlife.png)
23+
24+Since Creator DAOs are blank slates, primordial cryptographic objects just beginning to take shape, Murphy thinks Urbit is the most obvious place to start building one. Urbit lets creators spin up flexible DAOs to find, manage, keep members engaged in entirely new ways.
25+
26+
27+# Democratized Publishing
28+
29+In contrast to centralized programs like Discord, Urbit offers creators far more flexibility in interacting with their fanbases. Say, for example, you want to set up a trustless contribution program for guest writers. The Urbit app [Straw](https://urbit.org/applications/~pocwet/straw) supports group curation with voting on proposed articles. To increase guest engagement and expand participation while also maintaining quality control, Murphy can use Straw to initiate votes on his own pieces or potential guest pieces, which automates publication to the clear web when a vote passes.
30+
31+“Imagine I want to publish to the [Studio](https://urbit.org/applications/~tirrel/studio) newsletter, and when I go to click publish it first gets sent as a proposal to Straw, and it only actually gets published if a majority of the group agree that it passes the quality bar. As Straw develops, you can imagine that if the proposal is passed, two things happen. One: the post in the Urbit notebook gets sent to the email newsletter through Studio. Two: money is transferred.”
32+
33+Indeed, future functionality will enable automated payments after publication.
34+
35+![Image](https://storage.googleapis.com/media.urbit.org/blog/straw.jpg)
36+<div style="font-size:13px; text-align: center; color: #999;">The Straw App</div>
37+
38+“I’ll offer bounties, making a list of topics that I want people in the group to write about,” says Murphy. “They can publish permissionlessly to the group blog, through Studio and anyone in the group could potentially publish on any set of topics, kind of replicating a multi-author magazine.”
39+
40+Straw opens up a whole new way to decide what—and who—creators publish next. We’re the last to advocate art-by-democracy, but the potential is huge.
41+
42+# Decentralized Kicking and Adding
43+
44+Urbit also offers a novel solution with regards to vetting group members and weeding out bad ones. As Murphy points out, Holium’s Urbit app Ballot—which works like a decentralized [Snapshot](https://snapshot.org/#/) for Urbit Groups—allows creators to decentralize the expulsion process. A shift which many who run creator networks would much prefer.
45+
46+> If someone makes a proposal in [Ballot](https://urbit.org/applications/~lomder-librun/ballot), and maybe the owner gets to decide the threshold where if a certain amount of people want to kick someone out, they're kicked. It's actually a really annoying burden, in some ways, to know who to kick out. How bad does someone have to bet? You can have all the rules and regulations you want and try to be as objective as possible, but ultimately the owners and the admins have to use their judgment to decide. I would frankly much rather not have that responsibility. I would love for it to be hardwired such that only a super majority, or something like that, could do it. You can imagine that as a custom action on Ballot.
47+
48+One can imagine this custom action with a combination of Ballot and the [Forms](/applications/~donpub-datdux/forms) app. Since the form data is all on Urbit, it would be a simple matter for an app like Ballot to automatically access that information. With a few forms to vote on membership, this would make adding members equally simple, automated, and trustless as kicking them.
49+
50+“I think the Forms App is cool. You can use it on certain channels where if you want to get in, you fill out a form, then it's evaluated by Ballot. So the content of a form submission gets plugged into a proposal. People vote on the information supplied in the form and if the vote is approved, then the person gets added to the channel or group.”
51+
52+# An Owned Space
53+
54+These use cases help with DAO flexibility, usability, and decentralized automation. But another important reason to build a DAO on Urbit is that you’re building your network on P2P “real estate.” On Urbit, both creators and their communities own the address space and every action taken in it—it can’t be canceled or deleted or made inoperable, a far cry from other platforms where you can be suspended for arbitrary Terms of Service violations.
55+
56+“The main positive is you and your community getting to own the real estate that you operate on,” says Murphy. No other app, even dapps like Agora or Snapshot, allows for a genuinely P2P offchain operating environment. Your Urbit ID is self-owned and portable, and you build your community P2P. Your creations are yours and you can continue building them without corporate middlemen ripping your canvas out from under you, or changing your tools or access without notice.
57+
58+![Image](https://storage.googleapis.com/media.urbit.org/blog/otherlifegroup.png)
59+<div style="font-size:13px; text-align: center; color: #999">~hatryx-lastud/other-life</div>
60+
61+Furthermore, the more work you put into building your Creator DAO on Urbit, the more valuable the Urbit address space becomes. When you use Facebook, you’re relegated to the role of a content serf. The more you produce, the more Facebook grows in value. On Urbit, the more your produce, the more Urbit grows in value—and you are an owner of Urbit.
62+
63+![Image](https://storage.googleapis.com/media.urbit.org/blog/justinmurphy.jpg)
64+<div style="font-size:13px; text-align: center; color: #999">Murphy already offers his members access to the Other Life urbit group.</div>
65+
66+Finally, Murphy cites Urbit’s durability.
67+
68+> The second most important Urbit trait after ownership is durability. The creator economy tools change all the time. Every time you try to move your people from one new app to another app, you lose a lot, right? You want to be an influencer, you want to be an important thinker and speaker. All of a sudden, you’ve got to be on Clubhouse! This means telling the people on your newsletter, telling your Patreon subscribers, telling the people on your podcast, hey, download this cool new app called Clubhouse and find me there. It's going to be awesome. It's so cringe and corny and only a small number of them will even make it over there. Then all of a sudden, no one's on Clubhouse and no one wants to use Clubhouse anymore. This is a major problem for people navigating the creator economy. I think one of the big selling points of Urbit is—this is the one place that I’ll always be. I (will have) been working on my Urbit for over 10 years. This thing is going to be the nuclear bunker of the internet.
69+
70+Creator DAOs are perhaps the smallest, most nimble type of DAO—a creator, his followers, and the content they share between them. For that reason, they’ve been underplayed as archetypal DAOs. But their small size and flexibility may make them the perfect candidate to realize the possibilities of immensely improved DAO experiences.
71+
72+—
73+
74+*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/urbit-for-normies.md+3−4
@@ -51,7 +51,7 @@ By “intermediary” I’m talking about all those centralized servers that we
5151
5252Urbit will fundamentally change that — more about the privacy implications later.
5353
54−<img class="ba" src="https://media.urbit.org/site/posts/essays/normies-1.png">
54+![](https://media.urbit.org/site/posts/essays/normies-1.png)
5555
5656## What it looks like
5757
@@ -95,7 +95,7 @@ I’ll try to explain the most important of these without straying too deep into
9595
96964. **An incentive for good behavior**
9797
98− On the Urbit network, identities are finite, and they accrue reputation. Compare that to the current internet where identity is infinite (anyone can create as many email addresses or social media profiles as they want, essentially for free) and so spam, scams, and DoS attacks (“denial-of-service”: when many disposable identities ‘attack’ a server at the same time) are rampant. On the Urbit network, there are just over 4 billion total IDs (2<sup>32</sup> to be exact). Scarcity creates value. That scarcity, combined with reputation accrual, means there's an incentive for good behavior.
98+ On the Urbit network, identities are finite, and they accrue reputation. Compare that to the current internet where identity is infinite (anyone can create as many email addresses or social media profiles as they want, essentially for free) and so spam, scams, and DoS attacks (“denial-of-service”: when many disposable identities ‘attack’ a server at the same time) are rampant. On the Urbit network, there are just over 4 billion total IDs (2^32^ to be exact). Scarcity creates value. That scarcity, combined with reputation accrual, means there's an incentive for good behavior.
9999
100100 You might think 4 billion IDs sounds like too few given how many humans we have on the planet. I won’t go into the technical details here, but if we ever get to the point where that’s a problem (which would be a great problem to have), we’ve outlined several solutions that allow everyone alive to get on the network. We don’t intend to lock anyone out.
101101
@@ -121,9 +121,8 @@ I’ll try to explain the most important of these without straying too deep into
121121
122122 What all this adds up to is that the Urbit network is immensely more resource efficient, secure, easier to customize, and smaller in size than any other computing system in the world. If you care about data security, privacy, durability, or even just elegance, Urbit has the best design going.
123123
124− <br></br>
125124
126−<img class="ba" src="https://media.urbit.org/site/posts/essays/normies-2.png">
125+![](https://media.urbit.org/site/posts/essays/normies-2.png)
127126
128127## How it compares
129128
content/blog/urbit-is-for-communities.md+1−3
@@ -9,9 +9,7 @@ ship = "~ravmel-ropdyl"
99image = "https://media.urbit.org/site/posts/essays/urbit-is-for-communities.jpg"
1010+++
1111
12−<br>
13−
14−<img class="ba" src="https://media.urbit.org/site/posts/essays/urbit-is-for-communities.jpg">
12+![](https://media.urbit.org/site/posts/essays/urbit-is-for-communities.jpg)
1513
1614## Generated, not fabricated
1715
content/blog/using-urbit-in-2023.mdnew file+55
@@ -0,0 +1,55 @@
1++++
2+title = "Using Urbit in 2023"
3+date = "2023-02-06"
4+description = "There are more ways to run Urbit than ever, and more options coming soon."
5+[extra]
6+image = "https://storage.googleapis.com/media.urbit.org/blog/usingurbit-2023.jpg"
7+author = "Josh Lehman"
8+ship = "~wolref-podlex"
9++++
10+
11+![](https://storage.googleapis.com/media.urbit.org/blog/usingurbit-2023.jpg)
12+
13+Recent years have seen several iterations on ways to run an Urbit node and join the network. [Port](https://github.com/latterbolden/port) and support for running Urbit from Windows were added a couple of years ago and have previously been recommended ways of running Urbit. We no longer recommend these options for the vast majority of users in favor of better options that are now available.
14+
15+Read on to learn about the background underpinning these decisions and your options for joining the network going forward.
16+
17+
18+
19+# Background
20+
21+With the introduction of Landscape in 2020 the demand for being on the network rose substantially from what it had been, yet the only way of running Urbit was through the command line, which was a significant barrier for entry.
22+
23+In 2021 Port and a native Windows binary were both introduced via contributions from the open source community: Port was built via our [grants](https://urbit.org/grants/cross-platform-desktop-urbit-app) [program](https://urbit.org/grants), and the Windows binary was contributed via a [pull request](https://github.com/urbit/urbit/pull/4675). Together, these two projects enabled users to run Urbit locally without requiring command-line knowledge. Port was summarily added as an officially recommended way to run Urbit.
24+
25+Over the course of 2022 it became clear that, while often useful for trying Urbit out, the experience of running Urbit locally via Port was fundamentally limited: Urbit runs best as a server, and laptops provide neither a stable running environment nor consistent web-based access from other devices.
26+
27+Windows presented further challenges, particularly around maintenance: our team of runtime engineers has had their progress stymied by the need to support Windows, which has substantially different requirements from macOS and Linux. It’s ultimately much more important to our team that we make progress on the versions of the runtime that run well in a server environment, which is the best way to use Urbit, than for local installations.
28+
29+Going forward we no longer recommend Port as an officially supported option for joining the network, and have dropped support for the native Windows binary as of version [1.16](https://groups.google.com/a/urbit.org/g/dev/c/3S6A8Qf8Qzg) of the runtime. That said, it’s worth noting that Port *is not deprecated*! It is still actively [maintained here](https://github.com/latterbolden/port) by the same people that have been maintaining it since the beginning.
30+
31+Let’s move on and talk about your options for getting on the network going forward.
32+
33+
34+# Joining the Network Today
35+
36+Over the course of 2022 many companies emerged and built products that will get you on Urbit, and their teams are constantly working to provide you with a great experience.
37+
38+If you’re not comfortable at the command line you should use a [hosting provider](https://urbit.org/getting-started/hosted). Hosting providers run your Urbit for you and take care of any ongoing maintenance required. If you eventually want to transition to running Urbit yourself, they’ll let you pack up your node and run it however you want: whether that’s at a different hosting provider or your own infrastructure. Learn about [recommended hosting providers in our getting started guide.](https://urbit.org/getting-started/hosting-providers)
39+
40+For more technical users the [command line](https://urbit.org/getting-started/cli) is still a reliable option. For casual testing you can boot a planet or comet on your local macOS or Linux-based machine, and for more serious usage you should refer to our [cloud hosting guide](https://urbit.org/getting-started/cloud-hosting) to get set up on a VPS. A newer option for self-hosting is [Native Planet’s](https://nativeplanet.io) suite of [software](https://www.nativeplanet.io/software) for turning a local computer into an Urbit server complete with DNS.
41+
42+
43+# Coming soon
44+
45+New options for joining Urbit are just around the corner.
46+
47+Word has it that [Tlon](https://tlon.io/hosting) will soon allow you to invite your friends to groups directly from within their [suite of applications](https://tlon.io/landscape), with onboarding handled seamlessly through their hosting service.
48+
49+[Holium’s Realm app](https://www.youtube.com/watch?v=gdu4QtFR-Bs), a collaborative desktop computing environment available on macOS (for now), allows users to sign up with an existing Urbit or brand new hosted one — all seamlessly surfaced through Realm’s signup flow. You can sign up for the private alpha [here](https://holium.com).
50+
51+Tirrel’s [Scene](https://planet.one/scene) is a desktop application with built-in hosting, like Realm, that works on macOS, Windows and Linux, and it’s available now. Hosting is powered by their [Planet One](https://planet.one) service.
52+
53+For the self-hosting enthusiasts out there Native Planet has created [purpose-built Urbit home servers](https://www.nativeplanet.io/hardware) that [make self-hosting easy](https://twitter.com/jmrphy/status/1616196970384887808) and look great doing it.
54+
55+Joining Urbit has never been easier, and it’s constantly getting easier. See you on the network!
content/blog/value-of-address-space-pt1.md+4−4
@@ -47,15 +47,15 @@ We’ve often said that Urbit IDs have value because they’re useful and scarce
4747
4848The network of IDs is structured as a sponsorship tree consisting of 256 galaxies, ~65,000 stars, ~4B planets.
4949
50−Galaxies are the root nodes on the network. They each have a vote on upgrades to the rules that govern the network, they provide packet-routing and peer-discovery services, and they spawn stars. Each galaxy has 256 (2<sup>8</sup>) stars to spawn.
50+Galaxies are the root nodes on the network. They each have a vote on upgrades to the rules that govern the network, they provide packet-routing and peer-discovery services, and they spawn stars. Each galaxy has 256 (2^8^) stars to spawn.
5151
52−Stars similarly provide packet-routing and peer-discovery services, and spawn planets. Each unbooted star contains ~65,000 planets (2<sup>16</sup>).
52+Stars similarly provide packet-routing and peer-discovery services, and spawn planets. Each unbooted star contains ~65,000 planets (2^16^).
5353
54−Planets are the individual IDs that most people use on the network. There are a total of ~4B (2<sup>32</sup>) planets all combined. Planets can also each spawn ~4B ‘moons,’ which are Urbit IDs intended to be used for IoT and other devices. Moons are permanently locked to their planets for security and to protect the network from sybil attacks.
54+Planets are the individual IDs that most people use on the network. There are a total of ~4B (2^32^) planets all combined. Planets can also each spawn ~4B ‘moons,’ which are Urbit IDs intended to be used for IoT and other devices. Moons are permanently locked to their planets for security and to protect the network from sybil attacks.
5555
5656Stars and planets can leave their sponsors (i.e. the star or galaxy currently providing peer discovery and packet routing) if they wish, and sponsors can choose to stop servicing any given star or planet. This is intended to prevent lock-in and to encourage good behavior from both parties. This mutual accountability is important in a network of finite identities that accrue reputation.
5757
58−Essentially Urbit ID is 2<sup>32</sup> individual names that are bundled into blocks that are larger and larger in size. You might think of a planet like an individual house, a star like a town or a city, and a galaxy like a county or a state.
58+Essentially Urbit ID is 2^32^ individual names that are bundled into blocks that are larger and larger in size. You might think of a planet like an individual house, a star like a town or a city, and a galaxy like a county or a state.
5959
6060The Urbit ID registry and its rules are built on a set of smart contracts called [Azimuth](https://github.com/urbit/azimuth). These contracts are registered on the Ethereum blockchain. Galaxies can upgrade the mechanics of Azimuth by majority vote.
6161
content/blog/value-of-address-space-pt2.md+1−1
@@ -31,7 +31,7 @@ There are 65,280 total stars on the network. In turn, each star is initialized w
3131
3232One would expect that in an efficient market the relative pricing of stars on one hand, and planets on the other hand would eventually align (so to speak). This may come to pass as the Urbit community increases education about Urbit, and as additional planet sellers and hosting providers enter the space.
3333
34−Finally, there are 4,294,901,760 (or ~2<sup>32</sup>) planets on the network. Planets currently trade largely in a range of $10 to $15. We expect planet prices to fluctuate from provider to provider as described in the previous post, based on the quality of services various providers offer. That said, it's worth noting that the cost to configure addresses for distribution is fairly static and this may act as something of a lower bound.
34+Finally, there are 4,294,901,760 (or ~2^32^) planets on the network. Planets currently trade largely in a range of $10 to $15. We expect planet prices to fluctuate from provider to provider as described in the previous post, based on the quality of services various providers offer. That said, it's worth noting that the cost to configure addresses for distribution is fairly static and this may act as something of a lower bound.
3535
3636That said, we also anticipate that planet prices will be abstracted away from most purchasers, and will be included in bundled annual packages of hosting and data routing services. For this reason, infrastructure service providers (i.e. hosting providers) will likely be the best positioned parties to capture value from planet distribution.
3737
content/blog/value-of-address-space-pt3.md+1−3
@@ -9,8 +9,6 @@ ship = "~patnes-rigtyn + ~ravmel-ropdyl"
99image = "https://media.urbit.org/site/posts/essays/value-of-address-space-pt3.jpg"
1010+++
1111
12−<br>
13−
1412![](https://media.urbit.org/site/posts/essays/value-of-address-space-pt3.jpg)
1513
1614_This is the third in a series of three posts on Urbit address space. See also [part 1](https://urbit.org/blog/value-of-address-space-pt1/) and [part 2](https://urbit.org/blog/value-of-address-space-pt2/)._
@@ -33,7 +31,7 @@ In this post, we don’t expand that framework, but rather explore two elements
3331
3432## Lockups and spawning limits
3533
36−One way to think about galaxies, stars, and planets is that they’re different-sized buckets of Urbit IDs. A star contains 2<sup>16</sup> (~65K) planets, a galaxy contains 2<sup>8</sup> (256) stars and, in turn, 2<sup>24</sup> planets (16,777,216). Beyond this nesting pattern, there are three further considerations to note: booted versus unbooted addresses, locked versus unlocked addresses, and planet spawning limits.
34+One way to think about galaxies, stars, and planets is that they’re different-sized buckets of Urbit IDs. A star contains 2^16^ (~65K) planets, a galaxy contains 2^8^ (256) stars and, in turn, 2^24^ planets (16,777,216). Beyond this nesting pattern, there are three further considerations to note: booted versus unbooted addresses, locked versus unlocked addresses, and planet spawning limits.
3735
3836Booted and Unbooted Addresses –
3937
content/blog/why-hoon.md+3−3
@@ -125,7 +125,7 @@ Hoon and Nock have several unusual properties:
125125 converted to each other. Lisp dialects are also homoiconic, but Hoon
126126 and Nock are arguably even more so, since things like closures and the
127127 environment are just Nock trees. We even have a statically typed
128− metacircular interpreter called <code>+mule</code>. We run userspace code
128+ metacircular interpreter called `+mule`. We run userspace code
129129 metacircularly with negligible performance overhead because of Urbit's
130130 jet system. In Lisp, "eval is evil" is a common saying, but in Urbit,
131131 eval is a first-class feature.
@@ -145,7 +145,7 @@ Hoon and Nock have several unusual properties:
145145 the runtime has a matching jet, it will use that instead of the Nock
146146 implementation. Nock isn't as slow as you might think, especially
147147 considering it's a minimal, dynamic, axiomatic language.
148− <br/><br/>
148+
149149 This arrangement has the deeper implication that all code written in
150150 Nock is best considered as a specification for a program, which can be
151151 executed directly but might never run at all due to being jetted.
@@ -199,7 +199,7 @@ Hoon and Nock have several unusual properties:
199199 lot of the system manipulates types. In particular, the `!>` rune, when
200200 applied to a piece of data, uses compile-time type reflection to
201201 produce something called a "vase": a pair of type and data, similar to
202− a <code>Data.Dynamic</code> in Haskell, or a limited form of a dependent pair.
202+ a `Data.Dynamic` in Haskell, or a limited form of a dependent pair.
203203 Since the Arvo kernel does a lot of dynamic compilation, it uses vases
204204 to implement something akin to a dynamically typed language using
205205 Hoon. This allows for type-safe dynamic program loading, program
content/blog/your-last-computer.md+3−3
@@ -11,13 +11,13 @@ This whole ‘simple, durable, yours’ thing may sound good, but what does it a
1111
1212First, let’s talk about what it should feel like in the future.
1313
14−<img class="mv5 w-100" src="https://media.urbit.org/site/understanding-urbit/your-last-computer/your-last-computer-waves%402x.png">
14+![](https://media.urbit.org/site/understanding-urbit/your-last-computer/your-last-computer-waves%402x.png)
1515
1616Imagine that you can log in from anywhere with one simple, memorable name and password. And when you do, an entire OS appears for you. Inside is your whole digital life. Every conversation you’ve ever had, all your biometric data — every step and heartbeat. Your personal mesh of devices: your doors, your car, your irrigation. All of your communities, every message you’ve shared with friends and family. Every connection you’ve made and every archival piece of data, in one place. Secure and private, forever.
1717
1818You own and control this OS completely. Your system doesn’t live on someone else’s server, so there’s no risk of leaking it in a mass data breach or losing it when a service shuts down. Your Urbit is a sealed, secure, and durable system.
1919
20−<img class="ba mv5 w-100" src="https://media.urbit.org/site/understanding-urbit/your-last-computer/your-last-computer-is-rock%402x.png">
20+![](https://media.urbit.org/site/understanding-urbit/your-last-computer/your-last-computer-is-rock%402x.png)
2121
2222We’re on our way to this future, building it step by step, but we’re not there yet. The Urbit of today is much more stripped down.
2323
@@ -31,6 +31,6 @@ It’s a simple system for intentional digital communities. A first step away fr
3131
3232We think that a new system like this, even in a simple form, will be a relief from the chaos of the current web. Think of it as a “back to the land” computing movement. If we’re ever going to build new digital cities, they’ll have to start as a few colonies on the frontier.
3333
34−<img class="mv5 w-100" src="https://media.urbit.org/site/understanding-urbit/your-last-computer/your-last-computer-ocean%402x.png">
34+![](https://media.urbit.org/site/understanding-urbit/your-last-computer/your-last-computer-ocean%402x.png)
3535
3636Your Urbit is a simpler computer, a quieter computer, a more private computer. We want it to feel predictable, safe, and reliable — things only a complete, sealed system can do. This, we hope, can get us a world where technology keeps us connected, but doesn’t dominate our lives.
content/bounties.md+50−4
@@ -1,8 +1,54 @@
11+++
2−title = "Post a Bounty"
3−date = "2021-11-25"
2+title = "Guide to Bounties"
3+date = "2023-01-04"
44weight = 1
5−description = "A comprehensive guide to creating a bounty"
5+description = "A guide to posting and claiming bounties"
66+++
77
8−WIP
8+Bounties are opportunities to do work on Urbit in exchange for address space or other funding. Bounties can be provided by companies, DAOs or individuals ("sponsors") in the Urbit universe. To the extent that they benefit the rest of the universe, the Urbit Foundation will [chip in on funding](#funding).
9+
10+For **workers**, bounties offer substantial funding opportunities and, compared to [apprenticeships](/grants/apprenticeships), are a way to take on larger challenges in a more autonomous manner. Learn how to [work on a bounty here](#work-on-a-bounty).
11+
12+For **sponsors**, bounties allow you to scale your workforce through the Urbit community, get critical tools built, or just fund cool projects that you want to see exist. Learn how to [post a bounty here](#post-a-bounty).
13+
14+## Work on a Bounty
15+
16+You can see [open bounties here](/grants?program=bounty&open=true&wip=false&completed=false#view-grants), which can claimed by filling out the form on each individual bounty.
17+
18+### How it works
19+
20+After applying, the Urbit Foundation will circulate the details of your application to the sponsor and schedule a follow-up interview to see if you would be a good fit for the project. Should your application be accepted, you will undergo a quick KYC process and recieve a contract for signature. Some bounties may also entail additional direct compensation from the sponsor for which the Urbit Foundation is not responsible for managing; please discuss these parameters directly with your sponsor.
21+
22+The sponsor of the bounty is ultimately responsible for signing off on completed work. They'll also be the primary point of contact while work is underway, although the Urbit Foundation may assign personnel to assist on bounties that it is particularly invested in.
23+
24+Sponsors are vetted by the Urbit Foundation as trustworthy to ensure their ability to fund the work that they post. The Urbit Foundation also collaborates heavily with sponsors to ensure that the bounty is [well-specified](#well-specified-bounties), which ensures that your project is both properly scoped and technically viable.
25+
26+### Getting Paid
27+
28+After you've finished your work on a given milestone, you will need to get signoff from your sponsor. To do this, contact your sponsor with the details of the milestone completed, any relevant instructions, github repos, or app download links, and solicit review from your sponsor. They can submit their approval to the Foundation by contacting `~marfun-pacpet`, at which point you are ready to [submit an invoice](https://airtable.com/shrXXCs1uaxtNSBcg). Once the Urbit Foudnation receives approval from your sponsor 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.
29+
30+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.
31+
32+## Post a Bounty
33+
34+To get started posting a new bounty, [submit it via this form](https://airtable.com/shr6ky4yshlhhqSm0).
35+
36+We at the Urbit Foundation will work with you to ensure that all bounties have [clear specifications](#well-specified-bounties) &mdash; this ensures that they get what you pay for. If your bounty submission is missing details or could be otherwise improved, we'll provide that feedback and work with you to refine your bounty.
37+
38+### Well-specified Bounties
39+
40+A well-specified bounty generally has these elements:
41+
42+- **Overview**: A clear description of what the worker will do to complete this bounty. It's a good idea to include a problem statement or rationale for the work.
43+- **Project Requirements**: An articulation of what constitutes complete work. User stories, Figma designs, interface specifications, and other technical constraints are all examples of requirements. It is recommended to reference any specific requirements &mdash; such as key user stories &mdash; on a milestone level to ensure clarity in which requirements need to be met at each stage of the project.
44+- **Worker Requirements**: A description of the skills and/or qualifications required of a prospective worker. Technologies or skills known, years of experience, work schedule (e.g. time availability), and demonstrable accomplishments are all examples of this.
45+- **Milestones**: Logical segments of work that can be considered done on their own. Breaking the project up into smaller pieces will help a new worker pick up the work should that be necessary, keeps the worker motivated with incremental achievement and remuneration, and is generally a sign of a clear specification. Milestones don't always make sense; sometimes there's only one.
46+- **Timeline**: If you're trying hit a certain deadline, make sure to specify absolute dates on the milestones. Otherwise, use relative dates (e.g. _two months_) to give the worker an idea of how long each milestone will take. This helps form an agreement between the sponsor and worker on volume of work, and grounds to seek other arrangements should schedules be missed.
47+
48+The more detail in the bounty's specification, the better the results and the smoother your working relationship will be with a contributor. Once a contributor has been selected, parameters such as absolute dates or other open ended questions will be updated prior to contract to ensure there are clear expectations for all parties involved
49+
50+### Funding
51+
52+You're free to fund your bounty with as much of your own capital as you'd like. You can also request funding from the Urbit Foundation.
53+
54+We fund projects based on their benefit to the whole network. If your bounty is for contributions to Urbit itself, or other technical infrastructure, we might fund all of it. If the bounty is to build or contribute to your company's product, we'll be open to funding less of it.
content/campus/_index.mdnew file+37
@@ -0,0 +1,37 @@
1++++
2+title = "Software Developers"
3+slug = "software-developers"
4+description = "Getting started as a software developer on Urbit"
5+sort_by = "weight"
6++++
7+
8+
9+Urbit offers foundational primitives that make it easy to build decentralized applications. This means developers can focus on creativity and application logic instead of operations to make sure the server or database doesn't go down.
10+
11+
12+Here are a few links to resources for developers:
13+
14+
15+### [Urbit Developers Overview](https://developers.urbit.org/)
16+An overview of using Urbit for development.
17+
18+### [Lightning Tutorials](https://developers.urbit.org/guides/quickstart/intro)
19+Get a feel for the process of making and deploying an Urbit app in half an hour, no previous experience required.
20+
21+### [Core Curriculum](https://developers.urbit.org/guides/core)
22+Learn the Urbit stack at your own pace.
23+
24+The Foundation also regularly runs a series of cohort-based live courses that go over the core curriculum, free and open to all. One lesson per week over the course of about eight weeks.
25+
26+### [Live Courses](https://developers.urbit.org/courses)
27+Learn the Urbit stack as part of a group.
28+
29+### [New Hooniverse](https://urbit.org/groups/~hiddev-dannut/new-hooniverse)
30+Discussion group for learning the Urbit stack. Open to beginner, intermediate, and advanced developers.
31+
32+
33+### [TomeDB](https://holium.gitbook.io/tomedb/)
34+A framework for building Urbit apps solely with Javascript.
35+
36+### [Grants](https://urbit.org/grants)
37+Build on Urbit and take ownership of the network in the process.
content/campus/blockchain-enthusiasts.mdnew file+35
@@ -0,0 +1,35 @@
1++++
2+title = "Blockchain Enthusiasts"
3+slug = "blockchain-enthusiasts"
4+description = "Learn how sound computing and sound money fit together"
5+weight = 4
6+[extra]
7+flatten_pagination = "true"
8+hide_next_title = "true"
9+hide_previous_title = "true"
10+image = "https://media.urbit.org/site/understanding-urbit/urbit-id/urbit-id-cards%402x.png"
11++++
12+
13+We have yet to see the promised Cambrian explosion of general-purpose decentralized applications promised by blockchains. What happened?
14+
15+While blockchains are good for some problems, there remain others where a more general purpose computing solution is more useful. This is precisely what Urbit is for. Urbit’s vision of sound, easy-to-use, decentralized computing dovetails neatly with that of sound, easy-to-use, decentralized money.
16+
17+Learn more on how Urbit and blockchains work together:
18+
19+### [Bitcoin on Urbit: The Sovereign Stack](https://urbit.org/bitcoin)
20+How Urbit and Bitcoin fit together
21+
22+### [Azimuth](https://developers.urbit.org/reference/azimuth/azimuth)
23+Urbit’s PKI system on Ethereum
24+
25+### [Uqbar](https://uqbar.network)
26+The Urbit-native blockchain
27+
28+The leader in this space is Uqbar, an Urbit-native layer 2 blockchain that settles on Ethereum.
29+
30+From their [clearpaper](https://uqbar-network.gitbook.io/uqbar-clearpaper/uqbar-clearpaper/uqbar-clearpaper):
31+
32+>Leveraging Urbit’s peer-to-peer infrastructure, Uqbar provides a blockchain-native decentralized operating system uniquely positioned to deliver the composable primitives necessary to build a rich, functional distributed application layer. It fuses the trusted settlement of Ethereum with the decentralization, security, and interoperability benefits of full-scale peer-to-peer networking, unlocking the latent power of programmable blockchains.
33+
34+
35+
content/campus/creatives.mdnew file+21
@@ -0,0 +1,21 @@
1++++
2+title = "Creatives"
3+slug = "creatives"
4+description = "Urbit for everyone"
5+weight = 5
6+[extra]
7++++
8+
9+Urbit offers creatives the means to truly own the distribution of their work. An application becomes a tool you own rather than a service whose terms can change overnight. And with digital ownership on a decentralized network, the incentives of advertising based centralized services and an attention economy no longer apply.
10+
11+What would the world look like with more decentralized digital ownership? Check out the links below for a preview.
12+
13+### [Tirrel Studio](https://urbit.studio)
14+
15+Host, publish, and earn on Urbit. See the [Mars Review of Books.](https://marsreview.org/)
16+
17+
18+### [Meetup Grant](https://urbit.org/grants/community-meetups)
19+
20+Through our Grants program, the foundation rewards community-builders who
21+host regular meetups and help people learn about the project.
content/coinmarketcap.mdnew file+8
@@ -0,0 +1,8 @@
1++++
2+title = "CoinMarketCap"
3+[extra]
4+hidetitle = "true"
5+index = "true"
6++++
7+
8+The ticket number for CoinMarketCap verification is 429809.
content/communities/urbit-austin.mdnew file+11
@@ -0,0 +1,11 @@
1++++
2+title = "Urbit Austin"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-austin.png"
5++++
6+
7+Curious about Urbit? Questions about Hoon syntax? Fed up with the current state of the internet? Join us to talk about the internet's future.
8+
9+––
10+
11+[Meetup page](https://www.meetup.com/Urbit-Austin/)
content/communities/urbit-berlin.mdnew file+16
@@ -0,0 +1,16 @@
1++++
2+title = "Urbit Berlin"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-berlin.png"
5++++
6+
7+If you are sick of the current state of the web, of handing over your data and entire online presence to a handful of American corporations, of a web fueled with ads, then Urbit might be for you.
8+
9+Are you curious about Urbit and want to try it? Are you an Urbit OG looking to find to find others? Do you want to build your own peer-to-peer apps and leave the centralized web behind?
10+
11+We meet regularly in Berlin, and we try to have a theme or presentation for each meetup.
12+
13+
14+––
15+
16+[Meetup page](https://www.meetup.com/urbit-berlin/)
content/communities/urbit-christchurch.mdnew file+13
@@ -0,0 +1,13 @@
1++++
2+title = "Urbit Christchurch"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-christchurch.jpg"
5++++
6+
7+Curious about Urbit? Questions about Hoon syntax? Fed up with the current state of the internet? Join us to talk about the internet's future.
8+
9+––
10+
11+[Eventbrite](https://chchurbit.eventbrite.com)
12+
13+[Telegram](https://t.me/chchurbit)
content/communities/urbit-cph.mdnew file+11
@@ -0,0 +1,11 @@
1++++
2+title = "Urbit København"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-cph.png"
5++++
6+
7+~norsyr-torryn/nordics
8+
9+––
10+
11+[Twitter](https://twitter.com/UrbitCPH)
content/communities/urbit-dc.mdnew file+19
@@ -0,0 +1,19 @@
1++++
2+title = "DC Metro Urbit Meetup Group"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-dc.png"
5++++
6+
7+This is a DC/Northern Virginia/Southern Maryland Urbit discussion group.
8+
9+It is for Urbit users or the urbit-curious or people who like to think and talk about decentralization, independence, and freedom on the internet.
10+
11+We will socialize, discuss urbit and related topics, and support lab and learning activities.
12+
13+Find us on urbit chat at ~tillys-fasryp/nova-urbit-meetup-lobby-3347
14+
15+––
16+
17+[Meetup page](https://www.meetup.com/dc-urbit-meetup-group/)
18+
19+[Twitter](https://twitter.com/dcurbit)
content/communities/urbit-denver.mdnew file+19
@@ -0,0 +1,19 @@
1++++
2+title = "Urbit Denver"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-denver.png"
5++++
6+
7+While Urbit is the animating force behind this group, people of all interest levels & familiarity with the project - be they long-time users, or newcomers simply wondering what the heck Urbit is - are welcome & encouraged to attend these meet-ups. The conversations are lively and span a wide variety of topics, ranging from Urbit to philosophy, tech, crypto, the arts, health and well-being, and much more.
8+
9+Our goal is simply to build a community of people interested in the project and the future it envisions, in which members can freely connect and discuss the project and the various ideas & values adjacent to it.
10+
11+And for those wondering what the heck is Urbit? Urbit is an ambitious reimagining of what the internet can be; it is a virtual computer and peer-to-peer network, built on a philosophy of human-scale computing, where you own all your data and identity. Urbit strives to once again make the computer a useful tool under the control of the user, and not vice versa. Still confused? Stop by and we'll (try to) explain it.
12+
13+––
14+
15+~nospex-larsut/mile-high-mars
16+
17+[Meetup page](https://www.meetup.com/mile-high-mars-denver-urbit-group/)
18+
19+[Organizer's Twitter](https://twitter.com/OnAPersonaLevel)
content/communities/urbit-london.mdnew file+15
@@ -0,0 +1,15 @@
1++++
2+title = "Urbit London"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-london.jpg"
5++++
6+
7+Urbit London is a monthly, occasionally biweekly, meet-up series aiming to establish a long-lasting community within the London tech and cultural scene.
8+
9+––
10+
11+~tichus-holnet/urblon
12+
13+[Twitter](https://twitter.com/urblon)
14+
15+[Telegram](https://t.me/urblon)
content/communities/urbit-mst.mdnew file+13
@@ -0,0 +1,13 @@
1++++
2+title = "Urbit MST (Utah)"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-utah.png"
5++++
6+
7+Are you looking for more than the options presented to you?
8+
9+Come to our Urbit (MST) meetup. All are welcome. Bring a computer and we can onboard you with a planet and hosting for free on site. Whether you are new to Urbit or fluent in Hoon, come and meet others in Utah interested in Urbit.
10+
11+––
12+
13+[Website](https://urbitmst.org/)
content/communities/urbit-ny.mdnew file+11
@@ -0,0 +1,11 @@
1++++
2+title = "Urbit NY"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-ny.png"
5++++
6+
7+We love experimenting with Urbit & tinkering with Arvo, Hoon, & Nock
8+
9+––
10+
11+[Meetup page](https://www.meetup.com/Urbit-New-York/)
content/communities/urbit-paris.mdnew file+23
@@ -0,0 +1,23 @@
1++++
2+title = "Urbit Paris"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbitparis.png"
5++++
6+
7+Join us for our monthly Urbit meetups in Paris!
8+
9+Whether you're a tech enthusiast, an established Urbit aficionado, or a newcomer to the scene, our community is meant to welcome and engage everyone.
10+
11+If you're confused about what Urbit is, no worries, most people are at first. Drop by and we'll give you our best explanations of what Urbit is and how it's going to change the internet as we know it.
12+
13+We'll introduce Urbit, help you boot your own ship, and make sure you go back home all set!
14+
15+See you there!
16+
17+––
18+
19+~solsup-soplyd/urbit-paris
20+
21+[Twitter](https://twitter.com/urbitparis)
22+
23+[Meetup](https://www.meetup.com/urbit-paris/)
content/communities/urbit-seattle.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Urbit Seattle"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-seattle.png"
5++++
6+
7+Urbit is a simple, durable computer that you own 100% and forever. In this group, we'll discuss ongoing project developments, technical details, and how to use Urbit. With occasional speakers that will present on various topics.
8+
9+
10+––
11+
12+[Meetup page](https://www.meetup.com/urbit-seattle/)
13+
14+[Twitter](https://twitter.com/SeattleUrbit)
content/communities/urbit-sf.mdnew file+15
@@ -0,0 +1,15 @@
1++++
2+title = "Urbit SF"
3+description = ""
4+image = "https://storage.googleapis.com/media.urbit.org/site/ecosystem/communities/urbit-sf.png"
5++++
6+
7+Want to own and control the server side? Your digital identity, data and computation?
8+
9+So do we — so we're building Urbit. We set this group up for anyone excited about this kind of stuff, even those who think we're totally crazy.
10+
11+Come join us to talk about what the future of the internet might look like.
12+
13+––
14+
15+[Meetup page](https://www.meetup.com/urbit-sf/)
content/community/_index.mddeleted−5
@@ -1,5 +0,0 @@
1−+++
2−title = "Community"
3−sort_by = "weight"
4−template = "list.html"
5−+++
content/community/community-grants.mddeleted−14
@@ -1,14 +0,0 @@
1−+++
2−title = "Community Grants"
3−description = "Select Urbit address space grants for your group or community."
4−weight = 3
5−[extra]
6−hideprevious = "true"
7−hidenext = "true"
8−+++
9−
10−Interested in getting your community on Urbit? We are currently accepting applications for select groups to get started on Urbit together using an [invite pool](/using/id/creating-an-invite-pool).
11−
12−To get started, fill out the application below. Any information you share will be held privately, and only for the purpose of consideration for the grant.
13−
14−<iframe src="https://docs.google.com/forms/d/e/1FAIpQLSf_uD5fUw6xqoxtzUhSwURFYO57XQl067N3vEdy7_rTD8T2VQ/viewform?embedded=true" width="640" height="1394" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe>
content/community/governance.mddeleted−25
@@ -1,25 +0,0 @@
1−+++
2−title = "Governance"
3−description = "On the governance of the project, including both the senate of galaxies and the core developers."
4−aliases = ["/governance"]
5−weight = 4
6−[extra]
7−hideprevious = "true"
8−hidenext = "true"
9−+++
10−
11−Our goal is to design Urbit simply, such that as many decisions as possible are made by the architecture of the system itself – that is, code should be law whenever possible. Code can’t anticipate every eventuality, however, and so the system design must include mechanisms that allow decisions to be made outside of the code.
12−
13−Within Urbit, this form of governance is conducted by two groups: the senate of galaxies, and the body of core developers. The senate of galaxies is empowered to make changes to the solidity contracts which define Azimuth, Urbit’s PKI, by majority vote. This process is defined by the contracts themselves.
14−
15−An owner of a galaxy (or a delegate) can propose a new iteration of the contract logic. The proposal can then be voted on for a period of thirty days. Once that period is over, if at least a quarter of the galaxies has voted, and the majority is in favor, the old logic contract will hand over the reigns to the new one.
16−
17−In a similar process, document hashes can be proposed. While their off-chain documents can't be "technically enforced", this mechanism is useful for the Senate to record more abstract decisions.
18−
19−For off-chain process around proposals, as suggested by core developers, please see [senate.md](https://github.com/urbit/azimuth/blob/master/senate).
20−
21−The group of core developers manages Urbit’s [GitHub repository](https://github.com/urbit/), which controls Arvo, Urbit’s operating system. Changes and upgrades are decided upon by consensus.
22−
23−You can participate in the governance of the senate by acquiring a galaxy. If you would like to be involved with the governance of Arvo, check out our [developer guide](/docs/development/develop) to learn how you can contribute to core development.
24−
25−
content/community/hoonschool.mddeleted−15
@@ -1,15 +0,0 @@
1−+++
2−title = "Hoon School"
3−description = "A free, instructed, asynchronous program to learn Hoon with peers."
4−weight = 0
5−aliases = ["/hoonschool"]
6−[extra]
7−hideprevious = "true"
8−hidenext = "true"
9−+++
10−
11−Hoon School and Hooniversity (the community run Hoon School project) are currently on hiatus pending a rework of the course.
12−
13−You can still apply below and we'll let you know when the new course is ready!
14−
15−<iframe id="apply" src="https://docs.google.com/forms/d/e/1FAIpQLSdcEoEqpFvB1WCTKPaYUSbJcjQ2nHk_z4XcZPIQc0SFD1rgmA/viewform?embedded=true" width="640" height="1350" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe>
content/community/hosting-a-meetup.mddeleted−82
@@ -1,82 +0,0 @@
1−+++
2−title = "Hosting a Meetup"
3−description = "Best practices for hosting your Urbit meetups."
4−weight = 2
5−[extra]
6−flatten_pagination = "true"
7−hidenext = "true"
8−hide_previous_title = "true"
9−+++
10−
11−There are already [a few](/community/meetups) Urbit meetups that take place in cities around the United States. Want to start a meetup in your home town? Consider these best practices.
12−
13−### Create the Meetup Group Online
14−
15−The most straightforward way to start a meetup group online, like on [meetup.com](www.meetup.com). Services like this offer messaging, calendaring, payments, discussion boards, and basic group profiles.
16−
17−There are other options available but, regardless of what you choose, there should be a public place on the Web for people to access the group.
18−
19−Group suggestions:
20−
21−- Meetup.com
22−- Google groups
23−- Dedicated Website
24−
25−### Spread the word
26−
27−It’s not much fun if people don’t actually show up, so it’s important to get the word out. Use your existing network to tell people about your event. Remember it takes time to build a community, so don’t be discouraged if only a few people show up at first. Post to social media and email your friends. Also, be sure to email [support@urbit.org](mailto:support@urbit.org), and we'll promote your meetup.
28−
29−Outreach methods:
30−
31−- Post to social media
32−- Email your friends
33−- Put up signs
34−
35−### Format
36−
37−Meetups are about sharing ideas and meeting like-minded people. There are a few formats that can help achieve this goal. As the organizer, take the lead and prepare ahead of time. Think of some topics for the group to discuss, and try to ensure that the conversation isn’t dominated by one or two people.
38−
39−Presentations and guided group discussions are great ways to share ideas. If you have a speaker for your event, coordinate ahead of time and make sure they have everything they will need to make a great presentation and ask them to arrive early to the event. If you have a speaker, be sure to record the talk so that it can be posted online.
40−
41−Format considerations:
42−
43−- Guided group discussion
44−- Presentation
45−
46−### Venue
47−
48−Your meeting location can determine the success of your event. Ideally, you’d want to be away from congested areas and find locations with good parking and transit options nearby. However, this isn’t always possible, so just do your best to accommodate. It’s also a good idea to locate the event near bars or restaurants so people can continue the conversation after the event officially ends.
49−
50−Location considerations:
51−
52−- Easily reachable
53−- Consider parking and distance to transit
54−- Check out public libraries
55−- Coworking spaces
56−- [peerspace.com](https://www.peerspace.com/)
57−
58−### Date and time
59−
60−Most people are able to attend meetups after work on non-holiday weekdays, between about 6-8pm. This isn’t true for everyone but it’s a good rule of thumb. It’s also a good idea to avoid holidays and days when there are large sporting events happening.
61−
62−Date considerations:
63−
64−- Weekdays
65−- Between 6pm and 8pm
66−- Avoid holidays and weekends
67−
68−### Stay consistent
69−
70−Like basically anything worth doing, meetups take time, patience, and consistency. Come prepared to engage with people and have a good time. The more often you can meet the stronger the community can become, so schedule meetups regularly.
71−
72−### Bonus
73−
74−Here are a few tips and tricks to consider with hosting a meetup. You don’t have to have all these things at your first meeting, but try adding them in as you go.
75−
76−- Names tags
77−- Door signs
78−- Projector
79−- Extension cords and power strips
80−- Video camera
81−- Lapel microphone
82−- Bring your own internet
content/community/meetups.mddeleted−51
@@ -1,51 +0,0 @@
1−+++
2−title = "Meetups"
3−aliases = ["/meetups"]
4−description = "Information on Urbit meetups and other community-led, Urbit IRL groups."
5−weight = 1
6−[extra]
7−flatten_pagination = "true"
8−hideprevious = "true"
9−hide_next_title = "true"
10−+++
11−
12−<picture>
13−<source src="https://media.urbit.org/site/meetup1.jpg">
14−<img class="mt4" src="https://media.urbit.org/site/meetup1.jpg"/>
15−</picture>
16−
17−Turns out that getting Urbit fans together in one room is pretty fun. Here's an incomplete list of community-led Urbit IRL groups. These events are generally informal and very approachable – feel free to dive in.
18−
19−Interested in hosting an Urbit event of your own? Follow our [guide to meetup best-practices](/community/hosting-a-meetup). Send an email to [support@urbit.org](mailto:support@urbit.org) and we'll list your meetup on this page.
20−
21−### Asia
22−
23−Location | Contact information
24−:------------ | :-------------
25−Moscow, RU | [Timepad](https://urbitmoscow.timepad.ru/events/)
26−
27−### Europe
28−
29−Location | Contact information
30−:------------ | :-------------
31−Copenhagen, DK | [Twitter](https://twitter.com/UrbitCPH), [Meetup.com](https://www.meetup.com/Urbit-Copenhagen/)
32−
33−### North America
34−
35−Location | Contact information
36−:------------ | :-------------
37−Phoenix, AZ | [Twitter](https://twitter.com/UrbitPHX), [Meetup.com](https://www.meetup.com/urbit-phx/)
38−San Francisco, CA | [Meetup.com](https://www.meetup.com/urbit-sf/)
39−New York, NY | [Meetup.com](https://www.meetup.com/Urbit-New-York/)
40−Toronto, ON | [Twitter](https://twitter.com/UrbitToronto), [Meetup.com](https://www.meetup.com/Urbit-Toronto/)
41−Eugene, OR | [Twitter](https://twitter.com/EugeneUrbit)
42−Austin, TX | [Meetup.com](https://www.meetup.com/Urbit-Austin/)
43−Denton, TX | [Twitter](https://twitter.com/UrbitDFW)
44−Seattle, WA | [Meetup.com](https://www.meetup.com/urbit-seattle/)
45−
46−
47−### Oceania
48−
49−Location | Contact information
50−:------------ | :-------------
51−Sydney, AU | [Meetup.com](https://www.meetup.com/Urbit-Sydney)
content/docs/_index.mddeleted−56
@@ -1,56 +0,0 @@
1−+++
2−title = "Development Docs"
3−weight = 1
4−template = "sections/docs.html"
5−+++
6−
7−Welcome to the developer documentation for the Urbit project. This documentation
8−is maintained by [Tlon](https://tlon.io) and the Urbit community in a public
9−[Github repository](https://github.com/urbit/urbit.org/tree/master/content/docs). Issues and contributions are
10−welcome.
11−
12−This documentation provides a series of explainers, guides, tutorials and
13−reference material for assisting you in developing on the Urbit platform, or
14−contributing to the Urbit project. If you're looking for documentation on how to
15−_use_ your Urbit ship, see our [usage docs](/using/).
16−
17−### [Development](/docs/development/)
18−
19−The Development section is recommended reading for developers interested in
20−contributing to Urbit itself, or building apps on top of Urbit. It serves as a
21−high-level orientation to how to set up a development environment, the various
22−codebases the project comprises, our grants program, and the precepts that
23−drive the development of Urbit.
24−
25−### [System Overview](/docs/system-overview/)
26−
27−This section gives a high-level overview to all the major components of the
28−Urbit tech stack - namely, the operating system Arvo, the programming languages
29−Nock and Hoon, the runtime Vere, and the decentralized ID system Azimuth.
30−
31−### [Arvo (Urbit OS)](/docs/arvo/)
32−
33−This section covers the kernel of Urbit OS, called Arvo, as well as its kernel modules.
34−
35−### [Hoon (High-level Language)](/docs/hoon/)
36−
37−Here is contained all official documentation on Hoon, the high-level purely
38−functional programming language in which Arvo and much of userspace is written.
39−
40−### [Nock (Low-level Language)](/docs/nock/)
41−
42−Official guidance on Nock, the functional assembly-level language which serves
43−as the basis for Hoon.
44−
45−### [Vere (Interpreter)](/docs/vere/)
46−
47−Documentation on Vere, the Nock virtual machine which serves as the interface
48−between Urbit and Unix.
49−
50−### [Azimuth (Urbit ID)](/docs/azimuth/)
51−
52−The workings of Azimuth, the decentralized ID system utilized by Urbit.
53−
54−### [Userspace](/docs/userspace/)
55−
56−Developer guides for Gall (the vane for controlling userspace apps), Landscape (the web client by which most users interact with their ship), and Threads (transient apps for IO).
content/docs/arvo/_index.mddeleted−53
@@ -1,53 +0,0 @@
1−+++
2−title = "Arvo"
3−weight = 300
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−aliases = ["/docs/learn/arvo/"]
7−+++
8−
9−Resources about the Urbit OS.
10−
11−## [Overview](/docs/arvo/overview)
12−
13−Arvo is Urbit's functional operating system, written in [Hoon](/docs/hoon/hoon-school/). It's composed of modules called _vanes_, each of which has its own folder:
14−
15−## [Ames](/docs/arvo/ames/ames)
16−
17−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.
18−
19−## [Behn](/docs/arvo/behn/behn)
20−
21−Behn is our timer. It allows vanes and applications to set and timer events, which are managed in a simple priority queue.
22−
23−## [Clay](/docs/arvo/clay/clay)
24−
25−Clay is our filesystem and revision-control system.
26−
27−## [Dill](/docs/arvo/dill/dill)
28−
29−Dill is our terminal driver. Unix sends keyboard events to dill from the terminal, and dill produces terminal output.
30−
31−## [Eyre](/docs/arvo/eyre/eyre)
32−
33−Eyre is our HTTP server. Unix sends HTTP messages to `%eyre`, and `%eyre` produces HTTP messages in response.
34−
35−## [Ford](/docs/arvo/ford/ford)
36−
37−Ford is our build system. It handles resources and publishing.
38−
39−## [Gall](/docs/arvo/gall/gall)
40−
41−Gall is the vane for controlling userspace apps.
42−
43−## [Iris](/docs/arvo/iris/iris)
44−
45−Iris is our HTTP client.
46−
47−## [Concepts](/docs/arvo/concepts/)
48−
49−Explanations of design decisions that are pervasive throughout Arvo.
50−
51−## [Tutorials](/docs/arvo/tutorials/)
52−
53−Walkthroughs that teach you more about how Arvo works.
content/docs/arvo/ames/_index.mddeleted−27
@@ -1,27 +0,0 @@
1−+++
2−title = "Ames"
3−weight = 10
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−## [Overview](/docs/arvo/ames/ames)
10−
11−An overview of Ames and its capabilities.
12−
13−## [Cryptography](/docs/arvo/ames/cryptography)
14−
15−A technical overview of how Ames implements cryptography.
16−
17−## [API Reference](/docs/arvo/ames/tasks)
18−
19−The `task`s Ames takes and the `gift`s it returns.
20−
21−## [Scry Reference](/docs/arvo/ames/scry)
22−
23−The scry endpoints of Ames.
24−
25−## [Data Types](/docs/arvo/ames/data-types)
26−
27−Reference documentation of the various data types used by Ames.
content/docs/arvo/ames/ames.mddeleted−466
@@ -1,466 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/ames/"]
6−+++
7−
8−Our networking protocol.
9−
10−Ames is the name of both our network and the vane that communicates
11−over it. When Unix receives a packet over the correct UDP port, it pipes
12−it straight into Ames for handling. Also, all packets sent over the
13−Ames network are sent by the Ames vane. Apps and vanes may use
14−Ames to directly send messages to other ships. In general, apps use
15−[Gall](/docs/arvo/gall/gall) and [Clay](/docs/arvo/clay/clay)
16−to communicate with other ships rather than using Ames
17−directly, but this isn't a requirement. Of course, Gall and Clay use
18−Ames behind the scenes to communicate across the network. Jael is the only other
19−vane to utilize Ames.
20−
21−Ames includes several significant components. Although the actual
22−crypto algorithms are defined in `zuse`, they're used extensively in
23−Ames for encrypting and decrypting packets. Congestion control and
24−routing is handled entirely in Ames. Finally, the actual Ames
25−protocol itself, including how to route incoming packets to the correct
26−vane or app, is defined in Ames.
27−
28−## Technical Overview
29−
30−This section summarizes the design of Ames. Beyond this section are deeper
31−elaborations on the concepts presented here.
32−
33−Ames extends [Arvo's](/docs/arvo/overview) `%pass`/`%give` `move` semantics across the network.
34−
35−Ames receives packets as Arvo events and emits packets as Arvo
36−effects. The runtime is responsible for transferring the bytes in
37−an Ames packet across a physical network to another ship.
38−
39−The runtime tells Ames which physical address a packet came from,
40−represented as an opaque atom. Ames can emit a packet effect to
41−one of those opaque atoms or to the Urbit address of a galaxy
42−(root node), which the runtime is responsible for translating to a
43−physical address. One runtime implementation sends UDP packets
44−using IPv4 addresses for ships and DNS lookups for galaxies, but
45−other implementations may overlay over other kinds of networks.
46−
47−A local vane can pass Ames a `%plea` request message. Ames
48−transmits the message over the wire to the peer ship's Ames, which
49−passes the message to the destination vane.
50−
51−Once the peer has processed the `%plea` message, it sends a
52−message-acknowledgment packet over the wire back to the local
53−Ames. This "ack" can either be positive to indicate the request was
54−processed, or negative to indicate the request failed, in which
55−case it's called a "nack". (Don't confuse Ames nacks with TCP
56−nacks, which are a different concept).
57−
58−When the local Ames receives either a positive message-ack or a
59−combination of a nack and "naxplanation" (explained in more detail
60−below), it gives an `%done` `move` to the local vane that had
61−requested the original `%plea` message be sent.
62−
63−A local vane can give Ames zero or more `%boon` response messages in
64−response to a `%plea`, on the same duct that Ames used to pass the
65−`%plea` to the vane. Ames transmits a `%boon` over the wire to the
66−peer's Ames, which gives it to the destination vane on the same
67−duct the vane had used to pass the original `%plea` to Ames.
68−
69−`%boon` messages are acked automatically by the receiver Ames. They
70−cannot be nacked, and Ames only uses the ack internally, without
71−notifying the client vane that gave Ames the `%boon`.
72−
73−If the Arvo event that completed receipt of a `%boon` message
74−crashes, Ames instead sends the client vane a `%lost` message
75−indicating the `%boon` was missed.
76−
77−`%plea` messages can be nacked, in which case the peer will send
78−both a message-nack packet and a naxplanation message, which is
79−sent in a way that does not interfere with normal operation. The
80−naxplanation is sent as a full Ames message, instead of just a
81−packet, because the contained error information can be arbitrarily
82−large. A naxplanation can only give rise to a positive ack --
83−never ack an ack, and never nack a naxplanation.
84−
85−Ames guarantees a total ordering of messages within a "flow",
86−identified in other vanes by a duct and over the wire by a `bone`:
87−an opaque number. Each flow has a FIFO (first-in-first-out) queue of `%plea` requests
88−from the requesting ship to the responding ship and a FIFO queue
89−of `%boon`'s in the other direction.
90−
91−Message order across flows is not specified and may vary based on
92−network conditions.
93−
94−Ames guarantees that a message will only be delivered once to the
95−destination vane.
96−
97−Ames encrypts every message using symmetric-key encryption by
98−performing an elliptic curve Diffie-Hellman using our private key
99−and the public key of the peer. For ships in the Jael PKI
100−(public-key infrastructure), Ames looks up the peer's public key
101−from Jael. Comets (128-bit ephemeral addresses) are not
102−cryptographic assets and must self-attest over Ames by sending a
103−single self-signed packet containing their public key.
104−
105−When a peer suffers a continuity breach, Ames removes all
106−messaging state related to it. Ames does not guarantee that all
107−messages will be fully delivered to the now-stale peer. From
108−Ames's perspective, the newly restarted peer is a new ship.
109−Ames's guarantees are not maintained across a breach.
110−
111−A vane can pass Ames a `%heed` `$task` to request Ames track a peer's
112−responsiveness. If our `%boon`'s to it start backing up locally,
113−Ames will give a `%clog` back to the requesting vane containing the
114−unresponsive peer's urbit address. This interaction does not use
115−ducts as unique keys. Stop tracking a peer by sending Ames a
116−`%jilt` `$task`.
117−
118−Debug output can be adjusted using `%sift` and `%spew` `$task`'s.
119−
120−## Packets
121−
122−Ames datagram packets are handled as nouns internally by Arvo but as serial data
123−by Unix. In this section we describe how packets are formed, serialized, and relayed.
124−
125−### Packet format
126−
127−There is a 32-bit header followed by a variable width body.
128−
129−#### Header
130−
131−The 32-bit header is given by the following data, presented in order:
132−
133−- 3 bits: reserved
134−- 1 bit: is this Ames? (i.e. not using a different protocol, such as the
135− planned remote scry protocol)
136−- 3 bits: Ames protocol version (currently 0)
137−- 2 bits: sender address size
138−- 2 bits: receiver address size
139−- 20 bits: checksum (truncated insecure hash of the body, done with
140− [`+mug`](/docs/hoon/reference/stdlib/2e#mug)
141−- 1 bit: is this relayed? (if set, `origin` will be present in the body)
142−
143−Every packet sent between ships is encrypted except for self-signed attestation packets from 128-bit comets.
144−
145−#### Body
146−
147−The body is of variable length and consists of the following parts in this
148−order:
149−
150−- 4 bits: sender life (mod 16)
151−- 4 bits: receiver life (mod 16)
152−- variable: sender address
153−- variable: receiver address
154−- 48 bits: (optional) 48-bit `origin`
155−- 128 bits: `SIV`
156−- 16 bits: ciphertext size
157−- variable: ciphertext
158−
159−`origin` is the IP and port of the original sender if the packet was proxied
160−through a relay.
161−
162−`SIV` is a "synthetic initialization vector" as defined in AES-256 SIV, the encryption
163−algorithm utilized to encrypt Ames packets (see the page on [Ames
164−cryptography](/docs/arvo/ames/cryptography)). It is formed from the
165−following noun: `~[sender=@p receiver=@p sender-life=@ receiver-life=@]` (see
166−[Life and Rift](/docs/azimuth/life-and-rift) for information on what `life`
167−is). As this data is in Azimuth, it is not explicitly sent over the wire. Thus
168−the mod 16 sender and receiver life in the first 8 bits are only for quick
169−filtering of honest packets sent to or from a stale life.
170−
171−The ciphertext is formed by `+jam`ming a `$shut-packet` and then encrypting
172−using [`+en:sivc:aes:crypto`](/docs/arvo/reference/cryptography#en).
173−
174−### Packeting
175−
176−When Ames has a message to be sent it must first determine how many packets are
177−required to send the message. To do this, it first `+jam`s the
178−message, producing an atom. Ames checks how large the atom is, and if it is
179−bigger than a kilobyte it will split it into packets whose payloads are 1 kB or
180−less. It then numbers each one - this is message 17, packet 12, this is message
181−17, packet 13, etc., so that when the receiver receives these packets it knows
182−which number they are. Finally it encrypts each individual packet and enqueues
183−them to be sent along their stated flow.
184−
185−Network packets aren't always received in order, so this numbering is important
186−for reconstruction, and also packets may get lost. So Ames does transmission
187−control (the TC in TCP) to solve this problem. It makes sure that all packets
188−eventually get through, and when the other side gets them it can put them in the
189−correct order. If Ames doesn't get an ack on a packet then it will resend it
190−until it does. The logic for determining how many packets to send or re-send at what time is performed by an Ames-specific variant of TCP's "NewReno" congestion control algorithm.
191−
192−As each packet in a message is received, Ames decrypts it and stores the message fragment. Once it's received every packet for a message, Ames concatenates the fragments back into a single large atom and uses `+cue` to deserialize that back into the original message noun.
193−
194−### Acks and Nacks
195−
196−In this section we discuss acks and nacks. In Ames, an "ack", short for "acknowledgment", is a small packet attesting that a piece of information (either a packet or a whole message) was received. Ames makes use of
197−acks to maintain synchronization between two communicating parties. Nacks are 'negative
198−acknowledgments' and are used when something goes wrong.
199−
200−#### Acks
201−
202−Every message (i.e. a `%plea` or `%boon`) is split up by Ames into some number
203−of _fragments_ that are 1kB in size or less. The fragments are then encrypted
204−and encapsulated into
205−packets and sent along a flow. The message will be considered successfully
206−received once the sender has received the appropriate set of acks in response,
207−defined as follows.
208−
209−There are two types of acks: fragment acks and message acks. Acks are
210−not considered messages, and thus are not `%plea`s or `%boon`s. Given a message split into N
211−fragments, the sender of the message will expect N-1 fragment acks followed
212−by exactly one message ack (ignoring any duplicate packets, which are idempotent
213−from the perspective of the application). This is because the receiver
214−will send a fragment ack for the first N-1 packets it received, and what
215−would have been the final fragment ack will instead be a message ack.
216−
217−Acks are considered to be part of the flow in which that `%plea` or
218−`%boon` lives, as the packets containing their fragments and packets acking the
219−receipt of those packets are considered to be what makes up a given message.
220−Thus a message-level ack must be received before the next message on the flow
221−can begin. The full story is more complicated than this; see the section on
222−[flows](#flows).
223−
224−#### Nacks {#nacks}
225−
226−A nack indicates a negative acknowledgement to a `%plea`, meaning that the
227−requested action was not performed.
228−
229−`%boon`s and naxplanations are never nacked.
230−Individual packets are also never nacked, only complete `%plea` messages are.
231−Whether a malformed packet causes a `%plea` to be nacked depends on its content.
232−In the case of an incorrect checksum or a failure to decrypt then Ames drops the
233−packet and it is as though it never happened. However, if the packet does
234−decrypt and has invalid ciphertext (i.e. something other than a jammed
235−`$shutpacket` data structure), then Ames will nack the whole `%plea` since that
236−indicates that the peer is misbehaving. Eventually Ames should also present a
237−warning to the user that the peer is untrustworthy.
238−
239−A nack will be accompanied by a naxplanation, which is a special type of`%boon`
240−that uses its own `bone` (see [flows](#flows)). Ames won't give the vane that requested the
241−initial `%plea` a nack until it also receives the naxplanation, which it will send to
242−the vane as a `%done` gift. Naxplanations may only be acked, never nacked.
243−Furthermore, naxplanations can only ever be sent as a rejection of a `%plea` -
244−the receiver will never both perform a `%plea` and return a naxplanation.
245−
246−#### (N)ack packets
247−
248−A fragment ack's contents (before encryption) are a pure function of the
249−following noun:
250−
251−```hoon
252−[our-life her-life bone message-num fragment-num]
253−```
254−
255−This means all re-sends of an ack packet will be bitwise identical to each other, unless one of the peers changes its encryption keys.
256−
257−Each datum in this noun is an atom with the aura `@ud` or an aura that nests
258−under `@ud`.
259−
260−Here, `our-life` refers to the [`life`](/docs/glossary/breach), or revision
261−number, of the acking ship's networking keys, and `her-life` is the `life` of
262−the ack-receiving ship's networking keys. `bone` is an opaque number identifying
263−the flow. `message-num` denotes the number of the
264−message in the flow identified by `bone`. `fragment-num` denotes the number of
265−the fragment of the message identified by `message-num` that is being acked.
266−
267−A message (n)ack is a different kind of ack that is obtained by encrypting the
268−`+jam` of the following noun:
269−
270−```hoon
271−[our-life her-life bone message-num ok=? lag=@dr]
272−```
273−
274−`ok` is a flag that is set to `%.y` for a message ack and `%.n` for a message
275−nack. In the future, `lag` will be used to
276−describe the time it took to process a message, but for now it is always zero.
277−
278−### Flows
279−
280−Flows are asymmetric communication channels along which two ships send and
281−receive packets, and all Ames packets are part of some flow.
282−
283−To create a new flow, a ship sends a
284−`%plea` to another ship. Only the creator of the flow may send `%plea`s, and the
285−other party may only send `%boon`s. In this sense flows are asymmetric.
286−
287−The sequence of `%plea`s in a flow is totally ordered, though
288−the packets which make them up need not be. `%boon`s are totally ordered in the
289−same fashion, but there is not a coordinated ordering between `%plea`s and
290−`%boon`s in a given flow beyond the implicit one arising from the fact that a
291−`%boon` is always a response to a `%plea`. A `%plea` can give rise to zero, one,
292−or many `%boon`s.
293−
294−Inside of Ames, each flow has four sequential opaque `@ud`s
295−called bones that are unique to that flow. Thus the flow itself is often
296−referred to by its first bone. Each bone is a one-way street
297−for packets to travel along, so e.g. acks to packets making up a `%plea` are
298−sent along a different bone than the `%plea`.
299−
300−We give an example of such a partition. Let flow 12 be a flow between `~bacbel-tagfeg` and `~worwel-sipnum` with
301−`~bacbel-tagfeg` as the `%plea` sender. Then bones 12-15 are associated with the
302−flow, and the types of packets for each bone are:
303−
304−- bone 12, `%plea`s and acks to `~worwel-sipnum`,
305−- bone 13, `%boon`s and (n)acks to `~bacbel-tagfeg`,
306−- bone 14, acks of naxplanations to `~worwel-sipnum`,
307−- bone 15, naxplanations to `~bacbel-tagfeg`.
308−
309−Each bone is handled separately by congestion control, and this is one reason
310−for their segregation. For example, say a two-packet `%plea` is sent on bone 12,
311−with `~bacbel-tagfeg` requesting to join a group on `~worwel-sipnum`.
312−Then `~worwel-sipnum` can ack the first packet on bone 13, and then send a nack
313−on bone 13 as well. A nack by itself contains no information as to why the nack
314−happened. Then `~worwel-sipnum` can also send a naxplanation on bone 15 saying
315−to `~bacbel-tagfeg` that they cannot join the group, to which an ack is received
316−on bone 14.
317−
318−Another reason to separate bones is to avoid race conditions. If
319−`~worwel-sipnum` and `~bacbel-tagfeg` attempt to start a flow with each other at
320−the same time we do not wish there to be a conflict when they receive each
321−others' packets. Flipping the last bit of the bone based on whether a packet is
322−an ack or a message fragment allows for `~worwel-sipnum` to create flow 8 with
323−`~bacbel-tagfeg` without coming into conflict with the flow 8 `~bacbel-tagfeg`
324−created for `~worwel-sipnum`.
325−
326−`%plea`s and `%boon`s are handled on separate bones so that e.g. sending a large
327−`%boon` doesn't stop an additional `%plea` from being received. It is also
328−simply cleaner to make each bone one-way. Acks and nacks are very small packets
329−as well as integral to controlling the total orderings on `%plea`s and `%boon`s
330−and so they are included on these bones as well.
331−
332−Naxplanations can potentially be very large, as they often contain things like stack
333−traces or other crash reports. Thus it is undesirable to have them share a bone
334−with `%boon`s and create congestion there. So naxplanations have their own bone,
335−and so do acks to packets that make up a naxplanation, as well as the
336−message-level naxplanation ack.
337−
338−### Packet relaying and peer discovery
339−
340−Here we describes how the Ames network relays packets and does peer discovery.
341−We ignore all details about UDP, which occurs at a lower layer than Ames.
342−
343−When a ship first contacts another ship, it may only know its `@p`, but an IP
344−address and port are necessary for peer-to-peer communication to occur.
345−Thus the initial correspondence between two ships, or additional correspondence
346−following a change in IP or port of one of the parties, will need to be relayed
347−by an intermediary that knows the IP and port of the receiving ship.
348−
349−For now, peer discovery is handled entirely by galaxies. Every galaxy is
350−responsible for knowing the IP and port of every planet underneath it. In the
351−future, galaxies will only need to know the IP and port of the star sponsoring a
352−planet, and stars will be responsible for knowing the IP and port of their sponsored planets.
353−
354−Galaxies are also utilized for packet relaying in the case where two ships
355−cannot communicate directly with one another, as is often the case when one or
356−both are behind a
357−[NAT](https://en.wikipedia.org/wiki/Network_address_translation) or certain
358−firewalls. We remark that packet relaying is a necessary component of peer
359−discovery. Thus stars will also assist with packet relaying in the future.
360−
361−In the case of a moon, its parent ship is responsible for packet relaying and peer
362−discovery, analagous to the role that galaxies currently play for stars and planets.
363−
364−The following diagram summarizes the packet creation and forwarding process.
365−
366−<div style="text-align:center">
367−<img src="https://media.urbit.org/docs/arvo/datagram-updated-2021-06-09.png">
368−</div>
369−
370−We elaborate on the above diagram.
371−
372−A typical relay will look something like this: `~bacbel-tagfeb` wishes to
373−contact `~worwel-sipnum` but does not know the IP address and port at which
374−`~worwel-sipnum` resides. Both planets are sponsored by a star sponsored by
375−`~zod`, which knows both of their IP addresses and port numbers by virtue of
376−being the galaxy that both live under.
377−
378−To prepare, `~bacbel-tagfeb` forms a Diffie-Hellman symmetric key with their own
379−private key and the public key of `~worwel-sipnum`, obtained via Jael. Then
380−`~bacbel-tagfeb` sends a packet addressed to `~worwel-sipnum` to `~zod`.
381−
382−The packet has the following format:
383−
384−- The standard Ames header described in [header](#header), where the checksum
385− is the `+mug` of the body, and the sender and receiver ship types are `01`,
386− denoting that the sender and receiver are planets. The "is this relayed?" bit
387− is set to 0 since this is the first hop on the packet route.
388−- The body of this packet will be the life of `~bacbel-tagfeg` mod 16, followed
389− by the life of `~worwel-sipnum` mod 16, followed by `~bacbel-tagfeg`,
390− followed by the receiver `~worwel-sipnum`, followed by the origin `~`
391− (denoting that the ship sending the packet is the origin). After this comes
392− the payload.
393−- The payload of this packet will be the `+jam` of the `content`, which is an encrypted fragment of the message `%watch /path/to/recipes`.
394−
395−`~zod` receives the packet and reads the body. It sees that it is not the
396−intended recipient of the packet, and so gets ready to forward it to
397−`~worwel-sipnum`. First, it replaces the origin field with the IP and port of
398−`~bacbel-tagfeb`, then computes the `+mug` of the body and replaces the checksum
399−with the new mug. Since the packet is being relayed, `~zod` flips the "is it
400−relayed?" bit to `%.y`. `~zod` then forwards the packet to `~worwel-sipnum`.
401−
402−In order to decrypt the packet, `~worwel-sipnum` will need to calculate the
403−associated data vector utilized by SIV, which consists of `~[sender=@p receiver=@p sender-life=@ receiver-life=@]`. It then passes that along with the
404−SIV and ciphertext to the decryption function, and receives the unencrypted
405−packet as a return.
406−
407−Once `~worwel-sipnum` processes the packet, it will know the IP and port of
408−`~bacbel-tagfeb` since `~zod` included it when it forwarded the packet. Thus
409−`~worwel-sipnum` will send an ack packet directly to `~bacbel-tagfeb`, unless a
410−NAT and/or firewall prevents a direct peer-to-peer connection, in which case
411−`~zod` will continue to relay packets. Absent these factors preventing a
412−peer-to-peer connection, communication between the two ships will now be direct
413−until one of them changes their IP address, port, or networking keys.
414−
415−In this scenario, of course, the message is so short that a single packet would
416−be sufficient to send the message, so the `+cue` of the payload would contain
417−the complete message `%watch /path/to/recipes`. At this point, `~worwel-sipnum`
418−would ack (or nack) the packet, which would perform double duty as a message
419−ack. Assuming that a direct peer-to-peer connection is possible, the ack would
420−be sent directly to `~bacbel-tagfeb` using the IP and port found in the origin
421−field of the received packet rather than being relayed via `~zod`.
422−
423−But if the message were not short enough to be contained in a single packet,
424−each packet would need to be decrypted and `+cue`d to obtain the message
425−fragments that are then put together and `+cue`d again to obtain the complete
426−message.
427−
428−## The Serf and the King
429−
430−Urbit's functionality is split between the two binaries `urbit-worker` (sometimes
431−called the Serf) and `urbit-king` (sometimes called the King). This division of
432−labor is currently not well-documented outside of the [Vere documents](/docs/vere/), but we summarize it here.
433−
434−In short, the Serf is the Nock runtime and so keeps track of the current state
435−of Arvo as a Nock noun and updates the state by `%poke`ing it with nouns, and
436−then informs the King of the new state. The King manages snapshots of the Arvo
437−state and handles I/O with Unix, among other things. The Serf only ever talks to
438−the King, while the King talks with both the Serf and Unix.
439−
440−### Ames I/O submodule
441−
442−The King has several submodules, one of them being an Ames I/O submodule. This
443−submodule is responsible for wrapping outgoing Ames packets as UDP packets, and
444−unwrapping incoming UDP packets into Ames packets and forwarding them to the
445−worker. It also maintains an incoming packet queue.
446−
447−This division is summarized in the following diagram, describing how
448−`~bacbel-tagfeb` requests a subscription to the `recipes` notebook of
449−`~worwel-sipnum` in the Publish app.
450−
451−<div style="text-align:center">
452−<img src="https://media.urbit.org/docs/arvo/packet.png">
453−</div>
454−
455−Ames, as a part of Arvo, handles `+jam`ming, packetizing, encryption, and
456−forming Ames packets. Once it is ready to send an Ames packet, it `%give`s to
457−Unix a `%send` `gift` containing that packet. This will be a Nock noun
458−containing the `@tas` `%send` as well as the serialized packet.
459−
460−"Unix", in this case, is actually the King. The King receives the `%send`
461−instruction, wraps the packet contained within as a UDP packet, and immediately
462−hands it off the the Unix network interface to be sent.
463−
464−Now the receiving King is handed a UDP packet by Unix. The King removes the UDP
465−wrapper, `+jam`s the `lane` on which it heard the packet, and delivers the packet
466−to the Ames vane as an atom by copying the bytes it heard on the UDP port.
content/docs/arvo/ames/cryptography.mddeleted−145
@@ -1,145 +0,0 @@
1−+++
2−title = "Cryptography"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−Here we give a technical overview of how Ames implements cryptography.
8−
9−## Summary
10−
11−By default, all [packets are encrypted](#packets) with 256-bit
12−[AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) symmetric key
13−encryption, whose key is obtained by [Diffie-Hellman key exchange](#key-exchange),
14−with public/private keys generated using elliptic curve
15−[Curve25519](https://en.wikipedia.org/wiki/Curve25519). The only exception to
16−this are comet [self-attestation packets](#comets), which are unencrypted.
17−
18−All packets are also [signed](#packets) using [Elliptic Curve Digital Signature
19−Algorithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm).
20−
21−The `$ames-state` includes a [`+acru:ames`](#crypto-core) core, an interface
22−core into which one of the cryptosuites in `zuse` may be implemented. Some, but
23−not all, of the calls to cryptography-related tasks (encryption, signing,
24−decrypting, and authenticating) are peformed utilizing the `+acru` core.
25−
26−## Packet encryption and authentication {#packets}
27−
28−Each Urbit ship possesses two networking keypairs: one for encryption, and one
29−for authentication. We often refer to these two keypairs as though they were a
30−single keypair because they are stored as a single atom. [Elliptic Curve
31−Diffie-Hellman](https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman)
32−is used for encryption, while [Elliptic Curve Digital Signature
33−Algorithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)
34−is used for authentication
35−
36−The encrypted payload of each packet is a `$shut-packet`, which is the `+jam` of
37−a cell with the [$bone](/docs/arvo/ames/data-types#bone), message number, and message fragment or ack (see
38−[Ames](/docs/arvo/ames/ames) for more information on packet structure). The
39−message fragment is signed using the authentication key. It is encrypted using
40−[`+en:crub:crypto`](/docs/arvo/reference/cryptography#en) found in
41−`sys/zuse.hoon`, which utilizes the 256-bit AES-SIV algorithm.
42−
43−## Diffie-Hellman key exchange {#key-exchange}
44−
45−For each foreign ship a given ship has communicated with, `$ames-state` contains a
46−[$peer-state](/docs/arvo/ames/data-types#peer-state), inside which the [$symmetric-key](/docs/arvo/ames/data-types#symmetric-key) (an atom which nests under
47−`@uw`) is utilized for encrypting all Ames packets shared between the two ships.
48−The `symmetric-key` is derived using [`+shar:ed:crypto`](/docs/arvo/reference/cryptography#ed) found in `sys/zuse.hoon`,
49−which is an arm utilized for generating the symmetric key for elliptic curve
50−[Diffie-Hellman key
51−exchange](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange)
52−with [curve25519](https://en.wikipedia.org/wiki/Curve25519). Briefly, each ship
53−in a two-way conversation computes the shared symmetric key for that
54−conversation by computing the product of their own private key and the public
55−key of the other party.
56−
57−## Comet self-attestation {#comets}
58−
59−Recall that the `@p` of a comet is the hash of their 128-bit public key cast as
60−a `@p`. Since the public key of a comet is not stored on Azimuth, a comet proves
61−its identity with an "attestation packet". This is an unencrypted packet whose
62−payload is the comet's signature created with its private key. This is the only
63−circumstance under which a ship will send an unencrypted packet. The signature
64−is generated with
65−[`+sign:as:crub`](/docs/arvo/reference/cryptography#sign-as) found in
66−`sys/zuse.hoon`.
67−
68−Upon hearing an attestation packet, the receiving ship will generate a symmetric
69−key for communications with the comet, according to the [key
70−exchange](#key-exchange) protocol.
71−
72−The fact that the first packet exchanged between a comet and another ship must
73−be an attestation packet is why comets are unable to initiate communication with
74−one another, and also why comets must be the first to initiate communication
75−with a non-comet. This is a technical limitation with a planned workaround.
76−
77−## `+acru:ames` {#crypto-core}
78−
79−The `+crypto-core` in `$ames-state` is an `+acru:ames` core, a
80−[lead](/docs/hoon/reference/advanced#dry-polymorphism-and-core-nesting-rules)
81−interface core for asymmetric cryptosuites found in `sys/lull.hoon` which
82−handles encryption, decryption, signing, and verifying. In practice, the only
83−cryptosuite in use is [`+crub:crypto`](#crub), which implements [Suite B
84−Cryptography](https://en.wikipedia.org/wiki/NSA_Suite_B_Cryptography).
85−
86−```hoon
87− ++ acru $_ ^? :: asym cryptosuite
88− |% :: opaque object
89− ++ as ^? :: asym ops
90− |% ++ seal |~([a=pass b=@] *@) :: encrypt to a
91− ++ sign |~(a=@ *@) :: certify as us
92− ++ sure |~(a=@ *(unit @)) :: authenticate from us
93− ++ tear |~([a=pass b=@] *(unit @)) :: accept from a
94− -- ::as ::
95− ++ de |~([a=@ b=@] *(unit @)) :: symmetric de, soft
96− ++ dy |~([a=@ b=@] *@) :: symmetric de, hard
97− ++ en |~([a=@ b=@] *@) :: symmetric en
98− ++ ex ^? :: export
99− |% ++ fig *@uvH :: fingerprint
100− ++ pac *@uvG :: default passcode
101− ++ pub *pass :: public key
102− ++ sec *ring :: private key
103− -- ::ex ::
104− ++ nu ^? :: reconstructors
105− |% ++ pit |~([a=@ b=@] ^?(..nu)) :: from [width seed]
106− ++ nol |~(a=ring ^?(..nu)) :: from ring
107− ++ com |~(a=pass ^?(..nu)) :: from pass
108− -- ::nu ::
109− -- ::acru ::
110−```
111−
112−As the `+acru` core is merely an interface, the details on how it is implemented
113−may vary according to the cryptosuite. We summarize what each
114−core is utilized for here, but see
115−[`crub:crypto`](/docs/arvo/reference/cryptography#crub) for more details on
116−how the specific cryptosuite utilized by Ames is implemented.
117−
118−#### `+as:acru`
119−
120−This core is used for the standard asymmetric cryptographic operations: encrypting
121−(`+seal`), signing (`+sign`), authenticating (`+sure`), and decrypting (`+tear`).
122−
123−#### `+ex:acru`
124−
125−This core is used to extract keys and their fingerprints. `+sec` is the secret key (which
126−may be empty), `+pub` is the public key associated to the secret key, `+pac` is
127−the fingerprint associated to the secret key, and `+fig` is the fingerprint
128−associated to the public key. We note that when the core contains both
129−encryption and authentication keys, they are typically concatenated to be
130−returned as a single atom.
131−
132−#### `+nu:acru`
133−
134−This core contains constructors for the `+acru` core. `+pit:nu` is used to
135−construct an `+acru` core with both a private and public key (i.e. both
136−`+sec:ex` and `+pub:ex` are set) from a bitlength and seed. `+nol:nu` can then be
137−called from an `+acru` core created with `+pit:nu` to get an `+acru` core with
138−only the secret key, while `+com:nu` can be called to get an `+acru` core with
139−only the public key.
140−
141−#### `+en:acru`, `+de:acru`, and `+dy:acru`
142−
143−These arms are for symmetric encryption (`+en`) and decryption (`+de` and
144−`+dy`). The difference between the decryption arms is that `+de` returns null
145−and `+dy` crashes upon failure.
content/docs/arvo/ames/data-types.mddeleted−389
@@ -1,389 +0,0 @@
1−+++
2−title = "Data Types"
3−weight = 5
4−template = "doc.html"
5−+++
6−
7−Here are the data types used by Ames, as defined in `lull.hoon`.
8−
9−## `$address`
10−
11−```hoon
12−+$ address @uxaddress
13−```
14−
15−Opaque atomic transport address to or from Unix. For Ames over UDP, it will encode the IP address and port.
16−
17−## `$verb`
18−
19−```hoon
20−+$ verb ?(%snd %rcv %odd %msg %ges %for %rot)
21−```
22−
23−Verbosity flag for Ames. Use with `|ames-verb %flag1 %flag2 ...` and turn off with `|ames-verb`.
24−
25−- `%snd` - Sending packets.
26−- `%rcv` - Receiving packets.
27−- `%odd` - Unusual events.
28−- `%msg` - Message-level events.
29−- `%ges` - Congestion control.
30−- `%for` - Packet forwarding.
31−- `%rot` - Routing attempts.
32−
33−## `$blob`
34−
35−```hoon
36−+$ blob @uxblob
37−```
38−
39−Raw atom to or from Unix, representing a packet.
40−
41−## `$error`
42−
43−```hoon
44−+$ error [tag=@tas =tang]
45−```
46−
47−Tagged diagnostic trace.
48−
49−## `$lane`
50−
51−```hoon
52−+$ lane (each @pC address)
53−```
54−
55−Ship transport address; either opaque [$address](#address) or galaxy. The runtime knows how to look up galaxies, so we don't need to know their transport addresses.
56−
57−## `$plea`
58−
59−```hoon
60−+$ plea [vane=@tas =path payload=*]
61−```
62−
63−Application-level message, as a `%pass`.
64−
65−- `vane` - Destination vane on remote ship.
66−- `path` - Internal route on the receiving ship.
67−- `payload` - Semantic message contents.
68−
69−## `$bone`
70−
71−```hoon
72−+$ bone @udbone
73−```
74−
75−Message flow index - mapped to `duct`s in the [$ossuary](#ossuary).
76−
77−The first `bone` is 0. They increment by 4, since each flow includes a bit for each message determining forward vs. backward and a second bit for whether the message is on the normal flow or the associated diagnostic flow (for naxplanations).
78−
79−The least significant bit of a `bone` is:
80−
81−- 1 if "forward", i.e. we send `%plea`s on this flow.
82−- 0 if "backward", i.e. we receive `%plea`s on this flow.
83−
84−The second-least significant bit is 1 if the `bone` is a naxplanation `bone`, and 0 otherwise. Only naxplanation messages can be sent on a naxplanation `bone`, as `%boon`s.
85−
86−## `$fragment`
87−
88−```hoon
89−+$ fragment @uwfragment
90−```
91−
92−A message fragment.
93−
94−## `$fragment-num`
95−
96−```hoon
97−+$ fragment-num @udfragmentnum
98−```
99−
100−Message fragment count.
101−
102−## `$message-blob`
103−
104−```hoon
105−+$ message-blob @udmessageblob
106−```
107−
108−Unfragmented message blob.
109−
110−## `$message-num`
111−
112−```hoon
113−+$ message-num @udmessagenum
114−```
115−
116−Message count.
117−
118−## `$public-key`
119−
120−```hoon
121−+$ public-key @uwpublickey
122−```
123−
124−A peer's public key.
125−
126−## `$symmetric-key`
127−
128−```hoon
129−+$ symmetric-key @uwsymmetrickey
130−```
131−
132−A symmetric key for encrypting messages to a peer. This is produced by performing an elliptic curve Diffie-Hellman using our private key and the peer's public key.
133−
134−## `$ack`
135−
136−```hoon
137−+$ ack
138− $% [%ok ~]
139− [%nack ~]
140− [%naxplanation =error]
141− ==
142−```
143−
144−A message acknowledgement.
145−
146−- `%ok` - Positive acknowledgement.
147−- `%nack` - Negative acknowledgement.
148−- `%naxplanation` - Nack trace.
149−
150−## `$ship-state`
151−
152−```hoon
153−+$ ship-state
154− $% [%alien alien-agenda]
155− [%known peer-state]
156− ==
157−```
158−
159−All Ames knows about a peer.
160−
161−- `%alien` - No PKI data, so enqueue actions to perform once we learn it.
162−- `%known` - We know their `life` and public keys, so we have a channel.
163−
164−## `$alien-agenda`
165−
166−```hoon
167−+$ alien-agenda
168− $: messages=(list [=duct =plea])
169− packets=(set =blob)
170− heeds=(set duct)
171− ==
172−```
173−
174−What to do when Ames learns a peer's life and keys.
175−
176−- `messages` - [$plea](#plea)s local vanes have asked Ames to send.
177−- `packets` - Packets we've tried to send.
178−- `heeds` - Local tracking requests; passed through into [$peer-state](#peer-state).
179−
180−## `$peer-state`
181−
182−```hoon
183−+$ peer-state
184− $: $: =symmetric-key
185− =life
186− =public-key
187− sponsor=ship
188− ==
189− route=(unit [direct=? =lane])
190− =qos
191− =ossuary
192− snd=(map bone message-pump-state)
193− rcv=(map bone message-sink-state)
194− nax=(set [=bone =message-num])
195− heeds=(set duct)
196− ==
197−```
198−
199−State for a peer with known life and keys.
200−
201−- `route` - Transport-layer destination for packets to the peer.
202−- `qos` - Quality of service; connection status to the peer.
203−- `ossuary` - [$bone](#bone) to `duct` mapper.
204−- `snd` - Per-`bone` message pumps to send messages as fragments.
205−- `rcv` - Per-`bone` message sinks to assemble messages from fragments.
206−- `nax` - Unprocessed nacks (negative acknowledgments).
207−- `heeds` - Listeners for `%clog` notifications.
208−
209−## `$qos`
210−
211−```hoon
212−+$ qos
213− $~ [%unborn *@da]
214− [?(%live %dead %unborn) last-contact=@da]
215−```
216−
217−Quality of service; how is the connection to a peer doing?
218−
219−- `%live` - Peer is ok.
220−- `%dead` - Peer is not responding.
221−- `%unborn` - Peer is sunken.
222−- `last-contact` - Last time Ames heard from the peer, or if `%unborn`, the time when we first started tracking then.
223−
224−## `$ossuary`
225−
226−```hoon
227−+$ ossuary
228− $: =next=bone
229− by-duct=(map duct bone)
230− by-bone=(map bone duct)
231− ==
232−```
233−
234−[$bone](#bone) to `duct` mapping, `next` is the next `bone` to map to a `duct`.
235−
236−## `$message-pump-state`
237−
238−```hoon
239−+$ message-pump-state
240− $: current=_`message-num`1
241− next=_`message-num`1
242− unsent-messages=(qeu message-blob)
243− unsent-fragments=(list static-fragment)
244− queued-message-acks=(map message-num ack)
245− =packet-pump-state
246− ==
247−```
248−
249−Persistent state for a `|message-pump`.
250−
251−- `current`- Sequence number of earliest message sent or being sent.
252−- `next` - Sequence number of next message to send.
253−- `unsent-messages` - Messages to be sent after current message.
254−- `unsent-fragments` - Fragments of current message waiting for sending.
255−- `queued-message-acks` - Future message acks to be applied after current.
256−- `packet-pump-state` - State of corresponding `|packet-pump`.
257−
258−## `$static-fragment`
259−
260−```hoon
261−+$ static-fragment
262− $: =message-num
263− num-fragments=fragment-num
264− =fragment-num
265− =fragment
266− ==
267−```
268−
269−A packet; a fragment of a message and metadata.
270−
271−## `$packet-pump-state`
272−
273−```hoon
274−+$ packet-pump-state
275− $: next-wake=(unit @da)
276− live=(tree [live-packet-key live-packet-val])
277− metrics=pump-metrics
278− ==
279−```
280−
281−Persistent state for a `|packet-pump`.
282−
283−- `next-wake` - Last timer we've set, or null.
284−- `live` - Packets in flight; sent but not yet acked.
285−- `metrics` - Congestion control information.
286−
287−## `$pump-metrics`
288−
289−```hoon
290−+$ pump-metrics
291− $: rto=_~s1
292− rtt=_~s1
293− rttvar=_~s1
294− ssthresh=_10.000
295− cwnd=_1
296− num-live=@ud
297− counter=@ud
298− ==
299−```
300−
301−Congestion control state for a `|packet-pump`.
302−
303−- `rto` - Retransmission timeout.
304−- `rtt` - Roundtrip time estimate, low-passed using EWMA.
305−- `rttvar` - Mean deviation of `rtt`, also low-passed with EWMA.
306−- `num-live` - How many packets sent, awaiting ack.
307−- `ssthresh` - Slow-start threshold.
308−- `cwnd` - Congestion window; max unacked packets.
309−
310−## `$live-packet`
311−
312−```hoon
313−+$ live-packet
314− $: key=live-packet-key
315− val=live-packet-val
316− ==
317−```
318−
319−A packet in flight, as tracked in the [$packet-pump-state](#packet-pump-state).
320−
321−## `$live-packet-key`
322−
323−```hoon
324−+$ live-packet-key
325− $: =message-num
326− =fragment-num
327− ==
328−```
329−
330−Identifier of a packet in flight.
331−
332−## `$live-packet-val`
333−
334−```hoon
335−+$ live-packet-val
336− $: packet-state
337− num-fragments=fragment-num
338− =fragment
339− ==
340−```
341−
342−Content and metadata about a packet in flight.
343−
344−## `$packet-state`
345−
346−```hoon
347−+$ packet-state
348− $: last-sent=@da
349− retries=@ud
350− skips=@ud
351− ==
352−```
353−
354−Sending statistics about a packet in flight.
355−
356−## `$message-sink-state`
357−
358−```hoon
359−+$ message-sink-state
360− $: last-acked=message-num
361− last-heard=message-num
362− pending-vane-ack=(qeu [=message-num message=*])
363− live-messages=(map message-num partial-rcv-message)
364− nax=(set message-num)
365− ==
366−```
367−
368−State of a `|message-sink` to assemble received messages.
369−
370−- `last-acked` - Highest [$message-num](#message-num) Ames has fully acknowledged.
371−- `last-heard` - Highest `message-num` Ames has heard all fragments for.
372−- `pending-vane-ack` - Heard but not processed by local vane.
373−- `live-messages` - Partially received messages.
374−
375−## `$partial-rcv-message`
376−
377−```hoon
378−+$ partial-rcv-message
379− $: num-fragments=fragment-num
380− num-received=fragment-num
381− fragments=(map fragment-num fragment)
382− ==
383−```
384−
385−A message for which Ames has received some fragments.
386−
387−- `num-fragments` - Total number of fragments in the message.
388−- `num-received` - How many fragments Ames has received so far.
389−- `fragments` - The received fragments themselves.
content/docs/arvo/ames/scry.mddeleted−126
@@ -1,126 +0,0 @@
1−+++
2−title = "Scry Reference"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−Here are the scry endpoints of Ames. All of them take a `%x` `care` and require the `desk` in the path prefix be empty, so the general format is `.^([type] %ax /=//=/[some-path])`.
8−
9−## /protocol/version
10−
11−A scry with a `%x` `care` and a `path` of `/protocol/version` will return the current Ames protocol version as a `@`.
12−
13−#### Example
14−
15−```
16−> .^(@ %ax /=//=/protocol/version)
17−0
18−```
19−
20−## /peers
21−
22−A scry with a `%x` `care` and a `path` of `/peers` will return all ships that Ames is aware of. The type returned is a `(map ship ?(%alien %known))`, where `%known` means we have PKI data for them and `%alien` means we don't.
23−
24−#### Example
25−
26−```
27−> .^((map ship ?(%alien %known)) %ax /=//=/peers)
28−{[p=~wet q=%known] [p=~nes q=%known]}
29−```
30−
31−## /peers/[ship]
32−
33−A scry with a `%x` `care` and a `path` of `/peers/[ship]` where `[ship]` is a ship name like `~dopzod` will return everything Ames knows about that ship, or crash if the ship is unknown to Ames. The type returned is a [$ship-state](/docs/arvo/ames/data-types#ship-state).
34−
35−#### Example
36−
37−```
38−> .^(ship-state:ames %ax /=//=/peers/~nes)
39−[ %known
40− [ symmetric-key=0wEF.5-Mp4.ehBxk.a-ktl.CAUHq.~XNVq.AfPFk.TwBbj.rc7MS
41− life=1
42− public-key=0w9R.IG6Km.CQfuL.lP9Da.l~kh1.lOHzV.xactk.1ybiB.hekW~.VC2d0.DDRsU.h6GHl.PKmRX.p3u2-.vO4Hg.QTOlp.A4AI0.uGPVy
43− sponsor=~nes
44− ]
45− route=[~ [direct=%.y lane=[%.y p=~nes]]]
46− qos=[%dead last-contact=~2021.8.9..16.11.36..fdbc]
47− ossuary
48− [ next-bone=4
49− by-duct={[p=~[/gall/sys/way/~nes/hood /gall/use/hood/0w2.4d7EV/out/~nes/hood/helm/hi/~nes /dill //term/1] q=0]}
50− by-bone={[p=0 q=~[/gall/sys/way/~nes/hood /gall/use/hood/0w2.4d7EV/out/~nes/hood/helm/hi/~nes /dill //term/1]]}
51− ]
52− snd
53− { [ p=0
54− q
55− [ current=2
56− next=3
57− unsent-messages={}
58− unsent-fragments=~
59− queued-message-acks={}
60− packet-pump-state
61− [ next-wake=[~ ~2021.8.17..02.21.14..3d23]
62− live={[[message-num=2 fragment-num=0] [last-sent=~2021.8.17..02.19.14..3d23 retries=2.255 skips=0] num-fragments=1 fragment=0w2.QJ1qS.JzaQn.w7rMp.IzuTJ.7M7aP.-1s~1]}
63− metrics=[rto=~m2 rtt=~s1 rttvar=~s1 ssthresh=1 cwnd=1 num-live=1 counter=1]
64− ]
65− ]
66− ]
67− }
68− rcv={}
69− nax={}
70− heeds={~[/gall/sys/lag /dill //term/1]}
71−]
72−```
73−
74−## /peers/[ship]/forward-lane
75−
76−A scry with a `%x` `care` and a `path` of `/peers/[ship]/forward-lane` where `[ship]` is a ship name like `~dopzod` will return outbound routes to the given ship, or `~` if there are none. The type returned is a `(list lane:ames)`, see [$lane](/docs/arvo/ames/data-types#lane) for type details.
77−
78−#### Examples
79−
80−```
81−> .^((list lane:ames) %ax /=//=/peers/~nes/forward-lane)
82−~[[%.y p=~nes]]
83−```
84−
85−```
86−> .^((list lane:ames) %ax /=//=/peers/~nec/forward-lane)
87−~
88−```
89−
90−## /bones/[ship]
91−
92−A scry with a `%x` `care` and a `path` of `/bones/[ship]` where `[ship]` is a ship name like `~dopzod` will return inbound and outbound [$bone](/docs/arvo/ames/data-types#bone)s, which index message flows. If the ship in question is unknown to Ames, the scry will fail. The type returned is `[snd=(set bone) rcv=(set bone)]`.
93−
94−#### Example
95−
96−```
97−> .^([snd=(set bone) rcv=(set bone)] %ax /=//=/bones/~nes)
98−[snd={0} rcv={}]
99−```
100−
101−## /snd-bones/[ship]/[bone]
102−
103−A scry with a `%x` `care` and a `path` of `/snd-bones/[ship]/[bone]`, where `[ship]` is a ship name like `~dopzod` and `[bone]` is an outbound [$bone](/docs/arvo/ames/data-types#bone), will return message flow details for that `bone`. If the ship in question is unknown to Ames or the `bone` does not exist, the scry will fail. The type returned is a [$message-pump-state](/docs/arvo/ames/data-types#message-pump-state) wrapped in a `vase`.
104−
105−#### Example
106−
107−```
108−> !< message-pump-state:ames .^(vase %ax /=//=/snd-bones/~nes/0)
109−[ current=2
110− next=3
111− unsent-messages={}
112− unsent-fragments=~
113− queued-message-acks={}
114− packet-pump-state
115− [ next-wake=[~ ~2021.8.17..02.27.14..aaff]
116− live
117− { [ [message-num=2 fragment-num=0]
118− [last-sent=~2021.8.17..02.25.14..aaff retries=2.258 skips=0]
119− num-fragments=1
120− fragment=0w2.QJ1qS.JzaQn.w7rMp.IzuTJ.7M7aP.-1s~1
121− ]
122− }
123− metrics=[rto=~m2 rtt=~s1 rttvar=~s1 ssthresh=1 cwnd=1 num-live=1 counter=1]
124− ]
125−]
126−```
content/docs/arvo/ames/tasks.mddeleted−193
@@ -1,193 +0,0 @@
1−+++
2−title = "API Reference"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−In this document we describe the public interface for Ames. Namely, we describe
8−each `task` that Ames can be `%pass`ed, and which `gift`(s) Ames can `%give` in return.
9−
10−Some `task`s appear to have more than one arm associated to them, e.g. there are
11−four `+on-hear` arms. We denote this where it occurs, but always refer to the
12−`+on-hear:event-core` arm.
13−
14−Ames `task`s can be naturally divided into two categories: messaging tasks and
15−system/lifecycle tasks.
16−
17−## Messaging Tasks
18−
19−### `%hear`
20−
21−```hoon
22−[%hear =lane =blob]
23−```
24−
25−`%hear` handles raw packet receipt.
26−
27−This `task` only ever originates from Unix. It does the initial processing of a packet, namely by passing the raw packet information to `+decode-packet` which deserializes the packet and giving that data and the origin of the packet to `+on-hear-packet`, which begins the transformation of the packet into a new event in the form of a `+event-core`.
28−
29−There are multiple `+on-hear` arms in `ames.hoon`. Here we refer to `+on-hear:event-core`, as that is the one called by a `%hear` `task`. The other ones are used primarily for ack and nack processing, or receiving message fragments.
30−
31−`%hear` takes in a [$blob](/docs/arvo/ames/data-types#blob), which is essentially a large atom (around 1kB or less) that is the raw data of the message, and a [$lane](/docs/arvo/ames/data-types#lane), which is the origin of the message (typically an IP address).
32−
33−#### Returns
34−
35−`%hear` can trigger a number of possible returns. It can trigger the release of zero or more additional packets via `%send` `gift`s. It may also trigger a `%boon` or `%plea` `gift` (collectively referred to as a `%memo` within Ames) to a local vane in the case of a completed message.
36−
37−### `%heed`
38−
39−```hoon
40−[%heed =ship]
41−```
42−
43−A vane can pass Ames a `%heed` `task` to request Ames track a peer's responsiveness. If our `%boon`s to it start backing up locally, Ames will `give` a `%clog` back to the requesting vane containing the unresponsive peer's Urbit address.
44−
45−Stop tracking a peer by sending Ames a [%jilt](#jilt) `task`.
46−
47−The `ship` field specifies the peer to be tracked.
48−
49−#### Returns
50−
51−If the `ship` is indeed being unresponsive, as measured by backed up `%boon`s,
52−Ames will `give` a `%clog` `gift` to the requesting vane containing the
53−unresponsive peer's urbit address.
54−
55−### `%jilt`
56−
57−```hoon
58−[%jilt =ship]
59−```
60−
61−`%jilt` stops tracking a potentially unresponsive peer that was previously being
62−tracked as a result of the [%heed](#heed) `task`.
63−
64−There are two `+on-jilt` arms, this `task` utilizes `+on-hear:event-core`.
65−
66−The `ship` field specifies the peer we want to stop tracking.
67−
68−#### Returns
69−
70−This `task` returns no `gift`s.
71−
72−### `%plea`
73−
74−```hoon
75−[%plea =ship =plea:ames]
76−```
77−
78−`%plea` is the `task` used to instruct Ames to send a message. It extends the
79−`%pass`/`%give` semantics across the network. As such, it is the most
80−fundamental `task` in Ames and the primary reason for its existence.
81−
82−Ames also `pass`es a `%plea` `note` to another vane when it receives a message on a
83−"forward flow" from a peer, originally passed from one of the peer's vanes to the
84−peer's Ames.
85−
86−Ultimately `%plea` causes `%send` `gift`(s) to be sent to Unix, which tells
87−Unix to send packets. In terms of `%pass`/`%give` semantics, this is in
88−response to the `%born` `task`, which came along the Unix `duct`, rather than a
89−response to the `%plea`.
90−
91−A `%plea` `task` takes in the `ship` the `plea` is addressed to, and a [$plea](/docs/arvo/ames/data-types.md#plea).
92−
93−#### Returns
94−
95−This `task` returns no `gift`s.
96−
97−## System Tasks
98−
99−### `%born`
100−
101−```hoon
102−[%born ~]
103−```
104−
105−Each time you start your Urbit, the Arvo kernel calls the `%born` `task` for Ames.
106−
107−#### Returns
108−
109−In response to a `%born` `task`, Ames `%give`s Jael a `%turf` `gift`.
110−
111−The `duct` along which `%born` comes is Ames' only duct to Unix, so `%send`
112−`gift`s (which are instructions for Unix to send a packet) are also returned in
113−response to `%born`.
114−
115−### `%init`
116−
117−```hoon
118−[%init ~]
119−```
120−
121−`%init` is called a single time during the very first boot process, immediately
122−after the [larval stage](/docs/arvo/overview#larval-stage-core)
123−is completed. This initializes the vane. Jael is initialized first, followed by
124−other vanes such as Ames.
125−
126−In response to receiving the `%init` `task`, Ames subscribes to the information
127−contained by Jael.
128−
129−#### Returns
130−
131−```hoon
132−=~ (emit duct %pass /turf %j %turf ~)
133− (emit duct %pass /private-keys %j %private-keys ~)
134−```
135−
136−`%init` sends two moves that subscribe to `%turf` and `%private-keys` in Jael.
137−
138−### `%sift`
139−
140−```hoon
141−[%sift ships=(list ship)]
142−```
143−
144−This `task` filters debug output by ship. This `task` is used internally when the `|ames-sift` `hood` generator is run from the dojo.
145−
146−The `ships` field specifies the ships for which debug output is desired.
147−
148−#### Returns
149−
150−This `task` returns no `gift`s.
151−
152−### `%spew`
153−
154−```hoon
155−[%spew veb=(list verb)]
156−```
157−
158−Sets verbosity toggles on debug output. This `task` is used internally when the `|ames-verb` `hood` generator is run from the dojo.
159−
160−`%spew` takes in a `list` of [$verb](/docs/arvo/ames/data-types#verb), which are verbosity flags for Ames.
161−
162−`%spew` flips each toggle given in `veb`.
163−
164−#### Returns
165−
166−This `task` returns no `gift`s.
167−
168−### `%stir`
169−
170−```hoon
171−[%stir arg=@t]
172−```
173−
174−A `%stir` `task` starts timers for any flows that lack them.
175−
176−The `arg` field is unused.
177−
178−#### Returns
179−
180−This `task` returns no `gift`s.
181−
182−### `%vega`
183−
184−```hoon
185−[%vega ~]
186−```
187−
188−`%vega` is called whenever the kernel is updated. Ames currently does not do
189−anything in response to this.
190−
191−#### Returns
192−
193−This `task` returns no `gift`s.
content/docs/arvo/behn/_index.mddeleted−23
@@ -1,23 +0,0 @@
1−+++
2−title = "Behn"
3−weight = 20
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−## [Overview](/docs/arvo/behn/behn)
10−
11−An overview of Behn, Urbit's timer vane.
12−
13−## [API Reference](/docs/arvo/behn/tasks)
14−
15−The `task`s Behn takes and the `gift`s it returns.
16−
17−## [Scry Reference](/docs/arvo/behn/scry)
18−
19−The scry endpoints of Behn.
20−
21−## [Examples](/docs/arvo/behn/examples)
22−
23−Practical examples of using Behn's `task`s.
content/docs/arvo/behn/behn.mddeleted−19
@@ -1,19 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−+++
6−
7−Urbit's timer vane.
8−
9−Behn manages timers in a simple priority queue. Other vanes and applications ask Behn to set a timer to go off at the given time, and Behn produces effects that start the timers on Unix. When the timer goes off, Unix sends an event to Behn, which then notifies the original requester. We don't gurantee that a timer event will happen at exactly the time it was set for, or even that it'll be particularly close. A timer event is a request to not be woken until after the given time.
10−
11−Additional information about Behn is included in [Lesson 2.6 - Behn](/docs/hoon/hoon-school/behn) of the Hoon tutorial.
12−
13−## Sections
14−
15−[API Reference](/docs/arvo/behn/tasks) - The `task`s Behn takes and the `gift`s it returns.
16−
17−[Scry Reference](/docs/arvo/behn/scry) - The scry endpoints of Behn.
18−
19−[Examples](/docs/arvo/behn/examples) - Practical examples of using Behn's `task`s.
content/docs/arvo/behn/examples.mddeleted−95
@@ -1,95 +0,0 @@
1−+++
2−title = "Examples"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−Here are a couple of practical examples of using Behn's `%wait` and `%rest` `task`s.
8−
9−## %wait
10−
11−Here we'll look at setting a timer by passing Behn a `%wait` `task` and taking the `%wake` `gift` it returns when the timer fires.
12−
13−Below is a thread which will take a `@dr` as its argument and `%pass`es Behn a `%wait` `task` to fire `@dr` in the future. When the timer fires, it'll then take the `%wake` `gift` and print it to the terminal along with the time that has elapsed.
14−
15−`wait.hoon`
16−
17−```hoon
18−/- spider
19−/+ *strandio
20−=, strand=strand:spider
21−^- thread:spider
22−|= arg=vase
23−=/ m (strand ,vase)
24−^- form:m
25−=/ delay=@dr (need !<((unit @dr) arg))
26−;< t1=@da bind:m get-time
27−=/ =task:behn [%wait (add delay t1)]
28−=/ =card:agent:gall [%pass /timer %arvo %b task]
29−;< ~ bind:m (send-raw-card card)
30−;< res=(pair wire sign-arvo) bind:m take-sign-arvo
31−?> ?=([%timer ~] p.res)
32−?> ?=([%behn %wake *] q.res)
33−%- (slog ~[leaf+"Gift: {<+.q.res>}"])
34−?~ error.q.res
35− ;< t2=@da bind:m get-time
36− %- (slog ~[leaf+"Time elapsed: {<`@dr`(sub t2 t1)>}"])
37− (pure:m !>(~))
38−%- (slog u.error.q.res)
39−(pure:m !>(~))
40−```
41−
42−Save the thread to `/ted/wait.hoon` and `|commit %base`. Then we can try running the thread with a `@dr` of `~s2`:
43−
44−```
45−> -wait ~s2
46−Gift: [%wake error=~]
47−Time elapsed: ~s2..0154
48−```
49−
50−As you can see, the timer has fired successfully after `~s2` and Behn has given us a `%wake` `gift`.
51−
52−## %rest
53−
54−Here we'll look at cancelling a previously set timer by passing Behn a `%rest` `task`.
55−
56−Below is a variation on the [%wake](#wake) thread. It takes a `@dr` as its argument and sets a timer that far in the future, as before. However, it also sets a second timer twice the `@dr` in the future, and then cancels the first with a `%rest` `task`. If the `%rest` `task` succeeds in cancelling the first timer, the `%wake` `gift` will arrive after double the specified delay.
57−
58−`rest.hoon`
59−
60−```hoon
61−/- spider
62−/+ *strandio
63−=, strand=strand:spider
64−^- thread:spider
65−|= arg=vase
66−=/ m (strand ,vase)
67−^- form:m
68−=/ delay=@dr (need !<((unit @dr) arg))
69−;< t1=@da bind:m get-time
70−=/ timer1=@da (add t1 delay)
71−=/ timer2=@da (add t1 (mul delay 2))
72−;< ~ bind:m (send-raw-card [%pass /timer %arvo %b %wait timer1])
73−;< ~ bind:m (send-raw-card [%pass /timer %arvo %b %wait timer2])
74−;< ~ bind:m (send-raw-card [%pass /timer %arvo %b %rest timer1])
75−;< res=(pair wire sign-arvo) bind:m take-sign-arvo
76−?> ?=([%timer ~] p.res)
77−?> ?=([%behn %wake *] q.res)
78−%- (slog ~[leaf+"Gift: {<+.q.res>}"])
79−?~ error.q.res
80− ;< t2=@da bind:m get-time
81− %- (slog ~[leaf+"Time elapsed: {<`@dr`(sub t2 t1)>}"])
82− (pure:m !>(~))
83−%- (slog u.error.q.res)
84−(pure:m !>(~))
85−```
86−
87−Save the above thread to `/ted/rest.hoon`, and `|commit %base`. Let's try run it with an argument of `~s2`:
88−
89−```
90−> -rest ~s2
91−Gift: [%wake error=~]
92−Time elapsed: ~s4..00d4
93−```
94−
95−As you can see, the timer fired after four seconds, which means the two second timer was successfully cancelled by the `%rest` `task`.
content/docs/arvo/behn/scry.mddeleted−46
@@ -1,46 +0,0 @@
1−+++
2−title = "Scry Reference"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−Here are Behn's scry endpoints. There's only a few and they're mostly just useful for debugging. All of Behn's scries take a `%x` `care` and require the `desk` in the path prefix be empty, so the general format is `.^([type] %bx /=//=/[some-path])`.
8−
9−## /debug/timers
10−
11−A scry with a `%x` `care` and a `path` of `/debug/timers` will return the timestamp and `duct` of all timers which are currently set. The type returned is a `(list [@da duct])`.
12−
13−```
14−> .^((list [@da duct]) %bx /=//=/debug/timers)
15−~[
16− [~2021.8.9..16.16.30..9d49 ~[/ames/pump/~wet/0 /ames]]
17− [~2021.8.9..16.17.58..597d ~[/ames/pump/~nes/0 /ames]]
18−]
19−```
20−
21−## /timers
22−
23−A scry with a `%x` `care` and a `path` of `/timers` will return the timestamps of all timers currently set. The type returned is a `(list @da)`.
24−
25−```
26−> .^((list @da) %bx /=//=/timers)
27−~[~2021.8.9..16.17.02..9de6 ~2021.8.9..16.17.58..597d]
28−```
29−
30−## /timers/next
31−
32−A scry with a `%x` `care` and a `path` of `/timers/next` will return the timestamp of the timer set to fire next, or null if there's none. The type returned is a `(unit @da)`.
33−
34−```
35−> .^((unit @da) %bx /=//=/timers/next)
36−[~ ~2021.8.9..16.17.58..597d]
37−```
38−
39−## /timers/[da]
40−
41−A scry with a `%x` `care` and a `path` of `/timers/[da]` (where `[da]` is an absolute date) will return all timers which are scheduled to fire between now and the specified date (inclusive). The type returned is a `(list @da)`.
42−
43−```
44−> .^((list @da) %bx /=//=/timers/(scot %da (add now ~d1)))
45−~[~2021.8.9..16.17.58..597d ~2021.8.9..16.18.06..a24b]
46−```
content/docs/arvo/behn/tasks.mddeleted−155
@@ -1,155 +0,0 @@
1−+++
2−title = "API Reference"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−In this document we describe the public interface for Behn. Namely, we describe each `task` that Behn can be `pass`ed, and which `gift`(s) Behn can `give` in return.
8−
9−Most of Behn's `task`s are only used by the kernel or runtime. The two `task`s you're likely to use from userspace are [%wait](#wait) for setting a timer and [%rest](#rest) for cancelling a timer.
10−
11−## `%born`
12−
13−```hoon
14−[%born ~]
15−```
16−
17−Each time you start your urbit, the Arvo kernel calls the `%born` task for Behn. When called, Behn gets the current time from Unix and updates its list of timers accordingly.
18−
19−You would not use this `task` from userspace.
20−
21−#### Returns
22−
23−Behn does not return any `gift` in response to a `%born` `task`.
24−
25−## `%rest`
26−
27−```hoon
28−[%rest p=@da]
29−```
30−
31−Cancel a timer.
32−
33−Behn takes in a `@da` and cancels the timer at that time if it exists, then adjusts the next wakeup call from Unix if necessary.
34−
35−#### Returns
36−
37−Behn does not return any `gift` in response to a `%rest` `task`.
38−
39−#### Example
40−
41−See the [%rest](/docs/arvo/behn/examples#rest) section of the Examples document.
42−
43−## `%drip`
44−
45−```hoon
46−[%drip p=vase]
47−```
48−
49−`%drip` allows one to delay a `gift` until a timer set for `now` fires.
50−
51−A Client `%slip`s Behn a `%drip` task wrapping a `gift` to be `give`n to a Target. This launches a sequence of `move`s as written here:
52−
53−```
54−Client -- %slip %drip --> Behn -- %pass %wait --> Behn -- %give %wake --> Behn -- %give %meta --> Target
55−```
56−
57−Here the `%meta` `move` is a wrapper for the `%gift` inside of the initial `%drip` wrapper.
58−
59−`%drip` only handles `gift`s, and can only schedule `gift`s for as soon as possible after the prescribed timer fires.
60−
61−`%drip` takes in a `%give` `move` in a `vase`.
62−
63−A `%drip` `task` is not likely to be used from userspace.
64−
65−#### Returns
66−
67−In response to a `%drip` `task`, Behn will `%pass` a `%wait` to itself, which then triggers a `%wake` `gift` to itself, which then causes Behn to `%give` a `%meta` `gift` containing the `gift` originally `%give`n to Behn when `%drip` was first called. That makes Behn its own client for `%drip`.
68−
69−#### Example
70−
71−Say an app (the Target) is subscribed to updates from Clay (the Client). If Clay `%give`s updates to the app directly and the app crashes, this may cause Clay to crash as well. If instead Clay `%pass`es Behn a `%drip` `task` wrapping the update `gift`, Behn will set a timer for `now` that, when fired, will cause the update `gift` to be given. If it causes a crash then it will have been in response to the `%drip` move, thereby isolating Clay from the crash. Thus `%drip` acts as a sort of buffer against cascading sequences of crashes.
72−
73−## `%huck`
74−
75−```hoon
76−[%huck syn=sign-arvo]
77−```
78−
79−Immediately gives back a `sign-arvo`.
80−
81−You would not use this `task` from userspace.
82−
83−#### Returns
84−
85−Behn returns the input `sign-arvo` as a `%heck` `gift`:
86−
87−```hoon
88−[%heck syn=sign-arvo]
89−```
90−
91−## `%trim`
92−
93−```hoon
94−[%trim p=@ud]
95−```
96−
97−This `task` is sent by the interpreter in order to free up memory. Behn does not do anything with this `task`, since it is not a good idea to forget your timers.
98−
99−You would not use this `task` from userspace.
100−
101−#### Returns
102−
103−Behn does not return any `gift` in response to a `%trim` `task`.
104−
105−## `%vega`
106−
107−```hoon
108−[%vega ~]
109−```
110−
111−This `task` informs the vane that the kernel has been upgraded. Behn does not do anything in response to this.
112−
113−You would not use this `task` from userspace.
114−
115−#### Returns
116−
117−Behn does not return any `gift` in response to a `%vega` `task`.
118−
119−## `%wait`
120−
121−```hoon
122−[%wait p=@da]
123−```
124−
125−Set timer.
126−
127−This `task` sets a timer to fire at the `@da` specified in `p`.
128−
129−#### Returns
130−
131−Behn returns a `%wake` `gift` in response to a `%wait` `task`, once the timer has fired. A `%wake` `gift` looks like:
132−
133−```hoon
134−[%wake error=(unit tang)]
135−```
136−
137−The `error` `unit` will be `~` if successful, or contain a traceback in the `tang` if the timer failed for some reason.
138−
139−#### Example
140−
141−See the [%wait](/docs/arvo/behn/tasks#wait) section of the Examples document.
142−
143−## `%wake`
144−
145−```hoon
146−[%wake ~]
147−```
148−
149−This `task` is sent by the kernel when the Unix timer tells the kernel that it is time for Behn to wake up. This is often caused by a `%doze` `gift` that Behn originally sent to the kernel that is then forwarded to Unix, which is where the real timekeeping occurs.
150−
151−You would not use this `task` from userspace.
152−
153−#### Returns
154−
155−In response to receiving this `task`, Behn may `%give` a `%doze` `gift` containing the `@da` of the next timer to elapse. Behn may also `%give` a `%wake` `gift` to itself.
content/docs/arvo/clay/_index.mddeleted−36
@@ -1,36 +0,0 @@
1−+++
2−title = "Clay"
3−weight = 30
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−[Overview](/docs/arvo/clay/clay)
10−
11−High-level overview of Clay.
12−
13−[Architecture](/docs/arvo/clay/architecture)
14−
15−A conceptual overview of how Clay was designed.
16−
17−[Using Clay](/docs/arvo/clay/using)
18−
19−A quick overview of how the most common tasks involving Clay are performed:
20−reading and subscribing, syncing to Unix, and merging.
21−
22−[Data Types](/docs/arvo/clay/data-types)
23−
24−Explanations of the many data types found throughout Clay.
25−
26−[Scry Reference](/docs/arvo/clay/scry)
27−
28−Reference for Clay's various scry endpoints.
29−
30−[API Reference](/docs/arvo/clay/tasks)
31−
32−Details of the various `task`s you can use to interact with Clay.
33−
34−[Examples](/docs/arvo/clay/examples)
35−
36−Example usage of the various Clay `task`s.
content/docs/arvo/clay/architecture.mddeleted−177
@@ -1,177 +0,0 @@
1−+++
2−title = "Architecture"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−Clay is the primary filesystem for the [Arvo](/docs/arvo/overview)
8−operating system, which is the [core](/docs/glossary/core/) of an
9−urbit. The architecture of Clay is intrinsically connected with Arvo,
10−but for this section we assume no knowledge of either Arvo or Urbit.
11−We will point out only those features of Arvo that are necessary for
12−an understanding of Clay, and we will do so only when they arise.
13−
14−The first relevant feature of Arvo is that it is a deterministic
15−system where input and output are defined as a series of events and
16−effects. The state of Arvo is simply a pure function of its event log.
17−None of the effects from an event are emitted until the event is
18−entered in the log and persisted, either to disk or another trusted
19−source of persistence, such as a Kafka cluster. Consequently, Arvo is
20−a single-level store: everything in its state is persistent.
21−
22−In a more traditional OS, everything in RAM can be erased at any
23−time by power failure, and is always erased on reboot. Thus, a
24−primary purpose of a filesystem is to ensure files persist across
25−power failures and reboots. In Arvo, both power failures and
26−reboots are special cases of suspending computation, which is
27−done safely since our event log is already persistent. Therefore,
28−Clay is not needed in Arvo for persistence. Why, then, do we have a
29−filesystem? There are two answers to this question.
30−
31−First, Clay provides a filesystem tree, which is a convenient
32−user interface for some applications. Unix has the useful concept
33−of virtual filesystems, which are used for everything from direct
34−access to devices, to random number generators, to the /proc
35−tree. It is easy and intuitive to read from and write to a
36−filesystem tree.
37−
38−Second, Clay has a distributed revision-control system baked into
39−it. Traditional filesystems are not revision controlled, so
40−userspace software -- such as git -- is written on top of them to
41−do so. Clay natively provides the same functionality as modern
42−DVCSes, and more.
43−
44−Clay has two other unique properties that we'll cover later on:
45−it supports typed data and is referentially transparent.
46−
47−### Revision Control
48−
49−Every urbit has one or more desks, which are independently
50−revision-controlled branches. Each desk contains its own `mark`
51−definitions, apps, and so forth.
52−
53−Traditionally, an Urbit ship has at least a `%base` desk, and usually
54−`%garden` and `%landscape` desks. The `%base` desk has the kernel and
55−base system software. The `%garden` desk has software pertaining to
56−the home screen. The `%landscape` desk contains software for the
57−Groups app. The `%base` desk is a fork of the `%base` desk of
58−whichever ship you download system updates from - typically your
59−sponsor, but theoretically may be any ship.
60−
61−A desk is a series of numbered commits, the most recent of which
62−represents the current state of the desk. A commit is composed of
63−(1) an absolute time when it was created, (2) a list of zero or
64−more parents, and (3) a map from paths to data.
65−
66−Most commits have exactly one parent, but the initial commit on a
67−desk may have zero parents, and merge commits have more than one
68−parent.
69−
70−The non-metadata is stored as a `map` of `path`s to data. It's
71−worth noting that no constraints are put on this `map`, so, for
72−example, both `/a/b` and `/a/b/c` could have data. This is impossible
73−in a traditional Unix filesystem since it means that `/a/b` is both
74−a file and a directory. Conventionally, the final element in the
75−path is its `mark` -- much like a filename extension in Unix. Thus,
76−`/doc/readme.md` in Unix is stored as `/doc/readme/md` in urbit.
77−
78−The data is not stored directly in the `map`; rather, a hash of the
79−data is stored, and we maintain a master blob store. Thus, if the
80−same data is referred to in multiple commits (as, for example,
81−when a file doesn't change between commits), only the hash is
82−duplicated.
83−
84−In the master blob store, we either store the data directly, or
85−else we store a diff against another blob. The hash is dependent
86−only on the data within and not on whether or not it's stored
87−directly, so we may on occasion rearrange the contents of the
88−blob store for performance reasons.
89−
90−Recall that a desk is a series of numbered commits. Not every
91−commit in a desk must be numbered. For example, if the `%base` desk
92−has had 50 commits since `%foo` was forked from it, then a merge
93−from `%base` to `%foo` will only add a single revision number,
94−although the full commit history will be accessible by traversing
95−the parentage of the individual commits.
96−
97−We do guarantee that the first commit is numbered 1, commits are
98−numbered consecutively after that (i.e. there are no "holes"),
99−the topmost commit is always numbered, and every numbered commit
100−is an ancestor of every later numbered commit.
101−
102−There are three ways to refer to particular commits in the
103−revision history. Firstly, one can use the revision number.
104−Secondly, one can use any absolute time between the one numbered
105−commit and the next (inclusive of the first, exclusive of the
106−second). Thirdly, every desk has a `map` of labels to revision
107−numbers. These labels may be used to refer to specific commits.
108−
109−Additionally, Clay is a global filesystem, so data on other urbits
110−is easily accessible the same way as data on our local urbit. In
111−general, the path to a particular revision of a desk is
112−`/~urbit-name/desk-name/revision`. Thus, to get `/try/readme/md`
113−from revision 5 of the `%base` desk on `~sampel-sipnym`, we refer to
114−`/~sampel-sipnym/base/5/try/readme/md`. Clay's namespace is thus
115−global and referentially transparent.
116−
117−### A Typed Filesystem
118−
119−Since Clay is a general filesystem for storing data of arbitrary
120−types, in order to revision control correctly it needs to be
121−aware of types all the way through. Traditional revision control
122−does an excellent job of handling source code, so for source code
123−we act very similar to traditional revision control. The
124−challenge is to handle other data similarly well.
125−
126−For example, modern VCSs generally support "binary files", which
127−are files for which the standard textual diffing, patching, and
128−merging algorithms are not helpful. A "diff" of two binary files
129−is just a pair of the files, "patching" this diff is just
130−replacing the old file with the new one, and "merging"
131−non-identical diffs is always a conflict, which can't even be
132−helpfully annotated. Without knowing anything about the structure
133−of a blob of data, this is the best we can do.
134−
135−Often, though, "binary" files have some internal structure, and
136−it is possible to create diff, patch, and merge algorithms that
137−take advantage of this structure. An image may be the result of a
138−base image with some set of operations applied. With algorithms
139−aware of this set of operations, not only can revision control
140−software save space by not having to save every revision of the
141−image individually, these transformations can be made on parallel
142−branches and merged at will.
143−
144−Suppose Alice is tasked with touching up a picture, improving the
145−color balance, adjusting the contrast, and so forth, while Bob
146−has the job of cropping the picture to fit where it's needed and
147−adding textual overlay. Without type-aware revision control,
148−these changes must be made serially, requiring Alice and Bob to
149−explicitly coordinate their efforts. With type-aware revision
150−control, these operations may be performed in parallel, and then
151−the two changesets can be merged programmatically.
152−
153−Of course, even some kinds of text files may be better served by
154−diff, patch, and merge algorithms aware of the structure of the
155−files. Consider a file containing a pretty-printed JSON object.
156−Small changes in the JSON object may result in rather significant
157−changes in how the object is pretty-printed (for example, by
158−addding an indentation level, splitting a single line into
159−multiple lines).
160−
161−A text file wrapped at 80 columns also reacts suboptimally with
162−unadorned Hunt-McIlroy diffs. A single word inserted in a
163−paragraph may push the final word or two of the line onto the
164−next line, and the entire rest of the paragraph may be flagged as
165−a change. Two diffs consisting of a single added word to
166−different sentences may be flagged as a conflict. In general,
167−prose should be diffed by sentence, not by line.
168−
169−As far as we are aware, Clay is the first generalized,
170−type-aware revision control system. We'll go into the workings
171−of this system in some detail.
172−
173−### Marks
174−
175−Central to a typed filesystem is the idea of file types. In Clay, we
176−call these `mark`s. See the [Marks](/docs/arvo/clay/marks/marks)
177−section for more details.
content/docs/arvo/clay/clay.mddeleted−61
@@ -1,61 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/clay/"]
6−+++
7−
8−Our filesystem.
9−
10−`%clay` is version-controlled, referentially-transparent, and global.
11−While this filesystem is stored in `%clay`, it is mirrored to Unix for
12−convenience. Unix tells `%clay`s whenever a file changes in the Unix
13−copy of the filesystem so that the change may be applied. `%clay` tells
14−unix whenever an app or vane changes the filesystem so that the change
15−can be effected in Unix. Apps and vanes may use `%clay` to write to the
16−filesystem, query it, and subscribe to changes in it. Ford and gall use
17−`%clay` to serve up apps and web pages.
18−
19−`%clay` includes three components. First is the filesystem/version
20−control algorithms, which are mostly defined in `++ze` and `++zu` in
21−zuse. Second is the write, query, and subscription logic. Finally, there
22−is the logic for communicating requests to, and receiving requests from,
23−foreign ships.
24−
25−### User documentation
26−
27−[Filesystem](/using/os/filesystem)
28−
29−How to interact with the Clay filesystem via Dojo. This includes basics such as
30−mounting to Unix, changing directory, merging, and listing files.
31−
32−### Developer Documentation
33−
34−[Architecture](/docs/arvo/clay/architecture)
35−
36−A conceptual overview of how Clay was designed.
37−
38−[Using Clay](/docs/arvo/clay/using)
39−
40−A quick overview of how the most common tasks involving Clay are performed:
41−reading and subscribing, syncing to Unix, and merging.
42−
43−[Data Types](/docs/arvo/clay/data-types)
44−
45−Explanations of the many data types found throughout Clay.
46−
47−[Scry Reference](/docs/arvo/clay/scry)
48−
49−Reference for Clay's various scry endpoints.
50−
51−[API Reference](/docs/arvo/clay/tasks)
52−
53−Details of the various `task`s you can use to interact with Clay.
54−
55−[Examples](/docs/arvo/clay/examples)
56−
57−Example usage of the various Clay `task`s.
58−
59−[Marks](/docs/arvo/clay/marks/marks)
60−
61−Details of `mark`s as well as a guide to writing them and their usage.
content/docs/arvo/clay/data-types.mddeleted−681
@@ -1,681 +0,0 @@
1−+++
2−title = "Data Types"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−This section will be reference documentation for the data types used by our
8−filesystem.
9−
10−As a general guide, we recommend reading and attempting to understand the data
11−structures used in any Hoon code before you try to read the code itself.
12−Although complete understanding of the data structures is impossible without
13−seeing them used in the code, an 80% understanding greatly clarifies the code.
14−As another general guide, when reading Hoon, it rarely pays off to understand
15−every line of code when it appears. Try to get the gist of it, and then move on.
16−The next time you come back to it, it'll likely make a lot more sense.
17−
18−### Data Models
19−
20−As you're reading through this section, remember you can always come
21−back to this when you run into these types later on. You're not going to
22−remember everything the first time through, but it is worth reading, or
23−at least skimming, this so that you get a rough idea of how our state is
24−organized.
25−
26−The types that are certainly worth reading are `++raft`, `++room`,
27−`++dome:clay`, `++ankh:clay`, `++rung:clay`, `++rang:clay`, `++blob:clay`,
28−`++yaki:clay`, and `++nori:clay` (possibly in that order). All in all, though,
29−this section isn't too long, so many readers may wish to quickly read through
30−all of it. If you get bored, though, just skip to the next section. You can
31−always come back when you need to.
32−
33−### `$raft`, formal state
34−
35−```hoon
36−+$ raft :: filesystem
37− $: rom=room :: domestic
38− hoy=(map ship rung) :: foreign
39− ran=rang :: hashes
40− mon=(map term beam) :: mount points
41− hez=(unit duct) :: sync duct
42− cez=(map @ta crew) :: permission groups
43− pud=(unit [=desk =yoki]) :: pending update
44− == ::
45−```
46−
47−This is the state of the vane. Anything that must be remembered between
48−calls to Clay is stored in this state.
49−
50−`ran` is the store of all commits and deltas, keyed by hash. The is
51−where all the "real" data we know is stored; the rest is "just
52−bookkeeping".
53−
54−`rom` is the state for all local desks. It consists of a `duct` to
55−[Dill](/docs/arvo/dill/dill) and a collection of `desk`s.
56−
57−`hoy` is the state for all foreign desks.
58−
59−`ran` is the global, hash-addressed object store. It has maps of commit hashes
60−to commits and content hashes to content.
61−
62−`mon` is a collection of Unix mount points. `term` is the mount point (relative
63−to th pier) and `beam` is a domestic Clay directory.
64−
65−`hez` is the duct used to sync with Unix.
66−
67−`cez` is a collection of named permission groups.
68−
69−`pud` is an update that's waiting on a kernel upgrade.
70−
71−#### `$room`, filesystem per domestic ship
72−
73−```hoon
74−+$ room :: fs per ship
75− $: hun=duct :: terminal duct
76− dos=(map desk dojo) :: native desk
77− == ::
78−```
79−
80−This is the representation of the filesystem of a ship on our pier.
81−
82−`hun` is the duct we use to send messages to [Dill](/docs/arvo/dill/dill) to
83−display notifications of filesystem changes. Only `%note` `%gift`s should be
84−produced along this `duct`. This is set by the `%init` `move`.
85−
86−`dos` is a well-known operating system released in 1981. It is also the
87−set of `desk`s on this ship, mapped to their `desk` state.
88−
89−#### `$desk`, filesystem branch
90−
91−```hoon
92−+$ desk @tas
93−```
94−
95−This is the name of a branch of the filesystem. The default `desk`s are `%base`, `%garden`, `%landscape`, `%webterm` and `%bitcoin`. Desks have
96−independent histories and states, and they may be
97−[merged](/docs/arvo/clay/using#merging) into each other.
98−
99−### `$dojo`, domestic desk state
100−
101−```hoon
102−+$ dojo
103− $: qyx=cult :: subscribers
104− dom=dome :: desk state
105− per=regs :: read perms per path
106− pew=regs :: write perms per path
107− ==
108−```
109−
110−This is the all the data that is specific to a particular `desk` on a domestic
111−ship. `qyx` is the set of subscribers to this `desk`, and `dom` is the data in
112−the `desk`. `regs` are `(map path rule)`, and so `per` is a `map` of read
113−permissions by `path` and `pew` is a `map` of write permissions by `path`.
114−
115−#### `$cult`, subscriptions
116−
117−```hoon
118−+$ cult (jug wove duct)
119−```
120−
121−`cult`s keep track of subscribers. `wove`s are associated to requests, and each
122−`wove` is mapped to a set of `duct`s associated to subscribers who should be
123−notified when the request is filled/updated.
124−
125−#### `$rave:clay`, general subscription request
126−
127−```hoon
128− +$ rave :: general request
129− $% [%sing =mood] :: single request
130− [%next =mood] :: await next version
131− [%mult =mool] :: next version of any
132− [%many track=? =moat] :: track range
133− == ::
134−```
135−
136−This represents a subscription request for a `desk`.
137−
138−A `%sing` request asks for data at single revision.
139−
140−A `%next` request asks to be notified the next time there’s a change to the
141−specified file.
142−
143−A `%mult` request asks to be notified the next time there's a change to a
144−specified set of files.
145−
146−A `%many` request asks to be notified on every change in a `desk` for a range of changes (including into the future).
147−
148−### `$rove`, stored general subscription request
149−
150−```hoon
151− +$ rove :: stored request
152− $% [%sing =mood] :: single request
153− [%next =mood aeon=(unit aeon) =cach] :: next version of one
154− $: %mult :: next version of any
155− =mool :: original request
156− aeon=(unit aeon) :: checking for change
157− old-cach=(map [=care =path] cach) :: old version
158− new-cach=(map [=care =path] cach) :: new version
159− == ::
160− [%many track=? =moat lobes=(map path lobe)] :: change range
161− == ::
162−```
163−
164−Like a `rave` but with provisions to store current versions for `%next` and `%many`.
165−Generally used when we store a request in our state somewhere. This is so that
166−we can determine whether new versions actually affect the path we're subscribed to.
167−
168−#### `$mood:clay`, single subscription request
169−
170−```hoon
171− +$ mood [=care =case =path] :: request in desk
172−```
173−
174−This represents a request for data related to the state of the `desk` at a
175−particular commit, specfied by `case`. `care` specifies what kind of information
176−is desired, and `path` specifies the path we are requesting.
177−
178−#### `$moat:clay`, range subscription request
179−
180−```hoon
181− +$ moat [from=case to=case =path] :: change range
182−```
183−
184−This represents a request for all changes between `from` and `to` on `path`. You
185−will be notified when a change is made to the node referenced by the `path` or to
186−any of its children.
187−
188−### `$care:clay`, Clay submode
189−
190−```hoon
191− +$ care ?(%a %b %c %d %e %f %p %r %s %t %u %v %w %x %y %z) :: clay submode
192−```
193−
194−This specifies what type of information is requested in a subscription
195−or a scry.
196−
197−`%a` build a Hoon file at a `path`.
198−
199−`%b` build a dynamically typed `mark` by name (a `$dais` mark-interface core).
200−
201−`%c` build a dynamically typed `mark` conversion gate (a `$tube`) by "from" and
202−"to" `mark` names.
203−
204−`%d` returns a `(set desk)` of the `desk`s that exist on your ship.
205−
206−`%e` builds a statically typed `mark` by name (a `$nave` mark-interface core).
207−
208−`%f` builds a statically typed mark converstion gate.
209−
210−`%p` produces the permissions for a directory, returned as a `[dict:clay dict:clay]`.
211−
212−`%r` requests the file in the same fashion as `%x`, but wraps the result in a `vase`.
213−
214−`%s` has miscellaneous debug endpoints.
215−
216−`%t` produces a `(list path)` of descendent `path`s for a directory within a `yaki`.
217−
218−`%u` produces a `?` depending on whether or not the specified file exists. It
219−does not check any of its children.
220−
221−`%v` requests the entire `dome` for a specified `desk` at a particular `aeon`.
222−When used on a foreign `desk`, this get us up-to-date to the requested version.
223−
224−`%w` requests the revision number and date of the specified path, returned as a `cass:clay`.
225−
226−`%x` requests the file at a specified path at the specified commit, returned as
227−an `@`. If there is no node at that path or if the node has no contents (that
228−is, if `fil:ankh` is null), then this crashes.
229−
230−`%y` requests an `arch` of the specfied commit at the specified path. It will
231−return the bunt of an `arch` if the file or directory is not found.
232−
233−`%z` requests a recursive hash of a node and all its children, returned as a `@uxI`.
234−
235−#### `$ankh`, filesystem node
236−
237−```hoon
238−+$ ankh :: expanded node
239− $~ [~ ~]
240− $: fil=(unit [p=lobe q=cage]) :: file
241− dir=(map @ta ankh) :: folders
242− == ::
243−```
244−
245−This is a recursive filesystem node type that can describe a whole tree of
246−folders and files, with subtrees organized by path prefix. In Earth filesystems,
247−a node is a file xor a directory. On Mars, we're inclusive, so a node is a file
248−ior a directory.
249−
250−`fil` is the contents of this file, if any. `p.fil` is a hash of the
251−contents while `q.fil` is the data itself.
252−
253−`dir` is the set of children of this node. In the case of a pure file,
254−this is empty. The keys are the names of the children and the values
255−are, recursively, the nodes themselves.
256−
257−### `$arch`, shallow filesystem node
258−
259−```hoon
260−+$ arch (axil @uvI)
261−++ axil
262− |$ [item]
263− [fil=(unit item) dir=(map @ta ~)]
264−```
265−
266−An `arch` is a lightweight version of an `ankh` that only contains the hash
267−of the associated file and a `map` of child directories, but not the children of
268−those directories.
269−
270−The child directories are given by a `map` to null rather than a `set` so that the
271−ordering of the `map` will be the same as it is for an `axal`, allowing
272−efficient conversion for when the heavier node is needed.
273−
274−```hoon
275−++ axal
276− |$ [item]
277− [fil=(unit item) dir=(map @ta $)]
278−```
279−
280−#### `$case`, specifying a commit
281−
282−```hoon
283−+$ case
284− $% :: %da: date
285− :: %tas: label
286− :: %ud: sequence
287− ::
288− [%da p=@da]
289− [%tas p=@tas]
290− [%ud p=@ud]
291− ==
292−```
293−
294−A commit can be referred to in three ways: `%da` refers to the commit
295−that was at the head on date `p`, `%tas` refers to the commit labeled
296−`p`, and `%ud` refers to the commit numbered `p`. Note that since these
297−all can be reduced down to a `%ud`, only numbered commits may be
298−referenced with a `++case:clay`.
299−
300−#### `$dome`, desk data
301−
302−```hoon
303−+$ dome
304− $: ank=ankh :: state
305− let=aeon :: top id
306− hit=(map aeon tako) :: versions by id
307− lab=(map @tas aeon) :: labels
308− mim=(map path mime) :: mime cache
309− fod=ford-cache :: ford cache
310− fer=(unit reef-cache) :: reef cache
311− == ::
312−```
313−
314−A `dome` is the state of a `desk` and associated data.
315−
316−`ank` is the current state of the desk. Thus, it is the state of the
317−filesystem at revison `let`. The head of a `desk` is always a numbered
318−commit.
319−
320−`let` is the number of the most recently numbered commit. This is also
321−the total number of numbered commits.
322−
323−`hit` is a map of numerical ids to commit hashes. These hashes are mapped into
324−their associated commits in `hut.rang` in the `raft` of Clay. In general, the
325−keys of this map are exactly the numbers from 1 to `let`, with no gaps. Of
326−course, when there are no numbered commits, `let` is 0, so `hit` is null.
327−Additionally, each of the commits is an ancestor of every commit numbered
328−greater than this one. Thus, each is a descendant of every commit numbered less
329−than this one. Since it is true that the date in each commit (`t:yaki`) is no
330−earlier than that of each of its parents, the numbered commits are totally
331−ordered in the same way by both pedigree and date. Of course, not every commit
332−is numbered. If that sounds too complicated to you, don't worry about it. It
333−basically behaves exactly as you would expect.
334−
335−`lab` is a map of textual labels to numbered commits. Note that labels
336−can only be applied to numbered commits. Labels must be unique across a
337−desk.
338−
339−`mim` is a cache of the content in the directories that are mounted to Unix.
340−
341−`fod` is the Ford cache, which keeps a cache of the results of builds performed
342−at this `desk`'s current revision, including a full transitive closure of
343−dependencies for each completed build.
344−
345−`fer` is the system file cache, which consists of `vase`s for `hoon.hoon`,
346−`arvo.hoon`, `lull.hoon`, and `zuse.hoon`.
347−
348−#### `++rung`, filesystem per neighbor ship
349−
350−```hoon
351−+$ rung
352− $: rus=(map desk rede) :: neighbor desks
353− ==
354−```
355−
356−This is the filesystem of a neighbor ship. The keys to this `map` are all
357−the `desk`s we know about on their ship.
358−
359−#### `++rede`, generic desk state
360−
361−```hoon
362− ++ rede :: universal project
363− $: lim=@da :: complete to
364− qyx=cult :: subscribers
365− ref=(unit rind) :: outgoing requests
366− dom=dome :: revision state
367− == ::
368−+$ rede :: universal project
369− $: lim=@da :: complete to
370− ref=(unit rind) :: outgoing requests
371− qyx=cult :: subscribers
372− dom=dome :: revision state
373− per=regs :: read perms per path
374− pew=regs :: write perms per path
375− == ::
376−```
377−
378−This is our knowledge of the state of a desk, either foreign or
379−domestic.
380−
381−`lim` is the most recent `@da` for which we're confident we have all the
382−information for. For local `desk`s, this is always `now`. For foriegn `desk`s,
383−this is the last time we got a full update from the foreign ship.
384−
385−`ref` is the request manager for the desk. For domestic `desk`s, this is
386−null since we handle requests ourselves. For foreign `desk`s, this keeps track
387−of all pending foriegn requests plus a cache of the responses to previous requests.
388−
389−`qyx` is the `set` of subscriptions to this desk, with listening `duct`s. These
390−subscriptions exist only until they've been filled. For domestic `desk`s, this
391−is simply `qyx:dojo` - all subscribers to the `desk`. For foreign `desk`s this
392−is all the subscribers from our ship to the foreign `desk`.
393−
394−`dom` is the data in the `desk`.
395−
396−`regs` are `(map path rule)`, and so `per` is a `map` of read permissions by
397−`path` and `pew` is a `map` of write permissions by `path`.
398−
399−#### `$rind`, foreign request manager
400−
401−```hoon
402−+$ rind :: request manager
403− $: nix=@ud :: request index
404− bom=(map @ud update-state) :: outstanding
405− fod=(map duct @ud) :: current requests
406− haw=(map mood (unit cage)) :: simple cache
407− == ::
408−```
409−
410−This is the request manager for a foreign `desk`. When we send a request to a
411−foreign ship, we keep track of it in here.
412−
413−`nix` is one more than the index of the most recent request. Thus, it is the
414−next available request number.
415−
416−`bom` is the set of outstanding requests. The keys of this `map` are some subset
417−of the numbers between 0 and one less than `nix`. The members of the `map` are
418−exactly those requests that have not yet been fully satisfied.
419−
420−`fod` is the same set as `bom`, but from a different perspective. In particular,
421−the values of `fod` are the same as the keys of `bom`, and the `duct` of the
422−values of `bom` are the same as the keys of `fod`. Thus, we can map `duct`s to
423−their associated request number and `update-state`, and we can map request
424−numbers to their associated `duct`.
425−
426−`haw` is a map from `%sing` requests to their values. This acts as a cache for
427−requests that have already been filled.
428−
429−#### `$update-state`, status of outstanding foreign request
430−
431−```hoon
432−+$ update-state
433− $: =duct
434− =rave
435− have=(map lobe blob)
436− need=(list lobe)
437− nako=(qeu (unit nako))
438− busy=_|
439− ==
440−```
441−
442−An `update-state` is used to represent the status of an outstanding request to a
443−foreign `desk`.
444−
445−`duct` and `rave` are the `duct` along which the request was made and the
446−request itself.
447−
448−`have` is a map of hashes thus far acquired in the request to the data
449−associated with those hashes.
450−
451−`need` is a list of hashes yet to be acquired.
452−
453−`nako` is a queue of data yet to be validated.
454−
455−`busy` tracks whether or not the request is currently being fulfilled.
456−
457−#### `$rang:clay`, data repository
458−
459−```hoon
460− +$ rang :: repository
461− $: hut=(map tako yaki) :: changes
462− lat=(map lobe blob) :: data
463− == ::
464−```
465−
466−This is a data repository keyed by hash. Thus, this is where the "real" data
467−is stored, but it is only meaningful if we know the hash of what we're
468−looking for.
469−
470−`hut` is a `map` from commit hashes (`tako`s) to commits (`yaki`s). We often get
471−the hashes from `hit:dome`, which keys them by numerical id. Not every commit
472−has an numerical id.
473−
474−`lat` is a `map` from content hashes (`lobe`s) to the actual content (`blob`s).
475−We often get the hashes from a `yaki`, which references this `map` to get the
476−data. There is no `blob` in `yaki:clay`. They are only accessible through
477−`lat`.
478−
479−#### `$tako:clay`, commit reference
480−
481−```hoon
482− +$ tako @ :: yaki ref
483−```
484−
485−This is a hash of a `yaki:clay`, a commit. These are most notably used as the
486−keys in `hut:rang:clay`, where they are associated with the actual `yaki:clay`,
487−and as the values in `hit:dome:clay`, where sequential numerical ids are
488−associated with these.
489−
490−#### `$yaki:clay`, commit
491−
492−```hoon
493− +$ yaki :: commit
494− $: p=(list tako) :: parents
495− q=(map path lobe) :: namespace
496− r=tako :: self-reference
497− t=@da :: date
498− == ::
499−```
500−
501−This is a single commit.
502−
503−`p` is a `list` of the hashes of the parents of this commit. In most
504−cases, this will be a single commit, but in a merge there may be more
505−parents. In theory, there may be an arbitrary number of parents, but in
506−practice merges have exactly two parents. This may change in the future.
507−For commit 1, there is no parent.
508−
509−`q` is a `map` of the `path`s on a desk to the content hashes at that location.
510−If you understand what a `lobe:clay` and a `blob:clay` is, then the type
511−signature here tells the whole story.
512−
513−`r` is the hash associated with this commit.
514−
515−`t` is the date at which this commit was made.
516−
517−#### `$lobe:clay`, data reference
518−
519−```hoon
520− +$ lobe @uvI :: blob ref
521−```
522−
523−This is a hash of a `blob:clay`. These are most notably used in `lat:rang:clay`,
524−where they are associated with the actual `blob:clay`, and as the values in
525−`q:yaki:clay`, where `path`s are associated with their content hashes in a commit.
526−
527−#### `$blob:clay`, data
528−
529−```hoon
530− +$ blob :: fs blob
531− $% [%delta p=lobe q=[p=mark q=lobe] r=page] :: delta on q
532− [%direct p=lobe q=page] :: immediate
533−```
534−
535−This is a node of data. In both cases, `p` is the hash of the blob.
536−
537−`%delta` is the case where we define the data by a delta on other data. In
538−practice, the other data is always the previous commit, but nothing depends on
539−this. `p.q` is the `mark` of the parent blob, `q.q` is the hash of the parent
540−blob, and `r` is the delta.
541−
542−`%direct` is the case where we simply have the data directly. `q` is the data.
543−These almost always come from the creation of a file.
544−
545−#### `+urge`, list change
546−
547−```hoon
548− ++ urge |*(a=mold (list (unce a))) :: list change
549−```
550−
551−This is a parametrized type for list changes. For example, `(urge @t)`
552−is a list change for lines of text.
553−
554−#### `+unce`, change part of a list.
555−
556−```hoon
557− ++ unce :: change part
558− |* a=mold ::
559− $% [%& p=@ud] :: skip[copy]
560− [%| p=(list a) q=(list a)] :: p -> q[chunk]
561− == ::
562−```
563−
564−This is a single change in a list of elements of type `a`. For example,
565−`(unce @t)` is a single change in lines of text.
566−
567−`%&` means the next `p` lines are unchanged.
568−
569−`%|` means the lines `p` have changed to `q`.
570−
571−#### `$nori:clay`, repository action
572−
573−```hoon
574− +$ nori :: repository action
575− $% [%& p=soba] :: delta
576− [%| p=@tas] :: label
577− == ::
578−```
579−
580−This describes a change that we are asking Clay to make to the `desk`.
581−There are two kinds of changes that may be made: we can modify files or
582−we can apply a label to a commit.
583−
584−In the `|` case, we will simply label the current commit with the given
585−label. In the `&` case, we will apply the given changes.
586−
587−#### `$soba:clay`, delta
588−
589−```hoon
590− +$ soba (list [p=path q=miso]) :: delta
591−```
592−
593−This describes a `list` of changes to make to a `desk`. The `path`s are `path`s
594−to files to be changed, and the corresponding `miso` value is a description of
595−the change itself.
596−
597−#### `$miso:clay`, ankh delta
598−
599−```hoon
600− +$ miso :: ankh delta
601− $% [%del ~] :: delete
602− [%ins p=cage] :: insert
603− [%dif p=cage] :: mutate from diff
604− [%mut p=cage] :: mutate from raw
605− == ::
606−```
607−
608−There are four kinds of changes that may be made to a node in a `desk`.
609−
610−`%del` deletes the node.
611−
612−`%ins` inserts a file given by `p`.
613−
614−`%dif` is currently unimplemented. This may seem strange, so we remark that
615−diffs for individual files are implemented using `+diff` and `+pact` in `mark`s.
616−So for an `ankh`, which may include both files and directories, `%dif` being
617−unimplemented really just means that we do not yet have a formal concept of
618−changes in directory structure.
619−
620−`%mut` mutates the file using raw data given by `p`.
621−
622−#### `$riff:clay`, request/desist
623−
624−```hoon
625− +$ riff [p=desk q=(unit rave)] :: request+desist
626−```
627−
628−This represents a request for data about a particular `desk`. If `q`
629−contains a `rave`, then this opens a subscription to the `desk` for that
630−data. If `q` is null, then this tells Clay to cancel the subscription
631−along this duct.
632−
633−#### `$riot:clay`, response
634−
635−```hoon
636− +$ riot (unit rant) :: response+complete
637−```
638−
639−A `riot` is a response to a subscription. If null, the subscription has
640−been completed, and no more responses will be sent. Otherwise, the
641−`rant` is the produced data.
642−
643−#### `$rant:clay`, response data
644−
645−```hoon
646− +$ rant :: response to request
647− $: p=[p=care q=case r=desk] :: clade release book
648− q=path :: spur
649− r=cage :: data
650− == ::
651−```
652−
653−This is the data associated to the response to a request. `p.p` specifies
654−the type of data that was requested (and is produced). `q.p` gives the
655−specific version reported (since a range of versions may be requested in
656−a subscription). `r.p` is the `desk`. `q` is the path to the filesystem
657−node. `r` is the data itself (in the format specified by `p.p`).
658−
659−### `$nako`, subscription response data
660−
661−```hoon
662−+$ nako :: subscription state
663− $: gar=(map aeon tako) :: new ids
664− let=aeon :: next id
665− lar=(set yaki) :: new commits
666− bar=(set plop) :: new content
667− == ::
668−```
669−
670−This is the data that is produced by a request for a range of revisions
671−of a `desk`. This allows us to easily keep track of a remote repository --
672−all the new information we need is contained in the `nako`.
673−
674−`gar` is a map of the revisions in the range to the hash of the commit
675−at that revision. These hashes can be used with `hut:rang:clay` to find the
676−commit itself.
677−
678−`let` is either the last revision number in the range or the most recent
679−revision number, whichever is smaller.
680−
681−`lar` is the set of new commits, and `bar` is the set of new content.
content/docs/arvo/clay/examples.mddeleted−788
@@ -1,788 +0,0 @@
1−+++
2−title = "Examples"
3−weight = 7
4−template = "doc.html"
5−+++
6−
7−This document contains a number of examples of interacting with Clay using its various `task`s. Sections correspond to the general details in the [API Reference](/docs/arvo/clay/tasks) document.
8−
9−Most examples will either use `|pass` to just send a `task` or the following thread to send a `task` and take the resulting `gift`. You can save the following thread to the `ted` directory of the `%base` `desk` on a fake ship:
10−
11−`send-task-take-gift.hoon`
12−
13−```hoon
14−/- spider
15−/+ strandio
16−=, strand=strand:spider
17−^- thread:spider
18−|= arg=vase
19−=/ m (strand ,vase)
20−^- form:m
21−=/ uarg !< (unit task:clay) arg
22−?~ uarg
23− (strand-fail:strand %no-arg ~)
24−=/ =task:clay u.uarg
25−=/ =card:agent:gall [%pass /foo %arvo %c task]
26−;< ~ bind:m (send-raw-card:strandio card)
27−;< res=[wire sign-arvo] bind:m take-sign-arvo:strandio
28−~& +>:res
29−(pure:m !>(~))
30−```
31−
32−## `%warp`
33−
34−See the [Read and Subscribe](/docs/arvo/clay/tasks#warp---read-and-track) section of the [API Reference](/docs/arvo/clay/tasks) document for general details.
35−
36−### `%sing`
37−
38−Here we'll look at reading files by passing Clay a `%warp` `task` with a `%sing` `rave` and receiving a `%writ` `gift` containing the data in response.
39−
40−Using the `send-task-take-gift.hoon` thread, let's try reading `gen/hood/hi.hoon`:
41−
42−```
43−> -send-task-take-gift [%warp our %base ~ %sing %x da+now /gen/hood/hi/hoon]
44−```
45−
46−You should see something like this as the output:
47−
48−```
49−[ %writ
50− p
51− [ ~
52− [ p=[p=%x q=[%da p=~2021.5.20..23.37.50..e79b] r=%base]
53− q=/gen/hood/hi/hoon
54− r
55− [ p=%hoon
56− q
57− [ #t/@
58− q
59− 3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
60− ]
61− ]
62− ]
63− ]
64−]
65−```
66−
67−The `cage` in the `riot` of the `%writ` contains the file's data due to our use of an `%x` `care`. It needn't be `%x` though. If we change it to `%u`, for example, we'll get a `?` `cage` instead:
68−
69−```
70−> -send-task-take-gift [%warp our %base ~ %sing %u da+now /gen/hood/hi/hoon]
71−[ %writ
72− p
73− [ ~
74− [ p=[p=%u q=[%da p=~2021.5.20..23.42.21..bb33] r=%base]
75− q=/gen/hood/hi/hoon
76− r=[p=%flag q=[#t/?(%.y %.n) q=0]]
77− ]
78− ]
79−]
80−```
81−
82−Here's a breakdown of the `task` we sent:
83−
84−![%sing diagram](https://media.urbit.org/docs/arvo/clay/sing.png "%sing diagram")
85−
86−### `%next`
87−
88−Here we'll look at subscribing to the next version of a file by passing Clay a `%warp` `task` with a `%next` `rave` and receiving a `%writ` `gift` when the file changes.
89−
90−Using the `send-task-take-gift.hoon` thread, let's subscribe to the next version of `foo.txt`:
91−
92−```
93−> -send-task-take-gift [%warp our %base ~ %next %x da+now /foo/txt]
94−```
95−
96−Now, in unix, create a file called `foo.txt` in the root of the `base` directory of your ship. In the dojo, hit backspace to disconnect the thread from the dojo prompt and run `|commit %base`. You should see something like:
97−
98−```
99−> |commit %base
100−>=
101−[%writ p=[~ [p=[p=%x q=[%ud p=3] r=%base] q=/foo/txt r=[p=%txt q=[#t/*'' q=0]]]]]
102−+ /~zod/base/3/foo/txt
103−```
104−
105−As you can see, the `riot` in the `%writ` includes a `cage` with the data of `/foo/txt` due to our use of an `%x` `care`.
106−
107−Now run the thread again, and this time delete the file in unix and again `|commit %base` in the dojo. You should see:
108−
109−```
110−> |commit %base
111−>=
112−[%writ p=~]
113−- /~zod/base/4/foo/txt
114−```
115−
116−You can see the `riot` is just `~` due to the file being deleted.
117−
118−Here's a breakdown of the task we sent:
119−
120−![%next diagram](https://media.urbit.org/docs/arvo/clay/next.png "%next diagram")
121−
122−### `%mult`
123−
124−Here we'll look at subscribing to the next version of multiple files by passing Clay a `%warp` `task` with a `%mult` `rave` and receiving a `%wris` `gift` when any of the files change.
125−
126−This thread will subscribe to `/foo/txt` with an `%x` `care` and `/bar/txt` with a `%u` `care`. It will print out the `%wris` it gets back from Clay.
127−
128−`sub-mult.hoon`
129−
130−```hoon
131−/- spider
132−/+ strandio
133−=, strand=strand:spider
134−^- thread:spider
135−|= arg=vase
136−=/ m (strand ,vase)
137−^- form:m
138−=/ files=(set (pair care:clay path))
139− %- sy :~
140− [%x /foo/txt]
141− [%u /bar/txt]
142− ==
143−;< =bowl:strand bind:m get-bowl:strandio
144−=/ =task:clay [%warp our.bowl %base ~ %mult da+now.bowl files]
145−=/ =card:agent:gall [%pass /mult %arvo %c task]
146−;< ~ bind:m (send-raw-card:strandio card)
147−;< response=(pair wire sign-arvo) bind:m take-sign-arvo:strandio
148−~& +.q.response
149−(pure:m !>(~))
150−```
151−
152−Save the above to `ted/sub-mult.hoon`, `|commit %base` and run with `-sub-mult`. Now, create `foo.txt` and `bar.txt` in your base directory, hit backspace in the dojo to disconnect the thread and run `|commit %base`. You should see something like:
153−
154−```
155−> |commit %base
156−>=
157−[%wris p=[%da p=~2021.4.27..06.07.08..5ec4] q={[p=%u q=/bar/txt] [p=%x q=/foo/txt]}]
158−+ /~zod/base/151/foo/txt
159−+ /~zod/base/151/bar/txt
160−```
161−
162−You'll notice that, unlike a `%writ`, the `%wris` doesn't give you the data. It merely tells you the `care`s and `path`s of the files that changed. If you need to actually get the data, you can just scry or send a request for the files in question.
163−
164−Now, run the thread again, open `bar.txt` in an editor, modify its contents, save it and `|commit %base`. You'll notice you didn't receive a `%wris`. This is because we subscribed to `/bar/txt` with `%u` care and its existence didn't change.
165−
166−Lastly, delete `foo.txt` and `|commit %base`. You should see something like:
167−
168−```
169−> |commit %base
170−>=
171−[%wris p=[%da p=~2021.4.27..06.15.03..0da4] q={[p=%x q=/foo/txt]}]
172−- /~zod/base/153/foo/txt
173−```
174−
175−As you can see, a relevant change to any of the subscribed files will trigger a response, not just when all of them change.
176−
177−Here's a breakdown of the `task` we sent:
178−
179−![subscribe mult diagram](https://media.urbit.org/docs/arvo/clay/sub-mult.png "subscribe mult diagram")
180−
181−### `%many`
182−
183−Here we'll look at subscribing to a range of changes to a `desk` by passing Clay a `%warp` `task` with a `%many` `rave` and receiving `%writ` `gift`s when changes occur.
184−
185−This thread will subscribe to changes to your `%base` `desk` for the next three minutes. The `track` is `%.y` so it will only inform you of changes, not send the full `nako`. It will only get updates if the specified file exists. It contains a `main-loop` that will take an arbitrary number of `sign`s and print them out in the dojo. Since it never ends, you'll need to stop it with the `:spider|kill` command in the dojo.
186−
187−`sub-many.hoon`
188−
189−```hoon
190−/- spider
191−/+ strandio
192−=, strand=strand:spider
193−|%
194−++ take-sign-loop
195− =/ m (strand ,~)
196− ^- form:m
197− %- (main-loop:strandio ,~)
198− :~ |= ~
199− ^- form:m
200− ;< res=(pair wire sign-arvo)
201− bind:m
202− ((handle:strandio ,(pair wire sign-arvo)) take-sign-arvo:strandio)
203− ~& res
204− (pure:m ~)
205− ==
206−--
207−^- thread:spider
208−|= arg=vase
209−=/ m (strand ,vase)
210−^- form:m
211−=/ uarg !< (unit path) arg
212−?~ uarg
213− (strand-fail:strand %no-arg ~)
214−=/ =path u.uarg
215−;< =bowl:strand bind:m get-bowl:strandio
216−=/ =task:clay [%warp our.bowl %base ~ %many %.y da+now.bowl da+(add ~m3 now.bowl) path]
217−=/ =card:agent:gall [%pass /many %arvo %c task]
218−;< ~ bind:m (send-raw-card:strandio card)
219−;< ~ bind:m take-sign-loop
220−(pure:m !>(~))
221−```
222−
223−Make sure `foo.txt` doesn't exist in the root of your `%base` `desk`. Save this to `ted/sub-many.hoon`, `|commit %base`, run it like `-sub-many /foo/txt`, and hit backspace in the dojo to free up the dojo prompt. Now, add a file called `bar.txt` to your `desk` and `|commit %base`. You should see something like:
224−
225−```
226−> |commit %base
227−>=
228−+ /~zod/base/260/bar/txt
229−```
230−
231−Notice you've received no `%writ` from Clay. This is because `/foo/txt` doesn't exist. Now, create `foo.txt` and `|commit %base` again. You should see:
232−
233−```
234−> |commit %base
235−>=
236−[ p=/many
237− q=[%clay [%writ p=[~ [p=[p=%w q=[%ud p=261] r=%base] q=/ r=[p=%null q=[#t/@n q=0]]]]]]
238−]
239−+ /~zod/base/261/foo/txt
240−```
241−
242−Now that `/foo/txt` exists it will inform you of updates. Note that if you delete `/foo/txt` again it will again stop sending updates.
243−
244−Now try adding `baz.txt`:
245−
246−```
247−> |commit %base
248−>=
249−[ p=/many
250− q=[%clay [%writ p=[~ [p=[p=%w q=[%ud p=262] r=%base] q=/ r=[p=%null q=[#t/@n q=0]]]]]]
251−]
252−+ /~zod/base/262/baz/txt
253−```
254−
255−Now wait until the three minutes is up and try making a change, for example deleting `baz.txt`:
256−
257−```
258−> |commit %base
259−>=
260−[ p=/many
261− q=[%clay [%writ p=[~ [p=[p=%w q=[%ud p=264] r=%base] q=/ r=[p=%null q=[#t/@n q=0]]]]]]
262−]
263−[p=/many q=[%clay [%writ p=~]]]
264−- /~zod/base/263/baz/txt
265−```
266−
267−You can see that along with the normal `%writ` it's also sent a second `%writ` with a null `riot` to indicate the subscription has ended. This is because it has now passed the end of the range of `case`s to which you subscribed.
268−
269−Run `:spider|kill` to stop the thread.
270−
271−Here's a breakdown of the `task` we sent:
272−
273−![subscribe many diagram](https://media.urbit.org/docs/arvo/clay/sub-many.png "subscribe many diagram")
274−
275−### Cancel Subscription
276−
277−Here we'll look at cancelling a subscription by sending Clay a `%warp` `task` with a null `(unit rave)` in the `riff`.
278−
279−This thread will subscribe to the `%next` version of `/foo/txt`, then immediately cancel the subscription and wait for a response to print (which it will never receive).
280−
281−`stop-sub.hoon`
282−
283−```hoon
284−/- spider
285−/+ strandio
286−=, strand=strand:spider
287−^- thread:spider
288−|= arg=vase
289−=/ m (strand ,vase)
290−^- form:m
291−;< =bowl:strand bind:m get-bowl:strandio
292−=/ =task:clay [%warp our.bowl %base ~ %next %x da+now.bowl /foo/txt]
293−=/ =card:agent:gall [%pass /next %arvo %c task]
294−;< ~ bind:m (send-raw-card:strandio card)
295−=. task [%warp our.bowl %base ~]
296−=. card [%pass /next %arvo %c task]
297−;< ~ bind:m (send-raw-card:strandio card)
298−;< =riot:clay bind:m (take-writ:strandio /next)
299−~& riot
300−(pure:m !>(~))
301−```
302−
303−Save the above to `ted/stop-sub.hoon`, `|commit %base`, run it with `-stop-sub` and hit backspace to detach it from the dojo prompt. Now, add `foo.txt` to the root of your `%base` `desk` and `|commit %base`. You should see:
304−
305−```
306−> |commit %base
307−>=
308−+ /~zod/base/266/foo/txt
309−```
310−
311−As you can see we've received no `%writ`. We can thus conclude the subscription has successfully been cancelled.
312−
313−Run `:spider|kill` to stop the thread.
314−
315−Here's a breakdown of the `task` we sent:
316−
317−![cancel subscription diagram](https://media.urbit.org/docs/arvo/clay/stop-sub.png "cancel subscription diagram")
318−
319−## `%info`
320−
321−See the [Write and Modify](/docs/arvo/clay/tasks#write-and-modify) section of the [API Reference](/docs/arvo/clay/tasks) document for general details.
322−
323−### `%ins`
324−
325−Here we'll look at adding a file by sending Clay a `%info` `task` containing a `%ins` `miso`.
326−
327−Let's try adding a `foo.txt` file with 'foo' as its contents:
328−
329−```
330−> |pass [%c [%info %base %& [/foo/txt %ins %txt !>(~['foo'])]~]]
331−+ /~zod/base/5/foo/txt
332−```
333−
334−If you have a look in the base of your pier you'll see there's now a file called `foo.txt` with the text `foo` in it.
335−
336−We've created the `cage` of the content like `[%txt !>(~['foo'])]`, if you want to write something besides a text file you'd just give it the appropriate `mark` and `vase`.
337−
338−Here's a breakdown of the `task` we sent:
339−
340−![%ins diagram](https://media.urbit.org/docs/arvo/clay/ins.png)
341−
342−### `%del`
343−
344−Here we'll look at deleting a file by sending Clay a `%info` `task` containing a `%del` `miso`.
345−
346−Let's try deleting the `foo.txt` file created in the [previous example](#ins):
347−
348−```
349−> |pass [%c [%info %base %& [/foo/txt %del ~]~]]
350−- /~zod/base/6/foo/txt
351−```
352−
353−If you have a look in the base of your pier you'll see the `foo.txt` file is now gone.
354−
355−Here's a breakdown of the `task` we sent:
356−
357−![%del diagram](https://media.urbit.org/docs/arvo/clay/del.png)
358−
359−### `%mut`
360−
361−Identical to the [%ins](#ins) example, just replace `%ins` with `%mut`.
362−
363−### Multiple Changes
364−
365−Here we'll look at changing multiple files in one request by sending Clay a `%info` `task` containing multiple `miso` in the `soba`.
366−
367−Since `soba` is just a `list` of `miso`, you can add a bunch of `miso` and they'll all be applied. This thread adds three files and then deletes them. Here there's only one type of `miso` in each request but you could mix different types together too.
368−
369−`multi-change.hoon`
370−
371−```hoon
372−/- spider
373−/+ strandio
374−=, strand=strand:spider
375−^- thread:spider
376−|= arg=vase
377−=/ m (strand ,vase)
378−^- form:m
379−=/ soba-a :~ [/foo/txt %ins %txt !>(['foo' ~])]
380− [/bar/txt %ins %txt !>(['bar' ~])]
381− [/baz/txt %ins %txt !>(['baz' ~])]
382− ==
383−=/ soba-b :~ [/foo/txt %del ~]
384− [/bar/txt %del ~]
385− [/baz/txt %del ~]
386− ==
387−;< ~ bind:m (send-raw-card:strandio [%pass /info %arvo %c %info %base %& soba-a])
388−;< ~ bind:m (send-raw-card:strandio [%pass /info %arvo %c %info %base %& soba-b])
389−(pure:m !>(~))
390−```
391−
392−Save to `ted/multi-change.hoon`, `|commit %base`, and run:
393−
394−```
395−> -multi-change
396−+ /~zod/base/37/foo/txt
397−+ /~zod/base/37/bar/txt
398−+ /~zod/base/37/baz/txt
399−- /~zod/base/38/foo/txt
400−- /~zod/base/38/bar/txt
401−- /~zod/base/38/baz/txt
402−```
403−
404−## Manage Mounts
405−
406−See the [Manage Mounts](/docs/arvo/clay/tasks#manage-mounts) section of the [API Reference](/docs/arvo/clay/tasks) document for general details.
407−
408−### `%boat`
409−
410−Here we'll look at requesting the list of existing mount points on a ship by sending Clay a `%boat` `task` and receiving a `%hill` `gift`.
411−
412−Using the `send-task-take-gift.hoon` thread, let's make such a request:
413−
414−```
415−> -send-task-take-gift [%boat ~]
416−[%hill p=~[%base]]
417−```
418−
419−### `%mont`
420−
421−Here we'll look at mounting `desk`s, directories and files to unix by sending Clay a `%mont` `task`.
422−
423−Let's first try mounting our `%garden` desk:
424−
425−```
426−> |pass [%c [%mont %garden [our %garden da+now] /]]
427−```
428−
429−If you look in your pier, you should now see a `garden` folder which contains the contents of that `desk`.
430−
431−If we make a `%boat` request as detailed in the [%boat](#boat) section, we'll now see the mount point listed:
432−
433−```
434−> -send-task-take-gift [%boat ~]
435−[%hill p=~[%garden %base]]
436−```
437−
438−Note the mount point doesn't need to match a `desk`, file or directory. We can also do:
439−
440−```
441−> |pass [%c [%mont %wibbly-wobbly [our %base da+now] /]]
442−```
443−
444−And you'll now see that there's a `wibbly-wobbly` folder with the contents of the `%base` `desk`. You'll also notice we can mount the same file or directory more than once. There's no problem having `%base` mounted to both `base` and `wibbly-wobbly`. The only requirement is that their mount points be unique.
445−
446−Let's try mounting a subdirectory and a single folder:
447−
448−```
449−> |pass [%c [%mont %gen [our %base da+now] /gen]]
450−> |pass [%c [%mont %hi [our %base da+now] /gen/hood/hi]]
451−```
452−
453−If you look in your pier you'll now see a `gen` folder with the contents of `/gen` and a `hi.hoon` file by itself. Notice how the file extension has been automatically added.
454−
455−### `%ogre`
456−
457−Here we'll look at unmounting `desk`s, directories and files by sending Clay a `%ogre` `task`.
458−
459−Let's unmount what we mounted in the [%mont](#mont) section. First we'll unmount the `%garden` desk:
460−
461−```
462−|pass [%c [%ogre %garden]]
463−```
464−
465−Our custom mount point `%wibbly-wobbly`:
466−
467−```
468−|pass [%c [%ogre %wibbly-wobbly]]
469−```
470−
471−And the single `hi.hoon` we previously mounted by specifying its mount point `%hi`:
472−
473−```
474−|pass [%c [%ogre %hi]]
475−```
476−
477−If we specify a non-existent mount point it will fail with an error printed to the dojo like:
478−
479−```
480−> |pass [%c [%ogre %foo]]
481−[%not-mounted %foo]
482−```
483−
484−If we give it an unmounted `beam` it will not print an error but still won't work.
485−
486−### `%dirk`
487−
488−Here we'll look at committing changed files by sending Clay a `%dirk` `task`.
489−
490−This `task` performs the same function as the `|commit` dojo command.
491−
492−With your `%base` `desk` mounted, try adding a file and send a `%dirk` to commit the change:
493−
494−```
495−> |pass [%c [%dirk %base]]
496−+ /~zod/base/12/foo/txt
497−```
498−
499−Clay will print the changed files to the dojo with a leading `+`, `-` or `:` to indicate a new file, deleted file and changed file respectively.
500−
501−If you have the same `desk` mounted to multiple points, a committed change in one mount will also update the others.
502−
503−## Merge Desks
504−
505−See the [Merge Desks](/docs/arvo/clay/tasks#merge-desks) section of the [API Reference](/docs/arvo/clay/tasks) document for general details.
506−
507−### `%merg`
508−
509−Here we'll look at merging `desk`s by sending Clay a `%merg` `task` and receiving a `%mere` `gift` in response.
510−
511−First, using the `send-task-take-gift.hoon` thread, let's try creating a new `desk`:
512−
513−```
514−> -send-task-take-gift [%merg %foo our %base da+now %init]
515−[%mere p=[%.y p={}]]
516−```
517−
518−Now if we scry for our `desk`s we'll see `%foo` is there:
519−
520−```
521−> .^((set desk) %cd /===)
522−{%bitcoin %base %landscape %webterm %garden %foo}
523−```
524−
525−Next, we'll create a merge conflict and try a couple of things. Mount `%foo` with `|mount /=foo=`, then add a `foo.txt` to both `desk`s but with different text in each and `|commit` them.
526−
527−Now we'll try merging `%base` into `%foo` with a `%mate` strategy:
528−
529−```
530−> -send-task-take-gift [%merg %foo our %base da+now %mate]
531−[ /foo
532− [ %clay
533− [ %mere
534− p
535− [ %.n
536− p
537− [ p=%mate-conflict
538− q=~[[%rose p=[p="/" q="/" r=""] q=[i=[%leaf p="foo"] t=[i=[%leaf p="txt"] t=~]]]]
539− ]
540− ]
541− ]
542− ]
543−]
544−```
545−
546−As you can see, the merge has failed. Let's try again with a `%meld` strategy:
547−
548−```
549−> -send-task-take-gift [%merg %foo our %base da+now %meld]
550−[/foo [%clay [%mere p=[%.y p={/foo/txt}]]]]
551−```
552−
553−Now the merge has succeeded and the `%mere` notes the file with a merge conflict. If we try with a `%only-that` strategy:
554−
555−```
556−> -send-task-take-gift [%merg %foo our %base da+now %only-that]
557−[/foo [%clay [%mere p=[%.y p={}]]]]
558−: /~zod/foo/6/foo/txt
559−```
560−
561−...you can see it's overwritten the `foo/txt` in the `%foo` `desk` and the `%mere` now has an empty `set`, indicating no merge conflicts.
562−
563−Next, let's look at subscribing for future changes. Since the `case` is specified explicitly in the `%merge` `task`, we can set it in the future:
564−
565−```
566−> -send-task-take-gift [%merg %foo our %base da+(add ~m2 now) %only-that]
567−```
568−
569−Now change the text in the `foo.txt` in the `%base` `desk`, hit backspace to detach the thread and `|commit %base`. After the two minutes pass you should see:
570−
571−```
572−[/foo [%clay [%mere p=[%.y p={}]]]]
573−: /~zod/foo/7/foo/txt
574−```
575−
576−You can also specify it by revision number or label.
577−
578−## Permissions
579−
580−See the [Permissions](/docs/arvo/clay/tasks#permissions) section of the [API Reference](/docs/arvo/clay/tasks) document for general details.
581−
582−### `%perm`
583−
584−Here we'll look at setting permissions by sending Clay a `%perm` `task`.
585−
586−First, let's allow `~nes` to read `/gen/hood/hi/hoon`:
587−
588−```
589−> |pass [%c [%perm %base /gen/hood/hi/hoon %r ~ %white (sy [%.y ~nes]~)]]
590−```
591−
592−...and we'll do a `%p` scry to see that the permission was set:
593−
594−```
595−> .^([r=dict:clay w=dict:clay] %cp /===/gen/hood/hi/hoon)
596−[r=[src=/gen/hood/hi/hoon rul=[mod=%white who=[p={~nes} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
597−```
598−
599−You can see that `~nes` is now in the read whitelist. Next, let's try a write permission:
600−
601−```
602−> |pass [%c [%perm %base /ted %w ~ %white (sy [%.y ~nes]~)]]
603−```
604−
605−You can see `~nes` can now write to `/ted`:
606−
607−```
608−> .^([r=dict:clay w=dict:clay] %cp /===/ted)
609−[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ted rul=[mod=%white who=[p={~nes} q={}]]]]
610−```
611−
612−Since we've set it for the whole `/ted` directory, if we check a file inside it we'll see it also has this permission:
613−
614−```
615−> .^([r=dict:clay w=dict:clay] %cp /===/ted/aqua/ames/hoon)
616−[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ted rul=[mod=%white who=[p={~nes} q={}]]]]
617−```
618−
619−...and you'll notice that `src` tells us it's inherited the rule from `/ted`.
620−
621−Now let's try setting both read and write permissions:
622−
623−```
624−> |pass [%c [%perm %base /gen/help/hoon %rw `[%black (sy [%.y ~nes]~)] `[%white (sy [%.y ~nes]~)]]]
625−```
626−
627−```
628− .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
629−[r=[src=/gen/help/hoon rul=[mod=%black who=[p={~nes} q={}]]] w=[src=/gen/help/hoon rul=[mod=%white who=[p={~nes} q={}]]]]
630−```
631−
632−Lastly, let's look at deleting a permission rule we've previously set. To do that, we just send a null `(unit rule)` in the `rite`.
633−
634−For example, to remove a read permission (or write if you specify `%w`):
635−
636−```
637−> |pass [%c [%perm %base /gen/help/hoon %r ~]]
638−```
639−
640−```
641−> .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
642−[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/gen/help/hoon rul=[mod=%white who=[p={~nes} q={}]]]]
643−```
644−
645−...and to remove both read and write at the same time:
646−
647−```
648−> |pass [%c [%perm %base /gen/help/hoon %rw ~ ~]]
649−```
650−
651−```
652−> .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
653−[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
654−```
655−
656−As you can see it's back to the default inherited from `/`.
657−
658−Here's a breakdown of a `%perm` task:
659−
660−![perm diagram](https://media.urbit.org/docs/arvo/clay/perm-diagram.png)
661−
662−### `%cred`
663−
664−Here we'll look at creating a permission group by sending Clay a `%cred` `task`.
665−
666−Let's create a group called `'foo'` with a few ships:
667−
668−```
669−|pass [%c [%crew 'foo' (sy ~[~zod ~nec ~bud ~wes ~sev])]]
670−```
671−
672−We'll check it with the next kind of `task`: [%crew](#crew).
673−
674−### `%crew`
675−
676−Here we'll look at retrieving permission groups by sending Clay a `%crew` `task` and receiving a `%cruz` `gift` in response.
677−
678−Let's check, using the `send-task-take-gift.hoon` thread, for the permission group created in the [%cred](#cred) example:
679−
680−```
681−> -send-task-take-gift [%crew ~]
682−[%cruz cez={[p=~.foo q={~nec ~bud ~wes ~zod ~sev}]}]
683−```
684−
685−### `%crow`
686−
687−Here we'll look at retrieving a list of all files and directories in all `desk`s which have permissions set for a group by sending Clay a `%crow` `task` and receiving a `%croz` `gift` in response.
688−
689−First we'll set a couple of permissions for the `foo` group we created in the [%cred](#cred) section:
690−
691−```
692−> |pass [%c [%perm %base /gen/hood/hi/hoon %w ~ %white (sy [%.n 'foo']~)]]
693−> |pass [%c [%perm %base /ted %w ~ %white (sy [%.n 'foo']~)]]
694−```
695−
696−Notice we use a `%.n` in the `whom` to indicate a group rather than the `%.y` of a ship.
697−
698−Now we'll use the `send-task-take-gift.hoon` thread to try `%crow`:
699−
700−```
701−> -send-task-take-gift [%crow 'foo']
702−[ %croz
703− rus
704− { [ p=%base
705− q
706− [ r={}
707− w
708− { [p=/gen/hood/hi/hoon q=[mod=%white who={[%.n p=~.foo]}]]
709− [p=/ted q=[mod=%white who={[%.n p=~.foo]}]]
710− }
711− ]
712− ]
713− }
714−]
715−```
716−
717−## Foreign Ships
718−
719−See the [Foreign Ships](/docs/arvo/clay/tasks#foreign-ships) section of the [API Reference](/docs/arvo/clay/tasks) document for general details.
720−
721−### `%warp` - Remote
722−
723−Here we'll look at reading files on a foreign ship by sending Clay a `%warp` `task` with a foreign ship in the `wer` field and receiving a `%writ` `gift` in response.
724−
725−We'll use a fake `~nes` as the the foreign ship and a fake `~zod` as the local ship.
726−
727−First we'll set permissions on the foreign ship. Create a file called `foo.txt` in the `%base` of ~nes, then send a `%perm` request to allow ~zod to read and write the file:
728−
729−```
730−> |pass [%c [%perm %base /foo/txt %rw `[%white (sy [%.y ~zod]~)] `[%white (sy [%.y ~zod]~)]]]
731−```
732−
733−If we scry the file for its permissions with a `%p` `care`, we'll see `~zod` is now whitelisted:
734−
735−```
736−> .^([r=dict:clay w=dict:clay] %cp /===/foo/txt)
737−[r=[src=/foo/txt rul=[mod=%white who=[p={~zod} q={}]]] w=[src=/foo/txt rul=[mod=%white who=[p={~zod} q={}]]]]
738−```
739−
740−Back on `~zod`: Using the `send-task-take-gift.hoon` thread, send a `%x` read request for `/foo/txt` on ~nes like:
741−
742−```
743−> -send-task-take-gift [%warp ~nes %base ~ %sing %x da+now /foo/txt]
744−[ %writ
745− p
746− [ ~
747− [ p=[p=%x q=[%da p=~2021.5.3..08.24.22..9ce7] r=%base]
748− q=/foo/txt
749− r=[p=%txt q=[#t/txt=*'' q=[7.303.014 0]]]
750− ]
751− ]
752−]
753−```
754−
755−As you can see, we've received a `%writ` containing the requested data just as we would with a local request. Let's try a `%u`:
756−
757−```
758−> -send-task-take-gift [%warp ~nes %base ~ %sing %u da+now /foo/txt]
759−[ %writ
760− p
761− [ ~
762− [ p=[p=%u q=[%da p=~2021.5.3..08.26.32..88cf] r=%base]
763− q=/foo/txt
764− r=[p=%flag q=[#t/?(%.y %.n) q=0]]
765− ]
766− ]
767−]
768−```
769−
770−If we send a `%d` request however, it will crash:
771−
772−```
773−> -send-task-take-gift [%warp ~nes %base ~ %sing %d da+now /foo/txt]
774−call: failed
775−/sys/vane/clay/hoon:<[4.085 3].[4.314 5]>
776−...
777−/sys/vane/clay/hoon:<[1.365 7].[1.365 51]>
778−[ %clay-bad-foreign-request-care
779− [%sing mood=[care=%d case=[%da p=~2021.5.3..20.04.57..1092] path=/foo/txt]]
780−]
781−/sys/vane/clay/hoon:<[1.365 48].[1.365 50]>
782−```
783−
784−### `%merg` - Remote
785−
786−To merge a foreign `desk` into a local one, you just send Clay a `%merg` `task` (as you would for a local merge) and specify the foreign ship in the `her` field. For an example, see the [%merg](#merg) section.
787−
788−The foreign ship will respond only if correct permissions have been set. See the [%perm](#perm) section for an example.
content/docs/arvo/clay/marks/_index.mddeleted−23
@@ -1,23 +0,0 @@
1−+++
2−title = "Marks"
3−weight = 10
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−[Overview](/docs/arvo/clay/marks/marks)
10−
11−Overview of `mark`s.
12−
13−[Writing Marks](/docs/arvo/clay/marks/writing-marks)
14−
15−A practical walk-through of writing a `mark` file.
16−
17−[Using Marks](/docs/arvo/clay/marks/using-marks)
18−
19−Details of using `mark` conversion gates and `mark` cores in your own code.
20−
21−[Examples](/docs/arvo/clay/marks/examples)
22−
23−The example code used in the Writing Marks guide.
content/docs/arvo/clay/marks/examples.mddeleted−248
@@ -1,248 +0,0 @@
1−+++
2−title = "Examples"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−These are the files used in the [Writing Marks](/docs/arvo/clay/marks/writing-marks) guide.
8−
9−## `/lib/csv/hoon`
10−
11−```hoon
12−|%
13−++ validate :: All rows same length?
14− |= csv=(list (list @t))
15− ^- ?
16− =/ result
17− %+ roll csv
18− |= [row=(list @t) =flag ref=(unit @ud)]
19− ?. flag
20− [flag ref]
21− ?~ ref
22− [flag `(lent row)]
23− ?. =(u.ref (lent row))
24− [%.n ref]
25− [flag ref]
26− flag.result
27−++ en-csv :: csv -> atom (to mime)
28− |= csv=(list (list @t))
29− |^ ^- @t
30− (cat 3 (crip (join '\0a' (turn csv en-row))) '\0a')
31− ++ en-row :: encode row
32− |= row=(list @t)
33− ^- @t
34− (crip (join ',' (turn row en-field)))
35− ++ en-field :: encode field
36− |= field=@t
37− ^- @t
38− %+ rash
39− field
40− %+ cook
41− |= =tape
42− ^- @t
43− ?~ tape ''
44− ?: =('"' i.tape)
45− (cat 3 (crip tape) '"')
46− (crip tape)
47− ;~ pose
48− (full (star ;~(less (mask "\",\0a\0d") next)))
49− ;~ plug
50− (easy '"')
51− (star ;~(pose (cold '""' doq) next))
52− ==
53− ==
54− --
55−++ de-csv :: atom -> csv (from mime)
56− |= dat=@t
57− |^ ^- (list (list @t))
58− =/ parsed (parse dat)
59− ?. (validate parsed)
60− ~|(%mixed-col-count !!)
61− parsed
62− ++ parse :: parse cord
63− |= dat=@t
64− |^ ^- (list (list @t))
65− %+ rash
66− dat
67− %+ most
68− ;~(pose (jest '\0d\0a') (mask "\0a\0d"))
69− (most com parse-field)
70− ++ parse-field :: parse field from cord
71− |^
72− %+ cook
73− |=(a=tape (crip a))
74− ;~(pose unenclosed enclosed)
75− ++ unenclosed :: unquoted field
76− ;~ sfix
77− (star ;~(less (mask "\",\0a\0d") next))
78− ;~ pose
79− ;~ plug
80− ;~(pose (jest '\0d\0a') (mask "\0a\0d"))
81− ;~(less next (easy ~))
82− ==
83− ;~(less doq (easy ~))
84− ==
85− ==
86− ++ enclosed :: quoted field
87− |^
88− ;~ sfix
89− (ifix [prefix suffix] content)
90− ;~ pose
91− ;~(simu (mask ",\0a\0d") (easy ~))
92− ;~ plug
93− ;~(pose (jest '\0d\0a') (mask "\0a\0d"))
94− ;~(less next (easy ~))
95− ==
96− ;~(less next (easy ~))
97− ==
98− ==
99− ++ content :: quoted field contents
100− %- star
101− ;~ pose
102− (cold '"' (jest '""'))
103− %+ cold '\0a'
104− ;~(pose (jest '\0d\0a') (just '\0d'))
105− ;~(less doq next)
106− ==
107− ++ prefix ;~(pose ;~(plug (star ace) doq) doq) :: quoted field prefix
108− ++ suffix ;~(pose ;~(plug doq (star ace)) doq) :: quoted field suffix
109− --
110− --
111− --
112− --
113−++ csv-join
114− |= [ali=(urge:clay (list @t)) bob=(urge:clay (list @t))]
115− ^- (unit (urge:clay (list @t)))
116− |^
117− =. ali (clean ali)
118− =. bob (clean bob)
119− |- ^- (unit (urge:clay (list @t)))
120− ?~ ali `bob
121− ?~ bob `ali
122− ?- -.i.ali
123− %&
124− ?- -.i.bob
125− %&
126− ?: =(p.i.ali p.i.bob)
127− %+ bind $(ali t.ali, bob t.bob)
128− |=(cud=(urge:clay (list @t)) [i.ali cud])
129− ?: (gth p.i.ali p.i.bob)
130− %+ bind $(p.i.ali (sub p.i.ali p.i.bob), bob t.bob)
131− |=(cud=(urge:clay (list @t)) [i.bob cud])
132− %+ bind $(ali t.ali, p.i.bob (sub p.i.bob p.i.ali))
133− |=(cud=(urge:clay (list @t)) [i.ali cud])
134− ::
135− %|
136− ?: =(p.i.ali (lent p.i.bob))
137− %+ bind $(ali t.ali, bob t.bob)
138− |=(cud=(urge:clay (list @t)) [i.bob cud])
139− ?: (gth p.i.ali (lent p.i.bob))
140− %+ bind $(p.i.ali (sub p.i.ali (lent p.i.bob)), bob t.bob)
141− |=(cud=(urge:clay (list @t)) [i.bob cud])
142− ~
143− ==
144− ::
145− %|
146− ?- -.i.bob
147− %|
148− ?. =(i.ali i.bob)
149− ~
150− %+ bind $(ali t.ali, bob t.bob)
151− |=(cud=(urge:clay (list @t)) [i.ali cud])
152− ::
153− %&
154− ?: =(p.i.bob (lent p.i.ali))
155− %+ bind $(ali t.ali, bob t.bob)
156− |=(cud=(urge:clay (list @t)) [i.ali cud])
157− ?: (gth p.i.bob (lent p.i.ali))
158− %+ bind $(ali t.ali, p.i.bob (sub p.i.bob (lent p.i.ali)))
159− |=(cud=(urge:clay (list @t)) [i.ali cud])
160− ~
161− ==
162− ==
163− ++ clean :: clean
164− |= wig=(urge:clay (list @t))
165− ^- (urge:clay (list @t))
166− ?~ wig ~
167− ?~ t.wig wig
168− ?: ?=(%& -.i.wig)
169− ?: ?=(%& -.i.t.wig)
170− $(wig [[%& (add p.i.wig p.i.t.wig)] t.t.wig])
171− [i.wig $(wig t.wig)]
172− ?: ?=(%| -.i.t.wig)
173− $(wig [[%| (welp p.i.wig p.i.t.wig) (welp q.i.wig q.i.t.wig)] t.t.wig])
174− [i.wig $(wig t.wig)]
175− --
176−--
177−```
178−
179−## `/mar/csv/hoon`
180−
181−```hoon
182−/+ *csv
183−|_ csv=(list (list @t))
184−++ grab
185− |%
186− ++ mime |=((pair mite octs) (de-csv q.q))
187− ++ noun
188− |= n=*
189− ^- (list (list @t))
190− =/ result ((list (list @t)) n)
191− ?> (validate result)
192− result
193− --
194−++ grow
195− |%
196− ++ mime
197− ?> (validate csv)
198− [/text/csv (as-octs:mimes:html (en-csv csv))]
199− ++ noun
200− ?> (validate csv)
201− csv
202− --
203−++ grad
204− |%
205− ++ form %csv-diff
206− ++ diff
207− |= bob=(list (list @t))
208− ^- (urge:clay (list @t))
209− ?> (validate csv)
210− ?> (validate bob)
211− (lusk:differ csv bob (loss:differ csv bob))
212− ++ pact
213− |= dif=(urge:clay (list @t))
214− ^- (list (list @t))
215− =/ result (lurk:differ csv dif)
216− ?> (validate result)
217− result
218− ++ join
219− |= $: ali=(urge:clay (list @t))
220− bob=(urge:clay (list @t))
221− ==
222− ^- (unit (urge:clay (list @t)))
223− (csv-join ali bob)
224− ++ mash
225− |= $: [ship desk (urge:clay (list @t))]
226− [ship desk (urge:clay (list @t))]
227− ==
228− ^- (urge:clay (list @t))
229− ~|(%csv-mash !!)
230− --
231−--
232−```
233−
234−## `/mar/csv-diff/hoon`
235−
236−```hoon
237−|_ dif=(urge:clay (list @t))
238−++ grab
239− |%
240− ++ noun (urge:clay (list @t))
241− --
242−++ grow
243− |%
244− ++ noun dif
245− --
246−++ grad %noun
247−--
248−```
content/docs/arvo/clay/marks/marks.mddeleted−59
@@ -1,59 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−+++
6−
7−Clay is a typed filesystem, and we call these file types `mark`s. When talking about Hoon and Arvo we'll often talk of types like `@ud`, `(list @t)`, etc. A `mark` will specify such a type for its files, but it does more than just that - it also defines conversion routines to and from other `mark`s, as well as diff, patch, and merge routines.
8−
9−For example, a `%txt` `mark` defines the type of a `%txt` file as a `wain` (a `(list @t)`). It defines a conversion function to a `%mime` `mark` to allow it to be serialized and sent to a browser or to the Unix filesystem. It also includes Hunt-McIlroy diff, patch, and merge algorithms. Conversion functions will be different for different `mark`s, as will things like diff algorithms. An image file like a `%png`, for example, just replaces the old blob of data with the new one rather than implementing a complex binary diff and patch algorithm, so how these functions are implemented depends on the file type and use case.
10−
11−`mark` files are stored in the `/mar` directory. The `path` of the `%txt` `mark`, for example, is `/mar/txt/hoon`.
12−
13−A `mark` is a door (a core with a sample) with three arms: `+grab`, `+grow`, and `+grad`. The door's sample defines its type. In `+grab` is a series of functions to convert from other `mark`s to the given `mark`. In `+grow` is a series of functions to convert from the given `mark` to other `mark`s. In `+grad` is `+diff`, `+pact`, `+join`, `+mash`, and `+form`.
14−
15−Here's its basic structure in an informal pseudocode:
16−
17−```
18−|_ <mark-type>
19−++ grab:
20− ++ noun: <noun> -> <mark-type>
21− ++ mime: <mime> -> <mark-type>
22− ++ txt: <txt> -> <mark-type>
23− ...
24−++ grow:
25− ++ noun: <mark-type> -> <noun>
26− ++ mime: <mark-type> -> <mime>
27− ++ txt: <mark-type> -> <txt>
28− ...
29−++ grad
30− ++ form: <diff-mark>
31− ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
32− ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
33− ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
34− ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
35−```
36−
37−These types are basically what you would expect. In `+grab`, only a `+noun` arm is mandatory, the rest are optional. The `+grow` arm itself is optional, as are any arms within it. In `+grad`, all arms are mandatory unless revision control is delegated to another `mark`, which we'll discuss later.
38−
39−In general, for a particular `mark`, the `+grab` and `+grow` entries should be inverses of each other. They needn't be symmetrical though - you may want to be able to convert from your `mark` to `%json` but not from `%json` to your `mark`, for example.
40−
41−In `+grad`, `+diff` takes two instances of a `mark` and produces a diff of them whose `mark` is given by `+form`. `+pact` takes an instance of a `mark` and patches it with the given diff. In general, if `+diff` called with A and B produces diff D, then `+pact` called with A and D should produce B.
42−
43−`+join` takes two diffs and attempts to merge them into a single diff. If there are conflicts, it produces null. `+mash` takes two diffs and forces a merge, even if there are conflicts. How your `+mash` function force-merges conflicting diffs is up to you. The `%txt` `mark` annotates any conflicts, for example, but there may be other ways. If `+join` of two diffs does not produce null, then `+mash` of the same diffs should produce the same result. Note that `+mash` is not used by Clay in its ordinary filesystem operations, so you may wish to leave it as a dummy arm that crashes if called.
44−
45−Alternately, instead of `+form`, `+diff`, `+pact`, `+join`, and `+mash`, a `mark` can provide the same functionality by defining `+grad` to be the name of another `mark` to which we wish to delegate the revision control responsibilities. Then, before running any of those functions, Clay will convert to the other `mark`, and convert back afterward. For example, the `%hoon` `mark` is revision-controlled in the same way as `%txt`, so its `+grad` is simply `++ grad %txt`. Of course, `+txt` must be defined in `+grow` and `+grab` as well.
46−
47−We mentioned that `+noun` is the only mandatory arm in `+grab`, but there are a couple of others that, while not mandatory, are of particular interest.
48−
49−The first is a `+mime` arm for converting to and from the `%mime` `mark`. When you `|commit` a file to a `desk` mounted to Unix, Clay will receive the data as a `%mime` `mark`, and then convert it to the `mark` matching the file extension. It will perform the same operation in reverse when mounting a `desk` to Unix. For this reason, any `mark` you wish to be able to access from the Unix filesystem should have `%mime` conversion routines. In certain cases (such as the scry interface), Eyre will also need to convert your `mark` to a `%mime` in order to encode it in an HTTP response, so you may require a `+mime` arm for that reason as well.
50−
51−The second case of interest is the `+json` arm for converting to and from a `%json` `mark`. If, for example, you want to write a Gall agent to which you can subscribe through Eyre's channel system, it must produce data with a `mark` containing `%json` conversion routines. If it doesn't, Eyre will not be able to deliver the data to the subscribed HTTP client in the SSE stream.
52−
53−## Sections
54−
55−[Writing Marks](/docs/arvo/clay/marks/writing-marks) - A practical walk-through of writing a `mark` file.
56−
57−[Using Marks](/docs/arvo/clay/marks/using-marks) - Details of using `mark` conversion gates and `mark` cores in your own code.
58−
59−[Examples](/docs/arvo/clay/marks/examples) - The example code used in the Writing Marks guide.
content/docs/arvo/clay/marks/using-marks.mddeleted−240
@@ -1,240 +0,0 @@
1−+++
2−title = "Using Marks"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−In the last document, [Writing Marks](/docs/arvo/clay/marks/writing-marks), we walked through writing `mark` files and touched on how Clay handles them. They needn't just be left to background vane processes though, you can also use them yourself in your code.
8−
9−There are two kinds of cores that Clay can build for you: A `mark` conversion gate and a `mark` core. Each has two kinds: Statically typed and dynamically typed. Clay has a `care` for producing each of these:
10−
11−- `%b` - Build a dynamically typed `mark` core.
12−- `%c` - Build a dynamically typed `mark` conversion gate.
13−- `%e` - Build a statically typed `mark` core.
14−- `%f` - Build a statically typed `mark` conversion gate.
15−
16−You can either use these by `%pass`ing Clay a [%warp task](/docs/arvo/clay/tasks#warp) with the appropriate `care`, or else with a [Clay scry](/docs/arvo/clay/scry). In the examples here we've used the latter.
17−
18−## mark conversion gates
19−
20−`mark` conversion gates simply convert from one `mark` to another.
21−
22−### Static
23−
24−A static `mark` conversion gate looks like `$-(a b)`, where `a` is the type of the `mark` you're converting _from_, and `b` is type of the `mark` you're converting _to_. For example, a `mark` conversion gate from `%txt` to `%mime` would look like `$-(wain mime)`. You'd simply feed it a `wain` and get a `$mime` in return.
25−
26−#### Example
27−
28−We get our `%txt` to `%mime` `mark` conversion gate with a `%f` scry like so:
29−
30−```
31−> =txt-to-mime .^($-(wain mime) %cf /===/txt/mime)
32−```
33−
34−Note we had to specify the type of the gate as `$-(wain mime)` in the scry - if the type returned by the scry doesn't match that specification it'll fail. This is where a statically typed `mark` conversion gate differs from the dynamically typed gate, which we'll discuss later.
35−
36−Now that we have our conversion gate, we can just call it with a valid `wain` and we'll get our `$mime` in return:
37−
38−```
39−> (txt-to-mime ~['foo'])
40−[p=/text/plain q=[p=3 q=7.303.014]]
41−```
42−
43−### Dynamic
44−
45−A dynamically typed `mark` conversion gate is called a `$tube:clay`, and looks like:
46−
47−```hoon
48−+$ tube $-(vase vase)
49−```
50−
51−As you can see from the type definition, it takes and returns a `vase` rather than needing the types explicitly defined. Rather than failing on a type mismatch when the scry is performed, it'll instead fail when it's actually run and fed a `vase` of the wrong type. Apart from handling `vase`s, it otherwise behaves the same as a statically typed `mark` conversion gate.
52−
53−#### Example
54−
55−We get our `%txt` to `%mime` `$tube` with a `%c` scry like so:
56−
57−```
58−> =txt-mime-tube .^(tube:clay %cc /===/txt/mime)
59−```
60−
61−And then we can again feed it the `wain` that a `%txt` `mark` wants, only this time it's wrapped in a `vase`:
62−
63−```
64−> !< mime (txt-mime-tube !>(~['foo']))
65−[p=/text/plain q=[p=3 q=7.303.014]]
66−```
67−
68−We then get our `$mime` back, but also in a `vase`.
69−
70−## mark cores
71−
72−While a `mark` conversion gate is built from functions defined in `+grab` and `+grow`, a `mark` core gives you everything in `+grad` so you can create diffs, merge diffs, patch files, etc. An extra arm `+vale` is also included that lets you convert a `noun` to the type the `%mark` takes by running the `+noun` arm of `+grab` in the original `mark` file.
73−
74−### Static
75−
76−A statically typed `mark` core is a `(nave:clay a b)` where `a` is the type of the `mark` and `b` is the type for diffs (which is the type of the `mark` specified in `+form:grad`). For example, a static `mark` core for a `%txt` `mark` looks like `(nave:clay wain (urge:clay cord))`.
77−
78−`+nave:clay` looks like this in full:
79−
80−```hoon
81−++ nave
82− |$ [typ dif]
83− $_
84− ^?
85− |%
86− ++ diff |~([old=typ new=typ] *dif)
87− ++ form *mark
88− ++ join |~([a=dif b=dif] *(unit (unit dif)))
89− ++ mash
90− |~ [a=[ship desk dif] b=[ship desk dif]]
91− *(unit dif)
92− ++ pact |~([typ dif] *typ)
93− ++ vale |~(noun *typ)
94− --
95−```
96−
97−In brief, the arms of the core do the following:
98−
99−- `+form` - `mark` for diffs.
100−- `+vale` - Clam `noun` to the `mark`'s type.
101−- `+diff` - Create diff of two files.
102−- `+pact` - Patch a file with a diff.
103−- `+join` - Merge two diffs, returning `~` if there's a conflict.
104−- `+mash` - Force merge of two diffs.
105−
106−#### Examples
107−
108−First we get the `%txt` `mark` core with a `%e` scry:
109−
110−```
111−> =txt-nave .^((nave:clay wain (urge:clay cord)) %ce /===/txt)
112−```
113−
114−Note we specified the `mark` type `wain` and diff type `(urge:clay cord)` in the `nave` returned by the scry.
115−
116−We can see the `mark` for diffs with `+form`:
117−
118−```
119−> form.txt-nave
120−%txt-diff
121−```
122−
123−To clam a noun to the type of the `mark` (a `wain` in the case of a `%txt` `mark`), we can call `+vale` with a `noun`:
124−
125−```
126−> (vale:txt-nave ~['foo' 'bar'])
127−<|foo bar|>
128−```
129−
130−We can create a diff of two files with `+diff`:
131−
132−```
133−> (diff:txt-nave ~['foo' 'bar' 'baz'] ~['foo' 'zoo' 'baz'])
134−~[[%.y p=1] [%.n p=<|bar|> q=<|zoo|>] [%.y p=1]]
135−```
136−
137−Let's create some more diffs for experimentation:
138−
139−```
140−> =diff-a (diff:txt-nave ~['foo' 'bar' 'baz'] ~['foo' 'zoo' 'baz'])
141−> =diff-b (diff:txt-nave ~['foo' 'bar' 'baz'] ~['zap' 'bar' 'baz'])
142−> =diff-c (diff:txt-nave ~['foo' 'bar' 'baz'] ~['foo' 'bla' 'baz'])
143−```
144−
145−If we try merging diffs `a` and `b` with `+join`, we get a new merged diff back in a `unit`:
146−
147−```
148−> (join:txt-nave diff-a diff-b)
149−[~ [~ ~[[%.n p=<|foo|> q=<|zap|>] [%.n p=<|bar|> q=<|zoo|>] [%.y p=1]]]]
150−```
151−
152−If we try merging diffs `a` and `c` however, we get `~` because of a conflict:
153−
154−```
155−> (join:txt-nave diff-a diff-c)
156−[~ ~]
157−```
158−
159−If we run `+mash` on `a` and `b` we get the same diff as with `+join` (sans the `unit`):
160−
161−```
162−> (mash:txt-nave [our %base diff-a] [our %blah diff-b])
163−[~ ~[[%.n p=<|foo|> q=<|zap|>] [%.n p=<|bar|> q=<|zoo|>] [%.y p=1]]]
164−```
165−
166−If we `+mash` `a` and `c`, however, we get a diff with the conflict annotated rather than just `~`:
167−
168−```
169−> (mash:txt-nave [our %base diff-a] [our %blah diff-c])
170−[ ~
171− ~[
172− [%.y p=1]
173− [ %.n
174− p=<|bar|>
175− q
176− <|>>>>>>>>>>>> ~zod/base zoo ++++++++++++ bar ------------ bla <<<<<<<<<<<< ~zod/blah|>
177− ]
178− [%.y p=1]
179− ]
180−]
181−```
182−
183−Note that the `%txt` `mark` annotates conflicts, but there are no specific rules around how the `+mash` arm should force-merge conflicting diffs apart from that it must return a valid diff, however the `mark` specified in `+form` defines that.
184−
185−Finally, we can patch our `wain` with diff `a` and get a new, modified `wain`:
186−
187−```
188−> (pact:txt-nave ~['foo' 'bar' 'baz'] diff-a)
189−<|foo zoo baz|>
190−```
191−
192−### Dynamic
193−
194−A dynamically typed `mark` core is a `$dais:clay`, which looks like:
195−
196−```hoon
197−+$ dais
198− $_ ^|
199− |_ sam=vase
200− ++ diff |~(new=_sam *vase)
201− ++ form *mark
202− ++ join |~([a=vase b=vase] *(unit (unit vase)))
203− ++ mash
204− |~ [a=[ship desk diff=vase] b=[ship desk diff=vase]]
205− *(unit vase)
206− ++ pact |~(diff=vase sam)
207− ++ vale |~(noun sam)
208− --
209−```
210−
211−It has the same arms as the statically typed `mark` core, the difference is that it takes and returns `vase`s rather than the data directly. Additionally, it's a door rather than an ordinary core, and takes the type of the `mark` wrapped in a `vase` as its argument.
212−
213−#### Examples
214−
215−We can get a `%txt` `mark` `dais` with a `%b` scry:
216−
217−```
218−> =txt-dais .^(dais:clay %cb /===/txt)
219−```
220−
221−Its `+form` arm functions the same as a static core:
222−
223−```
224−> form.txt-dais
225−%txt-diff
226−```
227−
228−So does `+vale` except it returns a `vase`:
229−
230−```
231−> !< wain (vale:txt-dais ~['foo' 'bar'])
232−<|foo bar|>
233−```
234−
235−All the other arms also deal in `vase`s. Because it's a door, the `+pact` and `+diff` arms take the original file in a `vase` as the door sample rather than being given directly to the arm. Calling `+diff` arm, for example, works like so:
236−
237−```
238−> !< (urge:clay cord) (~(diff txt-dais !>(~['foo' 'bar'])) !>(~['foo' 'baz']))
239−~[[%.y p=1] [%.n p=<|bar|> q=<|baz|>]]
240−```
content/docs/arvo/clay/marks/writing-marks.mddeleted−333
@@ -1,333 +0,0 @@
1−+++
2−title = "Writing Marks"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−Here we'll walk through a practical example of writing a `mark` file.
8−
9−We'll create a `mark` for CSV (comma separated values) files, a simple format for storing tabular data in a text file. Note that there's already a `csv.hoon` `mark` and library, but we'll create new ones for demonstrative purposes. It shouldn't be an issue to overwrite the existing ones on a fakezod.
10−
11−CSV files separate fields with commas and rows with line breaks. They look something like:
12−
13−```
14−foo,bar,baz
15−blah,blah,blah
16−1,2,3
17−```
18−
19−There is a little complexity surrounding special characters in fields and line endings, but otherwise the only other rule is that all rows must have the same number of fields. You can refer to [RFC4180 on the IETF website](https://datatracker.ietf.org/doc/html/rfc4180) for more details.
20−
21−We'll represent such a structure in Hoon as a `(list (list @t))` like:
22−
23−```hoon
24−[['foo' 'bar' 'baz' ~] ['blah' 'blah' 'blah' ~] ['1' '2' '3' ~] ~]
25−```
26−
27−We could perhaps create the type with a `$|` rune to include row-length validation in the mold itself, but a `(list (list @t))` is simpler for demonstrative purposes.
28−
29−## A simple mark
30−
31−Let's begin with the simplest `mark` file:
32−
33−```hoon
34−|_ csv=(list (list @t))
35−++ grab
36− |%
37− ++ noun (list (list @t))
38− --
39−++ grow
40− |%
41− ++ noun csv
42− --
43−++ grad %noun
44−--
45−```
46−
47−The door takes a `(list (list @t))` as its sample, and we've given it a face of `csv` so we can easily reference it. Note its face could be anything, it needn't be the name of our `mark`. When we're doing something with data that has a `%csv` `mark` like converting it to another `mark` or creating a diff, this is where our data will reside.
48−
49−Next we have the `+grab` arm of our door, which contains a core with arms for converting _to_ our `mark` _from_ other `mark`s. We've given it one arm for the `%noun` `mark` - the most generic `mark` which will take any `noun`. Our `+noun` arm will simply clam whatever it's given with the `(list (list @t))` `mold`.
50−
51−Next is the `+grow` arm which does the inverse of `+grab`, converting _from_ our `mark` _to_ another `mark`. We've also given it a `+noun` arm, this time it will simply return the door's sample named `csv`, which is of course already a `noun`.
52−
53−Note that the `+noun` arm is _mandatory_ in `+grab`. Clay cannot build a `mark` core without it. Conversion arms for any other `mark`s apart from `%noun` are optional.
54−
55−Finally we have the `+grad` arm. This arm specifies functions for revision control like creating diffs, patching files and so on. In our case, rather than writing all those functions, we've just delegated those tasks to the `%noun` `mark`. We can do this because we've specified conversion routines to and from the `%noun` `mark` in our `+grow` and `+grab` arms. When we modify a file with a `%csv` `mark`, Clay will convert our data to a `%noun` `mark`, execute the necessary `+grad` functions from the `%noun` `mark` file, and then convert it back to a `%csv` `mark` again.
56−
57−So now we have a valid `%csv` `mark` file. If we save this as `csv.hoon` in the `/mar` directory we could store `%csv` data in Clay. This may be sufficient for some applications, but what if we want to import a CSV file from Unix or elsewhere? In the next section, we'll look at conversions to and from a `%mime` `mark` to address this.
58−
59−## `%mime` conversions
60−
61−The `$mime` type represents raw data from Unix or elsewhere. For example, if a text file from Unix containing the word `foo` were converted to a `$mime` type in Urbit, it would look something like:
62−
63−```hoon
64−[/text/plain q=[p=3 q=7.303.014]]
65−```
66−
67−`/text/plain` is its [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) and `p.q` is the byte-length of `q.q`, which is the data itself as an `atom`.
68−
69−The `%mime` `mark` is used by Clay to store and convert `$mime` data. It's an important `mark` for moving files from Unix to Urbit and vice versa. When you add a file to a `desk` you have mounted to Unix and `|commit` the change, Clay will first receive the file as a `%mime` `mark`, then convert from a `%mime` to whatever `mark` matches the file extension. For example, `foo.txt` will be converted from `%mime` to `%txt`. Additionally, data fetched by Iris over HTTP will come in as a `$mime-data:http`, which is an unvalidated form of `$mime` that you may wish to convert to a `%mime` `mark` and then to another `mark`. Likewise with Eyre, some of the lower-level interfaces receive HTTP requests with `$mime-data:http` in them.
70−
71−So with the nature of the `%mime` `mark` hopefully now clear, the reason we want conversion methods to and from `%mime` in our `%csv` `mark` is so we can import CSV files from Unix and vice versa.
72−
73−Since a CSV file on Unix will just be a long string with ASCII or UTF-8 encoding, we can treat `q.q` in the `$mime` as a `cord`, and thus write a parser to convert it to a `(list (list @t))`. For this purpose, here's a library: `csv.hoon`, which you can view in full on the [Examples](/docs/arvo/clay/marks/examples#libcsvhoon) page.
74−
75−The library contains four functions:
76−
77−- `+de-csv` - Parse a CSV `cord` to a `(list (list @t))`.
78−- `+en-csv` - Encode a `(list (list @t))` as a CSV `cord`.
79−- `+validate` - Check all rows of `(list (list @t))` are the same length.
80−- `+csv-join` - Ignore this for now, we'll use it later on.
81−
82−The decoding and encoding arms use parsing functions from the Hoon standard library. It's not important to be familiar with parsing in Hoon for our purposes here, but you can have a look at the [Parsing Guide](/docs/hoon/guides/parsing) in the Hoon documentation if you're interested. The important thing to note is that `+de-csv` takes a valid CSV-format `@t` and returns a `(list (list @t))`, and `+en-csv` does the reverse - it takes a `(list (list @t))` and returns a CSV-format `@t`.
83−
84−Let's try the library in the dojo. After we've added it to `/lib` and run `|commit`, we can build the file:
85−
86−```
87−> =csv -build-file %/lib/csv/hoon
88−```
89−
90−...try decode a CSV-format `@t`:
91−
92−```
93−> (de-csv:csv 'foo,bar,baz\0ablah,blah,blah\0a1,2,3')
94−~[<|foo bar baz|> <|blah blah blah|> <|1 2 3|>]
95−```
96−
97−...and try encode a `(list (list @t))` as a CSV-format `@t`:
98−
99−```
100−> (en-csv:csv [['foo' 'bar' 'baz' ~] ['blah' 'blah' 'blah' ~] ['1' '2' '3' ~] ~])
101−'foo,bar,baz\0ablah,blah,blah\0a1,2,3\0a'
102−```
103−
104−With that working, we can add an import for our library to our `%csv` `mark` defintion and add a `+mime` arm to both our `+grab` and `+grow` arms:
105−
106−```hoon
107−/+ *csv
108−|_ csv=(list (list @t))
109−++ grab
110− |%
111− ++ mime |=((pair mite octs) (de-csv q.q))
112− ++ noun
113− |= n=*
114− ^- (list (list @t))
115− =/ result ((list (list @t)) n)
116− ?> (validate result)
117− result
118− --
119−++ grow
120− |%
121− ++ mime
122− ?> (validate csv)
123− [/text/csv (as-octs:mimes:html (en-csv csv))]
124− ++ noun
125− ?> (validate csv)
126− csv
127− --
128−++ grad %noun
129−--
130−```
131−
132−In `+grab` we've added a `+mime` arm to convert _from_ a `%mime` `mark` _to_ our `%csv` `mark`. It's a simple gate that takes a `$mime` (specified as `(pair mite octs)` to avoid conflict with the arm name), runs the data through the `+de-csv` function and returns a `(list (list @t))` of the CSV data.
133−
134−We've also added a `+mime` arm to `+grow` for converting _from_ our `%csv` `mark` _to_ a `%mime` `mark`. We encode our `(list (list @t))` `csv` sample with our `+en-csv` function and then run that through `as-octs:mimes:html` to get a `$octs` (so it has the byte-length). We also add the `/text/csv` MIME type so it's a valid `$mime`.
135−
136−Additionally, we've used the `+validate` function in a few places to make sure our CSV data has consistent row lengths.
137−
138−If we save the above mark file as `csv.hoon` in `/mar` and `|commit %base`, we should now be able to import CSV files into Urbit. Let's give it a go. In the root of our `%base` `desk`, let's add a file named `foo.csv` with the following contents:
139−
140−```
141−foo,bar,baz
142−blah,blah,blah
143−1,2,3
144−```
145−
146−If we now `|commit %base`, we should see it's been successfully added:
147−
148−```
149−> |commit %base
150−>=
151−+ /~zod/base/4/foo/csv
152−```
153−
154−And if we try reading the file with the `-read` thread:
155−
156−```
157−> -read [%x our %base da+now /foo/csv]
158−~[<|foo bar baz|> <|blah blah blah|> <|1 2 3|>]
159−```
160−
161−We can see our `%csv` `mark` has successfully converted our `foo.csv` file to a `(list (list @t))` when it was imported.
162−
163−Let's try the other direction now. We can create a new `bar.csv` files in the root of `%base` from the dojo like so:
164−
165−```
166−> */bar/csv ~[['abc' 'def' ~] ['ghi' 'jkl' ~]]
167−+ /~zod/base/5/bar/csv
168−```
169−
170−And if we check it in the terminal on the Unix side we can see it's been correctly encoded:
171−
172−```
173−> cat zod/base/bar.csv
174−abc,def
175−ghi,jkl
176−```
177−
178−So now our `%csv` `mark` lets us move data in and out of Urbit. In the next section, we'll look at the `+grad` arm in more detail.
179−
180−## `+grad`
181−
182−So far we've just delegated `+grad` functions to the `%noun` `mark`, but now we'll look at writing our own.
183−
184−For demonstrative purposes, we can just poach the algorithms used in the `+grad` arm of the `%txt` `mark` and modify them to take our `(list (list @t))` type instead of a `wain`. It's not the most efficient algorithm for a CSV file but it'll do the job.
185−
186−Our diff format will be a `(urge:clay (list @t))`, and we'll use some `differ` functions from `zuse.hoon` like `+loss`, `+lusk` and `+lurk` to produce diffs and apply patches.
187−
188−The [csv.hoon library](/docs/arvo/clay/marks/examples#libcsvhoon) we imported also contains a `+csv-join` function which we'll use in the `+join` arm, just to save space here.
189−
190−Here's the new `%csv` `mark` defintion:
191−
192−```hoon
193−/+ *csv
194−|_ csv=(list (list @t))
195−++ grab
196− |%
197− ++ mime |=((pair mite octs) (de-csv q.q))
198− ++ noun
199− |= n=*
200− ^- (list (list @t))
201− =/ result ((list (list @t)) n)
202− ?> (validate result)
203− result
204− --
205−++ grow
206− |%
207− ++ mime
208− ?> (validate csv)
209− [/text/csv (as-octs:mimes:html (en-csv csv))]
210− ++ noun
211− ?> (validate csv)
212− csv
213− --
214−++ grad
215− |%
216− ++ form %csv-diff
217− ++ diff
218− |= bob=(list (list @t))
219− ^- (urge:clay (list @t))
220− ?> (validate csv)
221− ?> (validate bob)
222− (lusk:differ csv bob (loss:differ csv bob))
223− ++ pact
224− |= dif=(urge:clay (list @t))
225− ^- (list (list @t))
226− =/ result (lurk:differ csv dif)
227− ?> (validate result)
228− result
229− ++ join
230− |= $: ali=(urge:clay (list @t))
231− bob=(urge:clay (list @t))
232− ==
233− ^- (unit (urge:clay (list @t)))
234− (csv-join ali bob)
235− ++ mash
236− |= $: [ship desk (urge:clay (list @t))]
237− [ship desk (urge:clay (list @t))]
238− ==
239− ^- (urge:clay (list @t))
240− ~|(%csv-mash !!)
241− --
242−--
243−```
244−
245−In our modified `+grad` arm, we've replaced the `%noun` delegation with a core containing five arms: `+form`, `+diff`, `+pact`, `+join`, and `+mash`. These arms are all required for a valid `+grad` if it's not delegated to another `mark`. We'll now look at each in detail.
246−
247−### `+form`
248−
249−```hoon
250−++ form %csv-diff
251−```
252−
253−`+form` simply specifies the `mark` of the diff file that may be produced by other `+grad` functions. If your diff is the same type as your `mark`, it could just specify itself like `%csv`. In our case our diff is a `(urge:clay (list @t))` rather than a `(list (list @t))`, so we need a separate mark file for the diff itself.
254−
255−Here's another `mark` file which can be saved as `csv-diff.hoon` in `/mar`:
256−
257−```hoon
258−|_ dif=(urge:clay (list @t))
259−++ grab
260− |%
261− ++ noun (urge:clay (list @t))
262− --
263−++ grow
264− |%
265− ++ noun dif
266− --
267−++ grad %noun
268−--
269−```
270−
271−It's very bare-bones, we just need it for our `%csv` `mark` to work. In our `%csv` `mark`, we've specified it as `%csv-diff` in `+form`.
272−
273−### `+diff`
274−
275−```hoon
276−++ diff
277− |= bob=(list (list @t))
278− ^- (urge:clay (list @t))
279− ?> (validate csv)
280− ?> (validate bob)
281− (lusk:differ csv bob (loss:differ csv bob))
282−```
283−
284−This arm produces the diff of two `%csv` files. The first `%csv` file will be given as the sample of the parent door, which if you'll recall we gave a face of `csv`. The second `%csv` file will be given as the sample of the gate in `+diff`, which we've named `bob` here. We then just produce the diff of these two files and return it as the type of the mark specified in `+form`, which in our case is `(urge:clay (list @t))` for a `%csv-diff`. Clay will use `+diff` when a file is revised, so it doesn't have to store a whole new copy of the file each time it's modified.
285−
286−### `+pact`
287−
288−```hoon
289−++ pact
290− |= dif=(urge:clay (list @t))
291− ^- (list (list @t))
292− =/ result (lurk:differ csv dif)
293− ?> (validate result)
294− result
295−```
296−
297−`+pact` patches a `%csv` file with the given diff. Its gate takes a diff and applies it to the `%csv` given as the sample of the parent door (which we gave a face of `csv`). If the patch succeeds, it will return a new `%csv` file - a valid `(list (list @t))`. When we read a file that's been modified in Clay, Clay will apply all the diffs it has with `+pact` and return the resulting file.
298−
299−### `+join`
300−
301−```hoon
302−++ join
303− |= $: ali=(urge:clay (list @t))
304− bob=(urge:clay (list @t))
305− ==
306− ^- (unit (urge:clay (list @t)))
307− (csv-join ali bob)
308−```
309−
310−The `+join` arm merges two different diffs. It takes them both as the sample of its gate (which we've named `ali` and `bob`), and returns a new diff wrapped in a `unit` like `(unit (urge:clay (list @t)))`. The `unit` will be `~` if the merge failed due to a conflict. This is used by Clay in some cases when `desk`s are merged. If diff merges are not possible for your use case, you could just have it always return `~`.
311−
312−### `+mash`
313−
314−```hoon
315−++ mash
316− |= $: [ship desk (urge:clay (list @t))]
317− [ship desk (urge:clay (list @t))]
318− ==
319− ^- (urge:clay (list @t))
320− ~|(%csv-mash !!)
321−```
322−
323−This is like `+join` except it forces a diff merge even if there's a conflict. Rather than returning a `unit`, it just returns the diff - a `(urge:clay (list @t))` in our case. Also unlike `+join`, it takes the `ship` and `desk` each diff came from as well as the diff itself.
324−
325−The `+mash` arm is not used by Clay in its file revision operations, so it's safe to just make it a dummy arm that crashes as we've done here. If you were to use it, it would likely just be used manually in an agent, thread or generator.
326−
327−An example of its use would be the `%txt` `mark`, which includes a proper `+mash` function that produces a diff with any conflicts annotated, though how you have `+mash` handle conficts would depend on your use case. If there were no conflicts between the two diffs, it should produce the same diff as the `+join` arm.
328−
329−## Conclusion
330−
331−So there you have it, a fully functional `mark` for CSV files. A `mark` file can be as complex or as simple as you'd like, they're very flexible depending on your use case. Additional conversion methods can always be added as they're needed. For example, with just a few lines of code we could add arms for converting CSV files to `%json` or `%txt` and vice versa.
332−
333−In the next document, we'll look at building and using `mark` cores and `mark` conversion gates in our own code.
content/docs/arvo/clay/scry.mddeleted−398
@@ -1,398 +0,0 @@
1−+++
2−title = "Scry Reference"
3−weight = 5
4−template = "doc.html"
5−+++
6−
7−The various Clay scries are specified by a `care`, which is a single character corresponding with a Clay submodule. Apart from `%s` they just take a `path` to a `desk`, file or directory. All examples are dojo commands, the ='s in the path are automatically populated by the dojo like:
8−
9−```
10−> /===
11−[~.~zod ~.base ~.~2021.4.26..02.29.03..d31b ~]
12−```
13−
14−## %a - Build hoon.
15−
16−A scry with a `care` of `%a` will build a `hoon` file and return it as a `vase`.
17−
18−Example:
19−
20−```
21−.^(vase %ca /===/lib/strandio/hoon)
22−```
23−
24−## %b - Dyn. mark core.
25−
26−A scry with a `care` of `%b` will produce a `dais:clay` processed `mark` core for the specified `mark`. The `path` in the scry is a `mark`.
27−
28−Example:
29−
30−```
31−.^(dais:clay %cb /===/txt)
32−```
33−
34−## %c - Dyn. mark convert.
35−
36−A scry with a `care` of `%c` will produce a `tube:clay` dynamically typed `mark` conversion gate. The `path` specifies two `mark`s - _from_ and _to_, like `/txt/noun`.
37−
38−Example:
39−
40−```
41−> =a .^(tube:clay %cc /===/txt/mime)
42−> !< mime (a !>(~['foo']))
43−[p=/text/plain q=[p=3 q=7.303.014]]
44−```
45−
46−## %d - List desks.
47−
48−A scry with a `care` of `%d` will return a `(set desk)` of the `desk`s that exist on your ship.
49−
50−Example:
51−
52−```
53−> .^((set desk) %cd /===)
54−{%bitcoin %base %landscape %webterm %garden}
55−```
56−
57−## %e - Static mark core.
58−
59−A scry with a `care` of `%e` will return a statically typed `nave:clay` `mark` core. The `path` in the scry specifies the `mark`. The type returned is a `(nave:clay {type} {diff})`, where `{type}` is the type the `mark` takes and `{diff}` is the type taken by the `mark` specified in `+form:grad`.
60−
61−Example:
62−
63−```
64−.^((nave:clay noun noun) %ce /===/noun)
65−```
66−
67−## %f - Stat. mark convert.
68−
69−A scry with a `care` of `%f` will return a static `mark` conversion gate. The `path` specifies two `mark`s - _from_ and _to_, like `/txt/mime`.
70−
71−```
72−> =a .^($-(text mime) %cf /===/txt/mime)
73−> (a ~['foo'])
74−[p=/text/plain q=[p=3 q=7.303.014]]
75−```
76−
77−## %p - File permissions.
78−
79−A scry with a `care` of `%p` will return the permissions of the file or directory in question. The type returned is a `[dict:clay dict:clay]` where the head is read permissions and the tail is write permissions.
80−
81−If the specified file or directory has no permissions set, it will default to the permissions of its parent. If nothing above it has permissions set, it will default to empty whitelists. If the specified file or directory doesn't exist, it will also return the default empty whitelist.
82−
83−Example:
84−
85−```
86−> .^([dict:clay dict:clay] %cp /===/gen)
87−[[src=/ rul=[mod=%white who=[p={} q={}]]] src=/ rul=[mod=%white who=[p={} q={}]]]
88−```
89−
90−## %r - File as vase.
91−
92−A scry with a `care` of `%r` will return the data of the given file wrapped in a `vase` or crash if it's a directory. It's basically just a vase-wrapped `%x` scry.
93−
94−Examples:
95−
96−```
97−> .^(vase %cr /===/gen/hood/hi/hoon)
98−[ #t/@
99− q
100− 3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
101−]
102−```
103−
104−```
105−> !< @t .^(vase %cr /===/gen/hood/hi/hoon)
106−':: Helm: send message to an urbit\0a::\0a:::: /hoon/hi/hood/gen\0a ::\0a/? 310\0a:- %say\0a|=([^ [who=ship mez=$@(~ [a=tape ~])] ~] helm-send-hi+[who ?~(mez ~ `a.mez)])\0a'
107−```
108−
109−```
110−> .^(vase %cr /===/gen)
111−Crash!
112−```
113−
114−## %s - Misc. scries.
115−
116−A scry with a `care` of `%s` is for miscellaneous internal and debug functions and is liable to change in the future.
117−
118−Rather than just a `path` to a file, the head of the `path` is tagged with one of `%yaki %blob %hash %cage %open %late %base` and the tail depends on which tag you use. We'll look at each in turn.
119−
120−### %yaki - Commit.
121−
122−This will return the [yaki:clay](/docs/arvo/clay/data-types#yaki-clay-commit) of the specified commit. It takes a [tako:clay](/docs/arvo/clay/data-types#tako-clay-commit-reference).
123−
124−Example:
125−
126−Here we scry the [dome:clay](/docs/arvo/clay/data-types#dome-desk-data) for `/===`, get the latest `tako:clay` and the do a `%s` scry for the `yaki:clay` in question.
127−
128−```
129−> =/ =dome:clay .^(dome:clay %cv /===)
130− =/ =tako:clay (~(got by hit.dome) let.dome)
131− .^(yaki:clay %cs /===/yaki/(scot %uv tako))
132−[ p=~[80.174.473.756.485.530.520.259.753.935.584.637.641.665.425.899.348.092.348.244.635.557.986.495.151.006]
133− q
134− { [p=/mar/hark/graph-hook-update/hoon q=0v5.ea0bj.21s5c.mjrop.ishic.fpkvl.e5bbs.91kc9.tdo41.ifi06.60v41]
135− [p=/gen/hood/autocommit/hoon q=0v19.rh7jv.sa67o.t3jrb.4sdvs.7c45f.pv2u0.ragik.psp20.agqd8.8srkj]
136− ...
137− [p=/tests/lib/primitive-rsa/hoon q=0v1g.3qmq3.6i15q.arh6h.lfsqu.gvc9m.ql6m5.e2rdr.vnnt9.tptc6.mv9u7]
138− [p=/tests/sys/vane/gall/hoon q=0va.alspc.qptqn.7tuj0.bgecg.1093t.gtsjs.up03k.d1fmk.4jrh8.2tdfa]
139− }
140− r=88.666.797.531.755.181.802.690.473.856.185.443.710.929.766.582.249.039.904.824.278.074.149.777.897.099
141− t=~2021.4.16..10.41.57..3565
142−]
143−```
144−
145−### %blob - File blob.
146−
147−This will return the [blob:clay](/docs/arvo/clay/data-types#blob-clay-data) of some file. It takes a [lobe:clay](/docs/arvo/clay/data-types#lobe-clay-data-reference).
148−
149−Example:
150−
151−Here we grab the `lobe:clay` of `/gen/hood/hi/hoon` with a `%y` scry, then use it to do a `%s` scry for the `blob:clay` of the file.
152−
153−```
154−> =/ =arch .^(arch %cy /===/gen/hood/hi/hoon)
155− ?~ fil.arch
156− ~
157− .^(blob:clay %cs /===/blob/(scot %uv u.fil.arch))
158−[ %direct
159− p=0vp.k7nsm.qkdr3.t17rp.33bae.8gajg.v27gi.40itr.2u9qa.nppbt.7k255
160− q
161− [ p=%hoon
162− q
163−3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
164− ]
165−]
166−```
167−
168−### %hash - Commit hash.
169−
170−This will return the `@uvI` content hash of the specified commit. It takes a `tako:clay`.
171−
172−Example:
173−
174−Here we grab the `dome:clay` for `/===` with a `%v` scry, get the latest `tako:clay` and then do a `%s` `%hash` scry for it.
175−
176−```
177−> =/ =dome:clay .^(dome:clay %cv /===)
178− =/ =tako:clay (~(got by hit.dome) let.dome)
179− .^(tako:clay %cs /===/hash/(scot %uv tako))
180−0v16.er7uq.oke4u.cru7u.nglu9.q3su7.6ub1o.bh4qk.r5uav.ut12d.5rdl5
181−```
182−
183−### %cage - File as cage.
184−
185−This will return a `cage` of the data of some file. It takes a `lobe:clay`.
186−
187−Example:
188−
189−Here we grab the `lobe:clay` of `/gen/hood/hi/hoon` with a `%y` scry, then use it to do a `%s` scry for the `cage` of the data.
190−
191−```
192−> =/ =arch .^(arch %cy /===/gen/hood/hi/hoon)
193− ?~ fil.arch
194− ~
195− .^(cage %cs /===/cage/(scot %uv u.fil.arch))
196−[ p=%hoon
197− q
198− [ #t/@t
199− q
200−3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
201− ]
202−]
203−```
204−
205−### %open - Build prelude.
206−
207−This is like a `%a` scry but it only compiles the prelude to the file, e.g. the Ford rune imports. Proper documentation for this will be done as part of Ford documentaton at a later date.
208−
209−### %late - Latest case.
210−
211−This will return the most recent revision number of a `desk` that has been fully downloaded. The type it returns is a `cass:clay`. The `case` in the `beak` must be a revision number rather than a date. You can just provide a case of `1` since it returns the latest regardless. If we have nothing for the specified `desk`, this will just return the bunt of a `cass:clay` like `cass=[ud=0 da=~2000.1.1]`.
212−
213−Example:
214−
215−```
216−> .^(=cass:clay %cs /(scot %p (sein:title our now our))/base/1/late)
217−cass=[ud=50 da=~2021.4.22..10.38.50..57a8]
218−```
219−
220−```
221−> .^(=cass:clay %cs /~sampel/base/1/late)
222−cass=[ud=0 da=~2000.1.1]
223−```
224−
225−### %base - Merge-base.
226−
227−This will return the mergebase (i.e. most recent common ancestor) between two `desk`s. The type it returns is a `(list tako:clay)`. The first `desk` will just be the one in the `beak` `path` prefix and the second will be specified like `/ship/desk` at the end of the scry `path`. If there is no common ancestor between the two `desk`s, this will just produce an empty `list`.
228−
229−Examples:
230−
231−```
232−> .^((list tako:clay) %cs /===/base/(scot %p (sein:title our now our))/base)
233−~[102.787.244.596.033.419.950.995.540.301.493.841.569.518.772.322.508.085.465.561.801.703.148.627.263.473]
234−```
235−
236−```
237−> .^((list tako:clay) %cs /===/base/~sampel/base)
238−~
239−```
240−
241−## %t - List files.
242−
243−A scry with a `care` of `%t` will return a `(list path)` of all files in the given directory, or just a `(list path)` of the single file if it's a file. This is done recursively so will provide files in subdirectories as well. The paths will be fully qualified except for the `ship`, `desk` and `case`. If the directory or file specified does not exist, it will return an empty `list`.
244−
245−Examples:
246−
247−```
248−> .^((list path) %ct /===/app/landscape)
249−~[
250− /app/landscape/css/index/css
251− /app/landscape/img/favicon/png
252− /app/landscape/img/imageupload/png
253− /app/landscape/img/touch_icon/png
254− /app/landscape/index/html
255− /app/landscape/js/channel/js
256−]
257−```
258−
259−```
260−> .^((list path) %ct /===/gen/group-store/add/hoon)
261−~[/gen/group-store/add/hoon]
262−```
263−
264−```
265−> .^((list path) %ct /===/foobar)
266−~
267−```
268−
269−## %u - Check exists.
270−
271−A scry with a `care` of `%u` will return a `?` depending on whether the file exists. It will produce `%.n` if it's a directory or doesn't exist and will produce `%.y` if it's a file and exists.
272−
273−Examples:
274−
275−```
276−> .^(? %cu /===/app)
277−%.n
278−```
279−
280−```
281−> .^(? %cu /===/gen/code/hoon)
282−%.y
283−```
284−
285−```
286−> .^(? %cu /===/foobar)
287−%.n
288−```
289−
290−## %v - Desk state.
291−
292−A scry with a care of `%v` will return the entire state of a `desk` as a `dome:clay`.
293−
294−Example:
295−
296−```
297−> =a .^(dome:clay %cv /===)
298−> let.a
299−1
300−```
301−
302−Note: If you try printing this it will take forever and probably OOM your ship.
303−
304−## %w - Revision number.
305−
306−A scry with a `care` of `%w` will return the revision number and date of a given `case`. The type returned is a `cass:clay` like `[ud=@ud da=@da]` where `ud` is the revision number and `da` is the date.
307−
308−Example:
309−
310−```
311−> .^(cass:clay %cw /===)
312−[ud=2 da=~2021.4.13..19.12.49..3389]
313−```
314−
315−## %x - Read file.
316−
317−A scry with a `care` of `%x` will return the raw data of a file as an `@` or crash if it's a directory.
318−
319−Examples:
320−
321−```
322−> .^(@ %cx /===/gen/hood/hi/hoon)
323−3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
324−```
325−
326−```
327−> .^(@t %cx /===/gen/hood/hi/hoon)
328−':: Helm: send message to an urbit\0a::\0a:::: /hoon/hi/hood/gen\0a ::\0a/? 310\0a:- %say\0a|=([^ [who=ship mez=$@(~ [a=tape ~])] ~] helm-send-hi+[who ?~(mez ~ `a.mez)])\0a'
329−```
330−
331−```
332−> .^(@ %cx /===/gen/hood)
333−Crash!
334−```
335−
336−## %y - Read arch.
337−
338−A scry with a `care` of `%y` will return the `arch` of a file or directory.
339−
340−An `arch` is a `[fil=(unit lobe:clay) dir=(map @ta ~)]`. The `fil` will contain the `lobe:clay` hash if it's a file, otherwise it will be null. The `dir` will contain a map of the files and directories it contains, otherwise it will be null.
341−
342−It will return the bunt of an `arch` if the file or directory is not found.
343−
344−Examples:
345−
346−```
347−> .^(arch %cy /===/gen/group-store)
348−[ fil=~
349− dir
350− { [p=~.allow-ships q=~]
351− [p=~.add q=~]
352− [p=~.ban-ranks q=~]
353− [p=~.remove q=~]
354− [p=~.create q=~]
355− [p=~.join q=~]
356− [p=~.allow-ranks q=~]
357− [p=~.ban-ships q=~]
358− }
359−]
360−```
361−
362−```
363−> .^(arch %cy /===/gen/group-store/allow-ships)
364−[fil=~ dir={[p=~.hoon q=~]}]
365−```
366−
367−```
368−> .^(arch %cy /===/gen/group-store/allow-ships/hoon)
369−[fil=[~ 0vb.g8sqs.7gjm9.bl3vu.nk677.h5be1.g9eg3.4v1jo.00ivf.g8ndu.48a53] dir={}]
370−```
371−
372−```
373−> .^(arch %cy /===/foobar)
374−[fil=~ dir={}]
375−```
376−
377−## %z - Content hash.
378−
379−A scry with a `care` of `%z` will return the hash of a file or the recursive hash of a directory. If the file or directory doesn't exist it will return a null value.
380−
381−The type returned is a `@uxI`.
382−
383−Examples:
384−
385−```
386−> .^(@uvI %cz /===/gen)
387−0v5.itmhj.lt7ak.lgr1k.dr7vu.u7u9s.ko5rf.idfcr.ukrd2.t088n.3ml1k
388−```
389−
390−```
391−> .^(@uvI %cz /===/gen/code/hoon)
392−0v1t.vi1pf.3ba4n.87g6h.dcc1p.4t4l8.rm6a9.b4de4.v77qc.p9dc0.p8289
393−```
394−
395−```
396−> .^(@uvI %cz /===/foobar)
397−0v0
398−```
content/docs/arvo/clay/tasks.mddeleted−503
@@ -1,503 +0,0 @@
1−+++
2−title = "API Reference"
3−weight = 6
4−template = "doc.html"
5−+++
6−
7−This document details all the `task`s you're likely to use to interact with Clay, as well as the `gift`s you'll receive in response. Each section has a corresponding practical example in the [Examples](/docs/arvo/clay/examples) document. Many of the types referenced are detailed in the [Data Types](/docs/arvo/clay/data-types) document. It may also be useful to look at the `++ clay` section of `/sys/lull.hoon` in Arvo where these `task`s, `gift`s and data structures are defined.
8−
9−The focus of this document is on interacting with Clay from userspace applications and threads, so it doesn't delve into the internal mechanics of Clay from a kernel development perspective.
10−
11−## `%warp` - Read and track
12−
13−```hoon
14−[%warp wer=ship rif=riff]
15−```
16−
17−A `%warp` `task` is for reading and subscribing to files and directories.
18−
19−The `wer` field is the target ship. The `(unit rave)` of the [riff](/docs/arvo/clay/data-types#riff-clay-request-desist) is null to cancel an existing subscription, otherwise the [rave](/docs/arvo/clay/data-types#rave-clay-general-subscription-request) is tagged with one of:
20−
21−- `%sing` - Read a single file or directory.
22−- `%next` - Subscribe for the next change to a file or directory.
23−- `%mult` - Subscribe for the next change to a set of files and/or directories.
24−- `%many` - Track changes to a desk for the specified range of revisions.
25−
26−We'll look at each of these in more detail below.
27−
28−#### Returns
29−
30−Clay responds to a `%mult` request with a `%wris` `gift`, and the rest with a `%writ` `gift`.
31−
32−A `%wris` `gift` looks like:
33−
34−```hoon
35−[%wris p=[%da p=@da] q=(set (pair care path))] :: many changes
36−```
37−
38−...and a `%writ` `gift` looks like:
39−
40−```hoon
41−[%writ p=riot] :: response
42−```
43−
44−The `unit` of the [riot](/docs/arvo/clay/data-types#riot-clay-response) will be null if the target file cannot be found or if a subscription has ended (depending on context). Otherwise it will have a [rant](/docs/arvo/clay/data-types#rant-clay-response-data) with a `cage` containing the data you requested. Its contents will vary depending on the kind of request and `care`.
45−
46−Now we'll look at each of the `rave` request types in turn.
47−
48−### `%sing` - Read
49−
50−```hoon
51−[%sing =mood]
52−```
53−
54−This `rave` is for reading a single file or directory immediately.
55−
56−The `care` of the [mood](/docs/arvo/clay/data-types#mood-clay-single-subscription-request) will determine what you can read and what type of data will be returned. See the [care](/docs/arvo/clay/data-types#care-clay-clay-submode) documentation and [scry](/docs/arvo/clay/scry) documentation for details on the various `care`s.
57−
58−The [case](/docs/arvo/clay/data-types#case-specifying-a-commit) specifies the `desk` revision and you can use whichever kind you prefer. The `path` will usually be a path to a file or directory like `/gen/hood/hi/hoon` but may be something else depending on the `care`.
59−
60−#### Example
61−
62−[See here for an example of using %sing.](/docs/arvo/clay/examples#sing)
63−
64−### `%next` - Await next
65−
66−```hoon
67−[%next =mood] :: await next version
68−```
69−
70−This subscribes to the next version of the specified file. See [here](/docs/arvo/clay/data-types#mood-clay-single-subscription-request) for details of the `mood` structure.
71−
72−If you subscribe to the current `case` of the `desk`, Clay will not respond until the file changes. If you subscribe to a previous `case` of the `desk` and the file has changed in between then and now, it will immediately return the first change it comes across in that range. For example, if you're currently at `case` `100`, subscribe to case `50` and the file in question has been modified at both `60` and `80`, clay will immediately return the version of the file at `case` `60`.
73−
74−#### Example
75−
76−[See here for an example of using %next.](/docs/arvo/clay/examples#next)
77−
78−### `%mult` - Next of any
79−
80−```hoon
81−[%mult =mool]
82−```
83−
84−This subscribes to the next version of a `set` of files or directories. Clay will only send a single response, and it will send it when _any_ of the specified files change. For example, if you subscribe to both `/foo/txt` and `/bar/txt`, and only `/foo/txt` changes, Clay will send a response indicating a change to `/foo/txt`. If `/bar/txt` changes subsequently, it will not tell you. If more than one file changes at once, it will tell you about each of the changes in the one response.
85−
86−The behaviour with respect to requesting old `case`s is the same as explained in the [`%next`](#next---await-next) section above.
87−
88−The `mool` specified in the request is this structure:
89−
90−```hoon
91−+$ mool [=case paths=(set (pair care path))] :: requests in desk
92−```
93−
94−You can use a different `care` for each of the files specified by the `path` if you like. Significantly, the `care` will determine whether Clay sends a response for a given change. For example, if you subscribe to an existing `/foo/txt` with a `%u` `care` and `/foo/txt` is modified but isn't deleted, Clay will _not_ tell you. However, if you subscribe with an `%x` `care`, it _will_ tell you.
95−
96−#### Example
97−
98−[See here for an example of using %mult.](/docs/arvo/clay/examples#mult)
99−
100−### `%many` - Track range
101−
102−```hoon
103−[%many track=? =moat]
104−```
105−
106−This subscribes to all changes to a `desk` for the specified range of `case`s. Note that you're unlikely to use this directly, it's mostly used implicitly if you make a `%sing` or `%next` request with a `%v` `care` to a foreign `desk`. Regardless, we'll have a look at it for completeness.
107−
108−If the `track` is `%.y` it will just return a `%writ` like:
109−
110−```hoon
111−[%writ p=[~ [p=[p=%w q=[%ud p=256] r=%base] q=/ r=[p=%null q=[#t/@n q=0]]]]]
112−```
113−
114−...that merely informs you of a change. If you want the actual data you'll have to request it separately.
115−
116−If the `track` is `%.n`, the `cage` of the `%writ` will contain a [nako](/docs/arvo/clay/data-types#nako-subscription-response-data) with the relevant data for all changes to a desk between what you have and the `case` requested. It is very large and fairly complicated. The `nako` structure is defined in the `clay.hoon` source file itself rather than in `lull.hoon` or elsewhere since you're unlikely to work with it yourself.
117−
118−The `from` and `to` fields of the [moat](/docs/arvo/clay/data-types#moat-clay-range-subscription-request) specify the range of `case`s for which to subscribe. The range is _inclusive_. It can be specified by date or by revision number, whichever you prefer.
119−
120−The `path` in the `moat` is a path to a file or directory. If it's `~` it refers to the root of the `desk` in question. This lets you say "only inform me of changes to the `desk` if the specified file or directory exists". If it doesn't exist, Clay will not send you anything.
121−
122−When you reach the end of the subscribed range of `case`s, Clay will send you a `%writ` with a null `riot` to inform you the subscription has ended like:
123−
124−```hoon
125−[%writ p=~]
126−```
127−
128−#### Example
129−
130−[See here for an example of using %many.](/docs/arvo/clay/examples#many)
131−
132−### Cancel Subscription
133−
134−To cancel a subscription, you just send a `%warp` with a null `(unit rave)` in the `riff`. Clay will cancel the subscription based on the `wire`. The request is exactly the same regardless of which type of `rave` you subscribed with originally.
135−
136−#### Example
137−
138−[See here for an example of cancelling a subscription.](/docs/arvo/clay/examples#cancel-subscription)
139−
140−## Write and Modify
141−
142−### `%info` - Write
143−
144−```hoon
145−[%info des=desk dit=nori]
146−```
147−
148−To write or modify a file, we send Clay a `%info` `task`.
149−
150−The `%|` tag in the [nori](/docs/arvo/clay/data-types#nori-clay-repository-action) is not currently supported and will crash with a `%labelling-not-implemented` if used, so you can focus on the `%&` part. The [soba](/docs/arvo/clay/data-types#soba-clay-delta) in the `nori` is just a list of changes so you can make more than one change in one request. Its `path` is just the path to a file like `/gen/hood/hi/hoon` and the [miso](/docs/arvo/clay/data-types#miso-clay-ankh-delta) is one of these types of requests:
151−
152−- `%del` - Delete a file.
153−- `%ins` - Insert file. This will also replace an existing file.
154−- `%dif` - This has not yet been implemented so will crash with a `%dif-not-implemented` error.
155−- `%mut` - Change a file. At the time of writing this behaves identically to `%ins` so its use merely informs the reader.
156−
157−#### Returns
158−
159−Clay does not give any response to an `%info` `task` so don't expect a `sign` back.
160−
161−#### Example
162−
163−Here are examples of using each of these as well as making multiple changes in one request:
164−
165−- [%del](/docs/arvo/clay/examples#del)
166−- [%ins](/docs/arvo/clay/examples#ins)
167−- [%mut](/docs/arvo/clay/examples#mut)
168−- [Multiple Changes](/docs/arvo/clay/examples#multiple-changes)
169−
170−## Manage Mounts
171−
172−Here we'll look at managing Clay unix mounts programmatically.
173−
174−There are four Clay `task`s relevant to mounts:
175−
176−- [%boat](#boat---list-mounts) - List mounts.
177−- [%mont](#mont---mount) - Mount something.
178−- [%ogre](#ogre---unmount) - Unmount something.
179−- [%dirk](#dirk---commit) - Commit changes.
180−
181−### `%boat` - List mounts
182−
183−```hoon
184−[%boat ~]
185−```
186−
187−A `%boat` `task` requests the list of existing mounts and does not take any arguments.
188−
189−#### Returns
190−
191−The type it returns is a `%hill` `gift`, which looks like:
192−
193−```hoon
194−[%hill p=(list @tas)]
195−```
196−
197−...where the `@tas` is the name of the mount point.
198−
199−#### Example
200−
201−[See here for an example of using %boat.](/docs/arvo/clay/examples#boat)
202−
203−### `%mont` - Mount
204−
205−```hoon
206−[%mont pot=term bem=beam]
207−```
208−
209−A `%mont` `task` mounts the specified `beam` to the specified `term` mount point.
210−
211−A `beam:clay` is the following structure:
212−
213−```hoon
214−+$ beam [[p=ship q=desk r=case] s=path] :: global name
215−```
216−
217−You can mount the whole desk with a `path` of `/`, and you can also mount subdirectories or even individual files. If you want to mount an individual file, you must exclude its `mark` from the path. For example, if you want to mount `/gen/hood/hi/hoon`, you'd specify `/gen/hood/hi`. It will automatically be given the correct file extension when mounted. If you include the `hoon` mark it will crash (and currently crash your ship).
218−
219−#### Returns
220−
221−Clay does not return a `gift` in response to a `%mont` `%task`.
222−
223−#### Example
224−
225−[See here for an example of using %mont.](/docs/arvo/clay/examples#mont)
226−
227−### `%ogre` - Unmount
228−
229−```hoon
230−[%ogre pot=$@(desk beam)]
231−```
232−
233−A `%ogre` `task` unmounts the specified mount.
234−
235−It's defined in `lull.hoon` as taking `$@(desk beam)` but in fact it will only unmount the target when specified as a `term` mount name. Passing it a `desk` will incidentally work if the mount is named the same as the `desk` but otherwise it won't work. Passing it a `beam:clay` will simply not work.
236−
237−#### Returns
238−
239−Clay does not return a `gift` in response to a `%ogre` `task`.
240−
241−#### Example
242−
243−[See here for an example of using %ogre.](/docs/arvo/clay/examples#ogre)
244−
245−### `%dirk` - Commit
246−
247−```hoon
248−[%dirk des=desk]
249−```
250−
251−A `%dirk` `task` commits changes in the target mount.
252−
253−It's defined in `lull.hoon` as taking a `desk` but like [%ogre](#ogre---unmount), it actually takes the name of a mount point rather than a `desk` as is specified.
254−
255−#### Returns
256−
257−Clay does not return a `gift` in response to a `%dirk` `task`.
258−
259−#### Example
260−
261−[See here for an example of using %dirk.](/docs/arvo/clay/examples#dirk)
262−
263−## Merge Desks
264−
265−### `%merg` - Merge
266−
267−```hoon
268−$: %merg
269− des=desk :: target
270− her=@p dem=desk cas=case :: source
271− how=germ :: method
272−==
273−```
274−
275−A `%merg` `task` will merge the specified source `desk` into the target local `desk`.
276−
277−The `germ` specifies the merge strategy. You can refer to the [Strategies](/docs/arvo/clay/using#strategies) section of the [Using Clay](/docs/arvo/clay/using) document for details of each `germ`.
278−
279−If you're merging into a new `desk` you must use `%init`, all other strategies will fail. If the desk already exists, you cannot use `%init`. Otherwise, you're free to use whichever you'd like.
280−
281−#### Returns
282−
283−Clay will respond to the request with a `%mere` `gift` which looks like:
284−
285−```hoon
286−[%mere p=(each (set path) (pair term tang))] :: merge result
287−```
288−
289−If the merge succeeded, `p` will look like `[%mere p=[%.y p={}]]` where `p.p` is the set of files which had a merge conflict. For example, `[%mere p=[%.y p={/foo/txt}]]` means there was a conflict with `/foo/txt`. An empty set means there were no conflicts.
290−
291−If the merge failed, `p` will have a head of `%.n` and then a `[term tang]` where the `term` is an error message and the `tang` contains additional details, for example:
292−
293−```hoon
294−[ %mere
295− p
296− [ %.n
297− p=[p=%mate-conflict q=~[[%rose p=[p="/" q="/" r=""] q=~[[%leaf p="foo"] [%leaf p="txt"]]]]]
298− ]
299−]
300−```
301−
302−#### Example
303−
304−[See here for an example of using %merg.](/docs/arvo/clay/examples#merg)
305−
306−## Permissions
307−
308−For each file or directory, there is both a read permission and a write permission. Each may be set separately and is either a whitelist or a blacklist (but not both). The whitelist/blacklist contains a `set` of ships and/or groups which are allowed or banned respectively. If it's an empty whitelist it means all foreign ships are denied. If it's an empty blacklist it means all foreign ships are allowed.
309−
310−If permissions are not set for a particular file, they will be inherited from the directory in which it resides. If _that_ directory has no permissions set, they will be inherited from another level up, and so on to the `desk`'s root directory. If the root directory has no permissions set, it will have the default permissions of an empty whitelist, meaning "deny all".
311−
312−A group is called a `crew` and is just a `set` of ships with a `@ta` name.
313−
314−The permissions for each file or directory are a pair of `dict:clay` where the head is read permissions and the tail is write permissions.
315−
316−A `dict:clay` is this structure:
317−
318−```hoon
319−+$ dict [src=path rul=real] :: effective permission
320−```
321−
322−The `src` path is where the permissions were inherited from and the `real` is this structure:
323−
324−```hoon
325− +$ real :: resolved permissions
326− $: mod=?(%black %white) ::
327− who=(pair (set ship) (map @ta crew)) ::
328− == ::
329−```
330−
331−So if we scry for permissions with a `%p` `care`, it'll look like:
332−
333−```hoon
334−> .^([r=dict:clay w=dict:clay] %cp /===/lib/strandio/hoon)
335−[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
336−```
337−
338−There are four permission-related `task`s which you can pass to Clay.
339−
340−A `%perm` `task` is for setting permissions, and the other three are for managing groups:
341−
342−- `%cred` - Add permission group.
343−- `%crew` - Get permission groups.
344−- `%crow` - Get group usage.
345−
346−We'll look at each of these in turn.
347−
348−### `%perm` - Set perms
349−
350−```hoon
351−[%perm des=desk pax=path rit=rite]
352−```
353−
354−A `%perm` `task` sets permissions for the target file or directory.
355−
356−Note this will replace existing permissions rather than add to them, so if you want to add a ship to an existing whitelist or whatever you'll have to first read the existing permissions, add the ship, then send the whole lot back.
357−
358−The `pax` path is the file or directory whose permissions you want to change, and the `rite` is this structure:
359−
360−```hoon
361−+$ rite :: new permissions
362− $% [%r red=(unit rule)] :: for read
363− [%w wit=(unit rule)] :: for write
364− [%rw red=(unit rule) wit=(unit rule)] :: for read and write
365− ==
366−```
367−
368−Where a `rule` is this structure:
369−
370−```hoon
371−+$ rule [mod=?(%black %white) who=(set whom)] :: node permission
372−```
373−
374−...and finally `whom` is this:
375−
376−```hoon
377−+$ whom (each ship @ta) :: ship or named crew
378−```
379−
380−As the comment suggests, the `@ta` is the name of a `crew` (group).
381−
382−#### Returns
383−
384−Clay does not return a `gift` in response to a `%perm` `task`.
385−
386−#### Example
387−
388−[See here for an example of using %perm.](/docs/arvo/clay/examples#perm)
389−
390−### `%cred` - Add group
391−
392−```hoon
393−[%cred nom=@ta cew=crew]
394−```
395−
396−This simply creates a permission group.
397−
398−The `nom` is a name for the group and the `crew` is just a `(set ship)`:
399−
400−```hoon
401−+$ crew (set ship) :: permissions group
402−```
403−
404−#### Returns
405−
406−Clay does not return a `gift` in response to a `%cred` `task`.
407−
408−#### Example
409−
410−[See here for an example of using %cred.](/docs/arvo/clay/examples#cred)
411−
412−### `%crew` - Get groups
413−
414−```hoon
415−[%crew ~]
416−```
417−
418−This retrieves all permission groups.
419−
420−A `%crew` `task` takes no arguments.
421−
422−#### Returns
423−
424−Clay wil return a `%cruz` `gift`. It looks like:
425−
426−```hoon
427−[%cruz cez=(map @ta crew)] :: permission groups
428−```
429−
430−The `cez` is just a map from group name to `crew` which is just a `(set ship)`.
431−
432−#### Example
433−
434−[See here for an example of using %crew.](/docs/arvo/clay/examples#crew)
435−
436−### `%crow` - Group files
437−
438−```hoon
439−[%crow nom=@ta]
440−```
441−
442−A `%crow` `task` retrieves all files and directories in all `desk`s which have permissions set for the group in question. It will not return inherited permissions, only those explicitly set.
443−
444−The `nom` is the name of a `crew`.
445−
446−#### Returns
447−
448−The `gift` you get back is a `%croz` which looks like:
449−
450−```hoon
451−[%croz rus=(map desk [r=regs w=regs])] :: rules for group
452−```
453−
454−...where `regs` is this structure:
455−
456−```hoon
457−+$ regs (map path rule) :: rules for paths
458−```
459−
460−#### Example
461−
462−[See here for an example of using %crow.](/docs/arvo/clay/examples#crow)
463−
464−## Foreign Ships
465−
466−Here we'll looking at making Clay requests to a foreign ship.
467−
468−As it currently stands, it's not possible to write to a foreign `desk`. Additionally, remote scries are not implemented. That leaves requests to read files (`%warp`) and merge desks (`%merg`), which we'll look at next.
469−
470−### `%warp` - Remote
471−
472−To read files on a foreign `desk`, you just send Clay a `%warp` `task` (as you would for a local read) and specify the target ship in the `wer` field. For details on making such requests, see the [Read and Subscribe](#warp---read-and-track) section.
473−
474−Clay only allows a subset of `care`s to be used remotely. They are:
475−
476−- `%u` - Check for existence of file.
477−- `%v` - Get entire `dome:clay` state of a desk.
478−- `%w` - Get revision number.
479−- `%x` - Get data of file.
480−- `%y` - Get `arch` of file or directory.
481−- `%z` - Get content hash of file or directory.
482−
483−Any other `care` will crash with a `%clay-bad-foreign-request-care` error.
484−
485−The foreign ship will respond only if correct permissions have been set. See the [Permissions](#permissions) section for details.
486−
487−Note that if you're reading a whole `desk` or directory, all subfolders and files must also permit reading. If even a single file does not permit you reading it, the foreign ship will not respond to the request.
488−
489−#### Example
490−
491−[See here for examples of requests to foreign ships.](/docs/arvo/clay/examples#foreign-ships)
492−
493−### `%merg` - Remote
494−
495−To merge a foreign `desk` into a local one, you just send Clay a `%merg` `task` (as you would for a local merge) and specify the foreign ship in the `her` field. For details on making such requests, see the [Merge Desks](#merge-desks) section.
496−
497−The foreign ship will respond only if correct permissions have been set. See the [Permissions](#permissions) section for details.
498−
499−Note that all subfolders and individual files within the `desk` must permit your reading in order for the merge to succeed. If even one file does not permit you reading it, the remote ship will not respond to the request at all.
500−
501−#### Example
502−
503−[See here for examples of requests to foreign ships.](/docs/arvo/clay/examples#foreign-ships)
content/docs/arvo/clay/using.mddeleted−223
@@ -1,223 +0,0 @@
1−+++
2−title = "Using Clay"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−### Reading and Subscribing
8−
9−When reading from Clay, there are three types of requests. A
10−`%sing` request asks for data at single revsion. A `%next`
11−request asks to be notified the next time there's a change to
12−given file. A `%many` request asks to be notified on every
13−change in a `desk` for a range of changes.
14−
15−For `%sing` and `%next`, there are generally three things to be
16−queried. A `%u` request simply checks for the existence of a
17−file at a path. A `%x` request gets the data in the file at a
18−path. A `%y` request gets a hash of the data in the file at the
19−path combined with all its children and their data. Thus, `%y`
20−of a node changes if it or any of its children change.
21−
22−A `%sing` request is fulfilled immediately if possible. If the
23−requested revision is in the future, or is on another ship for
24−which we don't have the result cached, we don't respond
25−immediately. If the requested revision is in the future, we wait
26−until the revision happens before we respond to the request. If
27−the request is for data on another ship, we pass on the request
28−to the other ship. In general, Clay subscriptions, like most
29−things in Urbit, aren't guaranteed to return immediately.
30−They'll return when they can, and they'll do so in a
31−referentially transparent manner.
32−
33−A `%next` request checks the query at the given revision, and it
34−produces the result of the query the next time it changes, along
35−with the revision number when it changes. Thus, a `%next` of a
36−`%u` is triggered when a file is added or deleted, a `%next` of a
37−`%x` is triggered when a file is added, deleted, or changed, and
38−a `%next` of a `%y` is triggered when a file or any of its
39−children is added, deleted, or changed.
40−
41−A `%many` request is triggered every time the given `desk` has a
42−new revision. Unlike a `%next`, a `%many` has both a start and
43−an end revision, after which it stops returning. For `%next`, a
44−single change is reported, and if the caller wishes to hear of
45−the next change, it must resubscribe. For `%many`, every revision
46−from the start to the end triggers a response. Since a `%many`
47−request doesn't ask for any particular data, there aren't `%u`,
48−`%x`, and `%y` versions for it.
49−
50−### Unix sync
51−
52−Usage:
53−
54−```
55−|mount %/path/to/directory %mount-point
56−|commit %mount-point
57−|autocommit %mount-point
58−```
59−
60−One of the primary functions of Clay is as a convenient user
61−interface. While tools exist to use Clay from within Urbit, it's
62−often useful to be able to treat Clay like any other filesystem
63−from the Unix perspective -- to "mount" it, as it were.
64−
65−From the dojo, you can run `|mount %/path/to/directory %mount-point`, and this
66−will mount the given Clay directory to the mount-point directory in Unix, with
67−your pier as the root directory. For example `|mount %/gen %generators` will
68−create a `/generators` directory in your pier, and mount the `/gen` folder at
69−that point. If you'd like to use the directory name as the mount point, you can
70−elide the last argument, e.g. `|mount %/gen` mounts `/gen` to `/gen`.
71−
72−Every file is converted to `%mime` before it's written to Unix, and converted
73−back when read from Unix. The entire directory is watched (a la Dropbox), and
74−every change is committed once you run `|commit %mount-point`. Every change can
75−be automatically committed with `|autocommit %mount-point`.
76−
77−### Merging
78−
79−Usage:
80−
81−```
82−|merge %target-desk ~source-ship %source-desk
83−|merge %target-desk ~source-ship %source-desk, =gem %strategy
84−|merge %target-desk ~source-ship %source-desk, =cas ud+5
85−```
86−
87−Clay supports various merge strategies. A "commit" is a snapshot of
88−the files with a list of parents plus a date. Most commits have
89−one parent; a "merge" commit is a commit with two parents. The
90−`%base` `desk` starts with an initial commit with no parents; commits
91−with several parents ("octopus merges") are possible but we don't
92−generate them right now.
93−
94−Unless otherwise specified, all of the following create a new commit
95−with the source and destination commits as parents.
96−
97−Several strategies need a "merge-base". They find it by identifying
98−the most recent common ancestor of the two `desk`s. If none, fail
99−with `%merge-no-merge-base`; if there are two or more, pick one.
100−
101−#### Strategies
102−
103−**`%init`**: the only way to create a `desk`. Not a true merge, since it
104−simply assigns the source commit to the destination.
105−
106−**`%fine`**: if source or destination are in the ancestry of each other,
107−use the newer one; else abort. If the destination is ahead of the
108−source, succeed but do nothing. If the source is ahead of the
109−destination, assign the next revision number to the source commit.
110−Some call this "fast-forward".
111−
112−**`%meet`**: combine changes, failing if both sides changed the same file.
113−Specifically, take diff(merge-base,source) and
114−diff(merge-base,destination) and combine them as long as those diffs
115−touch different files.
116−
117−**`%mate`**: combine changes, failing if both sides changed the same part
118−of a file. Identical to `%meet`, except that some marks, like `%hoon`,
119−allow intelligent merge of changes to different parts of a file.
120−
121−**`%meld`**: combine changes; if both sides changed the same part of a
122−file, use the version of the file in the merge-base.
123−
124−**`%only-this`**: create a merge commit with exactly the contents of the
125−destination `desk`.
126−
127−**`%only-that`**: create a merge commit with exactly the contents of the
128−source commit.
129−
130−**`%take-this`**: create a merge commit with exactly the contents of the
131−destination `desk` except take any files from the source commit which
132−are not in the destination `desk`.
133−
134−**`%take-that`**: create a merge commit with exactly the contents of the
135−source commit except preserve any files from the destination `desk`
136−which are not in the source commit.
137−
138−**`%meet-this`**: merge as in `%meet`, except if both sides changed the same
139−file, use the version in the destination `desk`.
140−
141−**`%meet-that`**: merge as in `%meet`, except if both sides changed the same
142−file, use the version in the source commit.
143−
144−#### Examples and notes:
145−
146−The most common merge strategy is `%mate`, which is a normal 3-way
147−merge which aborts on conflict.
148−
149−`%take-that` is useful to "force" an OTA. After running `%take-that`,
150−you're guaranteed to have exactly the files in the source commit plus
151−any files you separately added.
152−
153−We speak of merging into a destination _`desk`_ from a source _commit_
154−because while you can only merge on top of a `desk`, you can merge from
155−historical commits. For example,
156−
157−```
158−|merge %old our %base, =cas ud+5, =gem %init
159−```
160−
161−will create a new `desk` called `%old` with the 5th commit in `%base`.
162−You can revert the contents of a `desk` to what they were yesterday
163−with
164−
165−```
166−|merge %base our %base, =cas da+(sub now ~d1), =gem %only-that
167−```
168−
169−Note this is a normal `%only-that merge`, which means you're creating a
170−_new_ commit with the old _contents_.
171−
172−`%meld` is rarely used on its own, however if you specify `%auto` or
173−omit the merge strategy, `%kiln` will run a `%meld` merge into a scratch
174−`desk` and then annotate the conflicts there.
175−
176−If you resolve merge conflicts manually, for example by mounting the
177−`desk`s, copying the files in Unix and then running `|commit`, you
178−should usually run an `%only-this merge`. This will not change the
179−newly-fixed contents of your `desk`, but it will record that the merge
180−happened so that those conflicts don't reappear in later merges.
181−
182−If you get a `%merge-no-merge-base` error, this means you're trying to
183−merge two `desk`s which have no common ancestors. You need to give
184−them a common ancestor by choosing a merge strategy which doesn't
185−need a merge-base, like `%only-this`, `%only-that`, `%take-this`, or
186−`%take-that`.
187−
188−`%take-this` could be useful to install 3rd party software, but you
189−couldn't get subsequent updates this way, since the files would
190−already exist in the destination `desk`. Something like "take only
191−the files which aren't in my OTA source or any other 3rd party app"
192−would be basically correct. This would require a parameter listing
193−the `desk`s to not conflict with.
194−
195−`%meet-this` and `%meet-that` imply the existence of `%mate-this` and
196−`%mate-that`, but those don't exist yet.
197−
198−### Autosync
199−
200−Usage:
201−
202−```
203−|sync %target-desk ~source-ship %source-desk
204−```
205−
206−Tracking and staying in sync with another `desk` is another
207−fundamental operation. We call this "autosync". This doesn't mean
208−simply mirroring a `desk`, since that wouldn't allow local changes.
209−We simply want to apply changes as they are made upstream, as
210−long as there are no conflicts with local changes.
211−
212−This is implemented by subscribing to changes to the other `desk`, with a
213−`%many` request and, when it has changes, merging these changes into our `desk`
214−with the usual merge strategies.
215−
216−Note that it's quite reasonable for two `desk`s to be autosynced to
217−each other. This results in any change on one `desk` being mirrored
218−to the other and vice versa.
219−
220−Additionally, it's fine to set up an autosync even if one `desk`,
221−the other `desk`, or both `desk`s do not exist. The sync will be
222−activated when the upstream `desk` comes into existence and will
223−create the downstream `desk` if needed.
content/docs/arvo/concepts/_index.mddeleted−17
@@ -1,17 +0,0 @@
1−+++
2−title = "Concepts"
3−weight = 100
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−Other concepts related to the way Arvo works.
10−
11−## [Scries](/docs/arvo/concepts/scries)
12−
13−Details of performing scries.
14−
15−## [Subscriptions](/docs/arvo/concepts/subscriptions)
16−
17−Urbit relies heavily on subscriptions throughout the stack. We strongly prefer reactive data flow compared to querying or polling, which is why for example our equivalent to git natively supports subscriptions to its data.
content/docs/arvo/concepts/scry.mddeleted−77
@@ -1,77 +0,0 @@
1−+++
2−title = "Scries"
3−weight = 40
4−template = "doc.html"
5−+++
6−
7−### What is a scry?
8−
9−A scry is a read-only request to Arvo's global namespace.
10−
11−Vanes and agents define _scry endpoints_ which allow one to request data from their respective states. The endpoints can process the data in any way before returning it, but they cannot alter the actual state - scries can _only_ read, not modify.
12−
13−### Why scry?
14−
15−The subject available in something like a Gall agent or thread contains a great many functions and structures from the standard library as well as `zuse` and `lull`, but it does not include any of the actual data stored elsewhere in the ship. All it has is its own state, a `bowl` and any `card`s it has been passed. Ordinarily, in order to access such data, one would need to `%poke` or `%watch` other agents, or `%pass` `task`s to vanes, then wait for a response. Arvo's scry system is the one exception to this; it allows direct retrieval of data from other vanes or agents in situ, from any context, without any of the normal messaging rigmarole.
16−
17−### How do I scry?
18−
19−Scries are performed exclusively with the dotket rune: `.^`
20−
21−For details of its usage, see the [dotket](/docs/hoon/reference/rune/dot#-dotket) section of the Nock rune documentation. In addition to the dotket documentation, below is a colour-coded diagram breaking down the structure of a dotket scry expression with some additional notes.
22−
23−![Scry diagram](https://media.urbit.org/docs/arvo/scry-diagram-v2.svg)
24−
25−One further note on `care`s (which can sometimes be confusing): While `care`s are part of the global namespace, they're most extensively used by Clay in particular. In Clay, `care`s specify Clay submodules with specific behaviour, and are used both in scries as well as `task`s and `gift`s. For example, a `%x` `care` reads the data of a file, a `%p` `care` reads file permissions, and so forth. To see all of Clay's `care`s and what they do, you can refer to Clay's [Scry Reference](/docs/arvo/clay/scry).
26−
27−Most other vanes also make use of `care`s in their scry endpoints. While such vanes don't have corresponding submodules with strictly defined behaviour like Clay, the `care`s still confer the general nature of the endpoint. The most widely used `care` is `%x`, which implies reading data in a general sense. Gall has special handling of `%x` scries as described in the [Gall agents](#gall-agents) section below, but otherwise `care`s have no special behaviour for non-Clay vanes (though they must still be included if the endpoint specifies it).
28−
29−### What can I scry?
30−
31−There are two places where scry endpoints are defined:
32−
33−#### Vanes
34−
35−Each of Arvo's eight vanes (kernel modules) include a `+scry` arm which defines that vane's scry endpoints. The number of endpoints and extent of data available varies between vanes. For example, Clay has a very extensive set of scry endpoints which provide read access to all files in all desks across all revisions, as well as the ability to build files, perform `mark` conversions, and various other functions. Jael provides access to a great deal of PKI data. On the other hand, Dill has only a couple of endpoints which are mostly useful for debugging, and Iris has none at all (apart from standard memory reporting endpoints you'd not typically use in your applications).
36−
37−To explore what scry endpoints are available for vanes, you can refer to the Scry Reference section of each vane in the [Arvo](/docs/arvo/overview) section of the documents.
38−
39−#### Gall agents
40−
41−Gall has a single scry endpoint of its own to check for the existence of an agent, but otherwise all Gall scries are passed through to one of the agents it manages. The target agent to scry is specified in place of the `desk` as described in the diagram above. Each Gall agent includes a `+on-peek` arm that defines its own scry endpoints. For example, `%graph-store` has a number of scry endpoints to access the data it stores, such as chat messages and the like.
42−
43−Gall agents can expose scry endpoints with any `care`, but most commonly they'll take a `%x` `care`. Gall handles `%x` scries specially - it expects an extra field at the end of the `path` that specifies a `mark`. Gall will attempt to perform a `mark` conversion from the `mark` returned by the scry endpoint to the `mark` specified. Note the trailing `mark` in the `path` will not be passed through to the agent itself.
44−
45−### What is an endpoint?
46−
47−"Endpoint" refers to a specific scry path in a vane or agent. They will sometimes informally be noted in documentation or source comments like `/x/foo/bar/baz` or maybe just `/foo/bar/baz`. The first part of the former example is the `care`, then the rest is the `path` portion as noted in the diagram earlier.
48−
49−If an agent's scry endpoints don't have formal documentation, you may need to refer to the `+on-peek` arm in its source code to determine its endpoints. While there's no exact pattern that's consistent across different agents, the general pattern will be some initial tests and conversions followed by a `?+` rune, whose cases will typically correspond to the endpoints. The `+on-peek` arm always return a `(unit (unit cage))` (a `cage` is a cell of `[mark vase]`), so each endpoint will typically finish by composing such a structure.
50−
51−Here's an example from the `+on-peek` arm of `%graph-store`:
52−
53−```hoon
54− [%x %keys ~]
55−:- ~ :- ~ :- %graph-update-2
56−!>(`update:store`[now.bowl [%keys ~(key by graphs)]])
57−```
58−
59−The case in the beginning says it takes a `%x` `care` and has a `path` of `/keys`. Additionally, it returns data with a `mark` of `%graph-update-2`. Assuming we wanted the `%graph-update-2` `mark` converted to a `%json` `mark`, our scry would be composed along the lines of:
60−
61−```hoon
62−.^(json %gx /(scot %p our)/graph-store/(scot %da now)/keys/json)
63−```
64−
65−### Web scries
66−
67−The webserver vane Eyre has a system which allows clients like web browsers to perform scries over HTTP. For details, refer to the [Scry section of Eyre's External API Reference](/docs/arvo/eyre/external-api-ref#scry).
68−
69−### Further reading
70−
71−[dotket](/docs/hoon/reference/rune/dot#-dotket) - Documentation of the `.^` rune which performs scries.
72−
73−[Arvo](/docs/arvo/overview) - Each vane has a Scry Reference section with details of their endpoints as well as examples.
74−
75−[Eyre's External API Reference](/docs/arvo/eyre/external-api-ref#scry) - Documentation of Eyre's scry system which allows web clients to perform scries over HTTP.
76−
77−[The Gall Guide](/docs/userspace/gall-guide/intro) - The Gall tutorial includes a section about `+on-peek` and writing scry endpoints.
content/docs/arvo/concepts/subscriptions.mddeleted−162
@@ -1,162 +0,0 @@
1−+++
2−title = "Subscriptions"
3−weight = 50
4−template = "doc.html"
5−+++
6−
7−Urbit relies heavily on subscriptions throughout the stack. We strongly
8−prefer reactive data flow compared to querying or polling, which is why
9−for example our equivalent to git natively supports subscriptions to its
10−data.
11−
12−We have many application-level styles of subscription, but we only have
13−three true subscription types in Arvo, named for the vane they're
14−implemented in: Clay subscriptions (filesystem), Gall subscriptions
15−(applications), and Jael subscriptions (Urbit ID info). They're at
16−three different points in the idea maze of subscriptions, and we'll
17−encounter each of them here.
18−
19−For our purposes, a subscription is a stream of events from a publisher
20−to a subscriber, where (1) the publisher has indicated interest in that
21−stream, (2) any update sent to one subscriber is sent to all subscribers
22−on the same stream, and (3) when the publisher has a new update ready,
23−they send it immediately to their subscribers instead of waiting for a
24−later request.
25−
26−## Basic properties
27−
28−### Exactly-once updates
29−
30−Some subscriptions need the subscriber to receive each update separately
31−instead of collapsing them into a single diff. Sometimes a subscription
32−is really a sequence of commands, in which case there's no meaningful
33−way to collapse them. Similarly, software updates may be expected to be
34−applied in order.
35−
36−### Syncing data
37−
38−Other times, it's more natural to think of a subscription as
39−communicating a data structure, where the only goal is to keep the data
40−structure on the subscriber's side up-to-date with what's on the
41−publisher's side. In this case, it's perfectly fine to collapse several
42−updates into one large update, or even to resend the entire data
43−structure. Partial updates exist only as an optimization.
44−
45−For this sort of subscription, we commonly use terms like "diff" instead
46−of "message" or "update", and we say that we "apply a diff" instead of
47−"process an update". We also often identify the subscription with the
48−data structure itself.
49−
50−## Memory pressure
51−
52−Naively implemented, subscriptions pose a memory leak risk if the
53−subscriber can't receive updates as fast as the publisher wants to send
54−them. This commonly happens when the subscriber goes offline for an
55−extended period of time (possibly forever; especially for comets). It's
56−sufficient to bound the amount of memory dedicated to any particular
57−subscriber.
58−
59−In a synchronous system, you don't have to worry about what happens if
60−one side or the other ceases to be available. All of our subscriptions,
61−though, can happen between ships.
62−
63−### Small data
64−
65−For particularly low-volume subscriptions, it may be acceptable to
66−ignore the problem. Jael uses this approach, since the only time it's
67−used across ships is to update moon keys, which is very low-volume and
68−less than 1KB per update. If these subscriptions are used for more,
69−this strategy will have to be revisited.
70−
71−### Buffers
72−
73−A common solution to this problem is the venerable buffer. If more than
74−N updates need to be sent, start dropping updates. There are several
75−options for what to do when the buffer is full and the publisher wishes
76−to send another message:
77−
78−- Drop the oldest message. Particularly suitable for systems where new
79− messages obsolete old ones. For example, if you just need the latest
80− ticker price for an asset, you could use a buffer size of one and
81− replaced it any time you have a new price.
82−
83−- Don't add the new message to the buffer. Semantically this is usually
84− less helpful, but mechanically it can be simpler and reduce memory
85− churn, since the buffer stops changing and new messages are simply
86− ignored.
87−
88−- Drop the newest message and close the subscription. Unlike the
89− previous two, this is compatible with the principle of exactly-once
90− messaging. Specifically, it preserves the guarantee that you won't
91− receive two non-consecutive subscription updates, at the cost of making
92− you resubscribe if you fall behind.
93−
94−Gall subscriptions use the last of these. The buffer is bounded by a
95−simple heuristic, and when a subscription exceeds that buffer, it is
96−closed and the app is expected to resubscribe when they come back
97−online. Note that even though the subscription is closed, messages in
98−flight cannot be removed until they've been acknowledged since Ames
99−guarantees exactly-once messaging, so those last few messages will be
100−stuck in memory until the subscriber comes back online.
101−
102−Buffers are commonly bounded by size, but this puts constraints on the
103−types of messages may be sent. They may also be bounded in time: if the
104−subscriber stops taking messages for at least X time, the buffer is
105−full. Gall taks a hybrid approach; currently the heuristic is that the
106−buffer counts as full if it has at least five messages and it has been
107−30 seconds since a message was acknowledged.
108−
109−### One at a time
110−
111−Another scheme is to avoid multi-message subscriptions. Instead of
112−allowing the subscriber to subscribe to all future updates on a path,
113−allow them to "subscribe" to the _next_ update only. When they get that
114−update, they subscribe to the new next update, so that they ultimately
115−get every message.
116−
117−Commonly this is implemented where each update is given a version
118−number, and every time you hear update N you request update N+1 (even
119−though you won't get an answer for an indeterminate period of time).
120−
121−This is near the theoretical ideal for memory usage, since you'll never
122−queue up several messages to send to the subscriber.
123−
124−It also encourages processing each update in order rather than zooming
125−forward from time to time. It's possible (if a little awkward) to
126−simulate this with buffers though, and it's possible to allow zooming
127−forward in the one-at-a-time scheme by having the requests be "most
128−recent after update N" instead of "next after update N".
129−
130−This scheme is at its strongest, then, when you're already storing
131−intermediate states or updates, or when you don't care about
132−intermediate states and always send the most recent one. Otherwise,
133−buffers are a convenient place to temporarily store updates that you
134−don't want to store internally. Of course, if it's semantically
135−important that you give each update separately, buffers won't save you
136−from having to store the intermediate updates, since they may fill up.
137−
138−Another conceptual advantage is that it has no notion of "connectivity".
139−It operates forever in a single mode. By contrast, buffer-based
140−solutions must keep track of whether the buffer is full and react to
141−that. This increases complexity in the system, and complexity is the
142−great evil.
143−
144−The biggest disadvantage of this system is that it takes much longer to
145−process many small updates. With buffers, the publisher could have a
146−dozen small updates in flight at the same time, while in this scheme
147−they would only send one at a time, waiting for a response between each
148−one. Losing this pipelining can be quite significant for some
149−applications, but for low-volume subscriptions (certainly anything that
150−updates less than once per minute) this will have no noticeable effect.
151−
152−Clay uses this scheme. It's low-volume, it stores all previous states
153−anyway (since it's a revision-control system), and it's sometimes
154−important to get updates one at a time (for example when downloading OTA
155−software updates). Ships that send OTA updates often have many ships
156−subscribed to them, and the updates themselves may be large, so it's
157−important they don't queue up when ships inevitably disappear.
158−
159−I tend to think most Gall subscriptions should follow this pattern as
160−well. Our most latency-sensitive subscriptions are chat messages, and
161−while I haven't tested it, I would guess that even those wouldn't be
162−affected by this scheme.
content/docs/arvo/dill/_index.mddeleted−23
@@ -1,23 +0,0 @@
1−+++
2−title = "Dill"
3−weight = 40
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−[Overview](/docs/avro/dill/dill)
10−
11−A brief overview of the Dill vane.
12−
13−[API Reference](/docs/arvo/dill/tasks)
14−
15−The `task`s Dill takes and the `gift`s it returns.
16−
17−[Scry Reference](/docs/arvo/dill/scry)
18−
19−The scry endpoints of Dill.
20−
21−[Data Types](/docs/arvo/dill/data-types)
22−
23−Reference documentation of the data types used by Dill.
content/docs/arvo/dill/data-types.mddeleted−187
@@ -1,187 +0,0 @@
1−+++
2−title = "Data Types"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−Here are the data types used by Dill, as defined in `/sys/lull.hoon`.
8−
9−## `$blew`
10−
11−```hoon
12− +$ blew [p=@ud q=@ud]
13−```
14−
15−Terminal dimension; `p` is columns, `q` is rows. This structure is passed to Dill by the runtime in a [%blew](/docs/arvo/dill/tasks#blew) `task` whenever the dimensions of the terminal changes.
16−
17−## `$belt`
18−
19−```hoon
20−+$ belt
21− $? bolt
22− $% [%mod mod=?(%ctl %met %hyp) key=bolt]
23− [%txt p=(list @c)]
24− [%ctl p=@c]
25− [%met p=@c]
26− == ==
27−```
28−
29−Terminal client input.
30−
31−A `$belt` is passed to Dill in a [%belt](/docs/arvo/dill/tasks#belt) `task` by the runtime whenever there is input, such as a user typing in the console. This is only used between the terminal client and Dill, a [$dill-belt](#dill-belt) is used between Dill and Arvo.
32−
33−May either be a [$bolt](#bolt) or one of:
34−
35−- `%mod` - Modifier (Ctrl, Meta or Hyper) plus [key].
36−- `%txt` - A series of characters
37−- `%ctl` - Ctrl+[key], deprecated in favour of `%mod`.
38−- `%met` - Meta+[key], deprecated in favour of `%mod`.
39−
40−## `$bolt`
41−
42−```hoon
43−+$ bolt
44− $@ @c
45− $% [%aro p=?(%d %l %r %u)]
46− [%bac ~]
47− [%del ~]
48− [%hit r=@ud c=@ud]
49− [%ret ~]
50− ==
51−```
52−
53−Simple input.
54−
55−Either a single simple character or one of:
56−
57−- `%aro` - Arrow keys.
58−- `%bac` - Backspace key.
59−- `%del` - Delete key.
60−- `%hit` - Mouse click - `r` is row and `c` is column. Note these are zero-indexed, with `[0 0]` being the _bottom left_ corner.
61−- `%ret` - Return (Enter) key.
62−
63−## `$blit`
64−
65−```hoon
66−+$ blit
67− $% [%bel ~]
68− [%clr ~]
69− [%hop p=@ud]
70− [%klr p=stub]
71− [%lin p=(list @c)]
72− [%mor ~]
73− [%sag p=path q=*]
74− [%sav p=path q=@]
75− [%url p=@t]
76− ==
77−```
78−
79−Terminal client output.
80−
81−A `$blit` is given to the terminal client by Dill in a `%blit` `gift` when it wants to print some text, clear the screen, go _ding_ or what have you.
82−
83−This is only used between Dill and the terminal client, a [$dill-blit](#dill-blit) is used instead between Arvo and Dill.
84−
85−A `$blit` is one of:
86−
87−- `%bel` - Ring the terminal bell.
88−- `%clr` - Clear the screen.
89−- `%hop` - Set cursor position, `p` specifies its position on the prompt line.
90−- `%klr` - Set styled line, the `$stub` specifies the text and style.
91−- `%lin` - Set current line, `p` contains the text.
92−- `%mor` - Newline.
93−- `%sag` - Save to jamfile, typically in `/[pier]/.urb/put/`. `p` is `/[path]/[filename]/[extension]`. For example, `/foo/bar` will save it in `/[pier]/.urb/put/foo.bar`, `/a/b/c/foo/bar` will save it in `/[pier]/.urb/put/a/b/c/foo.bar`, and `/foo` will save it in `/[pier]/.urb/put.foo`. `q` is the `noun` to `jam` and save in the file.
94−- `%sav` - Save to file. Same behaviour as `%sag` except `q` is an `atom` rather than a `noun` and therefore doesn't need to be `jam`med. The `atom` is written to disk as if it were the bytestring in the tail of an `$octs`. That is, `%sav`ing the `cord` `'abcdef'`, whose `@ux` value is `0x6665.6463.6261`, results in a unix file whose hex dump renders as `61 62 63 64 65 66`.
95−- `%url` - Activate URL, `p` is the URL.
96−
97−## `$dill-belt`
98−
99−```hoon
100−+$ dill-belt
101− $% [%aro p=?(%d %l %r %u)]
102− [%bac ~]
103− [%cru p=@tas q=(list tank)]
104− [%ctl p=@]
105− [%del ~]
106− [%hey ~]
107− [%met p=@]
108− [%ret ~]
109− [%rez p=@ud q=@ud]
110− [%txt p=(list @c)]
111− [%yow p=gill:gall]
112− ==
113−```
114−
115−Terminal input for Arvo.
116−
117−While [$belt](#belt) is used between the terminal client and Dill, `$dill-belt` is used between Dill and Arvo.
118−
119−a `$dill-belt` is one of:
120−
121−- `%aro` - Arrow keys.
122−- `%bac` - Backspace key.
123−- `%cru` - Echo error, `p` is an error `@tas` and `q` is a traceback.
124−- `%ctl` - Ctrl+[key].
125−- `%del` - Delete key.
126−- `%hey` - Refresh.
127−- `%met` - Meta+[key].
128−- `%ret` - Return key (Enter).
129−- `%rez` - Terminal resized, `p` is columns and `q` is rows.
130−- `%txt` - Text input.
131−- `%yow` - Connect to app.
132−
133−## `$dill-blit`
134−
135−```hoon
136−+$ dill-blit
137− $% [%bel ~]
138− [%clr ~]
139− [%hop p=@ud]
140− [%klr p=stub]
141− [%mor p=(list dill-blit)]
142− [%pom p=stub]
143− [%pro p=(list @c)]
144− [%qit ~]
145− [%out p=(list @c)]
146− [%sag p=path q=*]
147− [%sav p=path q=@]
148− [%url p=@t]
149− ==
150−```
151−
152−Terminal output from Arvo.
153−
154−While [$blit](#blit) is used between Dill and the terminal client, `$dill-blit` is used between Arvo and Dill.
155−
156−A `$dill-blit` is one of:
157−
158−- `%bel` - Terminal bell.
159−- `%clr` - Clear screen.
160−- `%hop` - Set cursor position, `p` is its horizontal position on the prompt line.
161−- `%klr` - Styled text, the `$stub` specifies both the text and style.
162−- `%mor` - Multiple `$dill-blit`.
163−- `%pom` - Styled prompt, the `$stub` specifies both the text and style.
164−- `%pro` - Set prompt, `p` is the text for the prompt.
165−- `%qit` - Close console.
166−- `%out` - Print text.
167−- `%sag` - Save `noun` to jamfile. See [$blit](#blit) section for further details.
168−- `%sav` - Save `atom` to file. See [$blit](#blit) section for further details.
169−- `%url` - Activate URL.
170−
171−## `$flog`
172−
173−```hoon
174−+$ flog
175− $% [%crop p=@ud]
176− [%crud p=@tas q=(list tank)]
177− [%heft ~]
178− [%meld ~]
179− [%pack ~]
180− [%text p=tape]
181− [%verb ~]
182− ==
183−```
184−
185−Wrapped Dill `task`s.
186−
187−These are a subset of Dill's `task`s which can be wrapped in a `%flog` `task`. See the [API Reference](/docs/arvo/dill/tasks) document for details of each of these `task`s.
content/docs/arvo/dill/dill.mddeleted−41
@@ -1,41 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/dill/"]
6−+++
7−
8−The terminal driver vane.
9−
10−Keyboard events and the like from Unix are received by Dill as [%belt](/docs/arvo/dill/tasks#belt) `task`s, and Dill sends `%blit` `gift`s containing [$blit](/docs/arvo/dill/data-types#blit)s back to the runtime to be displayed in the Unix terminal. The manner of interacting with Dill differs depending on whether you're in userspace or kernelspace, as we'll explore below.
11−
12−## Kernelspace
13−
14−For technical reasons, Dill performs a handful of system tasks related to booting a ship and some memory operations. Aside from those, other Vanes mostly just pass Dill [tasks](/docs/arvo/dill/tasks) to print error messages and the like to the terminal.
15−
16−## Userspace
17−
18−Unlike in kernelspace, userspace applications are unlikely to `%pass` Dill `task`s directly. Instead, Dill looks at things in terms of sessions. A session is a pipeline between a client and a handler, where:
19−
20−- The client is an external input source and output sink; a terminal with with dimensions and so forth.
21−- The handler is an application in Urbit that interprets input, maybe does something with it, maybe produces output to be displayed in the client, etc.
22−
23−There are plans for Dill to support multiple independent sessions (i.e. independent terminal clients displaying and processing different information at the same time), but at this stage Dill only supports a single session. The client for this default session is just the Unix terminal via the Urbit runtime. The handler for the default session is the `%hood` app, whose `drum` module does the heavy lifting.
24−
25−`drum` is the CLI app manager. By default you'll have a couple of CLI applications running—`%dojo` and `%chat-cli`—which you can switch between with `ctrl+x`. You may also have additional CLI apps which you have attached with the `|link` command. It's `drum` that keeps track of which one is active, which one input should be routed to, which one should be displayed, what each prompt should look like, and so forth. Dill itself is oblivious to the distinction between these CLI apps. It only sees the default session with `drum`, so it just passes all input to `drum` and display whatever `drum` gives it.
26−
27−While `drum` talks with Dill in `$dill-belt`s and `$dill-blit`s, it talks to CLI apps with `$sole-action`s and `$sole-event`s, which are defined in the `sole` library. For more information on the `sole` library and the related `shoe` library, and for information on how to build CLI apps, you can refer to the [CLI app tutorial](/docs/hoon/guides/cli-tutorial).
28−
29−To give a basic idea of how keyboard events flow through these systems and produce terminal output, here's a diagram showing the messages in pseudo-Hoon:
30−
31−![Dill userspace diagram](https://media.urbit.org/docs/arvo/dill/dill-userspace.svg)
32−
33−You can use a [move trace](/docs/arvo/tutorials/move-trace) to get a hands-on feel for this data flow.
34−
35−## Sections
36−
37−[API Reference](/docs/arvo/dill/tasks) - The `task`s Dill takes and the `gift`s it returns.
38−
39−[Scry Reference](/docs/arvo/dill/scry) - The scry endpoints of Dill.
40−
41−[Data Types](/docs/arvo/dill/data-types) - Reference documentation of the data types used by Dill.
content/docs/arvo/dill/scry.mddeleted−45
@@ -1,45 +0,0 @@
1−+++
2−title = "Scry Reference"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−Here are the scry endpoints of Dill. They take a `%x` `care` and require the `desk` in the path prefix be empty, so the general format is `.^([type] %dx /=//=/[some-path])`.
8−
9−Dill only has a couple of scry endpoints, both of which begin with `/session//`. The empty `//` would be where the target session would be specified, but at this stage Dill can only return a result for the default session, so it's always empty.
10−
11−## /sessions//line
12−
13−A scry with a `care` of `%x` and a `path` of `/sessions//line` returns the current text of the prompt line of the default session. The type returned is a [$blit](/docs/arvo/dill/data-types#blit).
14−
15−#### Example
16−
17−```
18−> .^(blit:dill %dx /=//=/sessions//line)
19−[ %lin
20− p
21− ~[
22− ~-~~
23− ~-z
24− ~-o
25− ~-d
26− ~-~3a.
27− ~-d
28− ~-o
29− ~-j
30− ~-o
31− ...truncated for brevity...
32− ]
33−]
34−```
35−
36−## /sessions//cursor
37−
38−A scry with a `care` of `%x` and a `path` of `/sessions//cursor` returns the current horizontal position of the cursor in the default session. The type returned is a `@ud`.
39−
40−#### Example
41−
42−```
43−> .^(@ud %dx /=//=/sessions//cursor)
44−44
45−```
content/docs/arvo/dill/tasks.mddeleted−342
@@ -1,342 +0,0 @@
1−+++
2−title = "API Reference"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−In this document we describe the public interface for Dill. Namely, we describe each `task` that Dill can be `pass`ed, and which `gift`(s) Dill can `give` in return.
8−
9−## `%belt`
10−
11−```hoon
12−[%belt p=belt]
13−```
14−
15−Terminal input.
16−
17−The runtime sends a `%belt` `task` to Dill whenever there is input in the terminal, such as a keystroke.
18−
19−The [$belt](/docs/arvo/dill/data-types#belt) in `p` contains the input such as which key was pressed.
20−
21−Dill will convert the `$belt` into a [$dill-belt](/docs/arvo/dill/data-types#dill-belt) and `%poke` the session handler (typically `drum`) with it.
22−
23−This `task` would not typically be used from userspace.
24−
25−#### Returns
26−
27−Dill returns no `gift` in response to a `%belt` `task`.
28−
29−## `%blew`
30−
31−```hoon
32−[%blew p=blew]
33−```
34−
35−Terminal resized.
36−
37−The runtime passes Dill a `%blew` `task` whenever the terminal is resized.
38−
39−The [$blew](/docs/arvo/dill/data-types#blew) specifies the new dimensions.
40−
41−Dill will convert the `$blew` into a `%rez` [$dill-belt](/docs/arvo/dill/data-types#dill-belt) and `%poke`s the session handler (typically `drum`) with it.
42−
43−This `task` would not typically be used from userspace.
44−
45−#### Returns
46−
47−Dill returns no `gift` in response to a `%blew` `task`.
48−
49−## `%boot`
50−
51−```hoon
52−[%boot lit=? p=*]
53−```
54−
55−This `task` is used only once, when Arvo first enters the [adult stage](/docs/arvo/overview#structural-interface-core). Dill is technically the first vane to be activated, via the `%boot` `task`, which then sends Jael (considered the "true" first vane) the `%dawn` or `%fake` `task` wrapped in the `%boot` `task`. Jael then goes on to call `%init` `task`s for other vanes (including Dill).
56−
57−`lit` specifies whether to boot in lite mode. `p` is either a [%dawn](/docs/arvo/jael/data-types#dawn) or [%fake](/docs/arvo/jael/tasks#fake) `task:jael`. `%dawn` is for an ordinary boot and `%fake` is for booting a fake ship.
58−
59−This `task` would not be used from userspace.
60−
61−#### Returns
62−
63−Dill returns no `gift` in response to a `%boot` `task`, but it will `%pass` the wrapped `%dawn` or `%fake` `task` to Jael.
64−
65−## `%crop`
66−
67−```hoon
68−[%crop p=@ud]
69−```
70−
71−Trim kernel state.
72−
73−This `task` is the same as the [%trim](#trim) `task`. Like `%trim`, Dill does nothing with it.
74−
75−#### Returns
76−
77−Dill returns no `gift` in response to a `%crop` `task`.
78−
79−## `%crud`
80−
81−```hoon
82−[%crud p=@tas q=(list tank)]
83−```
84−
85−Print error.
86−
87−Dill prints the given error to the terminal. The verbosity for the particular `@tas` error tag specified in `p` is determined by the `level` set by a [%knob](#knob) `task` - either `%hush`, `%soft` or `%loud`. The default is `%loud`, where it will print the full `(list tank)` specified in `q`. See [%knob](#knob) for details of verbosity levels.
88−
89−#### Returns
90−
91−Dill does not return a `gift` in response to a `%crud` `task`.
92−
93−## `%flee`
94−
95−```hoon
96−[%flee session=~]
97−```
98−
99−Unwatch a session to which you've previously subscribed with [%view](#view).
100−
101−The ability to specify a session is not yet implemented in Dill, so `session` is always `~`, the default session.
102−
103−#### Returns
104−
105−Dill does not return a `gift` in response to a `%flee` `task`.
106−
107−## `%flog`
108−
109−```hoon
110−[%flog p=flog]
111−```
112−
113−A `%flog` `task` is a wrapper over a `task` sent by another vane. Dill removes the wrapper and sends the bare `task` to itself over the default `duct`.
114−
115−A `%flog` `task` takes a [$flog](/docs/arvo/dill/data-types#flog) as its argument. A `$flog` is a subset of Dill's `task`s.
116−
117−#### Returns
118−
119−Dill does not return a `gift` in response to a `%flog` `task`.
120−
121−## `%flow`
122−
123−```hoon
124−[%flow p=@tas q=(list gill:gall)]
125−```
126−
127−Terminal config.
128−
129−This `task` is not used.
130−
131−## `%hail`
132−
133−```hoon
134−[%hail ~]
135−```
136−
137−Refresh.
138−
139−Dill converts a `%hail` `task` into a `%hey` [$dill-belt](/docs/arvo/dill/data-types#dill-belt) and `%poke`s the session handler (typically `drum`) with it to handle the refresh.
140−
141−This `task` would not be used from userspace.
142−
143−#### Returns
144−
145−Dill returns no `gift` in response to a `%hail` `task`.
146−
147−## `%heft`
148−
149−```hoon
150−[%heft ~]
151−```
152−
153−Produce memory report.
154−
155−When Dill receives a `%heft` `task` it passes Arvo a `%whey` `waif` to obtain a memory report and prints it to the terminal.
156−
157−#### Returns
158−
159−Dill does not return a `gift` in response to a `%heft` `task`.
160−
161−## `%hook`
162−
163−```hoon
164−[%hook ~]
165−```
166−
167−This terminal hung up.
168−
169−This task is not used.
170−
171−## `%harm`
172−
173−```hoon
174−[%harm ~]
175−```
176−
177−All terminals hung up.
178−
179−This `task` is not used.
180−
181−## `%init`
182−
183−```hoon
184−[%init ~]
185−```
186−
187−This `task` is called only once, when Arvo first enters the [adult stage](/docs/arvo/overview#structural-interface-core). It performs initial setup for Dill, such as setting the width of the console.
188−
189−Note that this is not actually the first `task` passed to Dill - see [%boot](#%boot).
190−
191−This `task` would not be used from userspace.
192−
193−#### Returns
194−
195−Dill does not return a `gift` in response to a `%init` `task`.
196−
197−## `%meld`
198−
199−```
200−[%meld ~]
201−```
202−
203−Deduplicate persistent state.
204−
205−Dill asks the runtime to perform the memory deduplication.
206−
207−#### Returns
208−
209−Dill does not return a `gift` in response to a `%meld` `task`.
210−
211−## `%noop`
212−
213−```hoon
214−[%noop ~]
215−```
216−
217−No operation.
218−
219−A `%noop` `task` does nothing, as the name implies.
220−
221−#### Returns
222−
223−Dill does not return a `gift` in response to a `%noop` `task`.
224−
225−## `%pack`
226−
227−```hoon
228−[%pack ~]
229−```
230−
231−Defragment persistent state.
232−
233−Dill asks the runtime to perform the defragmentation.
234−
235−#### Returns
236−
237−Dill does not return a `gift` in response to a `%meld` `task`.
238−
239−## `%talk`
240−
241−```hoon
242−[%talk p=tank]
243−```
244−
245−This `task` is not used.
246−
247−## `%text`
248−
249−```hoon
250−[%text p=tape]
251−```
252−
253−Print `tape` to terminal.
254−
255−Upon receiving a `%text` `task`, Dill will convert the `tape` given in `p` to a `(list @c)` and give it to the runtime in a `%blit` `gift` including a `%lin` [$blit](/docs/arvo/dill/data-types#blit).
256−
257−#### Returns
258−
259−Dill does not return a `gift` in response to a `%text` `task`, but it does give a `%blit` `gift` to the runtime which looks like:
260−
261−```hoon
262−[%blit p=(list blit)]
263−```
264−
265−## `%view`
266−
267−```hoon
268−[%view session=~]
269−```
270−
271−Watch session.
272−
273−A `%view` `task` subscribes for a copy of all `%blit` `gift`s which Dill `%give`s for the default session. This `task` is used by the `%herm` app so it can convert the `$blit`s to JSON and render them in the web terminal.
274−
275−The ability to specify a session is not yet implemented in Dill, so `session` is always `~`, the default session.
276−
277−#### Returns
278−
279−Dill will `%give` a copy of all `%blit`s for the default session. A `%blit` `gift` is:
280−
281−```hoon
282−[%blit p=(list blit)]
283−```
284−
285−## `%trim`
286−
287−```hoon
288−[%trim p=@ud]
289−```
290−
291−`%trim` is a common vane `task` used to reduce memory usage. It does nothing for Dill because Dill only keeps a minimal necessary state.
292−
293−#### Returns
294−
295−Dill does not return a `gift` in response to a `%trim` `task`.
296−
297−## `%vega`
298−
299−```hoon
300−[%vega ~]
301−```
302−
303−This is a common vane `task` used to inform the vane that the kernel has been
304−upgraded. Dill does not do anything in response to this.
305−
306−This `task` would not be used from userspace.
307−
308−#### Returns
309−
310−Dill returns no `gift` in response to a `%vega` `task`.
311−
312−## `%verb`
313−
314−```hoon
315−[%verb ~]
316−```
317−
318−This `task` toggles verbose mode for all of Arvo, which is located here since
319−Dill is the vane that prints errors. To be precise, `%verb` toggles the laconic
320−bit `lac` in the [Arvo state](/docs/arvo/overview#the-state) by passing a `%verb` `waif` to Arvo.
321−
322−#### Returns
323−
324−Dill does not return a `gift` in response to a `%verb` `task`.
325−
326−## `%knob`
327−
328−```hoon
329−[%knob tag=term level=?(%hush %soft %loud)]
330−```
331−
332−`%knob` sets the verbosity level for each error tag. The error `tag` can be any `@tas`. The given `tag` and `level` will be added to Dill's `veb` which maps tags to levels. Subsequent [%crud](#crud) `task`s will then print with the specified verbosity.
333−
334−The `level`s behave like so:
335−
336−- `%hush` - Completely silent, print nothing.
337−- `%soft` - Just print `crud: %error-tag event failed`, ignore any `tang` given in the `%crud`.
338−- `%loud` - Print the `%soft` message as well as the full `tang` given in the `%crud` `task`.
339−
340−#### Returns
341−
342−Dill does not return a `gift` in response to a `%knob` `task`.
content/docs/arvo/eyre/_index.mddeleted−31
@@ -1,31 +0,0 @@
1−+++
2−title = "Eyre"
3−weight = 50
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−## [Overview](/docs/arvo/eyre/eyre)
10−
11−An overview of Eyre and its capabilities.
12−
13−## [External API Reference](/docs/arvo/eyre/external-api-ref)
14−
15−Details of Eyre's external API including the channel system's JSON API.
16−
17−## [Internal API Reference](/docs/arvo/eyre/tasks)
18−
19−The `task`s Eyre takes and the `gift`s it returns.
20−
21−## [Scry Reference](/docs/arvo/eyre/scry)
22−
23−The scry endpoints of Eyre.
24−
25−## [Data Types](/docs/arvo/eyre/data-types)
26−
27−Reference documentation of the various data types used by Eyre.
28−
29−## [Guide](/docs/arvo/eyre/guide)
30−
31−Practical examples of the different ways of using Eyre.
content/docs/arvo/eyre/data-types.mddeleted−289
@@ -1,289 +0,0 @@
1−+++
2−title = "Data Types"
3−weight = 5
4−template = "doc.html"
5−+++
6−
7−This document describes the data types used by Eyre as defined in `/sys/lull.hoon`. It's separated into two sections:
8−
9−[Eyre](#eyre) - Eyre-specific data types.
10−
11−[HTTP](#http) - HTTP data types shared between Eyre and Iris.
12−
13−## Eyre
14−
15−### `$origin`
16−
17−```hoon
18−+$ origin @torigin
19−```
20−
21−A single CORS origin as used in an HTTP Origin header and the [$cors-registry](#cors-registry).
22−
23−### `$cors-registry`
24−
25−```hoon
26−+$ cors-registry
27− $: requests=(set origin)
28− approved=(set origin)
29− rejected=(set origin)
30− ==
31−```
32−
33−CORS origins categorised by approval status. The `requests` `set` contains all [$origin](#origin)s Eyre has received in the headers of HTTP requests that have not been explicitly approved or rejected. The `approved` and `rejected` `set`s are those that have been explicitly approved or rejected.
34−
35−### `$outstanding-connection`
36−
37−```hoon
38−+$ outstanding-connection
39− $: =action
40− =inbound-request
41− response-header=(unit response-header:http)
42− bytes-sent=@ud
43− ==
44−```
45−
46−An HTTP connection that is currently open. The [$action](#action) is how it's being handled (e.g. by a Gall app, the channel system, etc). The [$inbound-request](#inbound-request) is the original request which opened the connection. The `response-header` contains the status code and headers. The `bytes-sent` is the total bytes sent so far in response.
47−
48−### `$authentication-state`
49−
50−```hoon
51−+$ authentication-state sessions=(map @uv session)
52−```
53−
54−This represents the authentication state of all sessions. It maps session cookies (without the `urbauth-{SHIP}=` prefix) to [$session](#session)s.
55−
56−### `$session`
57−
58−```hoon
59−+$ session
60− $: expiry-time=@da
61− channels=(set @t)
62− ==
63−```
64−
65−This represents server-side data about a session. The `expiry-time` is when the `session` expires and `channels` is the `set` of [$channel](#channel) names opened by the session.
66−
67−### `$channel-state`
68−
69−```hoon
70−+$ channel-state
71− $: session=(map @t channel)
72− duct-to-key=(map duct @t)
73− ==
74−```
75−
76−The state used by the channel system. The `session` is a `map` between channel names and [$channel](#channel)s and the `duct-to-key` `map`s `duct`s to `channel` names.
77−
78−### `$timer`
79−
80−```hoon
81−+$ timer
82− $: date=@da
83− =duct
84− ==
85−```
86−
87−A reference to a timer so it can be cancelled or updated. The `date` is when it will fire and the `duct` is what set the timer.
88−
89−### `$channel-event`
90−
91−```hoon
92−+$ channel-event
93− $% $>(%poke-ack sign:agent:gall)
94− $>(%watch-ack sign:agent:gall)
95− $>(%kick sign:agent:gall)
96− [%fact =mark =noun]
97− ==
98−```
99−
100−An unacknowledged event in the channel system.
101−
102−### `$channel`
103−
104−```hoon
105−+$ channel
106− $: state=(each timer duct)
107− next-id=@ud
108− last-ack=@da
109− events=(qeu [id=@ud request-id=@ud =channel-event])
110− unacked=(map @ud @ud)
111− subscriptions=(map @ud [ship=@p app=term =path duc=duct])
112− heartbeat=(unit timer)
113− ==
114−```
115−
116−This is the state of a particular channel in the channel system. The `state` is either the expiration time or the duct currently listening. The `next-id` is the next event ID to be used in the event stream. The `last-ack` is the date of the last client ack and is used for clog calculations in combination with `unacked`. The `events` queue contains all unacked events - `id` is the server-set event ID, `request-id` is the client-set request ID and the [$channel-event](#channel-event) is the event itself. The `unacked` `map` contains the unacked event count per `request-id` and is used for clog calculations. The `subscriptions` `map` contains gall subscriptions by `request-id`. The `heartbeat` is the SSE heartbeat [$timer](#timer).
117−
118−### `$binding`
119−
120−```hoon
121−+$ binding
122− $: site=(unit @t)
123− path=(list @t)
124− ==
125−```
126−
127−A `binding` is a rule to match a URL `path` and optional `site` domain which can then be tied to an [$action](#action). A `path` of `/foo` will also match `/foo/bar`, `/foo/bar/baz`, etc. If the `site` is `~` it will be determined implicitly. A binding must be unique.
128−
129−### `$action`
130−
131−```hoon
132−+$ action
133− $% [%gen =generator] :: dispatch to a generator
134− [%app app=term] :: dispatch to an application
135− [%authentication ~] :: internal authentication page
136− [%logout ~] :: internal logout page
137− [%channel ~] :: gall channel system
138− [%scry ~] :: gall scry endpoint
139− [%four-oh-four ~] :: respond with the default file not found page
140− ==
141−```
142−
143−The action to take when a [$binding](#binding) matches an incoming HTTP request.
144−
145−### `$generator`
146−
147−```hoon
148−+$ generator
149− $: =desk :: desk on current ship that contains the generator
150− path=(list @t) :: path on :desk to the generator's hoon file
151− args=* :: args: arguments passed to the gate
152− ==
153−```
154−
155−This refers to a generator on a local ship that can handle requests. Note that serving generators via Eyre is not fully implmented and should not be used.
156−
157−### `$http-config`
158−
159−```hoon
160−+$ http-config
161− $: secure=(unit [key=wain cert=wain])
162− proxy=_|
163− log=?
164− redirect=?
165− ==
166−```
167−
168−The configuration of the runtime HTTP server itself. The `secure` field contains the PEM-encoded RSA private key and certificate or certificate chain when using HTTPS, and otherwise is `~` when using plain HTTP. The `proxy` field is not currently used. The `log` field turns on HTTP(S) access logs but is not currently implemented. The `redirect` field turns on 301 redirects to upgrade HTTP to HTTPS if the `key` and `cert` are set in `secure`.
169−
170−### `$http-rule`
171−
172−```hoon
173−+$ http-rule
174− $% [%cert cert=(unit [key=wain cert=wain])]
175− [%turf action=?(%put %del) =turf]
176− ==
177−```
178−
179−This is for updating the server configuration. In the case of `%cert`, a `cert` of `~` clears the HTTPS cert & key, otherwise `cert` contains the PEM-encoded RSA private key and certificate or certificate chain. In the case of `%turf`, a `%put` `action` sets a domain name and a `%del` `action` removes it. The [$turf](#turf) contains the domain name.
180−
181−### `$address`
182−
183−```hoon
184−+$ address
185− $% [%ipv4 @if]
186− [%ipv6 @is]
187− ==
188−```
189−
190−A client IP address.
191−
192−### `$inbound-request`
193−
194−```hoon
195−+$ inbound-request
196− $: authenticated=?
197− secure=?
198− =address
199− =request:http
200− ==
201−```
202−
203−An inbound HTTP request and metadata. The `authenticated` field says whether the request was made with a valid session cookie. The `secure` field says whether it was made with HTTPS. The [$address](#address) is the IP address from which the request originated, except if it came from localhost and included a `Forwarded` header, in which case it's the address specified in that header. The [$request:http](#requesthttp) contains the HTTP request itself.
204−
205−## HTTP
206−
207−### `$header-list:http`
208−
209−```hoon
210−+$ header-list (list [key=@t value=@t])
211−```
212−
213−An ordered list of HTTP headers. The `key` is the header name e.g `'Content-Type'` and the `value` is the value e.g. `text/html`.
214−
215−### `$method:http`
216−
217−```hoon
218−+$ method
219− $? %'CONNECT'
220− %'DELETE'
221− %'GET'
222− %'HEAD'
223− %'OPTIONS'
224− %'POST'
225− %'PUT'
226− %'TRACE'
227− ==
228−```
229−
230−An HTTP method.
231−
232−### `$request:http`
233−
234−```hoon
235−+$ request
236− $: method=method
237− url=@t
238− =header-list
239− body=(unit octs)
240− ==
241−```
242−
243−A single HTTP request. The [$method:http](#methodhttp) is the HTTP method, the `url` is the unescaped URL, the [$header-list:http](#header-listhttp) contains the HTTP headers of the request and the `body` is the actual data. An `octs` is just `[p=@ud q=@]` where `p` is the byte-length of `q`, the data.
244−
245−### `$response-header:http`
246−
247−```hoon
248−+$ response-header
249− $: status-code=@ud
250− headers=header-list
251− ==
252−```
253−
254−The status code and [$header-list:http](#header-listhttp) of an HTTP response.
255−
256−### `$http-event:http`
257−
258−```hoon
259−+$ http-event
260− $% $: %start
261− =response-header
262− data=(unit octs)
263− complete=?
264− ==
265− $: %continue
266− data=(unit octs)
267− complete=?
268− ==
269− [%cancel ~]
270− ==
271−```
272−
273−Packetized HTTP.
274−
275−Urbit treats Earth's HTTP servers as pipes, where Urbit sends or receives one or more `http-event`s. The first of these will be a `%start`, and the last will always be `%cancel` or will have `complete` set to `%.y` to finish the connection.
276−
277−Calculation of control headers such as `'Content-Length'` or `'Transfer-Encoding'` should be performed at a higher level; this structure is merely for what gets sent to or received from Earth.
278−
279−### `$simple-payload:http`
280−
281−```hoon
282−+$ simple-payload
283− $: =response-header
284− data=(unit octs)
285− ==
286−--
287−```
288−
289−A simple, one-event response used for generators. The [$reponse-header:http](#response-headerhttp) contains the status code and HTTP headers. The `octs` in the `data` contains the body of the response and is a `[p=@ud q=@]` where `p` is the byte-length of `q`, the data.
content/docs/arvo/eyre/external-api-ref.mddeleted−359
@@ -1,359 +0,0 @@
1−+++
2−title = "External API Reference"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−This document contains reference information about Eyre's external APIs including [the channel system](#channels) and [scries](#scry). Each section will also have practical examples in the [Guide](/docs/arvo/eyre/guide) document.
8−
9−## Authentication
10−
11−To use Eyre's channel system, run threads or perform scries you must first obtain a session cookie by authenticating with the following HTTP request:
12−
13−| HTTP Method | Data | URL Path | Notes |
14−| ----------- | -------------------------------------- | ---------- | ----------------------------------------------------------------------------------- |
15−| `POST` | `password=lidlut-tabwed-pillex-ridrup` | `/~/login` | The password is your web login code which can be obtained with `+code` in the dojo. |
16−
17−See the [Guide](/docs/arvo/eyre/guide#authenticating) for an example of how to do this using the curl.
18−
19−Eyre's response will include a `set-cookie` header like:
20−
21−```
22−set-cookie: urbauth-~zod=0v4.ilskp.psv00.t09r0.l8rps.3n97v; Path=/; Max-Age=604800
23−```
24−
25−The `urbauth-{...}` cookie provided must be included in a `cookie` header with all subsequent requests like:
26−
27−```
28−cookie: urbauth-~zod=0v4.ilskp.psv00.t09r0.l8rps.3n97v
29−```
30−
31−## Channels
32−
33−Eyre's channel system is the primary way of interacting with Gall agents from outside of Urbit.
34−
35−Data from an external HTTP client is sent to Eyre as an [HTTP PUT request](#http-requests) containing one or more [action](#actions) JSON objects. Clients must obtain a session cookie by [authenticating](#authentication) with Eyre in order to make such requests.
36−
37−Data from Eyre is sent back to the external HTTP client on a channel as SSEs ([Server Sent Events](https://html.spec.whatwg.org/#server-sent-events)) containing a [response](#responses) JSON object.
38−
39−A new channel is automatically created whenever a client sends an [action](#action) in an [HTTP PUT request](#http-requests) to `http{s}://{host}{port}/~/channel/{uid}` with a new `uid`. To connect to the channel and receive any pending events, you just send an HTTP GET request with a valid session cookie to that URL.
40−
41−The response you'll get to the GET request will be an event stream. Events will come in like:
42−
43−```
44−id: 0
45−data: {"ok":"ok","id":1,"response":"poke"}
46−```
47−
48−If you're working with Javascript in the browser context you'll handle these with an EventSource object or by using fetch and ReadableStream. If you're using another language, there'll likely be a library available to handle SSEs.
49−
50−All the events that Eyre sends you on a channel must be [ack](#ack)ed so that Eyre can forget about them and clear them from the channel state. If `fact`s (as [diff](#diff)s) from Gall agents to which you've subscribed are left un`ack`ed long enough, Eyre will consider the particular subscription clogged and automatically unsubscribe you. Note that `ack`ing one event will implicitly `ack` all previous events.
51−
52−When you're finished with a channel, you can send Eyre a [delete action](#delete-channel) to close it.
53−
54−See the [Using the Channel System](/docs/arvo/eyre/guide#using-channels) section of the [Guide](/docs/arvo/eyre/guide) document for a practical example.
55−
56−### HTTP Requests
57−
58−[Actions](#actions) are sent to Eyre in HTTP PUT requests:
59−
60−| HTTP Method | Required Headers | Data | URL Path |
61−| ----------- | ------------------------- | -------------------------------------------------------------- | ------------------ |
62−| `PUT` | `Content-Type` & `Cookie` | One or more [actions](#actions) wrapped in a JSON array (`[]`) | `/~/channel/{uid}` |
63−
64−The `cookie` header contains the session cookie obtained by [authenticating](#authentication). The data is a JSON array containing one or more JSON [action](#actions) objects. The channel `uid` is a unique name of your choosing. Typically you'd use the current unix time and a hash but there's no specific requirements. If you're opening a new channel you'd choose a new `uid` and if you already have a channel open you'd just use that.
65−
66−If successful, Eyre will respond with a status code of 204. Note the HTTP response will have no content, any [responses](#responses) will be sent as SSEs on the channel event stream.
67−
68−## Actions
69−
70−### Poke
71−
72−This is for poking a Gall agent.
73−
74−| Key | JSON Type | Example Value | Description |
75−| -------- | --------- | ------------- | ------------------------------------------------------------- |
76−| `id` | Number | `1` | ID for keeping track of sent messages. |
77−| `action` | String | `'poke'` | The kind of action. |
78−| `ship` | String | `'zod'` | Target ship name, excluding leading `~`. |
79−| `app` | String | `'hood'` | Name of the gall agent you're poking. |
80−| `mark` | String | `'helm-hi'` | Type of data. Must correspond to a mark definition in `/mar`. |
81−| `json` | Any | `'hello'` | Actual payload. Any JSON type, determined by app. |
82−
83−#### Example
84−
85−```json
86−{
87− "id": 1,
88− "action": "poke",
89− "ship": "zod",
90− "app": "hood",
91− "mark": "helm-hi",
92− "json": "hello"
93−}
94−```
95−
96−#### Response
97−
98−Eyre will send a [poke ack](#poke-ack) as an SSE event on the channel event stream.
99−
100−### Subscribe
101−
102−This is for subscribing to a watch `path` of a Gall agent.
103−
104−| Key | JSON Type | Example Value | Description |
105−| -------- | --------- | --------------- | --------------------------------------------------- |
106−| `id` | Number | `2` | ID for keeping track of sent messages. |
107−| `action` | String | `'subscribe'` | The kind of action. |
108−| `ship` | String | `'zod'` | Target ship name, excluding leading `~`. |
109−| `app` | String | `'graph-store'` | Name of the gall agent to which you're subscribing. |
110−| `path` | String | `'/updates'` | The path to watch. Depends on the app. |
111−
112−#### Example
113−
114−```json
115−{
116− "id": 2,
117− "action": "subscribe",
118− "ship": "zod",
119− "app": "graph-store",
120− "path": "/updates"
121−}
122−```
123−
124−#### Response
125−
126−Eyre will send back a [watch ack](#watch-ack). If subscribing was successful, you will also begin receiving any [diff](#diff)s sent by the Gall agent on the specified `path`.
127−
128−### Ack
129−
130−This is for acknowledging an SSE event. If you `ack` one event, you also implicitly `ack` all previous events. Events _must_ be `ack`ed so that Eyre can forget them. If you leave `fact`s (as [diff](#diff)s) un`ack`ed long enough, Eyre will consider the subscription clogged and automatically unsubscribe you.
131−
132−| Key | JSON Type | Example Value | Description |
133−| ---------- | --------- | ------------- | -------------------------------------------------------- |
134−| `id` | Number | `3` | ID for keeping track of sent messages. |
135−| `action` | String | `'ack'` | The kind of action. |
136−| `event-id` | Number | `7` | ID of SSE event up to which you're acknowledging receipt |
137−
138−#### Example
139−
140−```json
141−{
142− "id": 3,
143− "action": "ack",
144− "event-id": 7
145−}
146−```
147−
148−#### Response
149−
150−Eyre will not respond to an `ack` action.
151−
152−### Unsubscribe
153−
154−This is for unsubscribing from a Gall agent watch `path` to which you've previously subscribed.
155−
156−| Key | JSON Type | Example Value | Description |
157−| -------------- | --------- | ------------- | ---------------------------------------------------------- |
158−| `id` | Number | `4` | ID for keeping track of sent messages. |
159−| `action` | String | `unsubscribe` | The kind of action. |
160−| `subscription` | Number | `2` | Request ID of the initial `subscribe` action from earlier. |
161−
162−#### Example
163−
164−```json
165−{
166− "id": 4,
167− "action": "unsubscribe",
168− "subscription": 2
169−}
170−```
171−
172−#### Response
173−
174−Eyre will not respond to an `unsubscribe` action.
175−
176−### Delete Channel
177−
178−This is for deleting the channel itself.
179−
180−| Key | JSON Type | Example Value | Description |
181−| -------- | --------- | ------------- | -------------------------------------- |
182−| `id` | Number | `5` | ID for keeping track of sent messages. |
183−| `action` | String | `'delete'` | The kind of action. |
184−
185−#### Example
186−
187−```json
188−{
189− "id": 5,
190− "action": "delete"
191−}
192−```
193−
194−#### Response
195−
196−Eyre will not respond to a `delete` action.
197−
198−## Responses
199−
200−### Poke Ack
201−
202−This acknowledgement comes in response to a [poke](#poke) action. A poke ack with an `ok` key means the poke succeeded. A poke ack with an `err` key means the poke failed.
203−
204−#### Positive Poke Ack
205−
206−| Key | JSON Type | Example Value | Description |
207−| ---------- | --------- | ------------- | -------------------------------------------- |
208−| `ok` | String | `'ok'` | Positive acknowledgement. |
209−| `id` | Number | `1` | Request ID of the `poke` being acknowledged. |
210−| `response` | String | `'poke'` | The kind of action being acknowledged. |
211−
212−#### Example
213−
214−```json
215−{
216− "ok": "ok",
217− "id": 1,
218− "response": "poke"
219−}
220−```
221−
222−#### Negative Poke Ack
223−
224−| Key | JSON Type | Example Value | Description |
225−| ---------- | --------- | ---------------- | --------------------------------------------------------------------- |
226−| `err` | String | `'some text...'` | Negative acknowledgement. Contains an error message and/or traceback. |
227−| `id` | Number | `1` | Request ID of the `poke` being acknowledged. |
228−| `response` | String | `'poke'` | The kind of action being acknowledged. |
229−
230−#### Example
231−
232−```json
233−{
234− "err": "<error message and traceback>",
235− "id": 1,
236− "response": "poke"
237−}
238−```
239−
240−#### Action Required
241−
242−You must ack the event.
243−
244−### Watch Ack
245−
246−This acknowledgement comes in response to a [subscribe](#subscribe) action. A watch ack with an `ok` key means the subscription was successful. A watch ack with an `err` key means the subscription failed.
247−
248−#### Positive Watch Ack
249−
250−| Key | JSON Type | Example Value | Description |
251−| ---------- | --------- | ------------- | --------------------------------------------- |
252−| `ok` | String | `'ok'` | Positive acknowledgement. |
253−| `id` | Number | `2` | Request ID of the initial `subscribe` action. |
254−| `response` | String | `'subscribe'` | The kind of action being acknowledged. |
255−
256−#### Example
257−
258−```json
259−{
260− "ok": "ok",
261− "id": 2,
262− "response": "subscribe"
263−}
264−```
265−
266−#### Negative Watch Ack
267−
268−| Key | JSON Type | Example Value | Description |
269−| ---------- | --------- | ---------------- | --------------------------------------------------------------------- |
270−| `err` | String | `'some text...'` | Negative acknowledgement. Contains an error message and/or traceback. |
271−| `id` | Number | `2` | Request ID of the initial `subscribe` action. |
272−| `response` | String | `'subscribe'` | The kind of action being acknowledged. |
273−
274−#### Example
275−
276−```json
277−{
278− "err": "<error message and traceback>",
279− "id": 2,
280− "response": "subscribe"
281−}
282−```
283−
284−#### Action Required
285−
286−You must ack the event.
287−
288−### Diff
289−
290−All `fact`s sent by a Gall agent on the `path` to which you've subscribed are delivered as `diff`s. Note that Eyre makes a best effort to convert the `fact` to a `json` mark. If it can't, Eyre will crash and close the subscription, and you won't receive any `diff` for the `fact`.
291−
292−| Key | JSON Type | Example Value | Description |
293−| ---------- | --------- | ---------------- | ------------------------------------------------------------ |
294−| `json` | Any | `{'foo': 'bar'}` | The actual data from the agent, could be any JSON structure. |
295−| `id` | Number | `3` | Request ID of the initial `subscribe` action from earlier. |
296−| `response` | String | `'diff'` | The kind of response. All `fact`s are marked `'diff'`. |
297−
298−#### Example
299−
300−```json
301−{
302− "json": { "foo": "bar" },
303− "id": 3,
304− "response": "diff"
305−}
306−```
307−
308−#### Action Required
309−
310−You must [ack](#ack) each `diff` that comes in the event stream.
311−
312−### Quit
313−
314−A `quit` comes in when a subscription has been ended. You may be intentionally kicked by the Gall agent to which you're subscribed, but certain network conditions can also trigger a `quit`. As a result, it's best to try and re[subscribe](#subscribe) when you get a `quit`, and if the resulting [watch ack](#watch-ack) is negative you can then conclude the `quit` was intentional and give up.
315−
316−| Key | JSON Type | Example Value | Description |
317−| ---------- | --------- | ------------- | --------------------------------------------- |
318−| `id` | Number | `4` | Request ID of the initial `subscribe` action. |
319−| `response` | String | `'quit'` | The kind of response. |
320−
321−#### Example
322−
323−```json
324−{
325− "id": 4,
326− "response": "quit"
327−}
328−```
329−
330−#### Action Required
331−
332−You must ack the event and you may wish to try and re[subscribe](#subscribe).
333−
334−## Scry
335−
336−A scry is a read-only request for some data.
337−
338−A scry takes the form of an [authenticated](#authentication) HTTP GET request to a URL path with the following format:
339−
340−```
341−http{s}://{host}/~/scry/{app}{path}.{mark}
342−```
343−
344−The `{app}` is the name of the Gall agent you want to query, for example `graph-store`.
345−
346−The `{path}` is a scry endpoint of the Gall agent in question. Eyre will always scry with a care of `%x`, so the `{path}` needn't specify that. For example, the `/x/keys` scry endpoint of `graph-store` would just be specified as `keys`.
347−
348−The `{mark}` is the type you want returned. It needn't just be `json` as with the channel system, it can be any `mark`, with two conditions:
349−
350−1. It must be possible to convert the `mark` produced by the specified scry endpoint to the `mark` you want returned.
351−2. It must be possible to convert the `mark` you want returned to a `mime` `mark`, otherwise Eyre can't encode it in the HTTP response.
352−
353−If your session cookie is invalid or missing, Eyre will respond with a 403 Forbidden status. If the scry endpoint cannot be found, Eyre will respond with a 404 Missing status. If the `mark` conversions can't be done, Eyre will respond with a 500 Internal Server Error status. Otherwise, Eyre will respond with a 200 OK status with the requested data in the body of the HTTP response.
354−
355−See the [Scrying](/docs/arvo/eyre/guide#scrying) section of the [Guide](/docs/arvo/eyre/guide) document for a practical example.
356−
357−## Spider
358−
359−See the [HTTP API](/docs/userspace/threads/http-api) section of the [Threads](/docs/userspace/threads/overview) documentation.
content/docs/arvo/eyre/eyre.mddeleted−61
@@ -1,61 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−+++
6−
7−Eyre is the webserver vane.
8−
9−HTTP messages come in from outside and Eyre produces HTTP messages in response. In general, apps do not call Eyre; rather, Eyre calls apps. Eyre has a number of ways to handle such HTTP requests which we'll briefly describe.
10−
11−## Authentication
12−
13−Most types of requests require the client provide a valid session cookie which is obtained by authenticating with your ship's web login code. Authentication is documented in the [Authentication](/docs/arvo/eyre/external-api-ref#authentication) section of the [External API Reference](/docs/arvo/eyre/external-api-ref) documentation.
14−
15−## The Channel System
16−
17−Eyre's channel system is the primary way of interacting with Gall agents from outside of Urbit. It provides a simple JSON API that allows you to send data to apps and subscribe for updates from apps. Updates come back on a SSE ([Server Sent Event](https://html.spec.whatwg.org/#server-sent-events)) stream which you can easily handle with an EventSource object in Javascript or the equivalent in whichever language you prefer.
18−
19−The channel system is designed to be extremely simple with just a handful of `action` and `response` JSON objects to deal. Essentially it's a thin layer on top of the underlying Gall agent interface. You can poke agents, subscribe for updates, etc, just like you would from within Urbit.
20−
21−Detailed documentation of the channel system's JSON API is provided in the [External API Reference](/docs/arvo/eyre/external-api-ref) document with corresponding examples in the [Guide](/docs/arvo/eyre/guide#using-the-channel-system) document.
22−
23−## Scrying
24−
25−Along with the channel system, Eyre also provides a way to make read-only requests for data which are called scries. Eyre's scry interface is separate to the channel system but may be useful in conjunction with it.
26−
27−Details of Eyre's scry API are in the [Scry](/docs/arvo/eyre/external-api-ref#scry) section of the [External API Reference](/docs/arvo/eyre/external-api-ref) document.
28−
29−## Spider Threads
30−
31−Spider (the Gall agent that manages threads) has an Eyre binding that allows you to run threads through Eyre. Spider's [HTTP API](/docs/userspace/threads/http-api) is not part of Eyre proper, so is documented separately in the [Threads](/docs/userspace/threads/overview) documentation.
32−
33−## Generators
34−
35−Generators, which are like Hoon scripts, can also be used through Eyre. Rather than having a predefined JSON API, they instead handle HTTP requests and return HTTP responses directly, and are therefore a more complex case that you're less likely to use.
36−
37−Their usage is explained in the [%serve](/docs/arvo/eyre/tasks#serve) section of the [Internal API Reference](/docs/arvo/eyre/tasks) documentation and a practical example is provided in the [Generators](/docs/arvo/eyre/guide#generators) section of the [Guide](/docs/arvo/eyre/guide) document.
38−
39−## Direct HTTP Handling With Gall Agents
40−
41−As well as the [Channel System](#the-channel-system) and [Scries](#scrying), it's also possible for Gall agents to deal directly with HTTP requests. This method is much more complicated than the channel system so you're unlikely to use it unless you want to build a custom HTTP-based API or something like that.
42−
43−This method is explained in the [%connect](/docs/arvo/eyre/tasks#connect) section of the [Internal API Reference](/docs/arvo/eyre/tasks) document and a detailed example is provided in the [Agents: Direct HTTP](/docs/arvo/eyre/guide#agents-direct-http) section of the [Guide](/docs/arvo/eyre/guide) document.
44−
45−## Cross-Origin Resource Sharing
46−
47−Eyre supports both simple [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) requests and OPTIONS preflight requests. It has a CORS registry with three categories - `approved`, `rejected` and `requests`. Eyre will respond positively for origins in its `approved` list and negatively for all others. Eyre will add origins in requests that it doesn't have in either its `approved` or `rejected` lists to its `requests` list. Eyre always allows all methods and headers over CORS.
48−
49−There are three generators - `+cors-registry`, `|cors-approve`, and `|cors-reject` to view, approve, and deny origins respectively from the dojo. Eyre also has [tasks](/docs/arvo/eyre/tasks) to [approve](/docs/arvo/eyre/tasks#approve-origin) and [reject](/docs/arvo/eyre/tasks#reject-origin) origins programmatically, and a number of [scry endpoints](/docs/arvo/eyre/scry) to query them. Examples are also included in the [Managing CORS Origins](/docs/arvo/eyre/guide#managing-cors-origins) section of the Guide document.
50−
51−## Sections
52−
53−[External API Reference](/docs/arvo/eyre/external-api-ref) - Details of Eyre's external API including the channel system's JSON API.
54−
55−[Internal API Reference](/docs/arvo/eyre/tasks) - The `task`s Eyre takes and the `gift`s it returns.
56−
57−[Scry Reference](/docs/arvo/eyre/scry) - The scry endpoints of Eyre.
58−
59−[Data Types](/docs/arvo/eyre/data-types) - Reference documentation of the various data types used by Eyre.
60−
61−[Guide](/docs/arvo/eyre/guide) - Practical examples of the different ways of using Eyre.
content/docs/arvo/eyre/guide.mddeleted−619
@@ -1,619 +0,0 @@
1−+++
2−title = "Guide"
3−weight = 6
4−template = "doc.html"
5−+++
6−
7−This document walks through practical examples of the various ways of interacting with Eyre. The [Basic](#basic) sections goes over the common methods of interacting through Eyre from an HTTP client, and the [Advanced](#advanced) section explains how to handle HTTP directly with generators and Gall agents.
8−
9−General documentation of the `task`s and methods described here are available in the [External API Reference](/docs/arvo/eyre/external-api-ref) document and the [Internal API Reference](/docs/arvo/eyre/tasks) document.
10−
11−## Basic
12−
13−Eyre's channel system is the typical way of interacting with Gall agents from an HTTP client. It provides a simple JSON API for actions like pokes, watches, etc, and an SSE event stream for subscription updates. Additionally, Eyre has a scry interface so you can retrieve data in a more ad-hoc manner. These examples use `curl` to be more language agnostic and to show the nitty-gritty details. In practice you'd probably use an "airlock" library (like [http-api](https://github.com/urbit/urbit/tree/master/pkg/npm/http-api) for Javascript) which abstracts things like ack'ing events, incrementing event IDs, manually composing the JSON for actions, etc.
14−
15−It's advisable to have a read through the [External API Reference](/docs/arvo/eyre/external-api-ref) before going through these examples.
16−
17−### Authenticating
18−
19−You must have a valid session cookie in order to use Eyre's interfaces (such as the channel system or scry interface). If your HTTP client is served from your ship, your browser will automatically add the session cookie it obtained upon login, so there's no need to worry about authentication in practice. If your client does not run in the browser or is not served by your ship, [authenticating](/docs/arvo/eyre/external-api-ref#authentication) with your web login code (which can be obtained by running `+code` in the dojo) is necessary.
20−
21−Here we'll try authenticating with the default fakezod code.
22−
23−Using `curl` in the unix terminal, we'll make an HTTP POST request with `"password=CODE"` in the body:
24−
25−```
26−curl -i localhost:8080/~/login -X POST -d "password=lidlut-tabwed-pillex-ridrup"
27−```
28−
29−Eyre will respond with HTTP status 204, and a `set-cookie` header containing the session cookie.
30−
31−```
32−HTTP/1.1 204 ok
33−Date: Tue, 18 May 2021 01:38:48 GMT
34−Connection: keep-alive
35−Server: urbit/vere-1.5
36−set-cookie: urbauth-~zod=0v3.j2062.1prp1.qne4e.goq3h.ksudm; Path=/; Max-Age=604800
37−```
38−
39−The `urbauth-....` cookie can be now be included in subsequent requests (e.g. to the channel system) by providing it in a Cookie HTTP header.
40−
41−### Using Channels
42−
43−Here we'll look at a practical example of Eyre's channel system. You can refer to the [Channels](/docs/arvo/eyre/external-api-ref#channels) section of the [External API Reference](/docs/arvo/eyre/external-api-ref) document for relevant details.
44−
45−First, we must obtain a session cookie by [authenticating](#authenticating). You will be copying the entry of the `set-cookie` field into the `--cookie` field in subsequent commands.
46−
47−Now that we have our cookie, we can try poking an app & simultaneously opening a new channel. In this case, we'll poke the `hood` app with a `mark` of `helm-hi` to print "Opening airlock" in the dojo.
48−
49−We'll do this with an HTTP PUT request, and we'll include the cookie we obtained when we authenticated in the `Cookie` header. The URL path we'll make the request to will be `http://localhost:8080/~/channel/mychannel`. The last part of the path is the channel `UID` - the name for our new channel. Normally you'd use the current unix time plus a hash to ensure uniqueness, but in this case we'll just use `mychannel` for simplicity.
50−
51−The data will be a JSON array containing a [poke](/docs/arvo/eyre/external-api-ref#poke) `action`:
52−
53−```
54−curl --header "Content-Type: application/json" \
55− --cookie "urbauth-~zod=0v3.j2062.1prp1.qne4e.goq3h.ksudm" \
56− --request PUT \
57− --data '[{"id":1,"action":"poke","ship":"zod","app":"hood","mark":"helm-hi","json":"Opening airlock"}]' \
58− http://localhost:8080/~/channel/my-channel
59−```
60−
61−If we now have a look in the dojo we'll see it's printed our message, so the poke was successful:
62−
63−```
64−< ~zod: Opening airlock
65−```
66−
67−Now we can connect to the `mychannel` channel we opened. We do this with an HTTP GET request with our session cookie and the same path as the last request:
68−
69−```
70−curl -i --cookie "urbauth-~zod=0v3.j2062.1prp1.qne4e.goq3h.ksudm" http://localhost:8080/~/channel/my-channel
71−```
72−
73−Eyre will respond with an HTTP status code of 200 and a `content-type` of `text/event-stream`, indicating an SSE (Server Sent Event) stream. It will also send us any pending events on the channel - in this case the poke ack as a [poke](/docs/arvo/eyre/external-api-ref#poke-ack) `response` for our original poke:
74−
75−```
76−HTTP/1.1 200 ok
77−Date: Tue, 18 May 2021 01:40:47 GMT
78−Connection: keep-alive
79−Server: urbit/vere-1.5
80−set-cookie: urbauth-~zod=0v3.j2062.1prp1.qne4e.goq3h.ksudm; Path=/; Max-Age=604800
81−connection: keep-alive
82−cache-control: no-cache
83−content-type: text/event-stream
84−transfer-encoding: chunked
85−
86−id: 0
87−data: {"ok":"ok","id":1,"response":"poke"}
88−```
89−
90−Normally this event stream would be handled by an EventSource object or similar in Javascript or the equivalent in whatever other language you're using. Here, though, we'll continue using `curl` for simplicity.
91−
92−Leaving the event stream connection open, in another shell session on unix we'll try subscribing to the watch path of a Gall agent - the `/updates` watch path of `graph-store` in this case.
93−
94−We'll do this in the same way as the initial poke, except this time it will be a [subscribe](/docs/arvo/eyre/external-api-ref#subscribe) `action`:
95−
96−```
97−curl --header "Content-Type: application/json" \
98− --cookie "urbauth-~zod=0v3.j2062.1prp1.qne4e.goq3h.ksudm" \
99− --request PUT \
100− --data '[{"id":2,"action":"subscribe","ship":"zod","app":"graph-store","path":"/updates"}]' \
101− http://localhost:8080/~/channel/my-channel
102−```
103−
104−Notice we've incremented the `id` to `2`. Eyre doesn't require IDs to be sequential, merely numerical and unique, but sequential IDs are typically the most practical.
105−
106−Back in the event stream, we'll see a positive watch ack as a [subscribe](/docs/arvo/eyre/external-api-ref#watch-ack) `response`, meaning the subscription has been successful:
107−
108−```
109−id: 1
110−data: {"ok":"ok","id":2,"response":"subscribe"}
111−```
112−
113−Now we'll try trigger an event on our event stream. In fakezod's Landscape, create a new chat channel named "test". You should see the `add-graph` `graph-update` come through on our channel in a [diff](/docs/arvo/eyre/external-api-ref#diff) `response`:
114−
115−```
116−id: 2
117−data: {"json":{"graph-update":{"add-graph":{"graph":{},"resource":{"name":"test-1183","ship":"zod"},"mark":"graph-validator-chat","overwrite":false}}},"id":2,"response":"diff"}
118−```
119−
120−All events we receive must be `ack`ed so Eyre knows we've successfully received them. To do this we'll send an [ack](/docs/arvo/eyre/external-api-ref#ack) `action` which specifies the `event-id` of the event in question - `2` in this case:
121−
122−```
123−curl --header "Content-Type: application/json" \
124− --cookie "urbauth-~zod=0v3.j2062.1prp1.qne4e.goq3h.ksudm" \
125− --request PUT \
126− --data '[{"id":3,"action":"ack","event-id":2}]' \
127− http://localhost:8080/~/channel/my-channel
128−```
129−
130−This same pattern would be repeated for all subsequent events. Note that when you `ack` one event, you also implicitly `ack` all previous events, so in this case event `1` will also be `ack`ed.
131−
132−When we're finished, we can unsubscribe from `graph-store` `/update`. We do this by sending Eyre a [unsubscribe](/docs/arvo/eyre/external-api-ref#unsubscribe) `action`, and specify the request ID of the original `subscribe` `action` in the `subscription` field - `2` in our case:
133−
134−```
135−curl --header "Content-Type: application/json" \
136− --cookie "urbauth-~zod=0v3.j2062.1prp1.qne4e.goq3h.ksudm" \
137− --request PUT \
138− --data '[{"id":4,"action":"unsubscribe","subscription":2}]' \
139− http://localhost:8080/~/channel/my-channel
140−```
141−
142−Unlike `poke` and `subscribe` actions, Eyre doesn't acknowledge `unsubscribe`s, but we'll now have stopped receiving updates from `graph-store`.
143−
144−Finally, let's close the channel itself. We can do this simply by sending Eyre a [delete](/docs/arvo/eyre/external-api-ref#delete-channel) `action`:
145−
146−```
147−curl --header "Content-Type: application/json" \
148− --cookie "urbauth-~zod=0v3.j2062.1prp1.qne4e.goq3h.ksudm" \
149− --request PUT \
150− --data '[{"id":5,"action":"delete"}]' \
151− http://localhost:8080/~/channel/my-channel
152−```
153−
154−With our channel deleted, we can now close the connection on the client side.
155−
156−### Scrying
157−
158−Here we'll look at performing scries through Eyre. You can refer to the [Scry](/docs/arvo/eyre/external-api-ref#scry) section of the [External API Reference](/docs/arvo/eyre/external-api-ref) document for relevant details.
159−
160−First we must obtain a session cookie by [authenticating](#authenticating).
161−
162−Having obtained a cookie, we can now try a scry. We'll scry the `graph-store` Gall agent on the `/x/keys` scry path, which will return the list of channels it has. If you don't already have any chat channels on your fakezod, go ahead and create one via landscape so it'll have something to return.
163−
164−The url path will be `/~/scry/graph-store/keys.json`. The `/~/scry` part specifies a scry, the `/graph-store` part is the Gall agent, the `/keys` is the scry path without the `care`, and the `.json` file extension specifies the return `mark`.
165−
166−The request will be an HTTP GET request:
167−
168−```
169−curl -i --cookie "urbauth-~zod=0v1.1pseu.tq7hs.hps2t.ltaf1.tmqjm" \
170− --request GET \
171− http://localhost:8080/~/scry/graph-store/keys.json
172−```
173−
174−Eyre will respond with HTTP status 200 if it's successful and the body of the response will contain the data we requested:
175−
176−```
177−HTTP/1.1 200 ok
178−Date: Fri, 04 Jun 2021 10:16:32 GMT
179−Connection: keep-alive
180−Content-Length: 61
181−Server: urbit/vere-1.5
182−set-cookie: urbauth-~zod=0v1.1pseu.tq7hs.hps2t.ltaf1.tmqjm; Path=/; Max-Age=604800
183−content-type: application/json
184−
185−{"graph-update":{"keys":[{"name":"test-1183","ship":"zod"}]}}
186−```
187−
188−Now let's make a request to a non-existent scry endpoint:
189−
190−```
191−curl -i --cookie "urbauth-~zod=0v1.1pseu.tq7hs.hps2t.ltaf1.tmqjm" \
192− --request GET \
193− http://localhost:8080/~/scry/foo/bar/baz.json
194−```
195−
196−Eyre will respond with a 404 Missing status and an error message:
197−
198−```
199−HTTP/1.1 404 missing
200−Date: Fri, 04 Jun 2021 10:22:51 GMT
201−Connection: keep-alive
202−Content-Length: 187
203−Server: urbit/vere-1.5
204−set-cookie: urbauth-~zod=0v1.1pseu.tq7hs.hps2t.ltaf1.tmqjm; Path=/; Max-Age=604800
205−content-type: text/html
206−
207−&lt;html>&lt;head>&lt;title>404 Not Found&lt;/title>&lt;/head>&lt;body>&lt;h1>Not Found&lt;/h1>&lt;p>There was an error while handling the request for /foo/bar/baz.json.&lt;/p>&lt;code>no scry result&lt;/code>&lt;/body>&lt;/html>
208−```
209−
210−## Advanced
211−
212−Rather than using things like Eyre's channel system described in the [Basic](#basic) section, it's possible to handle HTTP requests directly in Gall agents or generators. This is useful if you want to implement a custom API or work with `sail` to dynamically compose HTML inside an agent.
213−
214−### Agents: Direct HTTP
215−
216−Here we'll look at handling HTTP requests directly in Gall agents rather than using Eyre's channel system.
217−
218−You can refer to the [%connect](/docs/arvo/eyre/tasks#connect) section of the [Internal API Reference](/docs/arvo/eyre/tasks) document for relevant details.
219−
220−Here's a Gall agent that demonstrates this method. It binds the URL path `/foo`, serves `Hello, World!` for GET requests and a `405` error for all others. It also prints debug information to the terminal as various things happen.
221−
222−Note that this example does a lot of things manually for demonstrative purposes. In practice you'd likely want to use a library like `/lib/server.hoon` to cut down on boilerplate code.
223−
224−`eyre-agent.hoon`
225−
226−```hoon
227−/+ default-agent, dbug
228−=* card card:agent:gall
229−%- agent:dbug
230−^- agent:gall
231−|_ =bowl:gall
232−+* this .
233− def ~(. (default-agent this %|) bowl)
234−::
235−++ on-init on-init:def
236−++ on-save on-save:def
237−++ on-load on-load:def
238−++ on-poke
239− |= [=mark =vase]
240− ^- (quip card _this)
241− ?+ mark
242− (on-poke:def [mark vase])
243− ::
244− %noun
245− ?. =(q.vase %bind)
246− %- (slog leaf+"Bad argument." ~)
247− `this
248− %- (slog leaf+"Attempting to bind /foo." ~)
249− :_ this
250− [%pass /bind-foo %arvo %e %connect `/'foo' %eyre-agent]~
251− ::
252− %handle-http-request
253− =/ req !< (pair @ta inbound-request:eyre) vase
254− ~& [mark req]
255− ?+ method.request.q.req
256− =/ data=octs
257− (as-octs:mimes:html '&lt;h1>405 Method Not Allowed&lt;/h1>')
258− =/ content-length=@t
259− (crip ((d-co:co 1) p.data))
260− =/ =response-header:http
261− :- 405
262− :~ ['Content-Length' content-length]
263− ['Content-Type' 'text/html']
264− ['Allow' 'GET']
265− ==
266− :_ this
267− :~
268− [%give %fact [/http-response/[p.req]]~ %http-response-header !>(response-header)]
269− [%give %fact [/http-response/[p.req]]~ %http-response-data !>(`data)]
270− [%give %kick [/http-response/[p.req]]~ ~]
271− ==
272− ::
273− %'GET'
274− =/ data=octs
275− (as-octs:mimes:html '&lt;h1>Hello, World!&lt;/h1>')
276− =/ content-length=@t
277− (crip ((d-co:co 1) p.data))
278− =/ =response-header:http
279− :- 200
280− :~ ['Content-Length' content-length]
281− ['Content-Type' 'text/html']
282− ==
283− :_ this
284− :~
285− [%give %fact [/http-response/[p.req]]~ %http-response-header !>(response-header)]
286− [%give %fact [/http-response/[p.req]]~ %http-response-data !>(`data)]
287− [%give %kick [/http-response/[p.req]]~ ~]
288− ==
289− ==
290− ==
291−++ on-watch
292− |= =path
293− ^- (quip card _this)
294− ?+ path
295− (on-watch:def path)
296− ::
297− [%http-response *]
298− %- (slog leaf+"Eyre subscribed to {(spud path)}." ~)
299− `this
300− ==
301−++ on-leave on-leave:def
302−++ on-peek on-peek:def
303−++ on-agent on-agent:def
304−++ on-arvo
305− |= [=wire =sign-arvo]
306− ^- (quip card _this)
307− ?. ?=([%bind-foo ~] wire)
308− (on-arvo:def [wire sign-arvo])
309− ?> ?=([%eyre %bound *] sign-arvo)
310− ?: accepted.sign-arvo
311− %- (slog leaf+"/foo bound successfully!" ~)
312− `this
313− %- (slog leaf+"Binding /foo failed!" ~)
314− `this
315−++ on-fail on-fail:def
316−--
317−```
318−
319−Save the above to `/app/eyre-agent.hoon`. Commit it:
320−
321−```
322−> |commit %base
323−>=
324−+ /~zod/base/2/app/eyre-agent/hoon
325−```
326−
327−...and start it:
328−
329−```
330−> |rein %base [& %eyre-agent]
331−```
332−
333−Now, first we need to bind a URL to our app. In the `++ on-poke` arm, our agent will send a [%connect](/docs/arvo/eyre/tasks#connect) `task` to Eyre when poked with `%bind`:
334−
335−```hoon
336− %noun
337−?. =(q.vase %bind)
338− %- (slog leaf+"Bad argument." ~)
339− `this
340−%- (slog leaf+"Attempting to bind /foo." ~)
341−:_ this
342−[%pass /eyre %arvo %e %connect `/'foo' %eyre-agent]~
343−```
344−
345−...and when `%eyre` responds with a `%bound` `gift`, the `+on-agent` arm will print whether the bind succeeded:
346−
347−```hoon
348− [%eyre %bound *]
349−?: accepted.sign-arvo
350− %- (slog leaf+"/foo bound successfully!" ~)
351− `this
352−%- (slog leaf+"Binding /foo failed!" ~)
353−`this
354−```
355−
356−...so let's try:
357−
358−```
359−> :eyre-agent %bind
360−>=
361−Attempting to bind /foo.
362−/foo bound successfully!
363−```
364−
365−As you can see, we have successfully bound the `/foo` url path. Now we can try making an HTTP request. Over in the unix terminal, we can make a GET request using curl:
366−
367−```
368−> curl -i localhost:8080/foo
369−HTTP/1.1 200 ok
370−Date: Mon, 17 May 2021 04:39:40 GMT
371−Connection: keep-alive
372−Server: urbit/vere-1.5
373−Content-Type: text/html
374−Content-Length: 22
375−transfer-encoding: chunked
376−
377−&lt;h1>Hello, World!&lt;/h1>%
378−```
379−
380−...which has succeed! This is because the `+on-poke` arm tests for http GET requests and responds with `Hello, World!` when it sees one:
381−
382−```hoon
383− %'GET'
384−=/ data=octs
385− (as-octs:mimes:html '&lt;h1>Hello, World!&lt;/h1>')
386−=/ content-length=@t
387− (crip ((d-co:co 1) p.data))
388−=/ =response-header:http
389− :- 200
390− :~ ['Content-Length' content-length]
391− ['Content-Type' 'text/html']
392− ==
393−:_ this
394−:~
395− [%give %fact [/http-response/[p.req]]~ %http-response-header !>(response-header)]
396− [%give %fact [/http-response/[p.req]]~ %http-response-data !>(`data)]
397− [%give %kick [/http-response/[p.req]]~ ~]
398−==
399−```
400−
401−Back in the dojo, our app's `+on-watch` arm has printed the path on which Eyre has subscribed for the response:
402−
403−```
404−Eyre subscribed to /http-response/~.eyre_0v3.1knjk.l544e.5uds6.fn9l2.f8929.
405−```
406−
407−...and it's also printed the request so you can see how it looks when it comes in:
408−
409−```
410−[ %handle-http-request
411− p=~.~.eyre_0v3.1knjk.l544e.5uds6.fn9l2.f8929
412− q
413− [ authenticated=%.n
414− secure=%.n
415− address=[%ipv4 .127.0.0.1]
416− request
417− [ method=%'GET'
418− url='/foo'
419− header-list
420− ~[
421− [key='host' value='localhost:8080']
422− [key='user-agent' value='curl/7.76.1']
423− [key='accept' value='*/*']
424− ]
425− body=~
426− ]
427− ]
428−]
429−```
430−
431−This is a very rudimentary app but it demonstrates the basic mechanics of dealing with HTTP requests and serving responses.
432−
433−### Generators
434−
435−Here we'll look at running a generator via Eyre. Eyre doesn't have a mediated JSON API for generators, instead it just passes through the HTTP request and returns the HTTP response composed by the generator.
436−
437−You can refer to the [%serve](/docs/arvo/eyre/tasks#serve) section of the [Internal API Reference](/docs/arvo/eyre/tasks) document for relevant details.
438−
439−Here's a very simple generator that will just echo back the body of the request (if available) along with the current datetime. You can save it in the `/gen` directory and `|commit %base`.
440−
441−Note that this example does some things manually for demonstrative purposes. In practice you'd likely want to use a library like `/lib/server.hoon` to cut down on boilerplate code.
442−
443−`eyre-gen.hoon`
444−
445−```hoon
446−|= [[now=@da eny=@uvJ bec=beak] ~ ~]
447−|= [authenticated=? =request:http]
448−^- simple-payload:http
449−=/ msg=@t
450− ?~ body.request
451− (scot %da now)
452− (cat 3 (cat 3 (scot %da now) 10) q.u.body.request)
453−=/ data=octs
454− (as-octs:mimes:html msg)
455−=/ =response-header:http
456− [200 ['Content-Type' 'text/plain']~]
457−[response-header `data]
458−```
459−
460−Eyre requires generators to be a gate within a gate. The sample of the first gate must be:
461−
462−```hoon
463−[[now=@da eny=@uvJ bec=beak] ~ ~]
464−```
465−
466−The sample of the second nested gate must be:
467−
468−```hoon
469−[authenticated=? =request:http]
470−```
471−
472−The return type of the generator must be [$simple-payload:http](/docs/arvo/eyre/data-types#simple-payloadhttp). If you look at our example generator you'll see it meets these requirements.
473−
474−Because generators return the entire HTTP message as a single `simple-payload`, Eyre can calculate the `content-length` itself and automatically add the header.
475−
476−In order to make our generator available, we must bind it to a URL path. To do this, we send Eyre a `%serve` `task`, which looks like:
477−
478−```hoon
479−[%serve =binding =generator]
480−```
481−
482−The [$binding](/docs/arvo/eyre/data-types#binding) specifies the site and URL path, and the [$generator](/docs/arvo/eyre/data-types#generator) specifies the `desk`, the `path` to the generator, and arguments. Note that the passing of arguments to the generator by Eyre is not currently implemented, so you can just leave that as `~` since it won't do anything.
483−
484−Let's bind our generator to the `/mygen` URL path with the `|pass` command in the dojo:
485−
486−```
487−|pass [%e [%serve `/mygen %base /gen/eyre-gen/hoon ~]]
488−```
489−
490−Note that Eyre responds with a `%bound` `gift` to indicate whether the binding succeeded but `|pass` doesn't take such responses so it's not shown.
491−
492−Now let's try making an HTTP request using `curl` in the unix terminal:
493−
494−```
495−curl -i http://localhost:8080/mygen --data 'blah blah blah'
496−```
497−
498−We can see that the request has succeeded and our generator has responded with the datetime and request body:
499−
500−```
501−HTTP/1.1 200 ok
502−Date: Sat, 29 May 2021 09:19:45 GMT
503−Connection: keep-alive
504−Content-Length: 41
505−Server: urbit/vere-1.5
506−Content-Type: text/plain
507−Content-Length: 41
508−
509−~2021.5.29..09.19.45..e096
510−blah blah blah
511−```
512−
513−## Managing CORS Origins
514−
515−Here we'll look at approving and rejecting a CORS origin by passing Clay a [%approve-origin](/docs/arvo/eyre/tasks#approve-origin) `task` and [%reject-origin](/docs/arvo/eyre/tasks#reject-origin) `task` respectively.
516−
517−In this example we'll use more manual methods for demonstrative purposes but note there are also the `|cors-approve` and `|cors-reject` generators to approve/reject origins from the dojo, and the `+cors-registry` generator for viewing the CORS configuration.
518−
519−First, using `|pass` in the dojo, let's approve the origin `http://foo.example` by sending Eyre a `%approve-origin` `task`:
520−
521−```
522−|pass [%e [%approve-origin 'http://foo.example']]
523−```
524−
525−Now if we scry for the [approved](/docs/arvo/eyre/scry#cors-approved) CORS `set`:
526−
527−```
528−> .^(approved=(set @t) %ex /=//=/cors/approved)
529−approved={'http://foo.example'}
530−```
531−
532−...we can see that `http://foo.example` has been added.
533−
534−Next, let's test it by sending Eyre a CORS preflight request via `curl` in unix:
535−
536−```
537−curl -i -X OPTIONS \
538− -H "Access-Control-Request-Method: POST" \
539− -H "Access-Control-Request-Headers: X-Requested-With" \
540− -H "Origin: http://foo.example" \
541− http://localhost:8080
542−```
543−
544−We can see in the response that it has succeeded:
545−
546−```
547−HTTP/1.1 204 ok
548−Date: Fri, 28 May 2021 12:37:12 GMT
549−Connection: keep-alive
550−Server: urbit/vere-1.5
551−Access-Control-Allow-Origin: http://foo.example
552−Access-Control-Allow-Credentials: true
553−Access-Control-Allow-Headers: X-Requested-With
554−Access-Control-Allow-Methods: POST
555−```
556−
557−Now we'll try rejecting an `origin`. Back in the dojo, let's `|pass` Eyre a `%reject-origin` `task` for `http://bar.example`:
558−
559−```
560−|pass [%e [%reject-origin 'http://bar.example']]
561−```
562−
563−If we scry for the [rejected](/docs/arvo/eyre/scry#cors-rejected) CORS `set`:
564−
565−```
566−> .^(rejected=(set @t) %ex /=//=/cors/rejected)
567−rejected={'http://bar.example'}
568−```
569−
570−...we can see that `http://bar.example` has been added.
571−
572−If we again test it with `curl` in unix:
573−
574−```
575−curl -i -X OPTIONS \
576− -H "Access-Control-Request-Method: POST" \
577− -H "Access-Control-Request-Headers: X-Requested-With" \
578− -H "Origin: http://bar.example" \
579− http://localhost:8080
580−```
581−
582−...we can see that, as expected, it has not returned the access control headers:
583−
584−```
585−HTTP/1.1 404 missing
586−Date: Fri, 28 May 2021 12:38:47 GMT
587−Connection: close
588−Server: urbit/vere-1.5
589−```
590−
591−Finally, let's look at CORS requests that are neither approved nor rejected.
592−
593−If we make another request with `curl` on unix, this time for `http://baz.example` which we haven't added to a list:
594−
595−```
596−curl -i -X OPTIONS \
597− -H "Access-Control-Request-Method: POST" \
598− -H "Access-Control-Request-Headers: X-Requested-With" \
599− -H "Origin: http://baz.example" \
600− http://localhost:8080
601−```
602−
603−...we can see it also correctly fails to return the access control headers:
604−
605−```
606−HTTP/1.1 404 missing
607−Date: Fri, 28 May 2021 12:39:59 GMT
608−Connection: close
609−Server: urbit/vere-1.5
610−```
611−
612−Now if we scry for the [requests](/docs/arvo/eyre/scry#cors-requests) CORS `set`:
613−
614−```
615−> .^(requests=(set @t) %ex /=//=/cors/requests)
616−requests={'http://baz.example' 'http://localhost:8080'}
617−```
618−
619−... we can see it has automatically been added by the mere fact of the request being made.
content/docs/arvo/eyre/scry.mddeleted−195
@@ -1,195 +0,0 @@
1−+++
2−title = "Scry Reference"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−Here are all of Eyre's scry endpoints. There's not too many and they mostly deal with either CORS settings or aspects of the state of connections.
8−
9−The first few have a `care` of `x` and are a scry like `.^({TYPE} %ex /=//=/{SOME-PATH})` (note the empty `desk`). The rest have no `care` and the tag replaces the `desk` like `.^({TYPE} %e /={SOMETHING}=)`.
10−
11−All examples are run from the dojo.
12−
13−## `/cors`
14−
15−An `x` scry with a `path` of `/cors` will return Eyre's CORS origin registry. The type returned is a [cors-registry](/docs/arvo/eyre/data-types#cors-registry) which contains the `set`s of approved, rejected and requested origins.
16−
17−### Example
18−
19−```
20−> .^(cors-registry:eyre %ex /=//=/cors)
21−[ requests={~~http~3a.~2f.~2f.baz~.example}
22− approved={~~http~3a.~2f.~2f.foo~.example}
23− rejected={~~http~3a.~2f.~2f.bar~.example}
24−]
25−```
26−
27−## `/cors/requests`
28−
29−An `x` scry with a `path` of `/cors/requests` will return the `set` of pending origin requests. These are origins that were in an `Origin: ...` HTTP header but weren't in the existing approved or rejected sets. The type returned is a `(set origin:eyre)`.
30−
31−### Example
32−
33−```
34−> .^(requests=(set origin:eyre) %ex /=//=/cors/requests)
35−requests={~~http~3a.~2f.~2f.baz~.example}
36−```
37−
38−## `/cors/approved`
39−
40−An `x` scry with a `path` of `/cors/approved` will return the `set` of approved CORS origins. The type returned is a `(set origin:eyre)`.
41−
42−### Example
43−
44−```
45−> .^(approved=(set origin:eyre) %ex /=//=/cors/approved)
46−approved={~~http~3a.~2f.~2f.foo~.example}
47−```
48−
49−## `/cors/approved/{ORIGIN}`
50−
51−An `x` scry whose `path` is `/cors/approved/{ORIGIN}` tests whether the given origin URL is in the `approved` set of the CORS registry. The type returned is a simple `?`.
52−
53−The origin URL is a `@t`, but since `@t` may not be valid in a path, it must be encoded in a `@ta` using `+scot` like `(scot %t 'foo')` rather than just `'foo'`.
54−
55−### Examples
56−
57−```
58−> .^(? %ex /=//=/cors/approved/(scot %t 'http://foo.example'))
59−%.y
60−```
61−
62−```
63−> .^(? %ex /=//=/cors/approved/(scot %t 'http://bar.example'))
64−%.n
65−```
66−
67−## `/cors/rejected`
68−
69−An `x` scry with a `path` of `/cors/rejected` will return the `set` of rejected CORS origins. The type returned is a `(set origin:eyre)`.
70−
71−### Example
72−
73−```
74−> .^(rejected=(set origin:eyre) %ex /=//=/cors/rejected)
75−rejected={~~http~3a.~2f.~2f.bar~.example}
76−```
77−
78−## `/cors/rejected/{ORIGIN}`
79−
80−An `x` scry whose `path` is `/cors/rejected/{ORIGIN}` tests whether the given origin URL is in the `rejected` set of the CORS registry. The type returned is a simple `?`.
81−
82−The origin URL must be a cord-encoded `@t` rather than just the plain `@t`, so you'll have to do something like `(scot %t 'foo')` rather than just `'foo'`.
83−
84−### Examples
85−
86−```
87−> .^(? %ex /=//=/cors/rejected/(scot %t 'http://bar.example'))
88−%.y
89−```
90−
91−```
92−> .^(? %ex /=//=/cors/rejected/(scot %t 'http://foo.example'))
93−%.n
94−```
95−
96−## `/authenticated/cookie`
97−
98−An `x` scry whose `path` is `/authenticated/cookie/{COOKIE}` tests whether the given cookie is currently valid. The type returned is a `?`.
99−
100−The cookie must be the full cookie including the `urbauth-{SHIP}=` part. The cookie must be a cord-encoded `@t` rather than just a plain `@t`, so you'll have to do something like `(scot %t 'foo')` rather than just `'foo'`.
101−
102−### Examples
103−
104−```
105−> .^(? %ex /=//=/authenticated/cookie/(scot %t 'urbauth-~zod=0vvndn8.bfsjj.j3614.k40ha.8fomi'))
106−%.y
107−```
108−
109−```
110−> .^(? %ex /=//=/authenticated/cookie/(scot %t 'foo'))
111−%.n
112−```
113−
114−## `%bindings`
115−
116−A scry with `bindings` in place of the `desk` in the `beak` will return Eyre's URL path bindings. The type returned is a `(list [binding:eyre duct action:eyre])` (see the [$binding](/docs/arvo/eyre/data-types#binding) & [$action](/docs/arvo/eyre/data-types#action) sections of the Data Types document for details).
117−
118−### Example
119−
120−```
121−> .^((list [binding:eyre duct action:eyre]) %e /=bindings=)
122−~[
123− [ [site=~ path=<|~landscape js bundle|>]
124− ~[/gall/use/file-server/0w2.EijQB/~zod/~landscape/js/bundle /dill //term/1]
125− [%app app=%file-server]
126− ]
127− [ [site=~ path=<|~landscape|>]
128− ~[/gall/use/file-server/0w2.EijQB/~zod/~landscape /dill //term/1]
129− [%app app=%file-server]
130− ]
131− ...(truncated for brevity)...
132−]
133−```
134−
135−## `%connections`
136−
137−A scry with `bindings` in place of the `desk` in the `beak` will return all open HTTP connections that aren't fully complete. The type returned is a `(map duct outstanding-connection:eyre)` (see the [$outstanding-connection](/docs/arvo/eyre/data-types#outstanding-connection) section of the Data Types document for details).
138−
139−### Example
140−
141−```
142−> .^((map duct outstanding-connection:eyre) %e /=connections=)
143−{}
144−```
145−
146−## `%authentication-state`
147−
148−A scry with `authentication-state` in place of the `desk` in the `beak` will return authentication details of all current sessions. The type returned is a [$authentication-state](/docs/arvo/eyre/data-types#authentication-state). The `p` field is the cookie sans the `urbauth-{SHIP}=` part.
149−
150−### Example
151−
152−```
153−> .^(authentication-state:eyre %e /=authentication-state=)
154− sessions
155−{ [ p=0v3.kags1.hj7hm.6llrl.cga2j.eh1r7
156− q=[expiry-time=~2021.5.20..08.44.27..39e0 channels={}]
157− ]
158−}
159−```
160−
161−## `%channel-state`
162−
163−A scry with `channel-state` in place of the `desk` in the `beak` will return details of the state of each channel. The type returned is a [channel-state](/docs/arvo/eyre/data-types#channel-state).
164−
165−### Example
166−
167−```
168−> .^(channel-state:eyre %e /=channel-state=)
169−[ session
170− { [ p='1601844290-ae45b'
171− q
172− [ state=[%.y p=[date=~2021.5.13..20.44.27..39e0 duct=~[//http-server/0v2.kmj6q/26/1]]]
173− next-id=1
174− last-ack=~2021.5.13..08.44.27..39e0
175− events={[id=0 request-id=2 channel-event=[%poke-ack p=~]]}
176− unacked={}
177− subscriptions={}
178− heartbeat=~
179− ]
180− ]
181− }
182− duct-to-key={}
183−]
184−```
185−
186−## `%host`
187−
188−A scry with `host` in place of the `desk` in the `beak` will return host details of the ship. The type returned is a `hart:eyre`.
189−
190−### Example
191−
192−```
193−> .^(hart:eyre %e /=host=)
194−[p=%.n q=[~ 8.080] r=[%.y p=<|localhost|>]]
195−```
content/docs/arvo/eyre/tasks.mddeleted−213
@@ -1,213 +0,0 @@
1−+++
2−title = "Internal API Reference"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−This document details all the `task`s you're likely to use to interact with Eyre, as well as the `gift`s you'll receive in response.
8−
9−The primary way of interacting with Eyre is from the outside with HTTP requests. As a result, most of its `task`s are only used internally and you're unlikely to need to deal with them directly. The ones you may want to use in certain cases are [%connect](#connect), [%serve](#serve), [%disconnect](#disconnect), [%approve-origin](#approve-origin) and [%reject-origin](#reject-origin), and they are also demonstrated in the [Guide](/docs/arvo/eyre/guide) document. The rest are just documented for completeness.
10−
11−Many of the types referenced are detailed in the [Data Types](/docs/arvo/eyre/data-types) document. It may also be useful to look at the `+eyre` section of `/sys/lull.hoon` in Arvo where these `task`s, `gift`s and data structures are defined.
12−
13−## `%live`
14−
15−```hoon
16−[%live insecure=@ud secure=(unit @ud)]
17−```
18−
19−This `task` notifies Eyre of the listening HTTPS and HTTP ports. It is automatically sent to Eyre by the runtime and should not be used manually.
20−
21−The `insecure` field is the HTTP port and `secure` is the optional HTTPS port.
22−
23−#### Returns
24−
25−Eyre returns no `gift` in response to a `%live` `task`.
26−
27−## `%rule`
28−
29−```hoon
30−[%rule =http-rule]
31−```
32−
33−This `task` either configures HTTPS with a certificate and keypair, or configures a DNS binding. This is typically done for you by the `%acme` app, rather than done manually.
34−
35−The [$http-rule](/docs/arvo/eyre/data-types#http-rule) is either tagged with `%cert` or `%turf`. A `%cert` `http-rule` sets an HTTPS certificate and keypair or removes it if null. A `%turf` `http-rule` either adds or removes a DNS binding depending on whether the `action` is `%put` or `%del`. Note that using `%turf` will automatically cause the system to try and obtain a certificate and keypair via Letsencrypt.
36−
37−#### Returns
38−
39−Eyre returns no `gift` in response to a `%rule` `task`.
40−
41−## `%request`
42−
43−```hoon
44−[%request secure=? =address =request:http]
45−```
46−
47−This `task` is how Eyre receives an inbound HTTP request. It will ordinarily be sent to Eyre by the runtime so you wouldn't use it except perhaps in tests.
48−
49−The `secure` field says whether it's over HTTPS. The `address` is the IP address from which the request originated. The [$request:http](/docs/arvo/eyre/data-types#requesthttp) is the HTTP request itself containing the method, URL, headers, and body.
50−
51−#### Returns
52−
53−Eyre may `pass` a `%response` `gift` on the appropriate `duct` depending on the contents of the `%request`, state of the connection, and other factors.
54−
55−## `%request-local`
56−
57−```hoon
58−[%request-local secure=? =address =request:http]
59−```
60−
61−This `task` is how Eyre receives an inbound HTTP request over the local loopback port. It behaves the same and takes the same arguments as in the [%request](#request) example except it skips any normally required authentication. Just like for a [%request](#request) `task`, you'd not normally use this manually.
62−
63−#### Returns
64−
65−Eyre may `pass` a `%response` `gift` on the appropriate `duct` depending on the contents of the `%request`, state of the connection, and other factors.
66−
67−## `%cancel-request`
68−
69−```hoon
70−[%cancel-request ~]
71−```
72−
73−This `task` is sent to Eyre by the runtime when an HTTP client closes its previously established connection. You would not normally use this manually.
74−
75−This `task` takes no arguments.
76−
77−#### Returns
78−
79−Eyre may `pass` a `%response` `gift` on the appropriate `duct` depending on the state of the connection and other factors.
80−
81−## `%connect`
82−
83−```hoon
84−[%connect =binding app=term]
85−```
86−
87−This `task` binds a Gall agent to a URL path so it can receive HTTP requests and return HTTP responses directly.
88−
89−The [$binding](/docs/arvo/eyre/data-types#binding) contains a URL path and optional domain through which the agent will be able to take HTTP requests. The `app` is just the name of the Gall agent to bind. Note that if you bind a URL path of `/foo`, Eyre will also match `/foo/bar`, `/foo/bar/baz`, etc.
90−
91−If an agent is bound in Eyre using this method, HTTP requests to the bound URL path are poked directly into the agent. The `cage` in the poke have a `%handle-http-request` `mark` and a `vase` of `[@ta inbound-request:eyre]` where the `@ta` is a unique `eyre-id` and the [$inbound-request](/docs/arvo/eyre/data-types#inbound-request) contains the HTTP request itself.
92−
93−Along with the poke, Eyre will also subscribe to the `/http-response/[eyre-id]` `path` of the agent and await a response, which it will pass on to the HTTP client who made the request. Eyre expects at least two `fact`s and a `kick` on this subscription path to complete the response and close the connection (though it can take more than two `fact`s).
94−
95−The first `fact`'s `cage` must have a `mark` of `%http-response-header` and a `vase` containing a [$response-header:http](/docs/arvo/eyre/data-types#response-headerhttp) with the HTTP status code and headers of the response.
96−
97−The `cage` of the second and subsequent `fact`s must have a `mark` of `%http-response-data` and a `vase` containing a `(unit octs)` with the actual data of the response. An `octs` is just `[p=@ud q=@]` where `p` is the byte-length of `q`, the data. You can send an arbitrary number of these.
98−
99−Finally, once you've sent all the `fact`s you want, you can `kick` Eyre's subscription and it will complete the response and close the connection to the HTTP client.
100−
101−#### Returns
102−
103−Eyre will respond with a `%bound` `gift` which says whether the binding was successful and looks like:
104−
105−```hoon
106−[%bound accepted=? =binding]
107−```
108−
109−The `accepted` field says whether the binding succeeded and the `binding` is the requested binding described above.
110−
111−#### Example
112−
113−See the [Agents: Direct HTTP](/docs/arvo/eyre/guide#agents-direct-http) section of the [Guide](/docs/arvo/eyre/guide) document for an example.
114−
115−## `%serve`
116−
117−```hoon
118−[%serve =binding =generator]
119−```
120−
121−This `task` binds a generator to a URL path so it can receive HTTP requests and return HTTP responses.
122−
123−The `binding` contains the URL path and optional domain through which the generator will take HTTP requests. The [$generator](/docs/arvo/eyre/data-types#generator) specifies the `desk`, the `path` to the generator in Clay, and also has a field for arguments. Note that the passing of specified arguments to the generator by Eyre is not currently implemented, so you can just leave it as `~`.
124−
125−The bound generator must be a gate within a gate and the type returned must be a [$simple-payload:http](/docs/arvo/eyre/data-types#simple-payloadhttp).
126−
127−The sample of the first gate must be:
128−
129−```hoon
130−[[now=@da eny=@uvJ bec=beak] ~ ~]
131−```
132−
133−...and the sample of the second, nested gate must be:
134−
135−```hoon
136−[authenticated=? =request:http]
137−```
138−
139−The `?` says whether the HTTP request contained a valid session cookie and the [$request:http](/docs/arvo/eyre/data-types#requesthttp) contains the request itself.
140−
141−The `simple-payload:http` returned by the generator is similar to the response described in the [%connect](#connect) section except the HTTP headers and body are all contained in the one response rather than staggered across several.
142−
143−#### Returns
144−
145−Eyre will return a `%bound` `gift` as described at the end of the [%connect](#connect) section.
146−
147−#### Example
148−
149−See the [Generators](/docs/arvo/eyre/guide#generators) section of the [Guide](/docs/arvo/eyre/guide) document for an example.
150−
151−## `%disconnect`
152−
153−```hoon
154−[%disconnect =binding]
155−```
156−
157−This `task` deletes a URL binding previously set by a `%connect` or `%serve` `task`.
158−
159−The [$binding](/docs/arvo/eyre/data-types#binding) is the URL path and domain of the binding you want to delete.
160−
161−#### Returns
162−
163−Eyre returns no `gift` in response to a `%disconnect` `task`.
164−
165−## `%code-changed`
166−
167−```hoon
168−[%code-changed ~]
169−```
170−
171−This `task` tells Eyre that the web login code has changed, causing Eyre to throw away all sessions and cookies. Typically it's automatically sent to Eyre by `hood` when you run `|code %reset`.
172−
173−This `task` takes no arguments.
174−
175−#### Returns
176−
177−Eyre returns no `gift` in response to a `%code-changed` `task`.
178−
179−## `%approve-origin`
180−
181−```hoon
182−[%approve-origin =origin]
183−```
184−
185−This `task` tells Eyre to start responding positively to CORS requests for the specified `origin`.
186−
187−The [$origin](/docs/arvo/eyre/data-types#origin) is a CORS origin like `http://foo.example` you want to approve.
188−
189−#### Returns
190−
191−Eyre returns no `gift` in response to a `%approve-origin` `task`.
192−
193−#### Example
194−
195−See the [Managing CORS Origins](/docs/arvo/eyre/guide#managing-cors-origins) section of the [Guide](/docs/arvo/eyre/guide) document for an example.
196−
197−## `%reject-origin`
198−
199−```hoon
200−[%reject-origin =origin]
201−```
202−
203−This `task` tells Eyre to start responding negatively to CORS requests for the specified `origin`.
204−
205−The [$origin](/docs/arvo/eyre/data-types#origin) is a CORS origin like `http://foo.example` you want want to reject.
206−
207−#### Returns
208−
209−Eyre returns no `gift` in response to a `%reject-origin` `task`.
210−
211−#### Example
212−
213−See the [Managing CORS Origins](/docs/arvo/eyre/guide#managing-cors-origins) section of the [Guide](/docs/arvo/eyre/guide) document for an example.
content/docs/arvo/ford/_index.mddeleted−7
@@ -1,7 +0,0 @@
1−+++
2−title = "Ford"
3−weight = 60
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
content/docs/arvo/ford/ford.mddeleted−223
@@ -1,223 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/ford/"]
6−+++
7−
8−*The Ford vane was refactored so drastically in 2020 that it was completely
9− removed as a standalone vane, with its functionality merged into
10− [clay](/docs/arvo/clay/clay). The following is a reproduced [blog
11− post](https://urbit.org/blog/ford-fusion/) that documents this transformation,
12− which we called "Ford Fusion".*
13−
14−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.
15−
16−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.
17−
18−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.
19−
20−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
21−itself in the general case, not just some special cases.
22−
23−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:
24−- Atomic: the update should complete or fail in one transaction. If it
25− fails, the system shouldn't get stuck.
26−- Self-contained: there must be no implicit dependencies or hysteresis
27− (dependence on previous system states) when building the new software
28− from source.
29−- Ordered: updates must be monotonically sequenced from the system's
30− lowest layer to highest.
31−
32−Let’s walk through them one by one.
33−
34−### Atomic
35−
36−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.
37−
38−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.
39−
40−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.
41−
42−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.
43−
44−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.
45−
46−[Steve Yegge's "platform
47−rant"](https://gist.github.com/chitchcock/1281611) describes a Bezosian
48−edict prohibiting synchronous communication among modules through direct
49−linking. This can be seen as an acknowledgment of the difficulty Amazon
50−was going to have when it needed to turn internal services external. If
51−your software needs to run in hell, build it that way from the start.
52−
53−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.
54−
55−### Self-Contained
56−
57−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.
58−
59−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.
60−
61−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.
62−
63−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.
64−
65−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.
66−
67−### Ordered
68−
69−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.
70−
71−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.
72−
73−## How Updates Work Now
74−
75−These are the layers of the stack that update themselves on the fly, from lowest to highest:
76−
77−+ hoon: the hoon language definition and compiler, defined in `/sys/hoon/hoon`
78−+ arvo: the arvo kernel proper and related type definitions, in `/sys/arvo/hoon`
79−+ zuse: the standard library, in `/sys/zuse/hoon`
80−+ vanes: arvo kernel modules, including clay itself, in folder `/sys/vane`
81−+ userspace: apps, marks, ancillary source code like libraries, and user data
82−
83−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.
84−
85−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.
86−
87−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.
88−
89−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.
90−
91−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.
92−
93−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.
94−
95−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.
96−
97−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.
98−
99−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.
100−
101−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.
102−
103−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.
104−
105−## How Clay Validates a Desk
106−
107−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.
108−
109−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.
110−
111−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.
112−
113−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`.
114−
115−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.
116−
117−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.
118−
119−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.
120−
121−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.
122−
123−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.
124−
125−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,
126−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.
127−
128−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.
129−
130−## Ford Build Semantics
131−
132−### The Three Types of Ford Builds: Files, Marks, and Casts
133−
134−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.
135−
136−#### File Builds
137−
138−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.
139−
140−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.
141−
142−#### Mark Builds
143−
144−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`.
145−
146−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.
147−
148−#### Cast Builds
149−
150−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:
151−
152−+ direct grow from `%foo`
153−+ direct grab from `%bar`
154−+ indirect jump from `%foo` through `%qux`
155−+ indirect grab from `%bar` through `%qux`
156−
157−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.
158−
159−Clay exposes cast builds into the scry namespace with `%cc`: as an example, `.^(tube:clay %cc
160−/~zod/home/3/foo/bar)` builds a `$tube` conversion gate from `%foo` to `%bar`.
161−
162−### Ford Runes
163−
164−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.
165−
166−```
167−/- foo, *bar, baz=qux
168−```
169−
170−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.
171−
172−```
173−/+ foo, *bar, baz=qux
174−```
175−
176−The `/+` rune imports a library file from `/lib`. Aside from the different source folder, the syntax and semantics are the same as for `/-`.
177−
178−```
179−/= clay-raw /sys/vane/clay
180−```
181−
182−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.
183−
184−```
185−/* hello-gen %hoon /gen/hello/hoon
186−```
187−
188−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.
189−
190−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:
191−
192−```
193−:* fastar-2 fastar-1
194− fastis-2 fastis-1
195− faslus-2 faslus-1
196− fashep-2 fashep-1
197− <zuse>
198−==
199−```
200−
201−## Future Work
202−
203−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.
204−
205−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
206−~norsyr-torryn/canvas` to load and build remote source. No one should experience dependency hell on Urbit, but we're not there yet.
207−
208−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
209−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.
210−
211−## Conclusion
212−
213−`~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.
214−
215−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.
216−
217−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.
218−
219−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.
220−
221−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.
222−
223−
content/docs/arvo/gall/_index.mddeleted−7
@@ -1,7 +0,0 @@
1−+++
2−title = "Gall"
3−weight = 70
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
content/docs/arvo/gall/data-types.mddeleted−492
@@ -1,492 +0,0 @@
1−+++
2−title = "Data Types"
3−weight = 5
4−template = "doc.html"
5−+++
6−
7−This document describes the data types for Gall defined in `lull.hoon`.
8−
9−## `bitt`
10−
11−```hoon
12−+$ bitt (map duct (pair ship path))
13−```
14−
15−Incoming subscriptions.
16−
17−This is the structure Gall uses to keep track of subscribers to our Gall agent.
18−The `sup` field of a [`bowl`](#bowl) contains the `bitt` for our agent.
19−
20−## `boat`
21−
22−```hoon
23−+$ boat
24− %+ map [=wire =ship =term]
25− [acked=? =path]
26−```
27−
28−Outgoing subscriptions.
29−
30−This is the structure Gall uses to keep track of subscriptions our agent has
31−initiated. The `wex` field of a [`bowl`](#bowl) contails the `boat` for that
32−agent.
33−
34−The `wire` field is the `wire` which [`sign:agent`](#signagent)s will come in on.
35−The `ship` and `term` fields are the ship and the name of the agent to which our
36−agent has subscribed.
37−
38−The `acked` field is `%.y` if they have acknowledged our subscription request,
39−and `%.n` if they have not. The `path` field is the `path` on the other agent to
40−which our agent has subscribed.
41−
42−## `bowl`
43−
44−```hoon
45−+$ bowl :: standard app state
46− $: $: our=ship :: host
47− src=ship :: guest
48− dap=term :: agent
49− == ::
50− $: wex=boat :: outgoing subs
51− sup=bitt :: incoming subs
52− == ::
53− $: act=@ud :: change number
54− eny=@uvJ :: entropy
55− now=@da :: current time
56− byk=beak :: load source
57− == == ::
58−```
59−
60−Additional agent state.
61−
62−A `bowl` is given to the agent core each time an event comes in. The fields are
63−as follows:
64−
65−- `our`: Our ship.
66−- `src`: The ship from which the current request originated.
67−- `dap`: The name of our agent.
68−- `wex`: Outgoing subscriptions. That is, subscriptions our agent has initiated.
69− See the [`boat`](#boat) section for details of the type.
70−- `sup`: Incoming subscriptions. That is, subscriptions others have made to our
71− agent. See the [`bitt`](#bitt) section for details of the type.
72−- `act`: The total number of [`move`](/docs/arvo/overview#move)s our agent has
73− processed so far.
74−- `eny`: 512 bits of entropy.
75−- `now`: The current date-time.
76−- `byk`: The ship, desk and `case` in Clay from which this agent was loaded. The
77− `case` will be `[%da @da]` where the `@da` is the when the agent was loaded. A
78− `beak` is a triple of `[ship desk case]`.
79−
80−## `dude`
81−
82−```hoon
83−+$ dude term
84−```
85−
86−Agent name.
87−
88−## `gill`
89−
90−```hoon
91−+$ gill (pair ship term)
92−```
93−
94−A general contact: A pair of the ship and agent name.
95−
96−## `scar`
97−
98−```hoon
99−+$ scar
100− $: p=@ud
101− q=(map duct bone)
102− r=(map bone duct)
103− ==
104−```
105−
106−Opaque duct - used internally.
107−
108−## `suss`
109−
110−```hoon
111−+$ suss (trel dude @tas @da)
112−```
113−
114−Configuration report.
115−
116−## `well`
117−
118−```hoon
119−+$ well (pair desk term)
120−```
121−
122−Desk and agent.
123−
124−## `neat`
125−
126−```hoon
127−+$ neat
128− $% [%arvo =note-arvo]
129− [%agent [=ship name=term] =deal]
130− [%pyre =tang]
131− ==
132−```
133−
134−Like a [`note:agent`](#noteagent), except the `%agent` case has a [`deal`](#deal) instead
135−of just a [`task:agent`](#taskagent). This is used for messages that come in over the
136−network and would not be used manually.
137−
138−## `deal`
139−
140−```hoon
141−+$ deal
142− $% [%raw-poke =mark =noun]
143− task:agent
144− ==
145−```
146−
147−Like a [`task:agent`](#taskagent) but with the additional case of a raw poke.
148−This is used for messages that come in over the network and would not be used
149−manually.
150−
151−## `unto`
152−
153−```hoon
154−+$ unto
155− $% [%raw-fact =mark =noun]
156− sign:agent
157− ==
158−```
159−
160−Like a [`sign:agent`](#signagent) but with the additional case of a raw fact.
161−This is used for messages that come in over the network and would not be used
162−manually.
163−
164−## `agent`
165−
166−```hoon
167−++ agent
168− =< form
169− |%
170−```
171−
172−Container for Gall agent types. The most significant arm is
173−[`form:agent`](#formagent), which specifies the structure of the agent itself.
174−There are also some additional structures defined here, mostly defining the
175−kinds of messages agents can send. The different arms of the core in `agent`
176−are considered separately below.
177−
178−### `step:agent`
179−
180−```hoon
181−+$ step (quip card form)
182−```
183−
184−A cell of [`card:agent`](#cardagent)s to be sent and a new agent state. This is the
185−type returned by most arms of an agent. A `(quip a b)` is the same as `[(list a) b]`, it's just a more convenient way to specify it.
186−
187−### `card:agent`
188−
189−```hoon
190−+$ card (wind note gift)
191−```
192−
193−An effect - typically a message to be sent to another agent or vane. A list of
194−these are returned by most agent arms along with a new state in a
195−[`step:agent`](#stepagent). A `wind` is the following:
196−
197−```hoon
198−++ wind
199− |$ [a b]
200− $% [%pass p=path q=a]
201− [%slip p=a]
202− [%give p=b]
203− ==
204−```
205−
206−Gall will not allow a `%slip`, so in practice a `card` will be one of:
207−
208−- `[%pass path note]`
209−- `[%give gift]`
210−
211−For `%pass`, `p` specifies the `wire` on which a response should be returned.
212−See [`note:agent`](#noteagent) and [`gift:agent`](#giftagent) below for details of their
213−types.
214−
215−### `note:agent`
216−
217−```hoon
218−+$ note
219− $% [%agent [=ship name=term] =task]
220− [%arvo note-arvo]
221− [%pyre =tang]
222− ==
223−```
224−
225−The type for messages initiated by our agent. This is opposed to
226−[`gift:agent`](#giftagent), which is the type for responding to other agents or
227−vanes, or for sending out updates to subscribers. The three cases are:
228−
229−- `%agent`: Poke another agent, subscribe to another agent, or cancel a
230− subscription to another agent. The `ship` and `name` fields are the ship and
231− agent to which the `task` should be sent. The `task` is the request itself,
232− see [`task:agent`](#taskagent) below for its possible types.
233−- `%arvo`: Pass a `task` to a vane. The type of a `note-arvo` is:
234− ```hoon
235− +$ note-arvo
236− $~ [%b %wake ~]
237− $% [%a task:ames]
238− [%b task:behn]
239− [%c task:clay]
240− [%d task:dill]
241− [%e task:eyre]
242− [%g task:gall]
243− [%i task:iris]
244− [%j task:jael]
245− [%$ %whiz ~]
246− [@tas %meta vase]
247− ==
248− ```
249− You can refer to the `/sys/lull.hoon` source code for all the possible vane
250− tasks, or see each vane's API Reference section in the [Arvo
251− documentation](/docs/arvo/overview)
252−- `%pyre`: This is for aborting side-effects initiated during agent
253− installation. The `tang` is an error message.
254−
255−A `note:agent` is always wrapped in a `%pass` [`card:agent`](#cardagent).
256−
257−### `task:agent`
258−
259−```hoon
260−+$ task
261− $% [%watch =path]
262− [%watch-as =mark =path]
263− [%leave ~]
264− [%poke =cage]
265− [%poke-as =mark =cage]
266− ==
267−```
268−
269−The types of messages initiated by our agent and sent to another agent. This is
270−in contrast to [`gift:agent`](#giftagent)s, which are responses to incoming
271−messages from agents or updates to agents already subscribed. The five kinds
272−are:
273−
274−- `%watch`: Subscribe to `path` on the target ship and agent.
275−- `%watch-as`: Same as `%watch`, except you ask the target's Gall to convert
276− subscription updates to the `mark` you specified rather than just giving you
277− the `mark` produced by the agent.
278−- `%leave`: Cancel subscription. The particular subscription to cancel will be
279− determined by the `wire` given in the `p` field of the containing `%pass`
280− [`card:agent`](#cardagent).
281−- `%poke`: Poke the target ship and agent with the given `cage`, which is a pair
282− of `[mark vase]`.
283−- `%poke-as`: Same as `%poke`, except the `cage` will be converted to the
284− specified `mark` before sending.
285−
286−A `task:agent` is always wrapped in a `%pass` [`card:agent`](#cardagent).
287−
288−### `gift:agent`
289−
290−```hoon
291−+$ gift
292− $% [%fact paths=(list path) =cage]
293− [%kick paths=(list path) ship=(unit ship)]
294− [%watch-ack p=(unit tang)]
295− [%poke-ack p=(unit tang)]
296− ==
297−```
298−
299−The types of messages our agent can either send in response to messages from
300−other agents, or send to subscribed agents. This is in contrast to
301−[`task:agent`](#taskagent)s, which are messages to other agents our agent
302−initiates rather than sends in response. The four kinds are:
303−
304−- `%fact`: An update to existing subscribers. The `paths` field specifies which
305− subscription paths the update should go out to. The `cage` is the data, and is
306− a `[mark vase]`.
307−- `%kick`: Kick subscriber, ending their subscription. The `paths` field
308− specifies which paths the subscriber should be kicked from, and the `ship`
309− field specifies the ship to kick. If the `ship` field is null, all subscribers
310− on the specified paths are kicked. Gall will automatically remove the
311− subscription from our agent's [`bitt`](#bitt) (inbound subscription `map`),
312− and subscriber will no longer receive updates on the `path`s in question.
313−- `%watch-ack`: Acknowledge a subscription request. If `p` is null, it's an ack
314− (positive acknowledgement), and if `p` is non-null, it's a nack (negative
315− acknowledgement). Simply crashing will caused Gall to nack a subscription
316− request, and not crashing but not explicitly producing a `%watch-ack` `gift`
317− will cause Gall to ack a subscription request. Therefore, you'd typically only
318− explicitly produce a `%watch-ack` `gift` if you wanted to nack a subscription
319− request with a custom error in the `tang`.
320−- `%poke-ack`: Acknowledge a poke. If `p` is null, it's an ack, and if `p` is
321− non-null, it's a nack. Simply crashing will cause Gall to nack a poke, and not
322− crashing but not explicitly producing a `%poke-ack` `gift` will cause Gall to
323− ack a poke. Therefore, you'd typically only explicitly produce a `%poke-ack`
324− `gift` if you wanted to nack a poke with a custom error in the `tang`.
325−
326−A `gift:agent` is always wrapped in a `%give` [`card:agent`](#cardagent).
327−
328−### `sign:agent`
329−
330−```hoon
331−+$ sign
332− $% [%poke-ack p=(unit tang)]
333− [%watch-ack p=(unit tang)]
334− [%fact =cage]
335− [%kick ~]
336− ==
337−```
338−
339−A `sign` is like a [`gift:agent`](#giftagent) but it's something that comes
340−_in_ to our agent from another agent rather than something we send out. The
341−possible types are:
342−
343−- `%poke-ack`: Another agent has acked (positively acknowledged) or nacked
344− (negatively acknowledged) a `%poke` [`task:agent`](#taskagent) we previously
345− sent. It's an ack if `p` is null and a nack if `p` is non-null. The `tang`
346− contains an error or traceback if it's a nack.
347−- `%watch-ack`: Another agent has acked or nacked a `%watch`
348− [`task:agent`](#taskagent) (subscription request) we previously sent. It's an
349− ack if `p` is null and a nack if `p` is non-null. The `tang` contains an error
350− or traceback if it's a nack. If it's a nack, Gall will automatically remove
351− the subscription from our agent's [`boat`](#boat) (outbound subscription
352− map).
353−- `%fact`: An update from another agent to which we've previously subscribed
354− with a `%watch` [`task:agent`](#taskagent) (subscription request). The `cage`
355− contains the data, and is a `[mark vase]`.
356−- `%kick`: Our subscription to another agent has been ended, and we'll no longer
357− receive updates. A `%kick` may be intentional, but it may also happen due to
358− certain network conditions or other factors. As a result, it's best to try and
359− resubscribe with another `%watch` [`task:agent`](#taskagent), and if they
360− nack the `%watch`, we can conclude it was intentional and give up.
361−
362−### `form:agent`
363−
364−```hoon
365−++ form
366− $_ ^|
367− |_ bowl
368− ++ on-init
369− *(quip card _^|(..on-init))
370− ::
371− ++ on-save
372− *vase
373− ::
374− ++ on-load
375− |~ old-state=vase
376− *(quip card _^|(..on-init))
377− ::
378− ++ on-poke
379− |~ [mark vase]
380− *(quip card _^|(..on-init))
381− ::
382− ++ on-watch
383− |~ path
384− *(quip card _^|(..on-init))
385− ::
386− ++ on-leave
387− |~ path
388− *(quip card _^|(..on-init))
389− ::
390− ++ on-peek
391− |~ path
392− *(unit (unit cage))
393− ::
394− ++ on-agent
395− |~ [wire sign]
396− *(quip card _^|(..on-init))
397− ::
398− ++ on-arvo
399− |~ [wire sign-arvo]
400− *(quip card _^|(..on-init))
401− ::
402− ++ on-fail
403− |~ [term tang]
404− *(quip card _^|(..on-init))
405− --
406−--
407−```
408−
409−This defines the structure of the agent itself. The agent is a door with a [`bowl`](#bowl) as its sample and exactly ten arms. Below we'll describe each arm briefly.
410−
411−#### `on-init`
412−
413−- Accepts: Nothing.
414−- Produces: [`step:agent`](#stepagent)
415−
416−This arm is called when the agent is initially installed.
417−
418−#### `on-poke`
419−
420−- Accepts: `cage`
421−- Produces: [`step:agent`](#stepagent)
422−
423−This arm is called when another agent pokes our agent.
424−
425−#### `on-watch`
426−
427−- Accepts: `path`
428−- Produces: [`step:agent`](#stepagent)
429−
430−This arm is called when another agent subscribes to our agent.
431−
432−#### `on-leave`
433−
434−- Accepts: `path`
435−- Produces: [`step:agent`](#stepagent)
436−
437−This arm is called when another agent unsubscribes from a subscription path on
438−our agent.
439−
440−#### `on-peek`
441−
442−- Accepts: `path`
443−- Produces: `(unit (unit cage))`
444−
445−This arm is called when a [scry](/docs/arvo/concepts/scry) is performed on our
446−agent.
447−
448−#### `on-agent`
449−
450−- Accepts: `[wire sign:agent]`
451−- Produces: [`step:agent`](#stepagent)
452−
453−This arm is called when another agent give our agent a
454−[`sign:agent`](#signagent).
455−
456−#### `on-arvo`
457−
458−- Accepts: `[wire sign-arvo]`
459−- Produces: [`step:agent`](#stepagent)
460−
461−This arm is called when a vane gives our agent a `gift`. A `sign-arvo` is:
462−
463−```hoon
464−+$ sign-arvo
465− $% [%ames gift:ames]
466− $: %behn
467− $% gift:behn
468− $>(%wris gift:clay)
469− $>(%writ gift:clay)
470− $>(%mere gift:clay)
471− $>(%unto gift:gall)
472− ==
473− ==
474− [%clay gift:clay]
475− [%dill gift:dill]
476− [%eyre gift:eyre]
477− [%gall gift:gall]
478− [%iris gift:iris]
479− [%jael gift:jael]
480− ==
481−```
482−
483−You can refer to the `/sys/lull.hoon` source code, or the API Reference of each
484−vane in the [Arvo documentation](/docs/arvo/overview).
485−
486−#### `on-fail`
487−
488−- Accepts: `[term tang]`
489−- Produces: [`step:agent`](#stepagent)
490−
491−This arm is called if certain errors occur in Gall, such as if our agent tries
492−to create a duplicate subscription.
content/docs/arvo/gall/gall-api.mddeleted−958
@@ -1,958 +0,0 @@
1−+++
2−title = "API Reference"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−## Reference Agent
8−
9−This app stores a number for each user. You can increment your number, increment
10−someone else's number, start tracking someone else's number by poking. It
11−exposes a scry namespace to inspect everyone's number.
12−
13−### `app/example-gall.hoon`
14−
15−```hoon
16−:: Import sur/example-gall
17−/- *example-gall
18−:: Import lib/default-agent
19−/+ default-agent
20−|%
21−+$ card card:agent:gall
22−+$ note
23− $%
24− [%arvo =note-arvo]
25− [%agent [=ship name=term] =task:agent:gall]
26− ==
27−+$ state-zero [%0 local=@ud]
28−+$ state-one [%1 local=@ud remote=(map @p @ud)]
29−+$ versioned-state
30− $%
31− state-zero
32− state-one
33− ==
34−--
35−=| state-one
36−=* state -
37−^- agent:gall
38−|_ =bowl:gall
39−+* this .
40− def ~(. (default-agent this %|) bowl)
41−::
42−:: Set local counter to 1 by default
43−++ on-init
44− ^- (quip card _this)
45− `this(local 1)
46−:: Expose state for saving
47−++ on-save
48− !>(state)
49−::
50−:: Load old state and upgrade if neccessary
51−++ on-load
52− |= old=vase
53− ^- (quip card _this)
54− =/ loaded=versioned-state
55− !<(versioned-state old)
56− ?- -.loaded
57− %0
58− `this(local local.loaded) :: Upgrade old state
59− %1
60− `this(state loaded)
61− ==
62−::
63−:: Respond to poke
64−:: App can be poked in the dojo by running the following commands
65−:: Increment local counter
66−:: :example-gall &example-gall-action [%increment ~]
67−:: Increment ~zod's counter
68−:: :example-gall &example-gall-action [%increment-remote ~zod]
69−:: Subscribe to ~zod's counter
70−:: :example-gall &example-gall-action [%view ~zod]
71−:: Unsubscribe from ~zod's counter
72−:: :example-gall &example-gall-action [%stop-view ~zod]
73−::
74−++ on-poke
75− |= [=mark =vase]
76− ^- (quip card _this)
77− :: Ensure poke is of mark %example-gall-action
78− ?> =(mark %example-gall-action)
79− =/ act=example-gall-action !<(example-gall-action vase)
80− ?- act
81− ::
82− :: Increment local counter and send new counter to subscribers
83− ::
84− [%increment ~]
85− :- [%give %fact ~[/local] %atom !>(+(local))]~
86− this(local +(local))
87− ::
88− :: Send remote %increment poke
89− ::
90− [%increment-remote who=@p]
91− :_ this
92− :~ :*
93− %pass
94− /inc/(scot %p who.act)
95− %agent
96− [who.act %example-gall]
97− %poke %example-gall-action !>([%increment ~])
98− == ==
99− ::
100− :: Subscribe to a remote counter
101− ::
102− [%view who=@p]
103− :_ this
104− [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
105− ::
106− :: Unsubscribe from remote counter and remove from state
107− ::
108− [%stop-view who=@p]
109− :_ this(remote (~(del by remote) who.act))
110− [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
111− ::
112− ==
113−::
114−:: Print on unsubscribe
115−::
116−++ on-leave
117− |= =path
118− ^- (quip card _this)
119− ~& "Unsubscribed by: {<src.bowl>} on: {<path>}"
120− `this
121−::
122−:: Handle new subscription
123−::
124−:: When another ship subscribes to our counter, give them the current state of
125−:: the counter immediately
126−::
127−++ on-watch
128− |= =path
129− ^- (quip card _this)
130− :_ this
131− :: Crash if we see a subscription we don't recognise
132− ?+ path ~|("unexpected subscription" !!)
133− ::
134− [%local ~]
135− [%give %fact ~ %atom !>(local)]~
136− ==
137−::
138−:: Expose scry namespace
139−::
140−:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
141−:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
142−:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
143−:: remote counters
144−++ on-peek
145− |= =path
146− ^- (unit (unit cage))
147− ?+ path [~ ~]
148− ::
149− :: Produce local counter
150− ::
151− [%x %local ~]
152− ``[%atom !>(local)]
153− ::
154− :: Produce remote counter
155− ::
156− [%x %remote who=@ta ~]
157− =* location i.t.t.path :: Ship name is third in the list
158− =/ res
159− (~(got by remote) (slav %p location))
160− ``[%atom !>(res)]
161− ::
162− :: Produce listing of remote counters
163− ::
164− [%y %remote ~]
165− =/ dir=(map @ta ~)
166− %- molt :: Map from list of k-v pairs
167− %+ turn :: iterate over list of k-v pairs
168− ~(tap by remote) :: list of k-v pairs from map
169− |= [who=@p *]
170− [(scot %p who) ~]
171− ``[%arch !>(`arch`[~ dir])]
172− ==
173−::
174−:: Handle sign from agent
175−::
176−++ on-agent
177− |= [=wire =sign:agent:gall]
178− ^- (quip card _this)
179− ?- -.sign
180− ::
181− :: Print error if poke failed
182− ::
183− %poke-ack
184− ?~ p.sign
185− `this
186− %- (slog u.p.sign)
187− `this
188− ::
189− :: Print error if subscription failed
190− ::
191− %watch-ack
192− ?~ p.sign
193− `this
194− =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
195− %- (slog tank u.p.sign)
196− `this
197− ::
198− :: Do nothing if unsubscribed
199− ::
200− %kick `this
201− ::
202− :: Update remote counter when we get a subscription update
203− ::
204− %fact
205− :- ~
206− ?. ?=(%atom p.cage.sign)
207− this
208− this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
209− ==
210−::
211−:: Handle arvo signs
212−::
213−:: We never give any cards to arvo. Therefore we never need to handle any signs
214−:: from arvo. We use the default-agent library to avoid implementing this arm,
215−:: as gall apps must have all the arms.
216−::
217−++ on-arvo on-arvo:def
218−::
219−:: Handle error
220−::
221−:: Print errors when they happen
222−::
223−++ on-fail
224− |= [=term =tang]
225− ^- (quip card _this)
226− %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
227− `this
228−--
229−
230−```
231−
232−### `sur/example-gall.hoon`
233−
234−```hoon
235−|%
236−+$ example-gall-action
237− $%
238− [%view who=@p]
239− [%stop-view who=@p]
240− [%increment-remote who=@p]
241− [%increment ~]
242− ==
243−--
244−```
245−
246−### `mar/example-gall/action.hoon`
247−
248−```hoon
249−/- *example-gall
250−|_ act=example-gall-action
251−++ grab
252− |%
253− ++ noun example-gall-action
254− --
255−--
256−```
257−
258−## Arms
259−
260−### `++on-init`
261−
262−Application initialisation
263−
264−`++on-init` is called when an application is first started. It is not a gate and
265−has no input.
266−
267−#### Returns
268−
269−```hoon
270−(quip card _this)
271−```
272−
273−List of cards and new agent
274−
275−#### Example
276−
277−```hoon
278−:: From reference agent.
279−:: Set local counter to 1 by default
280−::
281−++ on-init
282− ^- (quip card _this)
283− `this(local.sta 1)
284−:: From app/weather.hoon. This setup is typical of a landscape tile.
285−::
286−++ on-init
287− :_ this
288− :~ [%pass /bind/weather %arvo %e %connect [~ /'~weather'] %weather]
289− :* %pass /launch/weather %agent [our.bol %launch] %poke
290− %launch-action !>([%weather /weathertile '/~weather/js/tile.js'])
291− ==
292− ==
293−```
294−
295−### `++on-save`
296−
297−Expose state for saving.
298−
299−This arm is called immediately before the agent is upgraded. It packages the
300−permament state of the agent in a vase for the next version of the agent.
301−Unlike most handlers, this cannot produce effects. It is not a gate and has no input.
302−
303−#### Returns
304−
305−`vase` of permanent state.
306−
307−#### Example
308−
309−```hoon
310−:: From reference agent
311−::
312−:: Expose state for saving
313−::
314−++ on-save
315− !>(state)
316−```
317−
318−### `++on-load`
319−
320−Application upgrade.
321−
322−This arm is called immediately after the agent is upgraded. It receives
323−a vase of the state of the previously-running version of the agent, obtained
324−from `+on-save`, which allows it to cleanly upgrade from the old agent.
325−
326−#### Accepts
327−
328−```hoon
329−=vase
330−```
331−
332−`vase` of previous state, from `++on-save`
333−
334−#### Returns
335−
336−```hoon
337−(quip card _this)
338−```
339−
340−List of cards and new agent
341−
342−#### Examples
343−
344−```hoon
345−:: From reference agent
346−::
347−:: Load old state and upgrade if neccessary
348−++ on-load
349− |= old=vase
350− ^- (quip card _this)
351− =/ loaded=versioned-state
352− !<(versioned-state old)
353− ?- -.loaded
354− %0
355− `this(local local.loaded) :: Upgrade old state
356− %1
357− `this(state loaded)
358− ==
359−```
360−
361−### `++on-poke`
362−
363−Handle application poke.
364−
365−This arm is called when the agent is "poked". The input is a cage, so
366−it's a pair of a mark and a dynamic vase.
367−
368−#### Accepts
369−
370−```hoon
371−[=mark =vase]
372−```
373−
374−`mark` is the mark of the poked data.
375−
376−`vase` is a vase with the poked data inside.
377−
378−#### Returns
379−
380−```hoon
381−(quip card _this)
382−```
383−
384−List of cards and new agent.
385−
386−#### Example
387−
388−```hoon
389−:: From reference agent.
390−::
391−:: Respond to poke
392−:: App can be poked in the dojo by running the following commands
393−:: Increment local counter
394−:: :example-gall &example-gall-action [%increment ~]
395−:: Increment ~zod's counter
396−:: :example-gall &example-gall-action [%increment-remote ~zod]
397−:: Subscribe to ~zod's counter
398−:: :example-gall &example-gall-action [%view ~zod]
399−:: Unsubscribe from ~zod's counter
400−:: :example-gall &example-gall-action [%stop-view ~zod]
401−::
402−++ on-poke
403− |= [=mark =vase]
404− ^- (quip card _this)
405− :: Ensure poke is of mark %example-gall-action
406− ?> =(mark %example-gall-action)
407− =/ act=example-gall-action !<(example-gall-action vase)
408− ?- act
409− ::
410− :: Increment local counter and send new counter to subscribers
411− ::
412− [%increment ~]
413− :- [%give %fact ~[/local] %atom !>(+(local))]~
414− this(local +(local))
415− ::
416− :: Send remote %increment poke
417− ::
418− [%increment-remote who=@p]
419− :_ this
420− :~ :*
421− %pass
422− /inc/(scot %p who.act)
423− %agent
424− [who.act %example-gall]
425− %poke %example-gall-action !>([%increment ~])
426− == ==
427− ::
428− :: Subscribe to a remote counter
429− ::
430− [%view who=@p]
431− :_ this
432− [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]~
433− ::
434− :: Unsubscribe from remote counter and remove from state
435− ::
436− [%stop-view who=@p]
437− :_ this(remote (~(del by remote) who.act))
438− [%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]~
439− ::
440− ==
441−```
442−
443−### `++on-watch`
444−
445−Handle new subscriber.
446−
447−This arm is called when a program wants to subscribe to the agent on a
448−particular path. The agent may or may not need to perform setup steps
449−to intialize the subscription. It may produce a `%give`
450−`%subscription-result` to the subscriber to get it up to date, but after
451−this event is complete, it cannot give further updates to a specific
452−subscriber. It must give all further updates to all subscribers on a
453−specific path.
454−
455−If this arm crashes, then the subscription is immediately terminated.
456−More specifcally, it never started -- the subscriber will receive a
457−negative `%watch-ack`. You may also produce an explicit `%kick` to
458−close the subscription without crashing -- for example, you could
459−produce a single update followed by a `%kick`.
460−
461−#### Accepts
462−
463−```hoon
464−=path
465−```
466−
467−Path of new subscription.
468−
469−#### Returns
470−
471−```hoon
472−(quip card _this)
473−```
474−
475−List of cards and new agent.
476−
477−#### Example
478−
479−```hoon
480−:: From reference agent
481−::
482−:: Handle new subscription
483−::
484−:: When another ship subscribes to our counter, give them the current state of
485−:: the counter immediately
486−::
487−++ on-watch
488− |= =path
489− ^- (quip card _this)
490− :_ this
491− ?+ path on-watch:def
492− ::
493− [%local ~]
494− [%give %fact ~ %atom !>(local)]~
495− ==
496−```
497−
498−### `++on-leave`
499−
500−Handle unsubscribe.
501−
502−This arm is called when a program becomes unsubscribed to you.
503−Subscriptions may close because the subscriber intentionally
504−unsubscribed, but they also could be closed by an intermediary. For
505−example, if a subscription is from another ship which is currently
506−unreachable, Ames may choose to close the subscription to avoid queueing
507−updates indefinitely. If the program crashes while processing an
508−update, this may also generate an unsubscription. You should consider
509−subscriptions to be closable at any time.
510−
511−#### Accepts
512−
513−```hoon
514−=path
515−```
516−
517−Path of the closed subscription.
518−
519−#### Returns
520−
521−```hoon
522−(quip card _this)
523−```
524−
525−List of cards and new agent.
526−
527−#### Example
528−
529−```hoon
530−:: From reference agent. Prints a message when programs become unsubscribed.
531−++ on-leave
532− |= =path
533− ^- (quip card _this)
534− ~& "Unsubscribe by: {<src.bowl>} on: {<path>}"
535− `this
536−```
537−
538−### `++on-peek`
539−
540−Handle scry request.
541−
542−This arm is called when a program reads from the agent's "scry"
543−namespace, which should be referentially transparent. Unlike most
544−handlers, this cannot perform IO, and it cannot change the state. All
545−it can do is produce a piece of data to the caller, or not.
546−
547−#### Accepts
548−
549−```hoon
550−=path
551−```
552−
553−The path being scryed for.
554−
555−```hoon
556−:: Example scry to path mappings
557−::
558−.^(arch %gy /=example-gall=/remote)
559−:: Path will be /y/remote
560−.^(@ %gx /=example-gall=/local/atom)
561−:: Path will be /x/local
562−```
563−
564−#### Returns
565−
566−```hoon
567−(unit (unit cage))
568−```
569−
570−If this arm produces `[~ ~ data]`, then `data` is the value at the the
571−given path. If it produces `[~ ~]`, then there is no data at the given
572−path and never will be. If it produces `~`, then we don't know yet whether
573−there is or will be data at the given path. The head of the path is known as the
574−`care`. Requests with a care of `%x` should return a vase that matches or is
575−convertible to the mark at the end of the scry request. This mark is not
576−included in the path passed to `++on-peek`. Requests with a care of `%y` should
577−return a cage with a mark of `%arch` and a vase of `arch`.
578−
579−#### Example
580−
581−```hoon
582−:: From reference agent
583−::
584−:: Expose scry namespace
585−::
586−:: .^(@ %gx /=example-gall=/local/atom) will produce the current local counter
587−:: .^(@ %gx /=example-gall=/remote/~zod/atom) will produce the counter for ~zod
588−:: .^(arch %gy /=example-gall=/remote) will produce a listing of the current
589−:: remote counters
590−++ on-peek
591− |= =path
592− ^- (unit (unit cage))
593− ?+ path [~ ~]
594− ::
595− :: Produce local counter
596− ::
597− [%x %local ~]
598− ``[%atom !>(local)]
599− ::
600− :: Produce remote counter
601− ::
602− [%x %remote who=@ta ~]
603− =* location i.t.t.path :: Ship name is third in the list
604− =/ res
605− (~(got by remote) (slav %p location))
606− ``[%atom !>(res)]
607− ::
608− :: Produce listing of remote counters
609− ::
610− [%y %remote ~]
611− =/ dir=(map @ta ~)
612− %- molt :: Map from list of k-v pairs
613− %+ turn :: iterate over list of k-v pairs
614− ~(tap by remote) :: list of k-v pairs from map
615− |= [who=@p *]
616− [(scot %p who) ~]
617− ``[%arch !>(`arch`[~ dir])]
618− ==
619−```
620−
621−### `++on-agent`
622−
623−Handle `%pass` card
624−
625−This arm is called to handle responses to `%pass` cards to other agents.
626−It will be one of the following types of response:
627−
628−- `%poke-ack`: acknowledgment (positive or negative) of a poke. If the
629− value is `~`, then the poke succeeded. If the value is `[~ tang]`,
630− then the poke failed, and a printable explanation (eg a stack trace)
631− is given in the `tang`.
632−
633−- `%watch-ack`: acknowledgment (positive or negative) of a subscription.
634− If negative, the subscription is already ended (technically, it never
635− started).
636−
637−- `%fact`: update from the publisher.
638−
639−- `%kick`: notification that the subscription has ended. This happens because
640− either the target app passed a `%leave` note, or ames killed the subscription
641− due to backpressure. Most of the time you will want to resubscribe. If you can
642− no longer access the subscription you will get a negative `%watch-ack` and end
643− your flow there.
644−
645−#### Accepts
646−
647−```hoon
648−[=wire =sign:agent:gall]
649−```
650−
651−`wire` is the wire from the `+gift` that triggered `++on-agent`
652−
653−`sign` is response for the gift.
654−
655−#### Returns
656−
657−```hoon
658−(quip card _this)
659−```
660−
661−#### Example
662−
663−```hoon
664−:: From reference agent
665−::
666−:: Handle sign from agent
667−::
668−++ on-agent
669− |= [=wire =sign:agent:gall]
670− ^- (quip card _this)
671− ?- -.sign
672− ::
673− :: Print error if poke failed
674− ::
675− %poke-ack
676− ?~ p.sign
677− `this
678− %- (slog u.p.sign)
679− `this
680− ::
681− :: Print error if subscription failed
682− ::
683− %watch-ack
684− ?~ p.sign
685− `this
686− =/ =tank leaf+"subscribe failed from {<dap.bowl>} on wire {<wire>}"
687− %- (slog tank u.p.sign)
688− `this
689− ::
690− :: Do nothing if unsubscribed
691− ::
692− %kick `this
693− ::
694− :: Update remote counter when we get a subscription update
695− ::
696− %fact
697− :- ~
698− ?. ?=(%atom p.cage.sign)
699− this
700− this(remote (~(put by remote) src.bowl !<(@ q.cage.sign)))
701− ==
702−```
703−
704−### `++on-arvo`
705−
706−Handle vane response
707−
708−This arm is called to handle responses for `%pass` cards to vanes.
709−
710−#### Accepts
711−
712−```hoon
713− [=wire =sign:agent:gall]
714−```
715−
716−`wire` is the wire from the `++gift` that triggered `++on-arvo`.
717−
718−`sign` is the response from the vane. The list of possible responses from the
719−vanes is statically defined in sys/zuse.hoon (grep for `++ sign-arvo`).
720−
721−#### Returns
722−
723−```hoon
724−(quip card _this)
725−```
726−
727−List of cards and new agent.
728−
729−#### Example
730−
731−```hoon
732−:: From app/weather.hoon. Handles %bound, %wake and %http-response signs
733−++ on-arvo
734− |= [=wire =sign-arvo]
735− ^- (quip card:agent:gall _this)
736− ?: ?=(%bound +<.sign-arvo)
737− [~ this]
738− ?: ?=(%wake +<.sign-arvo)
739− =^ cards state
740− (wake:wc wire error.sign-arvo)
741− [cards this]
742− ?: ?=(%http-response +<.sign-arvo)
743− =^ cards state
744− (http-response:wc wire client-response.sign-arvo)
745− [cards this]
746− (on-arvo:def wire sign-arvo)
747−::
748−:: From reference agent
749−::
750−:: Handle arvo signs
751−::
752−:: We never give any cards to arvo. Therefore we never need to handle any signs
753−:: from arvo. We use the default-agent library to avoid implementing this arm,
754−:: as gall apps must have all the arms specified in the agent:gall definition.
755−::
756−++ on-arvo on-arvo:def
757−```
758−
759−### `++on-fail`
760−
761−Handle error.
762−
763−If an error happens in `+on-poke`, the crash report goes into the
764−`%poke-ack` response. Similarly, if an error happens in
765−`+on-subscription`, the crash report goes into the `%watch-ack`
766−response. If a crash happens in any of the other handlers, the report
767−is passed into this arm.
768−
769−#### Accepts
770−
771−```hoon
772−[=term =tang]
773−```
774−
775−`term` is a cord describing the error.
776−
777−`tang` is a stack trace for the error.
778−
779−#### Returns
780−
781−```hoon
782−(quip card _this)
783−```
784−
785−List of cards and new agent
786−
787−#### Example
788−
789−```hoon
790−::
791−:: Handle error
792−::
793−:: Print errors when they happen
794−::
795−++ on-fail
796− |= [=term =tang]
797− ^- (quip card _this)
798− %- (slog leaf+"error in {<dap.bowl>}" >term< tang)
799− `this
800−```
801−
802−## Agent Gifts
803−
804−Giving a gift takes the general form of
805−
806−```hoon
807−[%give =gift]
808−```
809−
810−### `%fact`
811−
812−Produce a subscription update.
813−
814−Produces a subscription update. A subscription update is a new piece of
815−subscription content for all subscribers on a given path.
816−
817−#### Structure
818−
819−```hoon
820−[%fact (list path) =cage]
821−```
822−
823−`(list path)` is a list of the paths to send the update on. If no path is
824−given, then the update is only given to the program that instigated the
825−request. Typical use of this mode is in `+on-watch` to give an initial update
826−to a new subscriber to get them up to date.
827−
828−`cage` is a cage of the subscription update.
829−
830−#### Example
831−
832−```hoon
833−:: From ++on-watch in reference agent.
834−::
835−:: Gives current local state to new subscribers.
836−[%give %fact ~ %atom !>(local.sta)]
837−
838−
839−:: From ++on-poke in reference agent
840−::
841−:: Gives incremented local state to any subscribers on /local
842−[%give %fact ~[/local] %atom !>(+(local))]
843−```
844−
845−### `%kick`
846−
847−Close subscription.
848−
849−Closes a subscription. A subscription close closes the subscription for all or
850−one subscribers on a given path.
851−
852−#### Structure
853−
854−```hoon
855−[%kick (unit path) (unit ship)]
856−```
857−
858−`(unit path)` is the path of the subscription being updated. If no path is
859−given, then the update is only given to the program that instigated the request.
860−Typical use of this mode would be in `+on-watch` to produce a single update to a
861−subscription then close the subscription.
862−
863−`(unit ship)` is the ship to close the subscription for. If no path is given,
864−then the subscription is closed for all subscribers.
865−
866−## Agent Notes
867−
868−Passing a agent note (a 'task') along a wire looks like so.
869−
870−```hoon
871−[%pass =wire %agent [=ship name=term] =task]
872−```
873−
874−`wire` is used to identify the response to the note.
875−
876−`ship` is the ship to pass the note to.
877−
878−`name` is the name of the agent that should receive the note.
879−
880−`task` is the task itself, described below.
881−
882−### `%poke`
883−
884−Poke an application.
885−
886−This note is passed to poke an application with a cage, a marked vase.
887−
888−#### Structure
889−
890−```hoon
891−[%poke =cage]
892−```
893−
894−`cage` is the marked data to poke the application with. It is a pair of a mark
895−and vase.
896−
897−#### Example
898−
899−```hoon
900−:: From ++on-poke in reference agent.
901−::
902−:: Sends an increment poke to the example-gall agent
903−:: on who.act.
904−:*
905− %pass
906− /inc/(scot %p who.act)
907− %agent
908− [who.act %example-gall]
909− %poke %example-gall-action !>([%increment ~])
910−==
911−```
912−
913−### `%watch`
914−
915−Subscribe to an application.
916−
917−This note is given to subscribe to an application at a path
918−
919−#### Structure
920−
921−```hoon
922−[%watch =path]
923−```
924−
925−`path` is the path to be subscribed to.
926−
927−#### Example
928−
929−```hoon
930−:: From ++on-poke in reference agent.
931−::
932−:: Subscribes to the example-gall agent on who.act on the path /local
933−::
934−[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %watch /local]
935−```
936−
937−### `%leave`
938−
939−Unsubscribe from an application.
940−
941−This note is passed to unsubscribe from an application. It should be passed on
942−the same wire that the corresponding `%watch` note for the subscription was
943−passed on.
944−
945−#### Structure
946−
947−```hoon
948−[%leave ~]
949−```
950−
951−#### Example
952−
953−```hoon
954−:: From ++on-poke in reference agent.
955−::
956−:: Unsubscribes from the example-gall agent on who.act
957−[%pass /view/(scot %p who.act) %agent [who.act %example-gall] %leave ~]
958−```
content/docs/arvo/gall/gall.mddeleted−558
@@ -1,558 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−aliases = ["/docs/learn/arvo/gall/"]
6−+++
7−
8−This document describes Gall, the Arvo userspace vane.
9−
10−# Agents
11−
12−Urbit code lives in the following basic categories:
13−
14−- Runtime (Nock interpreter, persistence engine, IO drivers, jets)
15−- Kernel vanes (managed by Arvo)
16−- Userspace agents (managed by Gall, permanent state)
17−- Userspace threads (managed by Spider, transient state)
18−
19−This lays out the framework for the third category: Agents.
20−
21−An agent is a piece of software that is primarily focused on maintaining
22−and distributing a piece of state with a defined structure. It exposes
23−an interface that lets programs read, subscribe to, and manipulate the
24−state. Every event happens in an atomic transaction, so the state is
25−never inconsistent. Since the state is permanent, when the agent is
26−upgraded with a change to the structure of the state, the developer
27−provides a migration function from the old state type to the new state
28−type.
29−
30−It's not too far off to think of an agent as simply a database with
31−developer-defined logic. But an agent is significantly less constrained
32−than a database. Databases are usually tightly constrained in one or
33−more ways because they need to provide certain guarantees (like
34−atomicity) or optimizations (like indexes). Urbit is a single-level
35−store, so atomicity comes for free. Many applications don't use
36−databases because they need relational indices; rather, they use them
37−for their guarantees around persistence. Some do need the indices,
38−though, and it's not hard to imagine an agent which provides a SQL-like
39−interface.
40−
41−On the other hand, an agent is also a lot like what many systems call a
42−"service". An agent is permanent and addressable -- a running program
43−can talk to an agent just by naming it. An agent can perform IO, unlike
44−most databases. This is a critical part of an agent: it performs IO
45−along the same transaction boundaries as changes to its state, so if an
46−effect happens, you know that the associated state change has happened.
47−You should be careful, though, to avoid creating implicit non-atomicity
48−-- eg if it comes into an inconsistent state pending a response to an IO
49−action.
50−
51−But the best way to think about an agent is as a state machine. Like a
52−state machine, any input could happen at any time, and it must react
53−coherently to that input. Ouput (effects) and the next state of the
54−machine are both pure functions of the previous state and the input
55−event. Of course, it's important to ensure there isn't an order of
56−events that could cause your agent to enter an inconsistent state.
57−
58−We often think of state machines as finite state machines, but of course
59−in this instance, the state is not actually finite (though it should be
60−definable in a regular recursive data type).
61−
62−## Specification
63−
64−An agent is defined as a [core](/docs/glossary/core/) with a set of [arms](/docs/glossary/arm/) to handle various
65−events. These handlers usually produce a list of effects and the next
66−state of the agent. The interface definition can be found in
67−`sys/lull.hoon`, which at the time of writing is:
68−
69−```hoon
70−++ agent
71− =< form
72− |%
73− +$ step (quip card form)
74− +$ card (wind note gift)
75− +$ note
76− $% [%arvo =note-arvo]
77− [%agent [=ship name=term] =task]
78− ==
79− +$ task
80− $% [%watch =path]
81− [%watch-as =mark =path]
82− [%leave ~]
83− [%poke =cage]
84− [%poke-as =mark =cage]
85− ==
86− +$ gift
87− $% [%fact path=(unit path) =cage]
88− [%kick path=(unit path) ship=(unit ship)]
89− [%watch-ack p=(unit tang)]
90− [%poke-ack p=(unit tang)]
91− ==
92− +$ sign
93− $% [%poke-ack p=(unit tang)]
94− [%watch-ack p=(unit tang)]
95− [%fact =cage]
96− [%kick ~]
97− ==
98− ++ form
99− $_ ^|
100− |_ bowl
101− ++ on-init
102− *(quip card _^|(..on-init))
103− ::
104− ++ on-save
105− *vase
106− ::
107− ++ on-load
108− |~ old-state=vase
109− *(quip card _^|(..on-init))
110− ::
111− ++ on-poke
112− |~ [mark vase]
113− *(quip card _^|(..on-init))
114− ::
115− ++ on-watch
116− |~ path
117− *(quip card _^|(..on-init))
118− ::
119− ++ on-leave
120− |~ path
121− *(quip card _^|(..on-init))
122− ::
123− ++ on-peek
124− |~ path
125− *(unit (unit cage))
126− ::
127− ++ on-agent
128− |~ [wire sign]
129− *(quip card _^|(..on-init))
130− ::
131− ++ on-arvo
132− |~ [wire sign-arvo]
133− *(quip card _^|(..on-init))
134− ::
135− ++ on-fail
136− |~ [term tang]
137− *(quip card _^|(..on-init))
138− --
139−```
140−
141−Here's a skeleton example of an implementation:
142−
143−```hoon
144−^- agent:gall
145−=| state=@
146−|_ bowl:gall
147−+* this .
148−++ on-init
149− `this
150−::
151−++ on-save
152− !>(state)
153−::
154−++ on-load
155− |= =old-state=vase
156− `this(state !<(@ old-state-vase))
157−::
158−++ on-poke
159− |= [=mark =vase]
160− ~& > state=state
161− ~& got-poked-with-data=mark
162− =. state +(state)
163− `this
164−::
165−++ on-watch
166− |= path
167− `this
168−::
169−++ on-leave
170− |= path
171− `this
172−::
173−++ on-peek
174− |= path
175− *(unit (unit cage))
176−::
177−++ on-agent
178− |= [wire sign:agent:gall]
179− `this
180−::
181−++ on-arvo
182− |= [wire sign-arvo]
183− `this
184−::
185−++ on-fail
186− |= [term tang]
187− `this
188−--
189−```
190−
191−We also supply a `default-agent` library, which is useful if you don't
192−want to handle some of the arms. Most of the above could also be
193−implemented as:
194−
195−```hoon
196−/+ default-agent
197−^- agent:gall
198−=| state=@
199−|_ =bowl:gall
200−+* this .
201− default ~(. (default-agent this %|) bowl)
202−::
203−++ on-init on-init:default
204−++ on-save on-save:default
205−++ on-load on-load:default
206−++ on-poke
207− |= [=mark =vase]
208− ~& > state=state
209− ~& got-poked-with-data=mark
210− =. state +(state)
211− `this
212−::
213−++ on-watch on-watch:default
214−++ on-leave on-leave:default
215−++ on-peek on-peek:default
216−++ on-agent on-agent:default
217−++ on-arvo on-arvo:default
218−++ on-fail on-fail:default
219−--
220−```
221−
222−So, an agent is a core with 10 arms. The handlers correspond to
223−different sorts of input. We'll discuss each of these in detail, but
224−first a few general concepts.
225−
226−## Basic concepts
227−
228−### Interacting with an agent
229−
230−There are two basic ways programs can interact with an agent: you may
231−subscribe to data as described above, or you may "poke" an agent to send
232−it a command. Suppose there is an agent for a calendar service; then,
233−pokes would likely include `%create-event`, `%modify-event`,
234−`%delete-event`, and `%change-time-zone` (along with assocated data).
235−Subscription paths could include `/next-event` and `/all-events`.
236−
237−Agents generally conform to CQRS -- pokes may change state, but
238−subscriptions generally shouldn't. In practice, there may be state
239−changes required to properly initialize the subscription, but these
240−shouldn't change the essential state of the agent.
241−
242−### Cards
243−
244−Most of the handlers produce a `(quip card agent:gall)`, which is just
245−`[(list card) agent:gall]`. The first allows us to produce effects, and
246−the second allows us to maintain state.
247−
248−A card is one of two things: a `note` or a `gift`. You `%pass` `note`s
249−and you `%give` `gift`s. When you pass a `note`, you expect zero or more
250−responses; when you give a `gift`, you will not get a response. Since you
251−may get a response to a `note`, you tag it with a `wire` so that you can
252−identify the response.
253−
254−Thus, we say you "pass a `note` along a `wire`", or you "give a `gift`".
255−These phrases correspond to producing a card that looks like:
256−
257−```hoon
258−[%pass /my/wire a-note]
259−```
260−
261−or
262−
263−```hoon
264−[%give a-gift]
265−```
266−
267−When you give a `gift`, that's the end of the story, but when you pass a
268−`note`, you may get a response. If you do, then the response will come
269−tagged with the `wire` that you used to pass the `note`. It's generally
270−good practice to make your `wire`s fairly unique within your agent, since
271−otherwise you may not be able to distinguish the responses.
272−
273−#### Notes
274−
275−An agent may pass `note`s to either Arvo or another agent. If the `note` is
276−to another agent, then it should usually be one of these:
277−
278−```hoon
279−[%pass /my/wire %agent [our.bowl agent-name] %watch /a/path]
280−[%pass /my/wire %agent [our.bowl agent-name] %leave ~]
281−[%pass /my/wire %agent [our.bowl agent-name] %poke %foo-mark !>(poke-data)]
282−```
283−
284−Note that to unsubscribe to a `path`, you must send the unsubscription on
285−the same `wire` that sent for the original subscription. Don't subscribe
286−to separate `path`s along the same `wire`, because then you can't properly
287−distinguish them for cancelling (besides not being able to distinguish
288−the subscription updates). In other words, besides letting _you_
289−distinguish your `card`s, the `wire` also identifies requests for the system.
290−
291−If the `note` is not to another agent but to Arvo itself, then it is a
292−request to one of the vanes, which are kernel modules that provide
293−various system services, including IO. Here are some examples:
294−
295−```hoon
296−[%pass /my/wire %arvo %b %wait (add now.hid ~s10)]
297−```
298−
299−This is a request to the `%b` vane (Behn, the timer vane) to set a timer
300−for 10 seconds in the future. After 10 seconds, Behn will respond with
301−a `%wake` card, which you will recieve in `+on-arvo`. It will come back
302−on `/my/wire`.
303−
304−```hoon
305−=/ =path /(scot %p our.hid)/base/(scot %da now.hid)/my-file/txt
306−=/ contents=cage [%txt !>(~['text file line 1' 'line 2'])]
307−[%pass /my/wire %arvo %c %info (foal:space:userlib path contents)]
308−```
309−
310−This is a request to the `%c` vane (Clay, the filesystem vane) to write
311−a file to `/my-file/txt` in the base desk. You will not receive a
312−response to this `note`.
313−
314−```hoon
315−=/ =path /my-file/txt
316−=/ =moat [da+now.hid da+(add now.hid ~h1) path]
317−[%pass /my/wire %arvo %c %warp our.hid %base ~ %many & moat]
318−```
319−
320−This is a request to the `%c` vane to send us a `%writ` `card` whenever
321−`/my-file/txt` changes in the next hour. There may be many responses to
322−this note if the file changes many times.
323−
324−```hoon
325−=/ =request:http
326− [%'GET' 'https://example.com' ~ ~]
327−[%pass /my/wire %arvo %i %request request *outbound-config:iris]
328−```
329−
330−This is a request to the `%i` vane (Iris, the HTTP client vane) to make
331−a GET HTTP request to example.com. The response will come as an
332−`%http-response` card.
333−
334−#### Gifts
335−
336−In contrast to the many possible `note`s, there are only two types of
337−`gift`s that an agent may give:
338−
339−```hoon
340−[%give %fact (unit path) =cage]
341−[%give %kick (unit path)]
342−```
343−
344−A subscription update is a new piece of subscription content for all
345−subscribers on a given `path`. If no `path` is given, then the update is
346−only given to the program that instigated this request. Typical use of
347−this mode is in `+on-watch` to give an initial update to a new
348−subscriber to get them up to date.
349−
350−A subscription close closes the subscription for all subscribers on a
351−given `path`. If no `path` is given, then the update is only given to the
352−program that instigated this request. Typical use of this mode would be
353−in `+on-watch` to produce a single update to a subscription then close
354−the subscription.
355−
356−### Vases and cages
357−
358−A `vase` is a piece of dynamic data. Structurally, it's a pair of an
359−explicit reification of a type and an untyped [noun](/docs/glossary/noun/). This lets us
360−represent a value which has a type that isn't known at compile time. A
361−vase has three operations:
362−
363−- `!>` is a unary rune that lifts a statically typed value to a
364− dynamically-typed `vase`. For example, `!>('hi')` gives `[#t/@t q=26.984]`.
365−
366−- `!<` is a binary rune that takes a mold and a dynamically typed `vase`
367− and reduces it to a statically typed value. If the `vase` does not in
368− fact have the type of the mold you give it, then it nest-fails, else
369− it produces `value`. For example, `!<(@t !>('hi'))` produces `'hi'` while `!<(^ !>('hi'))` causes a nest fail..
370−
371−- The compiler takes text and converts it to a `vase` of the compiled
372− code. Agents shouldn't need this directly, but Gall uses this to
373− compile agents to `vase`s, on which it calls `!<(agent:gall compiled-agent-vase)`.
374−
375−A `cage` is simply a pair of a mark and a vase. A mark is a textual tag
376−that should correspond to the particular dynamic type in the vase.
377−
378−In agents, we use vases to represent types which Gall doesn't know about
379−when it was compiled, but which nevertheless need to go outside the
380−agent. In practice, there are three common cases:
381−
382−- The data in a "poke" request is of a type that is defined by each
383− agent, so it must by dynamic. This is the input to `++on-poke` as well
384− as the cage in the `%poke` case of the `%agent` note.
385−
386−- The data in a subscription update is defined by each agent, so it must
387− be dynamic. This is the cage in `%fact`, both when giving the update
388− and in the input to `+on-agent`.
389−
390−- The state of an agent is also unique to each agent. Most of the time,
391− Gall doesn't interact directly with agent's state, but when upgrading
392− an agent, it must pass the state of the old version of the agent to
393− the new version of the agent. This is the output of `+on-save` and
394− the input to `+on-load`.
395−
396−### State
397−
398−In the definition of an agent, the entire core is wrapped with the `^|`
399−rune, which corresponds to the "iron" variance mode. This means it's
400−"contravariant" in the input, which allows Gall to write to the new bowl
401−on every event. It also means that the context of the core is opaque to
402−Gall, which means you can store state in your context in whatever
403−structure you want.
404−
405−This is why most of the handler arms produce not just a list of cards
406−but also a new `agent:gall`. Usually, this will be the "same" agent in
407−the sense that the code will be the same, but you may have changed the
408−state that's stored in its (opaque to Gall) context.
409−
410−The skeleton example above gives an example of keeping an atom as your
411−state. Define the state in the context of your agent core, then you can
412−change it with `=.` or `%=`, as long as you produce the new version of
413−the agent core.
414−
415−When you upgrade an agent, you need to extract the state from your
416−opaque context and produce it to Gall as a dynamically typed vase.
417−Usually, this will be easy: just call `!>` on whatever state you wish
418−to preserve. This is `+on-save`.
419−
420−When the new agent is about to be started, Gall will call it with
421−`+on-load` with the vase just produced above. This allows you to ingest
422−your old state and continue right where you left off.
423−
424−If the type of your state hasn't changed, you can just
425−
426−```hoon
427−=. state !<(state-type old-state-vase)
428−```
429−
430−If it has changed, then it should look more like:
431−
432−```hoon
433−=. state (upgrade-state !<(old-state-type old-state-vase))
434−```
435−
436−It's useful to tag your state with a version number so that the
437−`+upgrade-state` function can take a tagged union of all your old state
438−types and upgrade from any of them to the current state type. For
439−example, it may have the following structure:
440−
441−```hoon
442−+$ old-state-types
443− $% [%0 s=state-0]
444− [%1 s=state-1]
445− [%2 s=state-2]
446− ==
447−++ upgrade-state
448− |= old=old-state-types
449− =? old ?=(%0 -.old)
450− (state-0-to-1 s.old)
451− =? old ?=(%1 -.old)
452− (state-1-to-2 s.old)
453− ?> ?=(%2 -.old)
454− s.old
455−```
456−
457−### Bowl
458−
459−The core takes as input a `bowl`, which includes useful info like the
460−current ship, the current time, and a renewable source of entropy. This
461−information is available to any of the handlers.
462−
463−## Arms
464−
465−A description of each of the handler arms follows.
466−
467−### +on-init
468−
469−This arm is called once when the agent is started. It has no input and
470−lets you perform any initial IO.
471−
472−### +on-save
473−
474−This arm is called immediately before the agent is upgraded. It
475−packages the permament state of the agent in a `vase` for the next version
476−of the agent. Unlike most handlers, this cannot produce effects.
477−
478−### +on-load
479−
480−This arm is called immediately after the agent is upgraded. It receives
481−a `vase` of the state of the previously-running version of the agent,
482−which allows it to cleanly upgrade from the old agent.
483−
484−### +on-poke
485−
486−This arm is called when the agent is "poked". The input is a `cage`, so
487−it's a pair of a mark and a dynamic `vase`.
488−
489−### +on-watch
490−
491−This arm is called when a program wants to subscribe to the agent on a
492−particular `path`. The agent may or may not need to perform setup steps
493−to intialize the subscription. It may produce a `%give`
494−`%subscription-result` to the subscriber to get it up to date, but after
495−this event is complete, it cannot give further updates to a specific
496−subscriber. It must give all further updates to all subscribers on a
497−specific `path`.
498−
499−If this arm crashes, then the subscription is immediately terminated.
500−More specifcally, it never started -- the subscriber will receive a
501−negative `%watch-ack`. You may also produce an explicit `%kick` to
502−close the subscription without crashing -- for example, you could
503−produce a single update followed by a `%kick`.
504−
505−### +on-leave
506−
507−This arm is called when a program becomes unsubscribed to you.
508−Subscriptions may close because the subscriber intentionally
509−unsubscribed, but they also could be closed by an intermediary. For
510−example, if a subscription is from another ship which is currently
511−unreachable, Ames may choose to close the subscription to avoid queueing
512−updates indefinitely. If the program crashes while processing an
513−update, this may also generate an unsubscription. You should consider
514−subscriptions to be closable at any time.
515−
516−### +on-peek
517−
518−This arm is called when a program reads from the agent's "scry"
519−namespace, which should be referentially transparent. Unlike most
520−handlers, this cannot perform IO, and it cannot change the state. All
521−it can do is produce a piece of data to the caller, or not.
522−
523−If this arm produces `[~ ~ data]`, then `data` is the value at the the
524−given `path`. If it produces `[~ ~]`, then there is no data at the given
525−`path` and never will be. If it produces `~`, then we don't know yet
526−whether there is or will be data at the given `path`.
527−
528−### +on-agent
529−
530−This arm is called to handle responses to `%give` moves to other agents.
531−It will be one of the following types of response:
532−
533−- `%poke-ack`: acknowledgment (positive or negative) of a poke. If the
534− value is `~`, then the poke succeeded. If the value is `[~ tang]`,
535− then the poke failed, and a printable explanation (e.g. a stack trace)
536− is given in the `tang`.
537−
538−- `%watch-ack`: acknowledgment (positive or negative) of a subscription.
539− If negative, the subscription is already ended (technically, it never
540− started).
541−
542−- `%fact`: update from the publisher.
543−
544−- `%kick`: notification that the subscription has ended.
545−
546−### +on-arvo
547−
548−This arm is called to handle responses to `%pass` `move`s to vanes. The
549−list of possible responses from the system is statically defined in
550−`sys/lull.hoon` (grep for `+$ sign-arvo`).
551−
552−### +on-fail
553−
554−If an error happens in `+on-poke`, the crash report goes into the
555−`%poke-ack` response. Similarly, if an error happens in
556−`+on-subscription`, the crash report goes into the `%watch-ack`
557−response. If a crash happens in any of the other handlers, the report
558−is passed into this arm.
content/docs/arvo/iris/_index.mddeleted−23
@@ -1,23 +0,0 @@
1−+++
2−title = "Iris"
3−weight = 80
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−## [Overview](/docs/arvo/iris/iris)
10−
11−A brief overbview of Iris, Urbit's HTTP client vane.
12−
13−## [API Reference](/docs/arvo/eyre/tasks)
14−
15−The `task`s Iris takes and the `gift`s it returns.
16−
17−## [Data Types](/docs/arvo/iris/data-types)
18−
19−Reference documentation of the data types used by Iris.
20−
21−## [Example](/docs/arvo/iris/example)
22−
23−An example of using Iris to fetch a remote HTTP resource.
content/docs/arvo/iris/data-types.mddeleted−54
@@ -1,54 +0,0 @@
1−+++
2−title = "Data Types"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−Iris itself only has three structures defined in `lull.hoon`, but it also uses `$http` structures which are shared between Iris and Eyre. The `$http` structures are detailed in the [Eyre](/docs/arvo/eyre/data-types#http) Data Types documentation.
8−
9−## `$client-response`
10−
11−```hoon
12−+$ client-response
13− $%
14− $: %progress
15− =response-header:http
16− bytes-read=@ud
17− expected-size=(unit @ud)
18− incremental=(unit octs)
19− ==
20− [%finished =response-header:http full-file=(unit mime-data)]
21− [%cancel ~]
22− ==
23−```
24−
25−This structure represents data which Iris has fetched from a remote HTTP resource, and is what's returned in a `%http-response` `gift` (see the [%request](/docs/arvo/iris/tasks#request) documentation for details) by Iris to the app or thread which requested it. There are three kinds of `client-response` - `%progress`, `%finished` and `%cancel`. A `%progress` `client-response` is a partial response, such as when an HTTP response is split into multiple separate chunks. A `%finished` `client-response` is the final complete, assembled and parsed HTTP response. A `%cancel` `client-response` is sent when the runtime cancels the request for some reason.
26−
27−Note that at the time of writing, **neither `%progress` nor `%cancel` `client-response`s are implemented**, so in practice you'll only ever get a single `%finished` `client-response`.
28−
29−In a `%progress` `client-response`, the [$response-header:http](/docs/arvo/eyre/data-types#response-headerhttp) contains the HTTP status code and headers. The `bytes-read` field is the total number of bytes fetched so far. The `expected-size` field is the total size specified in the content-length header if it has one. The `incremental` field is the data received since the last `%http-response`.
30−
31−In a `%finished` `client-response`, the `full-file` is the complete body of the HTTP message as a (maybe) [$mime-data](#mime-data).
32−
33−## `$mime-data`
34−
35−```hoon
36−+$ mime-data
37− [type=@t data=octs]
38−```
39−
40−Unvalidated mime data that has been fetched from a remote HTTP resource.
41−
42−## `$outbound-config`
43−
44−```hoon
45−+$ outbound-config
46− $:
47− redirects=_5
48− retries=_3
49− ==
50−```
51−
52−This structure is used in a [%request task](/docs/arvo/iris/tasks#request) to specify settings for an HTTP request. The `redirects` field specifies the number of redirects to automatically follow before failing, and defaults to 5. The `retries` field specifies the number of times to retry a failed request before giving up, and defaults to 3.
53−
54−Note that at the time of writing, **neither redirects nor retries have been implemented**, so these settings will not do anything and you can just use the bunt value in all cases.
content/docs/arvo/iris/example.mddeleted−87
@@ -1,87 +0,0 @@
1−+++
2−title = "Example"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−Here we'll look at a simple example of fetching a remote HTTP resource with Iris. We'll use the following thread, which you can save in the `/ted` directory of your `%base` desk:
8−
9−`iris-thread.hoon`
10−
11−```hoon
12−/- spider
13−/+ strandio
14−=, strand=strand:spider
15−^- thread:spider
16−|= arg=vase
17−=/ m (strand ,vase)
18−^- form:m
19−=/ url=@t (need !<((unit @t) arg))
20−=/ =request:http [%'GET' url ~ ~]
21−=/ =task:iris [%request request *outbound-config:iris]
22−=/ =card:agent:gall [%pass /http-req %arvo %i task]
23−;< ~ bind:m (send-raw-card:strandio card)
24−;< res=(pair wire sign-arvo) bind:m take-sign-arvo:strandio
25−?. ?=([%iris %http-response %finished *] q.res)
26− (strand-fail:strand %bad-sign ~)
27−~& +.q.res
28−?~ full-file.client-response.q.res
29− (strand-fail:strand %no-body ~)
30−(pure:m !>(`@t`q.data.u.full-file.client-response.q.res))
31−```
32−
33−This thread takes a fully qualified URL in a `@t` as an argument. It will ask Iris to fetch the HTTP resource at the given URL by passing it a [%request task](/docs/arvo/iris/tasks#request) containing an HTTP GET [$request:http](/docs/arvo/eyre/data-types#requesthttp):
34−
35−```hoon
36−=/ url=@t (need !<((unit @t) arg))
37−=/ =request:http [%'GET' url ~ ~]
38−=/ =task:iris [%request request *outbound-config:iris]
39−=/ =card:agent:gall [%pass /http-req %arvo %i task]
40−```
41−
42−In this example, our `request:http` specifies no additional headers and has no body so it has a `~` for each of those fields. Of course in practice if you have headers or data you want to send you would include those.
43−
44−Our thread will take the `%http-response` `gift` that comes back from Iris and debug print it to the terminal so you can have a look at the structure, and then it will cast the body of the HTTP message to a `@t` and print it.
45−
46−Let's try it out:
47−
48−```
49−> -iris-thread 'http://example.com'
50−[ %http-response
51− client-response
52− [ %finished
53− response-header
54− [ status-code=200
55− headers
56− ~[
57− [key='age' value='212909']
58− [key='cache-control' value='max-age=604800']
59− [key='content-type' value='text/html; charset=UTF-8']
60− [key='date' value='Thu, 24 Jun 2021 04:12:13 GMT']
61− [key='expires' value='Thu, 01 Jul 2021 04:12:13 GMT']
62− [key='last-modified' value='Thu, 17 Oct 2019 07:18:26 GMT']
63− [key='server' value='ECS (oxr/8328)']
64− [key='vary' value='Accept-Encoding']
65− [key='x-cache' value='HIT']
66− [key='content-length' value='1256']
67− ]
68− ]
69− full-file
70− [ ~
71− [ type='text/html; charset=UTF-8'
72− data
73− [ p=1.256
74− q
75− 224.708.415.080.409.844.273.808.970.700.472.455.882.111.359.8(...truncated for brevity)
76− ]
77− ]
78− ]
79− ]
80−]
81−```
82−
83−...and here's the data from the HTTP response cast to a `@t`:
84−
85−```
86−'<!doctype html>\0a<html>\0a<head>\0a <title>Example Domain</title>\0a\0a (...truncated for brevity)'
87−```
content/docs/arvo/iris/iris.mddeleted−17
@@ -1,17 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−+++
6−
7−Iris is the HTTP client vane.
8−
9−Iris gets passed HTTP requests, makes the request to the specified URL, and returns the HTTP response.
10−
11−## Sections
12−
13−[Data Types](/docs/arvo/iris/data-types) - Reference documentation of the data types used by Iris.
14−
15−[API Reference](/docs/arvo/eyre/tasks) - The `task`s Iris takes and the `gift`s it returns.
16−
17−[Example](/docs/arvo/iris/example) - An example of using Iris to fetch a remote HTTP resource.
content/docs/arvo/iris/tasks.mddeleted−61
@@ -1,61 +0,0 @@
1−+++
2−title = "API Reference"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−This document details the `task`s used by Iris. Iris only has three `task`s besides the standard vane `task`s: [%request](#request), [%cancel-request](#cancel-request), and [%receive](#receive). The `%receive` `task` is only sent to Iris by the runtime, so you're likely to only use `%request` and `%cancel-request`.
8−
9−## `%request`
10−
11−```hoon
12−[%request =request:http =outbound-config]
13−```
14−
15−Fetch a remote HTTP resource.
16−
17−The [$request:http](/docs/arvo/eyre/data-types#requesthttp) is the request itself and contains the HTTP method, the fully qualified target URL, a list of HTTP headers to be included and maybe the data for the body of the request.
18−
19−The [$outbound-config](/docs/arvo/iris/data-types#outbound-config) specifies the number of redirects to follow before failing and the number of retries to attempt before giving up. The default values are `5` and `3` respectively. As of writing, **retries and auto-following redirects are not implemented**, so what you specify here is irrelevant and you can just use the bunt value of `outbound-config`.
20−
21−#### Returns
22−
23−Iris returns a `%http-response` `gift` in response to a `%request` task. A `%response` `gift` looks like:
24−
25−```hoon
26−[%http-response =client-response]
27−```
28−
29−The [$client-response](/docs/arvo/iris/data-types#client-response) contains the HTTP response from the server including the status code, HTTP headers and any data along with its mime type.
30−
31−The `client-response` structure specifies three kinds of responses - `%progress`, `%finished` and `%cancel`. The `%progress` response would contain each chunk of the message as it came in, `%finished` would contain the final assembled message from Vere's buffer, and `%cancel` would be sent if the runtime cancels the request.
32−
33−Note that neither `%progress` partial messages nor `%cancel` responses have been implemented in Vere at the time of writing, so **you will only ever receive a single `%http-response` `gift` with a `%finished` `client-response`**. If the request fails for some reason, you'll still get an empty `%finished` `client-response` with a `504` status code.
34−
35−#### Example
36−
37−See the [Example](/docs/arvo/iris/example) document.
38−
39−## `%cancel-request`
40−
41−```hoon
42−[%cancel-request ~]
43−```
44−
45−Cancel a previous request to fetch a remote HTTP resource.
46−
47−A `%cancel-request` `task` does not take any arguments, the [request](#request) to cancel is determined implicitly.
48−
49−#### Returns
50−
51−Iris does not return any `gift` in response to a `%cancel-request` `task`. You will also not receive any `gift` back from the original `%request` `task` you've cancelled.
52−
53−## `%receive`
54−
55−```hoon
56−[%receive id=@ud =http-event:http]
57−```
58−
59−Receives HTTP data from outside. This `task` is sent to Iris by the runtime, you would not use it manually.
60−
61−The `id` is a sequential ID for the event and the [$http-event:http](/docs/arvo/eyre/data-types#http-eventhttp) contains the HTTP headers and data.
content/docs/arvo/jael/_index.mddeleted−27
@@ -1,27 +0,0 @@
1−+++
2−title = "Jael"
3−weight = 90
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−insert_anchor_links = "right"
7−+++
8−
9−## [Overview](/docs/arvo/jael/jael)
10−
11−An overview of Jael, Urbit's security and encryption vane.
12−
13−## [API Reference](/docs/arvo/jael/tasks)
14−
15−The `task`s Jael takes and the `gift`s it returns.
16−
17−## [Scry Reference](/docs/arvo/jael/scry)
18−
19−The scry endpoints of Jael.
20−
21−## [Data Types](/docs/arvo/jael/data-types)
22−
23−Reference documentation of the various data types used by Jael.
24−
25−## [Examples](/docs/arvo/jael/examples)
26−
27−Practical examples of using Jael's `task`s.
content/docs/arvo/jael/data-types.mddeleted−243
@@ -1,243 +0,0 @@
1−+++
2−title = "Data Types"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−Jael's section in `lull.hoon` contains three ancillary cores with their own type definitions as well as Jael's general types.
8−
9−### `$public-keys-result`
10−
11−```hoon
12−+$ public-keys-result
13− $% [%full points=(map ship point)]
14− [%diff who=ship =diff:point]
15− [%breach who=ship]
16− ==
17−```
18−
19−This is what Jael gives (in a [%public-keys](/docs/arvo/jael/tasks#public-keys) `gift`) to subcribers who are tracking public key information for a `set` of `ship`s.
20−
21−Typically the `%full` kind with a `map` of `ship`s to [$point:point](#pointpoint)s is given immediately upon subscription and contains all public key records for the ships in question. After the `%full`, a `%diff` (including a [$diff:point](#diffpoint)) will be given whenever a change (such as the sponsor or pubkey) has occurred for one of the ships being tracked, and a `%breach` will be given whenever a continuity breach for a tracked ship occurs.
22−
23−### `$seed`
24−
25−```hoon
26−+$ seed [who=ship lyf=life key=ring sig=(unit oath:pki)]
27−```
28−
29−Private boot parameters. The `who` field is the name of the ship, `lyf` is the `life` (key revision number), `key` is the private key and `sig` is the signature of the parent ship if it's a moon, and `~` otherwise.
30−
31−### `$dawn-event`
32−
33−```hoon
34−+$ dawn-event
35− $: =seed
36− spon=(list [=ship point:azimuth-types])
37− czar=(map ship [=rift =life =pass])
38− turf=(list turf)
39− bloq=@ud
40− node=(unit purl:eyre)
41− ==
42−```
43−
44−Ship initialisation parameters.
45−
46−- [$seed](#seed) contains the private boot parameters.
47−- `spon` is a `list` of ships and their [$point](#pointpoint)s in the ship's sponsorship chain, all the way to the galaxy level.
48−- `czar` is a map from each galaxy's `@p` to its `rift`, `life`, and public key (`pass`).
49−- `turf` is a `list` of DNS suffixes used for galaxies, which is `urbit.org` by default.
50−- `bloq` is the number of the Ethereum block in which the ship registered its keys with the Azimuth smart contract.
51−- `node` is the URL of the Ethereum node used to monitor Azimuth.
52−
53−### `$source`
54−
55−```hoon
56−+$ source (each ship term)
57−```
58−
59−Source of public key updates for Jael. If it's a `term` it's a Gall agent e.g `%azimuth-tracker`. If it's a `ship`, Jael will subscribe to that ship's Jael for updates - e.g. Jael will subscribe to the parent planet of moons for updates about the moons.
60−
61−### `$source-id`
62−
63−```hoon
64−+$ source-id @udsourceid
65−```
66−
67−Numerical index for Jael to organise its `source`s. Jael assigns its `source-id`s sequentially, starting from `0`.
68−
69−### `$state-eth-node`
70−
71−```hoon
72−+$ state-eth-node :: node config + meta
73− $: top-source-id=source-id
74− sources=(map source-id source)
75− sources-reverse=(map source source-id)
76− default-source=source-id
77− ship-sources=(map ship source-id)
78− ship-sources-reverse=(jug source-id ship)
79− ==
80−```
81−
82−Jael's data about `source`s for PKI updates about ships.
83−
84−- `top-source-id` tracks the highest `source-id` so Jael can easily determine what the next `source-id` should be.
85−- `sources` is a `map` of [$source-id](#source-id)s to [$source](#source)s.
86−- `sources-reverse` the same as `sources` but in reverse.
87−- `default-source` is the default `source` to use (typically `0` - `%azimuth-tracker`).
88−- `ship-sources` is a `map` from `ship`s to `source-id`s and records where to get updates from for the ships in question. Typically these will map moons to their parent ships.
89−- `ship-sources-reverse` is the same as `ship-sources` but in reverse.
90−
91−## block
92−
93−Structures for Ethereum blocks.
94−
95−### `$hash:block`
96−
97−```hoon
98−+$ hash @uxblockhash
99−```
100−
101−Ethereum block hash.
102−
103−### `$number:block`
104−
105−```hoon
106−+$ number @udblocknumber
107−```
108−
109−Ethereum block number.
110−
111−### `$id:block`
112−
113−```hoon
114−+$ id [=hash =number]
115−```
116−
117−Ethereum block identifier - contains both the [$hash:block](#hashblock) and [$number:block](#numberblock).
118−
119−### `$block:block`
120−
121−```hoon
122−+$ block [=id =parent=hash]
123−```
124−
125−A reference to an Ethereum block - contains the [$id:block](#idblock) and the [$hash:block](#hashblock) of its parent for ordering purposes.
126−
127−## point
128−
129−Structures for points (Ship IDs in Azimuth).
130−
131−### `$point:point`
132−
133−```hoon
134−+$ point
135− $: =rift
136− =life
137− keys=(map life [crypto-suite=@ud =pass])
138− sponsor=(unit @p)
139− ==
140−```
141−
142−Public key data for a particular ship. The `rift` is the current continuity breach number and `life` is the current key revision number. The `keys` `map` contains the public key (`pass`) for each `life` up to the current one. The `sponsor` is the current sponsor of the ship in question, if it has one.
143−
144−### `$key-update:point`
145−
146−```hoon
147−+$ key-update [=life crypto-suite=@ud =pass]
148−```
149−
150−An update to a ship's keys. The `life` is the key revision number, `crypt-suite` is a version number for the cryptographic suite used for keys in Azimuth, and `pass` is the public key itself.
151−
152−### `$diffs:point`
153−
154−```hoon
155−+$ diffs (list diff)
156−```
157−
158−A list of invertible [$diff:point](#diffpoint)s.
159−
160−### `$diff:point`
161−
162−```hoon
163−+$ diff
164− $% [%rift from=rift to=rift]
165− [%keys from=key-update to=key-update]
166− [%spon from=(unit @p) to=(unit @p)]
167− ==
168−```
169−
170−An invertible diff for public key (and related) changes to the state of an Azimuth point (ship ID).
171−
172−- `%rift` is a change to the `rift` (continuity breach number) that occurs when a ship undergoes a continuity breach.
173−- `%keys` is a change to a ship's `life` and public key, specified in the [$key-update:point](#key-updatepoint).
174−- `%spon` is a change to a ship's sponsor.
175−
176−The `from` and `to` field specify the old a new values respectively.
177−
178−### `$udiffs:point`
179−
180−```hoon
181−+$ udiffs (list [=ship =udiff])
182−```
183−
184−A list of non-invertible [$udiff:point](#udiffpoint)s.
185−
186−### `$udiff:point`
187−
188−```hoon
189−+$ udiff
190− $: =id:block
191− $% [%rift =rift]
192− [%keys key-update]
193− [%spon sponsor=(unit @p)]
194− [%disavow ~]
195− == ==
196−```
197−
198−A non-invertible diff for public key (and related) changes to the state of an Azimuth point (ship ID).
199−
200−The [$id:block](#idblock) contains the block number and block hash of the Ethereum block in which the change occurred. The next part specifies what changed, where:
201−
202−- `%rift` means the ship has undergone a continuity breach and therefore the `rift` (continuity revision number) has changed.
203−- `%keys` means the ship's `life` (key revision number) has changed, the [$key-update:point](#key-updatepoint) contains the new `life` and pubkeys.
204−- `%spon` means the ship's sponsor has changed.
205−- `%disavow` means a previous Ethereum block has been disavowed.
206−
207−A `udiff:point` can be converted to a [$diff:point](#diffpoint) with the `+udiff-to-diff:point` function.
208−
209−## pki
210−
211−This structure is mostly a holdover from prior versions of Jael and is unused apart from [$oath:pki](#oathpki).
212−
213−### `$hand:pki`
214−
215−```hoon
216−+$ hand @uvH
217−```
218−
219−128-bit Hash.
220−
221−### `$mind:pki`
222−
223−```hoon
224−+$ mind [who=ship lyf=life]
225−```
226−
227−Key identifier.
228−
229−### `$name:pki`
230−
231−```hoon
232−+$ name (pair @ta @t)
233−```
234−
235−Name in both ASCII and Unicode.
236−
237−### `$oath:pki`
238−
239−```hoon
240−+$ oath @
241−```
242−
243−Signature. This type is used in the [$seed](#seed) for moons as a signature from the moon's parent.
content/docs/arvo/jael/examples.mddeleted−251
@@ -1,251 +0,0 @@
1−+++
2−title = "Examples"
3−weight = 5
4−template = "doc.html"
5−+++
6−
7−This documents contains practical examples of a number of Jael's `task`s.
8−
9−General documentation of the `task`s demonstrated here can be found in the [API Reference](/docs/arvo/jael/tasks) document, and details of the data types mentioned can be found in the [Data Types](/docs/arvo/jael/data-types) document.
10−
11−## `%private-keys`
12−
13−Here we'll look at subscribing to private key updates from Jael. We'll use a thread to pass Jael a `%private-keys` `task`, take the `%private-keys` `gift` it returns, debug print it to the terminal and finally unsubscribe with a `%nuke` `task`.
14−
15−`sub-priv.hoon`
16−
17−```hoon
18−/- spider
19−/+ strandio
20−=, strand=strand:spider
21−=, card=card:agent:gall
22−^- thread:spider
23−|= arg=vase
24−=/ m (strand ,vase)
25−^- form:m
26−;< ~ bind:m (send-raw-card:strandio %pass /sub-priv %arvo %j %private-keys ~)
27−;< res=[=wire =sign-arvo] bind:m take-sign-arvo:strandio
28−?> ?=([%sub-priv ~] wire.res)
29−?> ?=([%jael *] sign-arvo.res)
30−~& +.sign-arvo.res
31−;< ~ bind:m (send-raw-card:strandio %pass /sub-priv %arvo %j %nuke ~)
32−(pure:m !>(~))
33−```
34−
35−Save the above thread in the `/ted` directory of your `%base` desk and `|commit %base`.
36−
37−Now let's run the thread:
38−
39−```
40−> -sub-priv
41−```
42−
43−You should see the `%private-key` `gift` it returns in the Dojo:
44−
45−```
46−[ %private-keys
47− life=1
48− vein
49− { [ p=1
50− q
51− 1.729.646.917.183.337.[...truncated for brevity]
52− ]
53− }
54−]
55−```
56−
57−At this point our thread unsubscribes again with a `%nuke` `task` but without that it would send a new `%private-key` `gift` each time the private keys were changed.
58−
59−## `%public-keys` and `%nuke`
60−
61−Here we'll look at both subscribing and unsubscribing to updates of a ship's public keys in Jael. We'll subscribe by sending Jael a `%public-keys` `task`, take the `%public-keys` `gift` it responds with, print it to the terminal, scry for the `set` of `duct`s subscribed to the ship in question, print them to the terminal, and finally send Jael a `%nuke` `task` to unsubscribe.
62−
63−Here's a thread that performs these actions:
64−
65−`sub-pub.hoon`
66−
67−```hoon
68−/- spider
69−/+ strandio
70−=, strand=strand:spider
71−=, card=card:agent:gall
72−=>
73−|%
74−+$ subs
75− $: yen=(jug duct ship)
76− ney=(jug ship duct)
77− nel=(set duct)
78− ==
79−--
80−^- thread:spider
81−|= arg=vase
82−=/ m (strand ,vase)
83−^- form:m
84−=/ =@p (need !<((unit @p) arg))
85−::
86−:: sub to public updates for specified ship
87−=/ c1=card [%pass /sub-pubkeys %arvo %j %public-keys (silt ~[p])]
88−;< ~ bind:m (send-raw-card:strandio c1)
89−::
90−:: take response from jael & print it
91−;< res=[=wire =sign-arvo] bind:m take-sign-arvo:strandio
92−?> ?=([%sub-pubkeys ~] wire.res)
93−?> ?=([%jael %public-keys *] sign-arvo.res)
94−~& +.sign-arvo.res
95−::
96−:: scry for tracking subs for specified ship in jael & print
97−;< =subs bind:m (scry:strandio ,subs /j/subscriptions/1)
98−=/ ducts=(set duct) (~(get ju ney.subs) p)
99−~& ducts
100−::
101−:: unsub from public updates for specified ships
102−=/ c2=card [%pass /sub-pubkeys %arvo %j %nuke (silt ~[p])]
103−;< ~ bind:m (send-raw-card:strandio c2)
104−(pure:m !>(~))
105−```
106−
107−Note this example was performed on a comet as a fake ship won't have the required information in Jael.
108−
109−Save the above thread in the `/ted` directory and `|commit %base`. The thread takes a `ship` as an argument, so we'll try to subscribe to pubkey updates for `~dopzod`. Let's run the thread:
110−
111−```
112−> -sub-pub ~dopzod
113−```
114−
115−It first passes a `%public-keys` `task` to Jael that looks like `[%public-keys (silt ~[~dopzod])]` in order to subscribe. Jael will immediately respond with a `%public-keys` `gift` that contains a `%full` [$public-keys-result](/docs/arvo/jael/data-types#public-keys-result). The `(map ship point)` contained will (for each ship specified in the `task`) include the current pubkeys for the ship's current life as well as previous keys for previous `life`s. It thus contains a complete record of keys up to the present for each ship. Our thread will print these out to the terminal like so:
116−
117−```
118−[ %public-keys
119− public-keys-result
120− [ %full
121− points
122− { [ p=~dopzod
123− q
124− [ rift=2
125− life=3
126− keys
127− { [ p=1
128− q
129− [ crypto-suite=1
130− pass
131− 939.529.329.928[...truncated for brevity...]
132− ]
133− ]
134− [ p=2
135− q
136− [ crypto-suite=1
137− pass
138− 2.215.774.809.906.200.376.0[...truncated for brevity...]
139− ]
140− ]
141− [ p=3
142− q
143− [ crypto-suite=1
144− pass
145− 707.070.568.606.374.[...truncated for brevity...]
146− ]
147− ]
148− }
149− sponsor=~
150− ]
151− ]
152− }
153− ]
154−]
155−```
156−
157−Along with giving us the current information, Jael will also subscribe us to any future updates for the ships in question. Such updates will come as additional `%public-keys` `gift`s, but rather than a `%full` `public-keys-result`, they'll instead contain either a `%diff` or `%breach` `public-keys-result`, depending on what's happened to the ship in question. It's difficult to simulate such events for demonstrative purposes so an example is not included, but you can look at the [$public-keys-result](/docs/arvo/jael/data-types#public-keys-result) to get an idea.
158−
159−Jael maintains a `(jug duct ship)` and its reverse `(jug ship duct)` in its state to track subscriptions. If we do a [subscriptions](/docs/arvo/jael/scry#subscriptions) scry and filter the result for `~dopzod`, we can see the duct of our thread has now been added to the `~dopzod` `set`. Our thread does this, and will output something like:
160−
161−```
162−{~[/gall/use/spider/0w1.vGVi-/~sampel-palnet/thread/~.dojo_0v6.0hlak.dam1b.bcdou.ai7gq.19fi8/sub-pubkeys /dill //term/1]}
163−```
164−
165−At this point our thread will send a `%nuke` `task` like `[%nuke (silt ~[~dopzod])]` to cancel our subscription. Jael doesn't respond to it, but now, with our thread having finished and exited, we can again scry & filter for subscriptions to `~dopzod`:
166−
167−```
168−> =/(a .^([yen=(jug duct ship) ney=(jug ship duct) nel=(set duct)] %j /=subscriptions=/1) (~(get ju ney.a) ~dopzod))
169−~
170−```
171−
172−As you can see the `set` is now empty, so we know the `%nuke` succeeded and Jael will no longer send us pubkey updates for `~dopzod`. One thing to note about `%nuke` is that it _must_ come from the same `duct` as the original subscription. You can't unsubscribe another app, ship, thread or what have you, so if we'd tried `%nuke`ing the subscription from a separate thread it wouldn't have worked.
173−
174−## `%turf`
175−
176−Here we'll look at using a `%turf` `task` to get Jael's list of domains. Note on a fake ship the list will be empty, so you may with to run it on a comet or moon.
177−
178−Here's a simple thread that'll pass Jael a `%turf` `task`, take the `%turf` `gift` it sends back and print it to the terminal:
179−
180−`turf.hoon`
181−
182−```hoon
183−/- spider
184−/+ strandio
185−=, strand=strand:spider
186−^- thread:spider
187−|= arg=vase
188−=/ m (strand ,vase)
189−^- form:m
190−=/ =task:jael [%turf ~]
191−=/ =card:agent:gall [%pass /get-domains %arvo %j task]
192−;< ~ bind:m (send-raw-card:strandio card)
193−;< resp=[=wire =sign-arvo] bind:m take-sign-arvo:strandio
194−?> ?=([%get-domains ~] wire.resp)
195−?> ?=([%jael %turf *] sign-arvo.resp)
196−~& +.sign-arvo.resp
197−(pure:m !>(~))
198−```
199−
200−Save in in the `/ted` directory of your ship and `|commit %base`. Next, let's try running it:
201−
202−```
203−> -turf
204−[%turf turf=~[<|org urbit|>]]
205−```
206−
207−As you see, the `%turf` `gift` contains `urbit.org` as `~['org' 'urbit']`.
208−
209−## `%step`
210−
211−Here we'll look at changing the web login code with a `%step` task.
212−
213−First, let's see the current `step` with a `%step` scry:
214−
215−```
216−> .^(@ud %j /=step=/(scot %p our))
217−0
218−```
219−
220−...and the current code with the `+code` generator:
221−
222−```
223−> +code
224−lidlut-tabwed-pillex-ridrup
225−```
226−
227−Now, let's pass Jael a `%step` task by using `|pass` in the dojo:
228−
229−```
230−> |pass [%j %step ~]
231−```
232−
233−Jael will `pass` Eyre a `%code-changed` `task:eyre` to let Eyre know the code's changed so you'll see a message from Eyre in the terminal:
234−
235−```
236−eyre: code-changed: throwing away cookies and sessions
237−```
238−
239−Now let's again scry for the `step` and see that it's been incremented:
240−
241−```
242−> .^(@ud %j /=step=/(scot %p our))
243−1
244−```
245−
246−And finally, let's again run `+code` and see there's now a new web login code:
247−
248−```
249−> +code
250−raldev-topnul-mirnut-lablut
251−```
content/docs/arvo/jael/jael.mddeleted−25
@@ -1,25 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 1
4−template = "doc.html"
5−+++
6−
7−Jael is the networking key infrastructure vane.
8−
9−The main purpose of Jael is keeping track of [Azimuth](/docs/azimuth/azimuth) related information. For each ship, this consists of its public keys, its key revision number (or `life`), its continuity breach number (or `rift`) (see [Life and Rift](/docs/azimuth/life-and-rift)), and who the sponsor of the ship is. It also handles the local ship's private keys, keeps track of galaxy domain prefixes, and performs some boot-related tasks.
10−
11−By default, Jael's primary source of information is the Gall agent `%azimuth-tracker`, which (using `%eth-watcher`) runs a thread that polls an Ethereum node for transactions in the Azimuth contract. It can also get updates from other ships on the network. This is always the case for moons, where it subscribes to the moon's parent's Jael for updates.
12−
13−The database of PKI information that Jael maintains is used by other vanes and agents for identity validation, encryption, decryption, and other cryptographic functions. In particular, Ames (the network vane) uses the information stored in Jael to encrypt packets it sends to other ships, and to decrypt & validate packets it receives from other ships.
14−
15−Jael has a few `task`s you can use to interact with it. In particular, its [%public-keys task](/docs/arvo/jael/tasks#public-keys) allows an agent or thread to subscribe for PKI updates for a `set` of `ship`s.
16−
17−## Sections
18−
19−[API Reference](/docs/arvo/jael/tasks) - The `task`s Jael takes and the `gift`s it returns.
20−
21−[Scry Reference](/docs/arvo/jael/scry) - The scry endpoints of Jael.
22−
23−[Data Types](/docs/arvo/jael/data-types) - Reference documentation of the various data types used by Jael.
24−
25−[Examples](/docs/arvo/jael/examples) - Practical examples of using Jael's `task`s.
content/docs/arvo/jael/scry.mddeleted−204
@@ -1,204 +0,0 @@
1−+++
2−title = "Scry Reference"
3−weight = 3
4−template = "doc.html"
5−+++
6−
7−Jael's scry endpoints never take a `care`. The particular endpoints are specified in the place of the desk in the path prefix, then additional arguments are specified in the path. Note this style of scry path is considered outdated, and may be changed in the future.
8−
9−## `%step`
10−
11−A `%step` scry gets the current web login code revision number. It takes your ship name as its `path` and the type returned is a `@ud`.
12−
13−#### Example
14−
15−```
16−> .^(@ud %j /=step=/(scot %p our))
17−0
18−```
19−
20−## `%code`
21−
22−A `%code` scry gets the current web login code. It takes your ship name as its `path` and the type returned is a `@p`.
23−
24−#### Example
25−
26−```
27−> .^(@p %j /=code=/(scot %p our))
28−~lidlut-tabwed-pillex-ridrup
29−```
30−
31−## `%life`
32−
33−A `%life` scry gets the current `life` (key revision number) of a ship if known, otherwise it crashes. It takes a ship as its `path` and the type returned is a `@ud`.
34−
35−#### Example
36−
37−```
38−> .^(@ud %j /=life=/(scot %p our))
39−1
40−```
41−
42−## `%lyfe`
43−
44−A `%lyfe` scry gets the current unitized `life` (key revision number) of a ship if known, otherwise returns `~`. It takes a ship as its `path` and the type returned is a `(unit @ud)`.
45−
46−#### Example
47−
48−```
49−> .^((unit @ud) %j /=lyfe=/(scot %p our))
50−[~ 1]
51−```
52−
53−## `%rift`
54−
55−A `%rift` scry gets the current `rift` (continuity number) of a ship if known, otherwise it crashes. It takes a ship as its `path` and the type returned is a `@ud`.
56−
57−#### Example
58−
59−```
60−.^(@ud %j /=rift=/(scot %p our))
61−1
62−```
63−
64−## `%ryft`
65−
66−A `%ryft` scry gets the current unitized `rift` (continuity number) of a ship if known, otherwise it returns `~`. It takes a ship as its `path` and the type returned is a `(unit @ud)`.
67−
68−#### Example
69−
70−```
71−> .^((unit @ud) %j /=ryft=/(scot %p our))
72−[~ 1]
73−```
74−
75−## `%vein`
76−
77−A `%vein` scry gets your ship's private key for the specified `life`. It takes a `life` `@ud` as its `path` and the type returned is a `ring`.
78−
79−#### Example
80−
81−```
82−> .^(@uw %j /=vein=/1)
83−0w84.0MwlQ.y2Ly9.6HVmH.8SYwo.EvuLC.f5YRw.T2NzD.EHtjZ.gpHZb.J0Pu5.aTGVL.UugSA.EZ~E9.~PODC.cohVD.B1zWj.ZWnJ2
84−```
85−
86−## `%vile`
87−
88−A `%vile` scry gets your `jam`mmed private boot parameters at your ship's current `life`. It takes no additional arguments in its `path`. The type returned is a `@` which is a `jam`med [$seed](/docs/arvo/jael/data-types#seed).
89−
90−#### Examples
91−
92−```
93−> .^(@ %j /=vile=)
94−73.825.716.773.695.891.582.219.653.213.376.682.408.892.852.624.025.387.720.465.884.094.267.975.202.807.896.467.150.282.384.122.104.470.678.155.055.914.950.319.747.613.107.324.566.157.366.237.078.063.363.527.599.682.750.233
95−```
96−
97−```
98−> ;;(seed:jael (cue .^(@ %j /=vile=)))
99−[ who=~zod
100− lyf=1
101− key
102− 1.729.646.917.183.337.262.068.568.133.450.460.269.618.308.934.734.494.661.340.450.478.360.301.077.532.415.587.141.242.844.893.269.500.211.196.916.184.768.225.437.577.083.064.475.012.067.992.317.942.521.494.338
103− sig=~
104−]
105−```
106−
107−## `%deed`
108−
109−A `%deed` scry gets the `life`, pubkey and maybe a signature if the ship in question is a comet. It takes the target ship and life as its `path` like `/~sampel-palnet/1` and the type returned is a `[life pass (unit @ux)]`.
110−
111−#### Example
112−
113−```
114−> .^([life pass (unit @ux)] %j /=deed=/(scot %p our)/1)
115−[ 1
116− 2.649.818.598.466.464.524.534.996.841.661.372.043.001.125.438.577.869.575.450.096.229.472.239.369.342.882.589.479.483.389.735.480.760.982.635.242.955.515.616.049.650.771.700.602.823.946.406.713.457.849.302.626
117− ~
118−]
119−```
120−
121−## `%earl`
122−
123−A `%earl` scry deterministically derives a private key for a moon. Note this is a holdover from an old version of moon infrastructure, the current `|moon` generator doesn't use this and instead generates moon private keys non-deterministically. It takes the moon name and your ship's current `life` (not the moon's `life`) as its `path` like `/~doznec-dozzod-dozzod-dozzod/1`. The type returned is a [$seed](/docs/arvo/jael/data-types#seed), the `life` of the moon in the `lyf` field of the `seed` will always be `1`.
124−
125−#### Example
126−
127−```
128−> .^(seed:jael %j /=earl=/~doznec-dozzod-dozzod-dozzod/1)
129−[ who=~doznec-dozzod-dozzod-dozzod
130− lyf=1
131− key
132− 1.055.418.877.440.612.330.077.014.834.463.499.863.663.523.990.336.436.220.536.921.445.512.367.957.276.250.223.724.881.932.188.751.226.308.505.496.234.256.625.462.295.144.257.529.749.880.805.247.600.674.018.370
133− sig=~
134−]
135−```
136−
137−## `%sein`
138−
139−A `%sein` scry gets the sponsor for the specified ship. This scry is used implicitly by `sein:title`. It takes the target ship as its `path` and the type returned is a `@p`.
140−
141−#### Example
142−
143−```
144−> .^(@p %j /=sein=/~sampel-palnet)
145−~talpur
146−```
147−
148−## `%saxo`
149−
150−A `%saxo` scry gets the sponsorship chain for the target ship (including the target ship itself). For example, a `%saxo` scry for a planet will return the planet, its star and the star's galaxy. This scry is used implicitly by `saxo:title`. It takes the target ship as its `path` and the type returned is a `(list @p)`.
151−
152−#### Example
153−
154−```
155−> .^((list @p) %j /=saxo=/~sampel-palnet)
156−~[~sampel-palnet ~talpur ~pur]
157−```
158−
159−## `%subscriptions`
160−
161−A `%subscriptions` scry gets the current state of subscriptions to public key updates (typically initiated with a [%public-keys task](/docs/arvo/jael/tasks#public-keys)). It takes a `life` as its `path` and returns a triple consisting of the following:
162−
163−```hoon
164−yen=(jug duct ship) :: trackers
165−ney=(jug ship duct) :: reverse trackers
166−nel=(set duct) :: trackers of all
167−```
168−
169−The `yen` `jug` maps subscribed `duct`s to the `ship`s they're tracking, and `ney` is just the inverse, mapping tracked `ship`s to subscribed `duct`s. The `nel` set contains `duct`s track all public key updates.
170−
171−#### Example
172−
173−```
174−.^([yen=(jug duct ship) ney=(jug ship duct) nel=(set duct)] %j /=subscriptions=/1)
175−[yen={} ney={} nel={}]
176−```
177−
178−## `%sources`
179−
180−A `%sources` scry gets the current state of Jael's sources for PKI updates. It takes no additional arguments in its `path` and returns a [$state-eth-node](/docs/arvo/jael/data-types#state-eth-node).
181−
182−#### Example
183−
184−```
185−> .^(state-eth-node:jael %j /=sources=)
186−[ top-source-id=0
187− sources={}
188− sources-reverse={}
189− default-source=0
190− ship-sources={}
191− ship-sources-reverse={}
192−]
193−```
194−
195−## `%turf`
196−
197−A `%turf` scry gets the list of domain prefixes for galaxies. It takes no additional arguments in its `path`. It returns a `(list turf)`, where a `turf` is a TLD-first `(list @t)`, so `urbit.org` as a `turf` is `~['org' 'urbit']`.
198−
199−#### Example
200−
201−```
202−> .^((list turf) %j /=turf=)
203−~[<|org urbit|>]
204−```
content/docs/arvo/jael/tasks.mddeleted−225
@@ -1,225 +0,0 @@
1−+++
2−title = "API Reference"
3−weight = 2
4−template = "doc.html"
5−+++
6−
7−This document details all the `task`s you may wish to send Jael, as well as the `gift`s you'll receive in response.
8−
9−You may also wish to reference the [Data Types](/docs/arvo/jael/data-types) document for details of the types referenced here, and the [Examples](/docs/arvo/jael/examples) document for practical examples of using these `task`s.
10−
11−## `%dawn`
12−
13−```hoon
14−[%dawn dawn-event]
15−```
16−
17−Boot from keys.
18−
19−This `task` is called once per ship during the vane initialization phase immediately following the beginning of the [adult stage](/docs/arvo/overview#structural-interface-core). This `task` is `%pass`ed to Jael by Dill, as Dill is the first vane to be loaded for technical reasons, though we consider Jael to be the true "first" vane. This `task` is only used for ships that will join the Ames network - fake ships (i.e. made with `./urbit -F zod`) use the [%fake](#fake) `task` instead.
20−
21−`%dawn` is used to perform a sequence of initialization tasks related to saving information about Azimuth and the Ames network and booting other vanes for the first time. Upon receipt of a `%dawn` `task`, Jael will:
22−
23−- record the Ethereum block the public key is registered to,
24−- record the URL of the Ethereum node used,
25−- save the signature of the parent planet (if the ship is a moon),
26−- load the initial public and private keys for the ship,
27−- set the DNS suffix(es) used by the network (currently just `urbit.org`),
28−- save the public keys of all galaxies,
29−- set Jael to subscribe to `%azimuth-tracker`,
30−- `%slip` a `%init` `task` to Ames, Clay, Gall, Dill, and Eyre, and `%give` an `%init`
31− `gift` to Arvo, which then informs Unix that the initialization process has concluded.
32−
33−This `task` takes a [$dawn-event](/docs/arvo/jael/data-types#dawn-event) as its argument.
34−
35−You would not use this `task` manually.
36−
37−#### Returns
38−
39−Jael `%give`s an `%init` `gift` to Unix. This occurs after the Dill `%slip` init.
40−
41−## `%fake`
42−
43−```hoon
44−[%fake =ship]
45−```
46−
47−Boot fake ship.
48−
49−This `task` is used instead of [%dawn](#dawn) when creating a fake ship via the `-F` flag when calling the Urbit binary. It performs a subset of the actions that `%dawn` performs, modified to accommodate the fake ship.
50−
51−`%fake` endows the ship with a private key and a public key deterministically derived from the ship's `@p`. It sets `fak.own.pki` to `%.y`, which is the bit that determines whether or not a ship is fake. Other parts of the Jael state, such as the sponsorship chain and galaxy public keys are left at their bunted values.
52−
53−The `ship` field specifies the `@p` of the fake ship being created.
54−
55−You would not use this `task` manually.
56−
57−#### Returns
58−
59−Jael `%give`s a `%init` `gift` to Unix.
60−
61−## `%listen`
62−
63−```hoon
64−[%listen whos=(set ship) =source]
65−```
66−
67−Set Ethereum source.
68−
69−Sets the source that the public keys for a set of `ship`s should be obtained from. This can either be a Gall app that communicates with an Ethereum node such as `%azimuth-tracker`, as in the case of galaxies, stars, and planets, or a ship, as in the case of moons.
70−
71−`whos` is the set of ships whose key data source is to be monitored. The [$source](/docs/arvo/jael/data-types#source) is either a ship or the name of a Gall app to use as a source. A `%listen` `task` with empty `whos` will set the default source. When the `source` is a ship, Jael will obtain public keys for ships in `(set ship)` from the given ship. By default, the `source` for a moon will be the planet that spawned that moon.
72−
73−You are unlikely to use this `task` manually.
74−
75−#### Returns
76−
77−Jael will not return any `gift`s in response to a `%listen` `task`.
78−
79−## `%meet`
80−
81−```hoon
82−[%meet =ship =life =pass]
83−```
84−
85−This `task` is deprecated and does not perform any actions.
86−
87−## `%moon`
88−
89−```hoon
90−[%moon =ship =udiff:point]
91−```
92−
93−Register moon keys or otherwise administer a moon.
94−
95−This is what is sent to Jael by `%hood` behind the scenes when you run `|moon`, `|moon-breach` or `|moon-cycle-keys`. The `ship` field is the moon's `@p`. The [$udiff:point](/docs/arvo/jael/data-types#udiffpoint) will contain the bunt of an [$id:block](/docs/arvo/jael/data-types#idblock) (since moons aren't registered in Azimuth) and one of the `udiff` actions depending on what you want to do.
96−
97−#### Returns
98−
99−Jael does not return any `gift`s in response to a `%moon` `task`.
100−
101−## `%nuke`
102−
103−```hoon
104−[%nuke whos=(set ship)]
105−```
106−
107−Cancel subscription to public or private key updates.
108−
109−If you've subscribed to public or private key updates from Jael with a [%private-keys](#private-keys) or [%public-keys](#public-keys) `task`, you can unsubscribe and stop receiving updates with a `%nuke` `task`. The `(set ship)` is the `set` of `ship`s which you want to stop tracking. Jael organises subscriptions based on `duct`s, and will determine which subscription to cancel implicitly based on the `duct` the `%nuke` `task` came from. This means a `%nuke` `task` only works from the same thread or agent and on the same `path` as the original subscription request.
110−
111−To cancel a subscription to the ship's private keys you must leave `whos` empty like `[%nuke ~]`.
112−
113−#### Returns
114−
115−Jael does not return a `gift` in response to a `%nuke` `task`.
116−
117−#### Examples
118−
119−See the [%public-keys and %nuke](/docs/arvo/jael/examples#public-keys-and-nuke) section of the Examples document for an example of using `%nuke` to cancel a `%public-keys` subscription. See the thread in the [%private-keys](/docs/arvo/jael/examples#private-keys) example for cancelling a `%private-keys` subscription.
120−
121−## `%private-keys`
122−
123−```hoon
124−[%private-keys ~]
125−```
126−
127−Subscribe to private key updates.
128−
129−Subscribe to be notified of private key updates for the local ship. The subscription will continue until Jael receives a [%nuke](#nuke) `task` to cancel it.
130−
131−#### Returns
132−
133−Jael responds to a `%private-keys` `task` with a `%private-keys` `gift` which looks like:
134−
135−```hoon
136−[%private-keys =life vein=(map life ring)]
137−```
138−
139−The `life` is the current life of the ship and the `vein` `map` contains the private key for each life up to (and including) the current one. Upon first subscribing, Jael will immediately respond with a `%private-keys` `gift`. Then, whenever the ship's private keys are changed, it'll send a new and updated `%private-keys` `gift`.
140−
141−#### Example
142−
143−See the [%private-keys](/docs/arvo/jael/examples#private-keys) section of the Examples document for a practical example.
144−
145−## `%public-keys`
146−
147−```hoon
148−[%public-keys ships=(set ship)]
149−```
150−
151−Subscribe to public key (and related) updates from Jael.
152−
153−An agent or thread can subscribe to be notified of public key updates, sponsorship changes and continuity breaches for the `set` of `ship`s specified in the `ships` field. The subscription will continue until Jael receives a [%nuke](#nuke) `task` to cancel it.
154−
155−#### Returns
156−
157−Jael responds to a `%public-keys` `task` with `%public-keys` `gift`s which look like:
158−
159−```hoon
160−[%public-keys =public-keys-result]
161−```
162−
163−The [$public-keys-result](/docs/arvo/jael/data-types#public-keys-result) contains whatever changes have occurred.
164−
165−Upon subscription, Jael will immeditely respond with a `%public-keys` `gift` containing a `%full` `public-keys-result` with the public key for each `life` up until the current one for each `ship` specified in the original `task`. After than, Jael will send a `%public-keys` `gift` with either a `%diff` or `%breach` `public-keys-result` each time a change occurs for any of the `ship`s to which you're subscribed.
166−
167−#### Example
168−
169−See the [%public-keys and %nuke](/docs/arvo/jael/examples#public-keys-and-nuke) section of the Examples document for a practical example.
170−
171−## `%rekey`
172−
173−```hoon
174−[%rekey =life =ring]
175−```
176−
177−Update private keys.
178−
179−This is what is sent to Jael by `%hood` when you run `|rekey`, as you must after setting new Azimuth keys or running `|cycle-moon-keys` on a moon's parent. It will update your `life` (key revision number) and private keys. The `life` field is the new `life` (typically an increment of the current `life`) and the `ring` is a private key `@`.
180−
181−#### Returns
182−
183−Jael does not return any `gift` in response to a `%rekey` `task`.
184−
185−## `%turf`
186−
187−```hoon
188−[%turf ~]
189−```
190−
191−View domains.
192−
193−The domains returned by a `%turf` `task` are used as the base for individual galaxy domain names (e.g. from `urbit.org` you get `zod.urbit.org`, `bus.urbit.org`, etc). Jael gets these from Azimuth, then Ames gets them from Jael and passes them to the runtime, which will perform the DNS lookups and give Ames back the galaxy IP addresses. A `%turf` task takes no additional arguments. You're unlikely to use this manually - if you want the current `turf`s you'd likely want to do a [turf scry](/docs/arvo/jael/scry#turf) instead.
194−
195−#### Returns
196−
197−Jael will respond to a `%turf` `task` with a `%turf` `gift`, which looks like:
198−
199−```hoon
200−[%turf turf=(list turf)]
201−```
202−
203−The `turf` in the `(list turf)` is a domain as a `(list @t)`, TLD-first. The current default is `[['org' 'urbit' ~] ~]`.
204−
205−#### Example
206−
207−See the [%turf section of the Examples document](/docs/arvo/jael/examples#turf) for a practical example.
208−
209−## `%step`
210−
211−```hoon
212−[%step ~]
213−```
214−
215−Reset web login code.
216−
217−Jael maintains a `step` value that represents the web login code revision number, and uses it to derive the code itself. It begins at `0` and is incremented each time the code is changed. When Jael updates the web login code, it sends Eyre a `%code-changed` `task:eyre` so that Eyre can throw away all of its current cookies and sessions. A `%step` task takes no additional argument.
218−
219−#### Returns
220−
221−Jael does not return a `gift` in response to a `%step` `task`.
222−
223−#### Example
224−
225−See the [%step](/docs/arvo/jael/examples#step) section of the Examples document for a practical example.
content/docs/arvo/overview.mddeleted−554

This diff is too big to show here.

content/docs/arvo/reference/_index.mddeleted−11

This diff is too big to show here.

content/docs/arvo/reference/cryptography.mddeleted−222

This diff is too big to show here.

content/docs/arvo/reference/filesystem.mddeleted−103

This diff is too big to show here.

content/docs/arvo/tutorials/_index.mddeleted−9

This diff is too big to show here.

content/docs/arvo/tutorials/move-trace.mddeleted−378

This diff is too big to show here.

content/docs/azimuth/_index.mddeleted−41

This diff is too big to show here.

content/docs/azimuth/advanced-azimuth-tools.mddeleted−124

This diff is too big to show here.

content/docs/azimuth/azimuth-eth.mddeleted−158

This diff is too big to show here.

content/docs/azimuth/azimuth.mddeleted−138

This diff is too big to show here.

content/docs/azimuth/ecliptic.mddeleted−446

This diff is too big to show here.

content/docs/azimuth/flow.mddeleted−232

This diff is too big to show here.

content/docs/azimuth/hd-wallet.mddeleted−137

This diff is too big to show here.

content/docs/azimuth/l2/_index.mddeleted−35

This diff is too big to show here.

content/docs/azimuth/l2/bytestring.mddeleted−201

This diff is too big to show here.

content/docs/azimuth/l2/l2-actions.mddeleted−183

This diff is too big to show here.

content/docs/azimuth/l2/layer2-api.mddeleted−14

This diff is too big to show here.

content/docs/azimuth/l2/layer2.mddeleted−403

This diff is too big to show here.

content/docs/azimuth/l2/roller.mddeleted−66

This diff is too big to show here.

content/docs/azimuth/life-and-rift.mddeleted−60

This diff is too big to show here.

content/docs/development/_index.mddeleted−33

This diff is too big to show here.

content/docs/development/develop.mddeleted−113

This diff is too big to show here.

content/docs/development/environment.mddeleted−327

This diff is too big to show here.

content/docs/development/grants.mddeleted−84

This diff is too big to show here.

content/docs/development/precepts.mddeleted−336

This diff is too big to show here.

content/docs/development/project-repositories.mddeleted−47

This diff is too big to show here.

content/docs/glossary/_index.mddeleted−10

This diff is too big to show here.

content/docs/glossary/ames.mddeleted−21

This diff is too big to show here.

content/docs/glossary/aqua.mddeleted−12

This diff is too big to show here.

content/docs/glossary/arm.mddeleted−14

This diff is too big to show here.

content/docs/glossary/arvo.mddeleted−44

This diff is too big to show here.

content/docs/glossary/atom.mddeleted−20

This diff is too big to show here.

content/docs/glossary/azimuth.mddeleted−39

This diff is too big to show here.

content/docs/glossary/battery.mddeleted−14

This diff is too big to show here.

content/docs/glossary/behn.mddeleted−14

This diff is too big to show here.

content/docs/glossary/bridge.mddeleted−32

This diff is too big to show here.

content/docs/glossary/censure.mddeleted−14

This diff is too big to show here.

content/docs/glossary/ceremony.mddeleted−8

This diff is too big to show here.

content/docs/glossary/chat.mddeleted−32

This diff is too big to show here.

content/docs/glossary/claims.mddeleted−21

This diff is too big to show here.

content/docs/glossary/clay.mddeleted−18

This diff is too big to show here.

content/docs/glossary/comet.mddeleted−32

This diff is too big to show here.

content/docs/glossary/core.mddeleted−14

This diff is too big to show here.

content/docs/glossary/delegated-sending.mddeleted−9

This diff is too big to show here.

content/docs/glossary/desk.mddeleted−15

This diff is too big to show here.

content/docs/glossary/dill.mddeleted−22

This diff is too big to show here.

content/docs/glossary/docvote.mddeleted−9

This diff is too big to show here.

content/docs/glossary/dojo.mddeleted−15

This diff is too big to show here.

content/docs/glossary/door.mddeleted−14

This diff is too big to show here.

content/docs/glossary/ecliptic.mddeleted−12

This diff is too big to show here.

content/docs/glossary/eventlog.mddeleted−23

This diff is too big to show here.

content/docs/glossary/eyre.mddeleted−17

This diff is too big to show here.

content/docs/glossary/ford.mddeleted−17

This diff is too big to show here.

content/docs/glossary/galaxy.mddeleted−15

This diff is too big to show here.

content/docs/glossary/gall.mddeleted−18

This diff is too big to show here.

content/docs/glossary/gate.mddeleted−14

This diff is too big to show here.

content/docs/glossary/hdwallet.mddeleted−18

This diff is too big to show here.

content/docs/glossary/hoon.mddeleted−15

This diff is too big to show here.

content/docs/glossary/invite-tree.mddeleted−9

This diff is too big to show here.

content/docs/glossary/iris.mddeleted−11

This diff is too big to show here.

content/docs/glossary/jael.mddeleted−11

This diff is too big to show here.

content/docs/glossary/jaque.mddeleted−15

This diff is too big to show here.

content/docs/glossary/keyfile.mddeleted−15

This diff is too big to show here.

content/docs/glossary/landscape.mddeleted−11

This diff is too big to show here.

content/docs/glossary/mark.mddeleted−17

This diff is too big to show here.

content/docs/glossary/moon.mddeleted−34

This diff is too big to show here.

content/docs/glossary/nock.mddeleted−17

This diff is too big to show here.

content/docs/glossary/noun.mddeleted−15

This diff is too big to show here.

content/docs/glossary/ota-updates.mddeleted−9

This diff is too big to show here.

content/docs/glossary/payload.mddeleted−14

This diff is too big to show here.

content/docs/glossary/ph.mddeleted−9

This diff is too big to show here.

content/docs/glossary/pier.mddeleted−28

This diff is too big to show here.

content/docs/glossary/pill.mddeleted−14

This diff is too big to show here.

content/docs/glossary/planet.mddeleted−15

This diff is too big to show here.

content/docs/glossary/proxies.mddeleted−34

This diff is too big to show here.

content/docs/glossary/replay.mddeleted−13

This diff is too big to show here.

content/docs/glossary/reset.mddeleted−32

This diff is too big to show here.

content/docs/glossary/rollups.mddeleted−30

This diff is too big to show here.

content/docs/glossary/sailudon.mddeleted−13

This diff is too big to show here.

content/docs/glossary/senate.mddeleted−14

This diff is too big to show here.

content/docs/glossary/ship.mddeleted−26

This diff is too big to show here.

content/docs/glossary/shiparvonetwork.mddeleted−9

This diff is too big to show here.

content/docs/glossary/star.mddeleted−17

This diff is too big to show here.

content/docs/glossary/sync.mddeleted−16

This diff is too big to show here.

content/docs/glossary/trap.mddeleted−14

This diff is too big to show here.

content/docs/glossary/upgrade.mddeleted−13

This diff is too big to show here.

content/docs/glossary/vane.mddeleted−24

This diff is too big to show here.

content/docs/glossary/vere.mddeleted−18

This diff is too big to show here.

content/docs/glossary/voting.mddeleted−27

This diff is too big to show here.

content/docs/glossary/wallet-generator.mddeleted−11

This diff is too big to show here.

content/docs/hoon/_index.mddeleted−27

This diff is too big to show here.

content/docs/hoon/guides/_index.mddeleted−17

This diff is too big to show here.

content/docs/hoon/guides/aqua.mddeleted−80

This diff is too big to show here.

content/docs/hoon/guides/cli-tutorial.mddeleted−440

This diff is too big to show here.

content/docs/hoon/guides/json-guide.mddeleted−513

This diff is too big to show here.

content/docs/hoon/guides/parsing.mddeleted−709

This diff is too big to show here.

content/docs/hoon/guides/strings.mddeleted−531

This diff is too big to show here.

content/docs/hoon/hoon-school/_index.mddeleted−37

This diff is too big to show here.

content/docs/hoon/hoon-school/ackermann.mddeleted−29

This diff is too big to show here.

content/docs/hoon/hoon-school/arms-and-cores.mddeleted−652

This diff is too big to show here.

content/docs/hoon/hoon-school/atoms-auras-and-simple-cell-types.mddeleted−779

This diff is too big to show here.

content/docs/hoon/hoon-school/bank-account.mddeleted−80

This diff is too big to show here.

content/docs/hoon/hoon-school/behn.mddeleted−110

This diff is too big to show here.

content/docs/hoon/hoon-school/caesar.mddeleted−394

This diff is too big to show here.

content/docs/hoon/hoon-school/conditionals.mddeleted−105

This diff is too big to show here.

content/docs/hoon/hoon-school/doors.mddeleted−516

This diff is too big to show here.

content/docs/hoon/hoon-school/egg-timer.mddeleted−164

This diff is too big to show here.

content/docs/hoon/hoon-school/fibonacci.mddeleted−61

This diff is too big to show here.

content/docs/hoon/hoon-school/gall.mddeleted−129

This diff is too big to show here.

content/docs/hoon/hoon-school/gates.mddeleted−272

This diff is too big to show here.

content/docs/hoon/hoon-school/generators.mddeleted−460

This diff is too big to show here.

content/docs/hoon/hoon-school/hoon-syntax.mddeleted−356

This diff is too big to show here.

content/docs/hoon/hoon-school/intro.mddeleted−121

This diff is too big to show here.

content/docs/hoon/hoon-school/iron-polymorphism.mddeleted−88

This diff is too big to show here.

content/docs/hoon/hoon-school/lead-polymorphism.mddeleted−155

This diff is too big to show here.

content/docs/hoon/hoon-school/libraries.mddeleted−191

This diff is too big to show here.

content/docs/hoon/hoon-school/list-of-numbers.mddeleted−132

This diff is too big to show here.

content/docs/hoon/hoon-school/lists.mddeleted−497

This diff is too big to show here.

content/docs/hoon/hoon-school/molds.mddeleted−98

This diff is too big to show here.

content/docs/hoon/hoon-school/nouns.mddeleted−563

This diff is too big to show here.

content/docs/hoon/hoon-school/recursion.mddeleted−194

This diff is too big to show here.

content/docs/hoon/hoon-school/structures-and-complex-types.mddeleted−356

This diff is too big to show here.

content/docs/hoon/hoon-school/the-subject-and-its-legs.mddeleted−726

This diff is too big to show here.

content/docs/hoon/hoon-school/trees-sets-and-maps.mddeleted−321

This diff is too big to show here.

content/docs/hoon/hoon-school/type-checking-and-type-inference.mddeleted−643

This diff is too big to show here.

content/docs/hoon/hoon-school/type-polymorphism.mddeleted−584

This diff is too big to show here.

content/docs/hoon/overview.mddeleted−276

This diff is too big to show here.

content/docs/hoon/reference/_index.mddeleted−53

This diff is too big to show here.

content/docs/hoon/reference/advanced.mddeleted−206

This diff is too big to show here.

content/docs/hoon/reference/auras.mddeleted−98

This diff is too big to show here.

content/docs/hoon/reference/basic.mddeleted−177

This diff is too big to show here.

content/docs/hoon/reference/cheat-sheet.mddeleted−18

This diff is too big to show here.

content/docs/hoon/reference/hoon-errors.mddeleted−187

This diff is too big to show here.

content/docs/hoon/reference/irregular.mddeleted−308

This diff is too big to show here.

content/docs/hoon/reference/limbs/_index.mddeleted−18

This diff is too big to show here.

content/docs/hoon/reference/limbs/limb.mddeleted−71

This diff is too big to show here.

content/docs/hoon/reference/limbs/wing.mddeleted−44

This diff is too big to show here.

content/docs/hoon/reference/rune/_index.mddeleted−73

This diff is too big to show here.

content/docs/hoon/reference/rune/bar.mddeleted−708

This diff is too big to show here.

content/docs/hoon/reference/rune/buc.mddeleted−606

This diff is too big to show here.

content/docs/hoon/reference/rune/cen.mddeleted−466

This diff is too big to show here.

content/docs/hoon/reference/rune/col.mddeleted−245

This diff is too big to show here.

content/docs/hoon/reference/rune/constants.mddeleted−193

This diff is too big to show here.

content/docs/hoon/reference/rune/dot.mddeleted−224

This diff is too big to show here.

content/docs/hoon/reference/rune/ket.mddeleted−396

This diff is too big to show here.

content/docs/hoon/reference/rune/lus.mddeleted−230

This diff is too big to show here.

content/docs/hoon/reference/rune/mic.mddeleted−462

This diff is too big to show here.

content/docs/hoon/reference/rune/sig.mddeleted−452

This diff is too big to show here.

content/docs/hoon/reference/rune/terminators.mddeleted−78

This diff is too big to show here.

content/docs/hoon/reference/rune/tis.mddeleted−496

This diff is too big to show here.

content/docs/hoon/reference/rune/wut.mddeleted−551

This diff is too big to show here.

content/docs/hoon/reference/rune/zap.mddeleted−240

This diff is too big to show here.

content/docs/hoon/reference/stdlib/1a.mddeleted−799

This diff is too big to show here.

content/docs/hoon/reference/stdlib/1b.mddeleted−309

This diff is too big to show here.

content/docs/hoon/reference/stdlib/1c.mddeleted−538

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2a.mddeleted−616

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2b.mddeleted−1645

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2c.mddeleted−1518

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2d.mddeleted−374

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2e.mddeleted−188

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2f.mddeleted−315

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2g.mddeleted−105

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2h.mddeleted−826

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2i.mddeleted−1417

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2j.mddeleted−397

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2k.mddeleted−456

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2l.mddeleted−110

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2m.mddeleted−316

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2n.mddeleted−450

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2o.mddeleted−200

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2p.mddeleted−248

This diff is too big to show here.

content/docs/hoon/reference/stdlib/2q.mddeleted−586

This diff is too big to show here.

content/docs/hoon/reference/stdlib/3a.mddeleted−881

This diff is too big to show here.

content/docs/hoon/reference/stdlib/3b.mddeleted−6054

This diff is too big to show here.

content/docs/hoon/reference/stdlib/3c.mddeleted−664

This diff is too big to show here.

content/docs/hoon/reference/stdlib/3d.mddeleted−820

This diff is too big to show here.

content/docs/hoon/reference/stdlib/3e.mddeleted−8

This diff is too big to show here.

content/docs/hoon/reference/stdlib/3f.mddeleted−868

This diff is too big to show here.

content/docs/hoon/reference/stdlib/3g.mddeleted−355

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4a.mddeleted−424

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4b.mddeleted−1320

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4c.mddeleted−396

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4d.mddeleted−100

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4e.mddeleted−466

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4f.mddeleted−1380

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4g.mddeleted−229

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4h.mddeleted−703

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4i.mddeleted−1086

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4j.mddeleted−1796

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4k.mddeleted−841

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4l.mddeleted−618

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4m.mddeleted−486

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4n.mddeleted−723

This diff is too big to show here.

content/docs/hoon/reference/stdlib/4o.mddeleted−1473

This diff is too big to show here.

content/docs/hoon/reference/stdlib/5a.mddeleted−7

This diff is too big to show here.

content/docs/hoon/reference/stdlib/5b.mddeleted−7

This diff is too big to show here.

content/docs/hoon/reference/stdlib/5c.mddeleted−83

This diff is too big to show here.

content/docs/hoon/reference/stdlib/5d.mddeleted−7

This diff is too big to show here.

content/docs/hoon/reference/stdlib/5e.mddeleted−7

This diff is too big to show here.

content/docs/hoon/reference/stdlib/5f.mddeleted−171

This diff is too big to show here.

content/docs/hoon/reference/stdlib/5g.mddeleted−7

This diff is too big to show here.

content/docs/hoon/reference/stdlib/_index.mddeleted−1733

This diff is too big to show here.

content/docs/hoon/reference/stdlib/table-of-contents.mddeleted−1934

This diff is too big to show here.

content/docs/hoon/reference/style.mddeleted−476

This diff is too big to show here.

content/docs/hoon/reference/zuse/2d_1-5.mddeleted−587

This diff is too big to show here.

content/docs/hoon/reference/zuse/2d_6.mddeleted−1551

This diff is too big to show here.

content/docs/hoon/reference/zuse/2d_7.mddeleted−1307

This diff is too big to show here.

content/docs/hoon/reference/zuse/2e_2-3.mddeleted−67

This diff is too big to show here.

content/docs/hoon/reference/zuse/_index.mddeleted−31

This diff is too big to show here.

content/docs/hoon/reference/zuse/table-of-contents.mddeleted−247

This diff is too big to show here.

content/docs/nock/_index.mddeleted−27

This diff is too big to show here.

content/docs/nock/definition.mddeleted−186

This diff is too big to show here.

content/docs/nock/example.mddeleted−362

This diff is too big to show here.

content/docs/nock/explanation.mddeleted−605

This diff is too big to show here.

content/docs/nock/implementations.mddeleted−2879

This diff is too big to show here.

content/docs/system-overview/_index.mddeleted−77

This diff is too big to show here.

content/docs/system-overview/arvo.mddeleted−32

This diff is too big to show here.

content/docs/system-overview/azimuth.mddeleted−34

This diff is too big to show here.

content/docs/system-overview/cryptography.mddeleted−124

This diff is too big to show here.

content/docs/system-overview/hoon.mddeleted−28

This diff is too big to show here.

content/docs/system-overview/nock.mddeleted−34

This diff is too big to show here.

content/docs/system-overview/vere.mddeleted−45

This diff is too big to show here.

content/docs/userspace/_index.mddeleted−29

This diff is too big to show here.

content/docs/userspace/dist/_index.mddeleted−29

This diff is too big to show here.

content/docs/userspace/dist/dist.mddeleted−105

This diff is too big to show here.

content/docs/userspace/dist/docket.mddeleted−296

This diff is too big to show here.

content/docs/userspace/dist/glob.mddeleted−102

This diff is too big to show here.

content/docs/userspace/dist/guide.mddeleted−269

This diff is too big to show here.

content/docs/userspace/dist/tools.mddeleted−342

This diff is too big to show here.

content/docs/userspace/gall-guide/1-arvo.mddeleted−305

This diff is too big to show here.

content/docs/userspace/gall-guide/10-scry.mddeleted−362

This diff is too big to show here.

content/docs/userspace/gall-guide/11-fail.mddeleted−146

This diff is too big to show here.

content/docs/userspace/gall-guide/12-next-steps.mddeleted−42

This diff is too big to show here.

content/docs/userspace/gall-guide/2-agent.mddeleted−305

This diff is too big to show here.

content/docs/userspace/gall-guide/3-imports-and-aliases.mddeleted−285

This diff is too big to show here.

content/docs/userspace/gall-guide/4-lifecycle.mddeleted−499

This diff is too big to show here.

content/docs/userspace/gall-guide/5-cards.mddeleted−244

This diff is too big to show here.

content/docs/userspace/gall-guide/6-pokes.mddeleted−538

This diff is too big to show here.

content/docs/userspace/gall-guide/7-sur-and-marks.mddeleted−408

This diff is too big to show here.

content/docs/userspace/gall-guide/8-subscriptions.mddeleted−911

This diff is too big to show here.

content/docs/userspace/gall-guide/9-vanes.mddeleted−284

This diff is too big to show here.

content/docs/userspace/gall-guide/_index.mddeleted−45

This diff is too big to show here.

content/docs/userspace/gall-guide/intro.mddeleted−83

This diff is too big to show here.

content/docs/userspace/gall-guide/types.mddeleted−228

This diff is too big to show here.

content/docs/userspace/graph-store/_index.mddeleted−23

This diff is too big to show here.

content/docs/userspace/graph-store/advanced-info.mddeleted−64

This diff is too big to show here.

content/docs/userspace/graph-store/data-structure-overview.mddeleted−359

This diff is too big to show here.

content/docs/userspace/graph-store/graph-store-reference.mddeleted−243

This diff is too big to show here.

content/docs/userspace/graph-store/overview.mddeleted−103

This diff is too big to show here.

content/docs/userspace/graph-store/sample-application-overview.mddeleted−369

This diff is too big to show here.

content/docs/userspace/graph-store/validator-walkthrough.mddeleted−476

This diff is too big to show here.

content/docs/userspace/overview.mddeleted−24

This diff is too big to show here.

content/docs/userspace/threads/_index.mddeleted−27

This diff is too big to show here.

content/docs/userspace/threads/basics/_index.mddeleted−29

This diff is too big to show here.

content/docs/userspace/threads/basics/bind.mddeleted−97

This diff is too big to show here.

content/docs/userspace/threads/basics/fundamentals.mddeleted−168

This diff is too big to show here.

content/docs/userspace/threads/basics/input.mddeleted−145

This diff is too big to show here.

content/docs/userspace/threads/basics/output.mddeleted−119

This diff is too big to show here.

content/docs/userspace/threads/basics/summary.mddeleted−81

This diff is too big to show here.

content/docs/userspace/threads/examples/_index.mddeleted−33

This diff is too big to show here.

content/docs/userspace/threads/examples/child-thread.mddeleted−238

This diff is too big to show here.

content/docs/userspace/threads/examples/get-json.mddeleted−114

This diff is too big to show here.

content/docs/userspace/threads/examples/main-loop.mddeleted−178

This diff is too big to show here.

content/docs/userspace/threads/examples/poke-agent.mddeleted−60

This diff is too big to show here.

content/docs/userspace/threads/examples/scry.mddeleted−70

This diff is too big to show here.

content/docs/userspace/threads/examples/take-fact.mddeleted−65

This diff is too big to show here.

content/docs/userspace/threads/gall/_index.mddeleted−29

This diff is too big to show here.

content/docs/userspace/threads/gall/poke-thread.mddeleted−115

This diff is too big to show here.

content/docs/userspace/threads/gall/start-thread.mddeleted−145

This diff is too big to show here.

content/docs/userspace/threads/gall/stop-thread.mddeleted−152

This diff is too big to show here.

content/docs/userspace/threads/gall/take-facts.mddeleted−184

This diff is too big to show here.

content/docs/userspace/threads/gall/take-result.mddeleted−132

This diff is too big to show here.

content/docs/userspace/threads/http-api.mddeleted−73

This diff is too big to show here.

content/docs/userspace/threads/overview.mddeleted−82

This diff is too big to show here.

content/docs/userspace/threads/reference.mddeleted−87

This diff is too big to show here.

content/docs/vere/_index.mddeleted−42

This diff is too big to show here.

content/docs/vere/api.mddeleted−1040

This diff is too big to show here.

content/docs/vere/c.mddeleted−114

This diff is too big to show here.

content/docs/vere/cryptography.mddeleted−43

This diff is too big to show here.

content/docs/vere/jetting.mddeleted−779

This diff is too big to show here.

content/docs/vere/nouns.mddeleted−477

This diff is too big to show here.

content/docs/vere/runtime.mddeleted−44

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.md+2−2

This diff is too big to show here.

content/events/2017-09-22-after-hours-fun-with-arvo-the-urbit-os.md+2−2

This diff is too big to show here.

content/events/2017-10-26-after-hours-designing-robust-human-systems.md+2−2

This diff is too big to show here.

content/events/2017-11-16-after-hours-visiting-contributors.md+2−2

This diff is too big to show here.

content/events/2018-01-26-urbit-irl-20181.md+2−2

This diff is too big to show here.

content/events/2018-02-23-urbit-irl-20182.md+2−2

This diff is too big to show here.

content/events/2018-03-11-20183-hoon-school.md+2−2

This diff is too big to show here.

content/events/2018-03-23-urbit-irl-20183.md+2−2

This diff is too big to show here.

content/events/2018-05-25-urbit-irl-20185.md+2−2

This diff is too big to show here.

content/events/2018-08-03-after-hours-decentralized-web-summit.md+2−2

This diff is too big to show here.

content/events/2018-08-17-urbit-irl-20188.md+2−2

This diff is too big to show here.

content/events/2018-09-21-urbit-irl-20189.md+2−2

This diff is too big to show here.

content/events/2018-10-10-urbit-zcash-blockchain-week.md+2−2

This diff is too big to show here.

content/events/2018-12-20-after-hours-its-just-a-party-man.md+2−2

This diff is too big to show here.

content/events/2019-03-01-after-hours-ask-galen-anything.md+2−2

This diff is too big to show here.

content/events/2019-03-08-urbit-irl-austin-tx.md+2−2

This diff is too big to show here.

content/events/2019-04-19-urbit-irl-20194.md+2−2

This diff is too big to show here.

content/events/2019-05-17-urbit-irl-20195.md+2−2

This diff is too big to show here.

content/events/2019-06-21-urbit-irl-20196.md+2−2

This diff is too big to show here.

content/events/2019-07-19-urbit-irl-20197.md+4−2

This diff is too big to show here.

content/events/2019-08-29-urbit-austin-20198.md+4−2

This diff is too big to show here.

content/events/2019-10-04-urbit-irl-201910.md+4−2

This diff is too big to show here.

content/events/2019-11-15-urbit-irl-201911.md+4−2

This diff is too big to show here.

content/events/2019-12-13-urbit-irl-201912.md+4−2

This diff is too big to show here.

content/events/2020-01-24-urbit-irl-20201.md+4−2

This diff is too big to show here.

content/events/2020-02-28-urbit-irl-20202.md+4−2

This diff is too big to show here.

content/events/2020-04-03-urbit-os1-launch-party.md+8−6

This diff is too big to show here.

content/events/2020-10-09-urbit-hosting-launch-event.md+13−8

This diff is too big to show here.

content/events/2020-12-10-developer-call-injecting-external-services-into-urbit.md+1−2

This diff is too big to show here.

content/events/2021-03-18-developer-call-pressure-and-protolith.md+1−1

This diff is too big to show here.

content/events/2021-04-01-developer-call-javascript-apps-on-urbit.md+1−1

This diff is too big to show here.

content/events/2021-04-27-bitcoin-launch.md+3−1

This diff is too big to show here.

content/events/2021-05-13-developer-call-versioned-networking.md+1−1

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.md+45−47

This diff is too big to show here.

content/getting-started/_index.md+20−124

This diff is too big to show here.

content/getting-started/cli.md+220−126

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/planet.mddeleted−216

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/grants/bitcoin-node-json-rpc-api-part-1.md → content/grants/2019/bitcoin-node-json-rpc-api-part-1.mdrenamed+4−3

This diff is too big to show here.

content/grants/bitcoin-node-json-rpc-api-part-2.md → content/grants/2019/bitcoin-node-json-rpc-api-part-2.mdrenamed+4−3

This diff is too big to show here.

content/grants/bitcoin-node-json-rpc-api-part-3.md → content/grants/2019/bitcoin-node-json-rpc-api-part-3.mdrenamed+4−3

This diff is too big to show here.

content/grants/bitcoin-node-json-rpc-api-part-4.md → content/grants/2019/bitcoin-node-json-rpc-api-part-4.mdrenamed+4−3

This diff is too big to show here.

content/grants/bitcoin-wallet-on-bridge.md → content/grants/2019/bitcoin-wallet-on-bridge.mdrenamed+4−3

This diff is too big to show here.

content/grants/escape.md → content/grants/2019/escape.mdrenamed+2−2

This diff is too big to show here.

content/grants/gall-api-documentation.md → content/grants/2019/gall-api-documentation.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-1.md → content/grants/2019/host-two-urbit-meetups-1.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-10.md → content/grants/2019/host-two-urbit-meetups-10.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-2.md → content/grants/2019/host-two-urbit-meetups-2.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-3.md → content/grants/2019/host-two-urbit-meetups-3.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-4.md → content/grants/2019/host-two-urbit-meetups-4.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-5.md → content/grants/2019/host-two-urbit-meetups-5.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-6.md → content/grants/2019/host-two-urbit-meetups-6.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-7.md → content/grants/2019/host-two-urbit-meetups-7.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-8.md → content/grants/2019/host-two-urbit-meetups-8.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-9.md → content/grants/2019/host-two-urbit-meetups-9.mdrenamed+2−2

This diff is too big to show here.

content/grants/ragnarok-online-on-urbit.md → content/grants/2019/ragnarok-online-on-urbit.mdrenamed+2−2

This diff is too big to show here.

content/grants/udon-syntax-highlighter.md → content/grants/2019/udon-syntax-highlighter.mdrenamed+2−2

This diff is too big to show here.

content/grants/unit-tests-for-json-parsing.md → content/grants/2019/unit-tests-for-json-parsing.mdrenamed+2−2

This diff is too big to show here.

content/grants/unit-tests-for-pure-algorithms.md → content/grants/2019/unit-tests-for-pure-algorithms.mdrenamed+2−2

This diff is too big to show here.

content/grants/unit-tests-for-sha-functions.md → content/grants/2019/unit-tests-for-sha-functions.mdrenamed+2−2

This diff is too big to show here.

content/grants/unit-tests-for-zuse-cryptographic-functions.md → content/grants/2019/unit-tests-for-zuse-cryptographic-functions.mdrenamed+2−2

This diff is too big to show here.

content/grants/a-book-about-urbit.md → content/grants/2020/a-book-about-urbit.mdrenamed+2−2

This diff is too big to show here.

content/grants/a-network-enabled-spatial-database-and-demonstration-app.md → content/grants/2020/a-network-enabled-spatial-database-and-demonstration-app.mdrenamed+13−16

This diff is too big to show here.

content/grants/antechamber.md → content/grants/2020/antechamber.mdrenamed+2−2

This diff is too big to show here.

content/grants/art-by-urbit.md → content/grants/2020/art-by-urbit.mdrenamed+2−2

This diff is too big to show here.

content/grants/bart-train-tracker-landscape-tile.md → content/grants/2020/bart-train-tracker-landscape-tile.mdrenamed+2−2

This diff is too big to show here.

content/grants/bitcoin-full-node-provider-and-wallet.md → content/grants/2020/bitcoin-full-node-provider-and-wallet.mdrenamed+4−3

This diff is too big to show here.

content/grants/bitcoin-key-derivation.md → content/grants/2020/bitcoin-key-derivation.mdrenamed+4−3

This diff is too big to show here.

content/grants/boston-t-train-tracker-landscape-tile.md → content/grants/2020/boston-t-train-tracker-landscape-tile.mdrenamed+2−2

This diff is too big to show here.

content/grants/calendar-ui.md → content/grants/2020/calendar-ui.mdrenamed+2−2

This diff is too big to show here.

content/grants/calendar.md → content/grants/2020/calendar.mdrenamed+2−2

This diff is too big to show here.

content/grants/content-saver.md → content/grants/2020/content-saver.mdrenamed+3−3

This diff is too big to show here.

content/grants/cta-train-tracker-landscape-tile.md → content/grants/2020/cta-train-tracker-landscape-tile.mdrenamed+2−2

This diff is too big to show here.

content/grants/display-eth-data.md → content/grants/2020/display-eth-data.mdrenamed+2−2

This diff is too big to show here.

content/grants/docker-image-for-cloud-container-orchestration.md → content/grants/2020/docker-image-for-cloud-container-orchestration.mdrenamed+2−2

This diff is too big to show here.

content/grants/ethereum-abi-parser.md → content/grants/2020/ethereum-abi-parser.mdrenamed+2−2

This diff is too big to show here.

content/grants/go-airlock-library.md → content/grants/2020/go-airlock-library.mdrenamed+2−2

This diff is too big to show here.

content/grants/haskell-airlock-library.md → content/grants/2020/haskell-airlock-library.mdrenamed+2−2

This diff is too big to show here.

content/grants/hoon-001-learner-efficiency-and-early-learner-resources.md → content/grants/2020/hoon-001-learner-efficiency-and-early-learner-resources.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-three-college-university-urbit-meetups-1.md → content/grants/2020/host-three-college-university-urbit-meetups-1.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-three-college-university-urbit-meetups-2.md → content/grants/2020/host-three-college-university-urbit-meetups-2.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-three-college-university-urbit-meetups-3.md → content/grants/2020/host-three-college-university-urbit-meetups-3.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-three-virtual-urbit-meetups.md → content/grants/2020/host-three-virtual-urbit-meetups.mdrenamed+2−2

This diff is too big to show here.

content/grants/links-in-urbit-reference-docs.md → content/grants/2020/links-in-urbit-reference-docs.mdrenamed+2−2

This diff is too big to show here.

content/grants/llelogram.md → content/grants/2020/llelogram.mdrenamed+2−2

This diff is too big to show here.

content/grants/matrices-in-hoon.md → content/grants/2020/matrices-in-hoon.mdrenamed+2−2

This diff is too big to show here.

content/grants/matrixriotim-bridge-bot.md → content/grants/2020/matrixriotim-bridge-bot.mdrenamed+2−2

This diff is too big to show here.

content/grants/open-street-maps-data-importation.md → content/grants/2020/open-street-maps-data-importation.mdrenamed+2−2

This diff is too big to show here.

content/grants/staff-the-urbit-help-desk-1.md → content/grants/2020/staff-the-urbit-help-desk-1.mdrenamed+2−2

This diff is too big to show here.

content/grants/staff-the-urbit-help-desk-2.md → content/grants/2020/staff-the-urbit-help-desk-2.mdrenamed+2−2

This diff is too big to show here.

content/grants/staff-the-urbit-helpdesk-west.md → content/grants/2020/staff-the-urbit-helpdesk-west.mdrenamed+2−2

This diff is too big to show here.

content/grants/the-complete-guide-to-gall-and-landscape.md → content/grants/2020/the-complete-guide-to-gall-and-landscape.mdrenamed+2−2

This diff is too big to show here.

content/grants/tor-nodes-relay-search-tile.md → content/grants/2020/tor-nodes-relay-search-tile.mdrenamed+2−2

This diff is too big to show here.

content/grants/typescript-airlock-library.md → content/grants/2020/typescript-airlock-library.mdrenamed+2−2

This diff is too big to show here.

content/grants/up-to-date-hoon-reference-card.md → content/grants/2020/up-to-date-hoon-reference-card.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbian-a-customized-linux-distribution-for-urbit-appliances.md → content/grants/2020/urbian-a-customized-linux-distribution-for-urbit-appliances.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-event-series.md → content/grants/2020/urbit-event-series.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-explainer-video.md → content/grants/2020/urbit-explainer-video.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-http-api-for-kotlin.md → content/grants/2020/urbit-http-api-for-kotlin.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-http-api-for-rust.md → content/grants/2020/urbit-http-api-for-rust.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-http-interface-java-edition.md → content/grants/2020/urbit-http-interface-java-edition.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-http-library-for-ruby.md → content/grants/2020/urbit-http-library-for-ruby.mdrenamed+3−3

This diff is too big to show here.

content/grants/urbit-online-meetup.md → content/grants/2020/urbit-online-meetup.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-ship-and-star-hosting-and-troubleshooting-docs.md → content/grants/2020/urbit-ship-and-star-hosting-and-troubleshooting-docs.mdrenamed+2−2

This diff is too big to show here.

content/grants/verifying-urbit-id-on-keybase.md → content/grants/2020/verifying-urbit-id-on-keybase.mdrenamed+2−2

This diff is too big to show here.

content/grants/web-scraper.md → content/grants/2020/web-scraper.mdrenamed+2−2

This diff is too big to show here.

content/grants/analytics-script.md → content/grants/2021/analytics-script.mdrenamed+2−2

This diff is too big to show here.

content/grants/authenticate-with-urbit.md → content/grants/2021/authenticate-with-urbit.mdrenamed+4−4

This diff is too big to show here.

content/grants/azimuth-cli.md → content/grants/2021/azimuth-cli.mdrenamed+4−4

This diff is too big to show here.

content/grants/bitcoin-wallet-maintenance.md → content/grants/2021/bitcoin-wallet-maintenance.mdrenamed+5−3

This diff is too big to show here.

content/grants/bridge-l2-revamp.md → content/grants/2021/bridge-l2-revamp.mdrenamed+2−2

This diff is too big to show here.

content/grants/clojure-urbit-client.md → content/grants/2021/clojure-urbit-client.mdrenamed+5−3

This diff is too big to show here.

content/grants/comprehensive-local-server-and-mum-explanation-video.md → content/grants/2021/comprehensive-local-server-and-mum-explanation-video.mdrenamed+2−2

This diff is too big to show here.

content/grants/contacts.md → content/grants/2021/contacts.mdrenamed+3−3

This diff is too big to show here.

content/grants/content-producer.md → content/grants/2021/content-producer.mdrenamed+3−3

This diff is too big to show here.

content/grants/cross-platform-desktop-urbit-app.md → content/grants/2021/cross-platform-desktop-urbit-app.mdrenamed+2−2

This diff is too big to show here.

content/grants/cypherscope-bot.md → content/grants/2021/cypherscope-bot.mdrenamed+4−4

This diff is too big to show here.

content/grants/educational-guide-todomvc-urbit-edition.md → content/grants/2021/educational-guide-todomvc-urbit-edition.mdrenamed+2−2

This diff is too big to show here.

content/grants/feed-aggregator.md → content/grants/2021/feed-aggregator.mdrenamed+4−4

This diff is too big to show here.

content/grants/graph-store-documentation-guide.md → content/grants/2021/graph-store-documentation-guide.mdrenamed+2−2

This diff is too big to show here.

content/grants/guide-to-s3.md → content/grants/2021/guide-to-s3.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-11.md → content/grants/2021/host-two-urbit-meetups-11.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-12.md → content/grants/2021/host-two-urbit-meetups-12.mdrenamed+3−3

This diff is too big to show here.

content/grants/host-two-urbit-meetups-13.md → content/grants/2021/host-two-urbit-meetups-13.mdrenamed+3−3

This diff is too big to show here.

content/grants/host-two-urbit-meetups-14.md → content/grants/2021/host-two-urbit-meetups-14.mdrenamed+3−3

This diff is too big to show here.

content/grants/host-two-urbit-meetups-15.md → content/grants/2021/host-two-urbit-meetups-15.mdrenamed+2−2

This diff is too big to show here.

content/grants/host-two-urbit-meetups-16.md → content/grants/2021/host-two-urbit-meetups-16.mdrenamed+2−2

This diff is too big to show here.

content/grants/json-jet.md → content/grants/2021/json-jet.mdrenamed+4−4

This diff is too big to show here.

content/grants/login-with-urbit.md → content/grants/2021/login-with-urbit.mdrenamed+2−3

This diff is too big to show here.

content/grants/machine-learning.md → content/grants/2021/machine-learning.mdrenamed+4−4

This diff is too big to show here.

content/grants/market-interface.md → content/grants/2021/market-interface.mdrenamed+3−2

This diff is too big to show here.

content/grants/meetup-bom.md → content/grants/2021/meetup-bom.mdrenamed+4−4

This diff is too big to show here.

content/grants/minimal-urbit-os.md → content/grants/2021/minimal-urbit-os.mdrenamed+2−2

This diff is too big to show here.

content/grants/native-urbit.md → content/grants/2021/native-urbit.mdrenamed+3−3

This diff is too big to show here.

content/grants/network-explorer-data-pipeline-http-api.md → content/grants/2021/network-explorer-data-pipeline-http-api.mdrenamed+2−2

This diff is too big to show here.

content/grants/nuck-jet.md → content/grants/2021/nuck-jet.mdrenamed+3−3

This diff is too big to show here.

content/grants/overhaul-the-urbitorg-website.md → content/grants/2021/overhaul-the-urbitorg-website.mdrenamed+2−2

This diff is too big to show here.

content/grants/planet-sales.md → content/grants/2021/planet-sales.mdrenamed+4−4

This diff is too big to show here.

content/grants/pokur.md → content/grants/2021/pokur.mdrenamed+3−3

This diff is too big to show here.

content/grants/ra-debugging-tools.md → content/grants/2021/ra-debugging-tools.mdrenamed+5−5

This diff is too big to show here.

content/grants/ra-page-tracking.md → content/grants/2021/ra-page-tracking.mdrenamed+3−3

This diff is too big to show here.

content/grants/ra-segfaults.md → content/grants/2021/ra-segfaults.mdrenamed+3−3

This diff is too big to show here.

content/grants/ra-stack-overflow.md → content/grants/2021/ra-stack-overflow.mdrenamed+3−3

This diff is too big to show here.

content/grants/search-in-groups.md → content/grants/2021/search-in-groups.mdrenamed+2−2

This diff is too big to show here.

content/grants/send-emails-to-a-mailing-list.md → content/grants/2021/send-emails-to-a-mailing-list.mdrenamed+3−3

This diff is too big to show here.

content/grants/smol-future-sustained-knowledge-sharing-and-marketing.md → content/grants/2021/smol-future-sustained-knowledge-sharing-and-marketing.mdrenamed+2−2

This diff is too big to show here.

content/grants/speech-recognition.md → content/grants/2021/speech-recognition.mdrenamed+3−3

This diff is too big to show here.

content/grants/staff-the-urbit-helpdesk-east.md → content/grants/2021/staff-the-urbit-helpdesk-east.mdrenamed+2−2

This diff is too big to show here.

content/grants/static-site-generation.md → content/grants/2021/static-site-generation.mdrenamed+3−3

This diff is too big to show here.

content/grants/thread-documentation.md → content/grants/2021/thread-documentation.mdrenamed+2−2

This diff is too big to show here.

content/grants/translate-key-parts-of-urbitorg-into-german.md → content/grants/2021/translate-key-parts-of-urbitorg-into-german.mdrenamed+2−2

This diff is too big to show here.

content/grants/translate-key-parts-of-urbitorg-into-korean.md → content/grants/2021/translate-key-parts-of-urbitorg-into-korean.mdrenamed+3−3

This diff is too big to show here.

content/grants/translate-key-parts-of-urbitorg-into-norwegian.md → content/grants/2021/translate-key-parts-of-urbitorg-into-norwegian.mdrenamed+2−2

This diff is too big to show here.

content/grants/translate-key-parts-of-urbitorg-into-spanish.md → content/grants/2021/translate-key-parts-of-urbitorg-into-spanish.mdrenamed+2−2

This diff is too big to show here.

content/grants/try-urbit-website.md → content/grants/2021/try-urbit-website.mdrenamed+2−2

This diff is too big to show here.

content/grants/twitter-uv-extension.md → content/grants/2021/twitter-uv-extension.mdrenamed+3−3

This diff is too big to show here.

content/grants/ua-collaborative-text-editor.md → content/grants/2021/ua-collaborative-text-editor.mdrenamed+3−3

This diff is too big to show here.

content/grants/ua-filesharer.md → content/grants/2021/ua-filesharer.mdrenamed+3−3

This diff is too big to show here.

content/grants/ua-heads-up-poker.md → content/grants/2021/ua-heads-up-poker.mdrenamed+3−3

This diff is too big to show here.

content/grants/ua-invoice-system.md → content/grants/2021/ua-invoice-system.mdrenamed+3−3

This diff is too big to show here.

content/grants/ua-marketplace.md → content/grants/2021/ua-marketplace.mdrenamed+6−4

This diff is too big to show here.

content/grants/ucal-google-and-outlook-integration.md → content/grants/2021/ucal-google-and-outlook-integration.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-api-for-elixir.md → content/grants/2021/urbit-api-for-elixir.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-community-concierge-east-coast-2q2021.md → content/grants/2021/urbit-community-concierge-east-coast-2q2021.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-community-concierge-east-coast.md → content/grants/2021/urbit-community-concierge-east-coast.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-community-concierge-west-coast-2q2021.md → content/grants/2021/urbit-community-concierge-west-coast-2q2021.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-community-concierge-west-coast.md → content/grants/2021/urbit-community-concierge-west-coast.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-http-api-for-emacs-elisp.md → content/grants/2021/urbit-http-api-for-emacs-elisp.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-http-api-for-python.md → content/grants/2021/urbit-http-api-for-python.mdrenamed+3−3

This diff is too big to show here.

content/grants/urbit-irc-bridge.md → content/grants/2021/urbit-irc-bridge.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-lfs-filehosting.md → content/grants/2021/urbit-lfs-filehosting.mdrenamed+2−2

This diff is too big to show here.

content/grants/urbit-notes.md → content/grants/2021/urbit-notes.mdrenamed+4−4

This diff is too big to show here.

content/grants/urbit-react-cookbook.md → content/grants/2021/urbit-react-cookbook.mdrenamed+2−2

This diff is too big to show here.

content/grants/uturn.md → content/grants/2021/uturn.mdrenamed+9−8

This diff is too big to show here.

content/grants/uv-extension-library.md → content/grants/2021/uv-extension-library.mdrenamed+4−4

This diff is too big to show here.

content/grants/video-content-manager.md → content/grants/2021/video-content-manager.mdrenamed+2−2

This diff is too big to show here.

content/grants/volt-lightning-on-urbit.md → content/grants/2021/volt-lightning-on-urbit.mdrenamed+4−3

This diff is too big to show here.

content/grants/webrtc-gall-agent-and-external-app.md → content/grants/2021/webrtc-gall-agent-and-external-app.mdrenamed+2−2

This diff is too big to show here.

content/grants/~home-urbit.md → content/grants/2021/~home-urbit.mdrenamed+3−2

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/app-openbsd.md → content/grants/2022/app-openbsd.mdrenamed+9−4

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/slaw-scot-jets.md → content/grants/2022/slaw-scot-jets.mdrenamed+6−5

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/media/blockchannel-episode-19-virtual-land-in-the-clouds-with-urbit.mddeleted−14

This diff is too big to show here.

content/media/blueprint-2017-galen-wolfe-pauly-on-the-distributed-web.mddeleted−15

This diff is too big to show here.

content/media/epicenter-episode-205-urbit-a-digital-republic-reinventing-the-internet.mddeleted−15

This diff is too big to show here.

content/media/governing-the-future-e09-urbit-a-user-owned-internet-on-top-of-the-internet.mddeleted−16

This diff is too big to show here.

content/media/lambdaconf-2016-curtis-yarvin-urbit-a-clean-slate-functional-operating-stack.mddeleted−15

This diff is too big to show here.

content/media/lambdaconf-2018-ted-blackman-ford-urbits-build-system.mddeleted−15

This diff is too big to show here.

content/media/on-the-brink-castle-island.mddeleted−14

This diff is too big to show here.

content/media/the-ether-review-46-curtis-yarvin-and-galen-wolfe-pauly-on-urbit.mddeleted−15

This diff is too big to show here.

content/media/urbit-and-the-not-so-dark-future-of-the-internet.mddeleted−11

This diff is too big to show here.

content/media/what-is-urbit.mddeleted−10

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/understanding-urbit/_index.md → content/overview/_index.mdrenamed+20−24

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/understanding-urbit/urbit-id.md → content/overview/urbit-id.mdrenamed+13−18

This diff is too big to show here.

content/understanding-urbit/urbit-os.md → content/overview/urbit-os.mdrenamed+7−20

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.md+5−4

This diff is too big to show here.

content/proposals.md+25−45

This diff is too big to show here.

content/reset.mddeleted−109

This diff is too big to show here.

content/rfps.mdnew file+40

This diff is too big to show here.

content/terms-of-use.md → content/terms-of-service.mdrenamed+1−1

This diff is too big to show here.

content/understanding-urbit/interface.mddeleted−68

This diff is too big to show here.

content/understanding-urbit/people-history.mddeleted−101

This diff is too big to show here.

content/understanding-urbit/roadmap.mddeleted−97

This diff is too big to show here.

content/updates/2018-7-30-update.md+1−1

This diff is too big to show here.

content/updates/2019-2-11-update.md+1−1

This diff is too big to show here.

content/updates/2020-07-27-update.md−2

This diff is too big to show here.

content/using/_index.mddeleted−33

This diff is too big to show here.

content/using/id/_index.mddeleted−59

This diff is too big to show here.

content/using/id/bridge-troubleshooting.mddeleted−37

This diff is too big to show here.

content/using/id/creating-an-invite-pool.mddeleted−106

This diff is too big to show here.

content/using/id/guide-to-resets.mddeleted−93

This diff is too big to show here.

content/using/id/hd-wallet.mddeleted−164

This diff is too big to show here.

content/using/id/l2-star.mddeleted−41

This diff is too big to show here.

content/using/id/overview.mddeleted−203

This diff is too big to show here.

content/using/id/proxies.mddeleted−55

This diff is too big to show here.

content/using/id/using-bridge.mddeleted−111

This diff is too big to show here.

content/using/os/_index.mddeleted−36

This diff is too big to show here.

content/using/os/basics.mddeleted−236

This diff is too big to show here.

content/using/os/dist-faq.mddeleted−162

This diff is too big to show here.

content/using/os/filesystem.mddeleted−379

This diff is too big to show here.

content/using/os/messaging.mddeleted−254

This diff is too big to show here.

content/using/os/s3.mddeleted−38

This diff is too big to show here.

content/using/os/shell.mddeleted−343

This diff is too big to show here.

content/using/os/ship-troubleshooting.mddeleted−225

This diff is too big to show here.

content/using/os/stars-and-galaxies.mddeleted−38

This diff is too big to show here.

content/using/running/_index.mddeleted−24

This diff is too big to show here.

content/using/running/hosting.mddeleted−202

This diff is too big to show here.

content/using/running/minio.mddeleted−141

This diff is too big to show here.

content/using/running/port.mddeleted−157

This diff is too big to show here.

content/voting-instructions.md+1−1

This diff is too big to show here.

gnosis-safe.mdnew file+48

This diff is too big to show here.

images/favicon.icodeleted

Binary file not shown.

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.js+25−8

This diff is too big to show here.

lib/constants.js+65

This diff is too big to show here.

lib/glossary.jsdeleted−7720

This diff is too big to show here.

lib/hooks.js+12

This diff is too big to show here.

lib/lib.js+153−261

This diff is too big to show here.

lib/rss.js+1−1

This diff is too big to show here.

next.config.js+11−48

This diff is too big to show here.

package-lock.json+4242−4878

This diff is too big to show here.

package.json+35−31

This diff is too big to show here.

pages/404.js+7−3

This diff is too big to show here.

pages/[slug].jsnew file+48

This diff is too big to show here.

pages/_app.js+11−8

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.js+39−4

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/audits.jsdeleted−17

This diff is too big to show here.

pages/bitcoin-wallet.jsdeleted−21

This diff is too big to show here.

pages/bitcoin.jsnew file+98

This diff is too big to show here.

pages/blog.js+82−44

This diff is too big to show here.

pages/blog/[slug].js+25−32

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/community/[[...slug]].jsdeleted−130

This diff is too big to show here.

pages/decentralized-discord.jsnew file+291

This diff is too big to show here.

pages/docs/[[...slug]].jsdeleted−234

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.js+113−53

This diff is too big to show here.

pages/events/[slug].js+15−26

This diff is too big to show here.

pages/faq.jsdeleted−17

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]].js+240−79

This diff is too big to show here.

pages/grants.js+254−345

This diff is too big to show here.

pages/grants/[slug].js+190−39

This diff is too big to show here.

pages/grants/apprenticeships.js+3−18

This diff is too big to show here.

pages/grants/bounties.js+2−18

This diff is too big to show here.

pages/grants/proposals.js+2−17

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.js+307−242

This diff is too big to show here.

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

This diff is too big to show here.

pages/media.jsdeleted−109

This diff is too big to show here.

pages/media/[slug].jsdeleted−115

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/privacy.jsdeleted−17

This diff is too big to show here.

pages/terms-of-service.jsdeleted−21

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/understanding-urbit/[[...slug]].jsdeleted−211

This diff is too big to show here.

pages/updates.js+17−10

This diff is too big to show here.

pages/updates/[slug].js+21−30

This diff is too big to show here.

pages/using/[[...slug]].jsdeleted−163

This diff is too big to show here.

pages/voting-instructions.jsdeleted−21

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/developers-guide-logo.pngdeleted

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/network-explorer-logo.pngdeleted

Binary file not shown.

public/images/operators-guide-logo.pngdeleted

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.

public/images/star-market-logo.pngdeleted

Binary file not shown.

public/rss.xmldeleted−17770

This diff is too big to show here.

styles/globals.cssdeleted−212

This diff is too big to show here.

styles/markdown.cssdeleted−185

This diff is too big to show here.

styles/prism.cssdeleted−170

This diff is too big to show here.

tailwind.config.js+14−64

This diff is too big to show here.

vercel.json+112−683

This diff is too big to show here.