From 62d921a9f467e282a591b1d0ed01bf8f6cc86bb2 Mon Sep 17 00:00:00 2001 From: thelifeandtimes Date: Tue, 3 Mar 2026 21:25:39 -0800 Subject: [PATCH 1/4] fix: stabilize anchor scrolling and blurbs Restore consistent hash navigation and ensure Markdoc blurbs render as HTML to avoid client-side rendering errors. --- app/blog/page.js | 2 +- app/components/BlogNav.js | 35 ++--- app/components/ContentBlurbs.js | 46 +++++-- app/components/EcosystemNav.js | 35 ++--- app/components/HeaderNav.js | 14 +- app/components/Heading.jsx | 95 +++++++++++--- app/components/HomepageSectionNav.js | 58 +++------ app/components/MarkdocComponents.js | 37 ++++-- app/components/MobileFloatingNav.js | 25 ++-- app/components/ScrollManager.js | 88 ++++++++++--- app/ecosystem/page.js | 2 +- app/globals.css | 13 +- app/layout.js | 8 +- app/lib/anchorScroll.js | 150 ++++++++++++++++++++++ app/lib/queries.js | 21 ++- app/markdocConfig.js | 19 ++- app/overview/running-urbit/[slug]/page.js | 9 +- app/page.js | 12 +- 18 files changed, 480 insertions(+), 189 deletions(-) create mode 100644 app/lib/anchorScroll.js diff --git a/app/blog/page.js b/app/blog/page.js index 8c381502d9..226f3980ba 100644 --- a/app/blog/page.js +++ b/app/blog/page.js @@ -120,7 +120,7 @@ export default async function BlogHome() { {Object.entries(yearGroups) .sort(([yearA], [yearB]) => yearB - yearA) .map(([year, posts]) => ( -
+
{/* Year header */} {/*

{year}

*/} diff --git a/app/components/BlogNav.js b/app/components/BlogNav.js index 0514bb4e71..6b689d7824 100644 --- a/app/components/BlogNav.js +++ b/app/components/BlogNav.js @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import { usePathname } from "next/navigation"; +import { getVisibleAnchorElement } from "../lib/anchorScroll"; import { useLayoutSlots } from "../lib/layoutSlots"; /** @@ -23,49 +24,33 @@ export function BlogNav({ sections = [] }) { }, [setSidebarVisible]); const handleSectionClick = (sectionId) => { - // Find the visible element (not the first one which might be hidden) - const getVisibleElement = (id) => { - const escapedId = CSS.escape(id); - const elements = document.querySelectorAll(`#${escapedId}`); - return Array.from(elements).find(el => el.getBoundingClientRect().height > 0) || null; - }; - - const element = getVisibleElement(sectionId); + const element = getVisibleAnchorElement(sectionId); if (!element) { + console.warn(`Anchor not found for blog section: ${sectionId}`); return; } - // Responsive offset: 72px mobile, 100px desktop (matches scroll-mt) - const isMobile = window.innerWidth < 768; // md breakpoint - const offset = isMobile ? 72 : 100; - + const isMobile = window.innerWidth < 768; + const offset = isMobile ? 90 : 100; const rect = element.getBoundingClientRect(); const targetPosition = rect.top + window.scrollY - offset; window.scrollTo({ top: targetPosition, - behavior: "smooth" + behavior: "smooth", }); }; // Scroll-spy to track active year useEffect(() => { const handleScroll = () => { - // Responsive offset: 72px mobile, 100px desktop (matches scroll-mt) - const isMobile = window.innerWidth < 768; // md breakpoint - const offset = isMobile ? 72 : 100; + const isMobile = window.innerWidth < 768; + const offset = isMobile ? 90 : 100; let currentSection = ""; - // Helper to find visible element - const getVisibleElement = (id) => { - const escapedId = CSS.escape(id); - const elements = document.querySelectorAll(`#${escapedId}`); - return Array.from(elements).find(el => el.getBoundingClientRect().height > 0) || null; - }; - // Find active year based on scroll position for (const section of sections) { - const element = getVisibleElement(section.id); + const element = getVisibleAnchorElement(section.id); if (element) { const rect = element.getBoundingClientRect(); const isInRange = rect.top <= offset && rect.bottom >= offset; @@ -81,7 +66,7 @@ export function BlogNav({ sections = [] }) { // Fallback: find the first visible section if none are at offset if (!currentSection) { for (const section of sections) { - const element = getVisibleElement(section.id); + const element = getVisibleAnchorElement(section.id); if (element) { const rect = element.getBoundingClientRect(); const viewportHeight = window.innerHeight; diff --git a/app/components/ContentBlurbs.js b/app/components/ContentBlurbs.js index 76c82712f6..815664d014 100644 --- a/app/components/ContentBlurbs.js +++ b/app/components/ContentBlurbs.js @@ -3,7 +3,20 @@ import { useState } from "react"; import Link from "next/link"; import Image from "next/image"; -const renderHtml = (content) => ({ __html: content || "" }); +const renderContent = (Tag, content, className) => { + if (content === null || content === undefined) { + return null; + } + + const Wrapper = Tag; + if (typeof content === "string") { + return ( + + ); + } + + return {content}; +}; const slugify = (value) => { if (!value) { @@ -92,7 +105,7 @@ export const CollapsibleContentBlurb = ({ title, description, content, reference ); })} -
+ {renderContent("div", content, "text-base text-gray-87 line-clamp-5")}
+ )} + {/* Persistent Submenus - Mobile Only */} @@ -292,12 +359,17 @@ const MobileNav = ({ nav, currentRoute, announcements, urbitExplainedSections, r ); }; -const GlobalNav = ({ nav }) => { +const GlobalNav = ({ nav, onSearchOpen }) => { const currentRoute = usePathname(); + const [shortcutLabel, setShortcutLabel] = useState(null); + + useEffect(() => { + setShortcutLabel(getShortcutLabel()); + }, []); return ( -
    +
      {nav?.map((navItem, i) => { const isActive = currentRoute.startsWith(navItem.url); @@ -337,6 +409,26 @@ const GlobalNav = ({ nav }) => { ); })} + {onSearchOpen && ( + + )}
    ); diff --git a/app/components/HeroSection.js b/app/components/HeroSection.js index 5f69f39d8a..5976406b6b 100644 --- a/app/components/HeroSection.js +++ b/app/components/HeroSection.js @@ -281,44 +281,51 @@ export function HeroSection({ hero }) { {/* Desktop Tertiary Link */} - {tertiaryLink && ( - tertiaryLink.link.startsWith('http') ? ( - - ) : ( - - {tertiaryLink.label} - - ) - )} +
    + {tertiaryLink && ( + tertiaryLink.link.startsWith('http') ? ( + + ) : ( + + {tertiaryLink.label} + + ) + )} +
    {/* Leaving Site Modal */} - setIsModalOpen(false)}> + setIsModalOpen(false)} + >

    - Quickstart with Tlon Messenger + Quickstart with Tlon Messenger

    - Tlon will onboard you to Urbit without needing to run your own node. They provide free hosting and a free Urbit ID with their mobile app.

    + Tlon will onboard you to Urbit without needing to run your own node. They provide free hosting and a free Urbit ID with their mobile app. +

    - The link below will get you set up and added to the Urbit Foundation public group; say hello and someone will show you around!

    + The link below will get you set up and added to the Urbit Foundation public group; say hello and someone will show you around! +

    +
); } diff --git a/app/components/LayoutFrame.js b/app/components/LayoutFrame.js index d18a25d7c7..6c9f13aec0 100644 --- a/app/components/LayoutFrame.js +++ b/app/components/LayoutFrame.js @@ -1,9 +1,10 @@ "use client"; -import { useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useLayoutSlots } from "../lib/layoutSlots"; import { HeaderNav } from "./HeaderNav"; import { FooterSection, FooterExpansion } from "./FooterSection"; +import { SearchModal } from "./SearchModal"; /** * LayoutFrame - Client component that renders the frame with hero/sidebar slots @@ -14,6 +15,45 @@ export function LayoutFrame({ children, nav, homepage, footerData, mobileNav, an const { hero, sidebar, sidebarPosition, sidebarVisible, sidebarTransitionsEnabled } = useLayoutSlots(); const [expansionHeight, setExpansionHeight] = useState(0); const [expandedSection, setExpandedSection] = useState(null); + const [isSearchOpen, setIsSearchOpen] = useState(false); + + const openSearch = useCallback(() => { + setIsSearchOpen(true); + }, []); + + const closeSearch = useCallback(() => { + setIsSearchOpen(false); + }, []); + + const toggleSearch = useCallback(() => { + setIsSearchOpen((prev) => !prev); + }, []); + + useEffect(() => { + const handleKeyDown = (event) => { + if (event.defaultPrevented) return; + if (!(event.metaKey || event.ctrlKey)) return; + if (String(event.key).toLowerCase() !== "k") return; + + const target = event.target; + if (target?.tagName) { + const tag = target.tagName.toLowerCase(); + if (["input", "textarea", "select"].includes(tag)) { + return; + } + } + if (target?.isContentEditable) return; + if (typeof target?.closest === "function" && target.closest("[contenteditable='true']")) { + return; + } + + event.preventDefault(); + toggleSearch(); + }; + + document.addEventListener("keydown", handleKeyDown); + return () => document.removeEventListener("keydown", handleKeyDown); + }, [toggleSearch]); // Separate resources and socials from footerData for FooterExpansion const resources = footerData?.find(col => col.column_label === "resources"); @@ -21,6 +61,8 @@ export function LayoutFrame({ children, nav, homepage, footerData, mobileNav, an return ( <> + + {/* Mobile View - No Frame */}
{/* Optional Hero - Mobile */} @@ -78,7 +121,12 @@ export function LayoutFrame({ children, nav, homepage, footerData, mobileNav, an - +
diff --git a/app/components/Modal.js b/app/components/Modal.js index c566e08df8..195e01a139 100644 --- a/app/components/Modal.js +++ b/app/components/Modal.js @@ -15,8 +15,16 @@ import { createPortal } from "react-dom"; * @param {boolean} isOpen - Controls modal visibility * @param {function} onClose - Called when modal is dismissed * @param {ReactNode} children - Custom content slot + * @param {string} panelClassName - Optional panel styling overrides + * @param {string} contentClassName - Optional content wrapper classes */ -export function Modal({ isOpen, onClose, children }) { +export function Modal({ + isOpen, + onClose, + children, + panelClassName = "", + contentClassName = "", +}) { const canUseDOM = typeof document !== "undefined"; // Handle escape key @@ -58,7 +66,7 @@ export function Modal({ isOpen, onClose, children }) { onClick={onClose} >
e.stopPropagation()} > {/* Close button */} @@ -83,7 +91,7 @@ export function Modal({ isOpen, onClose, children }) { {/* Content */} -
{children}
+
{children}
, document.body diff --git a/app/components/SearchModal.js b/app/components/SearchModal.js new file mode 100644 index 0000000000..ccb7b94af0 --- /dev/null +++ b/app/components/SearchModal.js @@ -0,0 +1,444 @@ +"use client"; + +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useRouter } from "next/navigation"; +import { Modal } from "./Modal"; + +const SECTION_ORDER = ["overview", "blog", "grants", "events", "pages", "other"]; +const SECTION_LABELS = { + overview: "Overview", + blog: "Blog", + grants: "Grants", + events: "Events", + pages: "Pages", + other: "Other", +}; + +const toTitleCase = (value) => + value + .split("-") + .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)) + .join(" "); + +const getEntries = (payload) => { + if (Array.isArray(payload)) return payload; + if (payload && Array.isArray(payload.entries)) return payload.entries; + return []; +}; + +const normalizeTokens = (value) => + value + .trim() + .toLowerCase() + .split(/\s+/) + .filter(Boolean); + +const filterEntries = (entries, tokens) => { + if (!tokens.length) return []; + return entries.filter((entry) => { + const searchText = String(entry.searchText || "").toLowerCase(); + return tokens.every((token) => searchText.includes(token)); + }); +}; + +const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + +const highlightMatches = (text, tokens) => { + if (!text || !tokens.length) return text; + const uniqueTokens = Array.from( + new Set(tokens.map((token) => token.toLowerCase()).filter(Boolean)) + ); + if (!uniqueTokens.length) return text; + + const regex = new RegExp( + `(${uniqueTokens.map((token) => escapeRegExp(token)).join("|")})`, + "gi" + ); + const segments = String(text).split(regex); + + return segments.map((segment, index) => { + const isMatch = uniqueTokens.includes(segment.toLowerCase()); + if (!isMatch) return segment; + return ( + + {segment} + + ); + }); +}; + +export function SearchModal({ isOpen, onClose, children }) { + const router = useRouter(); + const inputRef = useRef(null); + const hasRequestedRef = useRef(false); + const queryRef = useRef(""); + const [query, setQuery] = useState(""); + const [indexEntries, setIndexEntries] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + const [activeIndex, setActiveIndex] = useState(-1); + + const resetSearch = useCallback(() => { + setQuery(""); + queryRef.current = ""; + setActiveIndex(-1); + setErrorMessage(""); + }, []); + + const handleClose = useCallback(() => { + resetSearch(); + onClose(); + }, [resetSearch, onClose]); + + const ensureIndexLoaded = useCallback(() => { + if (indexEntries.length > 0 || isLoading || hasRequestedRef.current) { + return; + } + + hasRequestedRef.current = true; + setIsLoading(true); + setErrorMessage(""); + + fetch("/search-index.json") + .then((response) => { + if (!response.ok) { + throw new Error(`Search index request failed: ${response.status}`); + } + return response.json(); + }) + .then((payload) => { + const entries = getEntries(payload); + if (!entries.length) { + console.warn("Search index loaded with no entries."); + } else { + console.info(`Search index loaded (${entries.length} entries).`); + } + setIndexEntries(entries); + + const tokens = normalizeTokens(queryRef.current); + if (tokens.length) { + const nextResults = filterEntries(entries, tokens); + setActiveIndex(nextResults.length ? 0 : -1); + } + }) + .catch((error) => { + console.error("Failed to load search index:", error); + setErrorMessage("Search index unavailable."); + hasRequestedRef.current = false; + }) + .finally(() => { + setIsLoading(false); + }); + }, [indexEntries.length, isLoading]); + + useEffect(() => { + if (!isOpen) return; + inputRef.current?.focus(); + inputRef.current?.select(); + }, [isOpen]); + + + const queryTokens = useMemo(() => normalizeTokens(query), [query]); + const highlightText = useCallback( + (text) => highlightMatches(text, queryTokens), + [queryTokens] + ); + + const filteredResults = useMemo( + () => filterEntries(indexEntries, queryTokens), + [indexEntries, queryTokens] + ); + + const groupedResults = useMemo(() => { + const groups = new Map(); + + for (const entry of filteredResults) { + const section = entry.section || "other"; + if (!groups.has(section)) { + groups.set(section, []); + } + groups.get(section).push(entry); + } + + return SECTION_ORDER.map((section) => { + const items = groups.get(section) || []; + if (!items.length) return null; + + const label = + SECTION_LABELS[section] || + items[0]?.sectionLabel || + toTitleCase(section); + + const sortedItems = [...items].sort((a, b) => + String(a.title || "").localeCompare(String(b.title || ""), undefined, { + sensitivity: "base", + }) + ); + + return { section, label, items: sortedItems }; + }).filter(Boolean); + }, [filteredResults]); + + const flatResults = useMemo( + () => + groupedResults.flatMap((group) => + group.items.map((item) => ({ + ...item, + group: group.section, + groupLabel: group.label, + })) + ), + [groupedResults] + ); + + const resultIndexByPath = useMemo(() => { + const indexMap = new Map(); + flatResults.forEach((result, index) => { + if (result.path) { + indexMap.set(result.path, index); + } + }); + return indexMap; + }, [flatResults]); + + + useEffect(() => { + if (activeIndex < 0) return; + const element = document.getElementById(`search-result-${activeIndex}`); + element?.scrollIntoView({ block: "nearest" }); + }, [activeIndex]); + + const handleQueryChange = (event) => { + const nextQuery = event.target.value; + queryRef.current = nextQuery; + setQuery(nextQuery); + + if (!indexEntries.length) { + ensureIndexLoaded(); + } + + const tokens = normalizeTokens(nextQuery); + if (!tokens.length) { + setActiveIndex(-1); + return; + } + + const nextResults = filterEntries(indexEntries, tokens); + setActiveIndex(nextResults.length ? 0 : -1); + }; + + const handleSelect = (item) => { + if (!item?.path) { + console.warn("Search result missing path:", item); + return; + } + console.info("Search result selected:", { + title: item.title, + path: item.path, + query: queryRef.current, + }); + router.push(item.path); + handleClose(); + }; + + const handleKeyDown = (event) => { + if (!indexEntries.length) { + ensureIndexLoaded(); + } + + if (!flatResults.length) return; + + if (event.key === "ArrowDown") { + event.preventDefault(); + setActiveIndex((prev) => (prev + 1) % flatResults.length); + return; + } + + if (event.key === "ArrowUp") { + event.preventDefault(); + setActiveIndex((prev) => + prev <= 0 ? flatResults.length - 1 : prev - 1 + ); + return; + } + + if (event.key === "Enter" && activeIndex >= 0) { + event.preventDefault(); + handleSelect(flatResults[activeIndex]); + } + }; + + const activeId = activeIndex >= 0 ? `search-result-${activeIndex}` : undefined; + + return ( + +
+
+

+ Search urbit.org +

+ {queryTokens.length > 0 && !isLoading && !errorMessage && ( + + {flatResults.length} results + + )} +
+

+ Browse site content, guides, grants, and updates. +

+
+ Use ↑/↓ to navigate, Enter to open. + {!indexEntries.length && !isLoading && ( + Focus the field to load results. + )} +
+ +
+ + +
+ +
+ {isLoading && ( +
Loading search index…
+ )} + + {errorMessage && ( +
{errorMessage}
+ )} + + {!isLoading && !errorMessage && !queryTokens.length && ( +
+ Start typing to see search results. +
+ )} + + {!isLoading && !errorMessage && queryTokens.length > 0 && !flatResults.length && ( +
+ No results found. Try a different search. +
+ )} + + {!isLoading && !errorMessage && groupedResults.length > 0 && ( +
+ {groupedResults.map((group) => ( +
+
+ {group.label} +
+
+ {group.items.map((item) => { + const resultIndex = resultIndexByPath.get(item.path); + const isActive = resultIndex === activeIndex; + const resultId = + typeof resultIndex === "number" + ? `search-result-${resultIndex}` + : undefined; + const tags = Array.isArray(item.tags) ? item.tags : []; + const visibleTags = tags.slice(0, 3); + const extraTags = tags.length - visibleTags.length; + + return ( + + ); + })} +
+ +
+ ))} +
+ )} +
+
+ + {children && ( +
{children}
+ )} +
+ ); +} diff --git a/package.json b/package.json index 5e7f2a81e7..ee7d206718 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "version": "0.1.0", "private": true, "scripts": { + "predev": "node scripts/build-search-index.js", "dev": "next dev", + "prebuild": "node scripts/build-search-index.js", "build": "next build", "start": "next start", "lint": "eslint ." diff --git a/scripts/build-search-index.js b/scripts/build-search-index.js new file mode 100644 index 0000000000..cb870dd73c --- /dev/null +++ b/scripts/build-search-index.js @@ -0,0 +1,248 @@ +#!/usr/bin/env node + +/** + * Search Index Builder + * + * Builds a static JSON index from app/content for the homepage search modal. + * + * Usage: node scripts/build-search-index.js + */ + +const fs = require("fs"); +const path = require("path"); +const matter = require("gray-matter"); +const { glob } = require("glob"); +const toml = require("@iarna/toml"); + +const CONTENT_DIR = path.join(process.cwd(), "app/content"); +const OUTPUT_PATH = path.join(process.cwd(), "public/search-index.json"); +const EXCLUDED_FILE_NAMES = new Set(["config.md", "index.md"]); +const EXCLUDED_SLUGS = new Set(["get-on-the-network"]); +const EXCLUDED_DIRECTORIES = new Set(["blurbs", "homepage"]); +const SECTION_ORDER = ["overview", "blog", "grants", "events", "pages", "other"]; +const SECTION_LABELS = { + overview: "Overview", + blog: "Blog", + grants: "Grants", + events: "Events", + pages: "Pages", + other: "Other", +}; + +const toTitleCase = (value) => + value + .split("-") + .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)) + .join(" "); + +const normalizeArray = (value) => { + if (!value) return []; + return Array.isArray(value) ? value : [value]; +}; + +const collectTags = (frontMatter) => { + const tags = [ + ...normalizeArray(frontMatter.tags), + ...normalizeArray(frontMatter.extra?.tags), + ...normalizeArray(frontMatter.taxonomies?.tags), + ...normalizeArray(frontMatter.taxonomies?.grant_type), + ...normalizeArray(frontMatter.taxonomies?.grant_category), + ] + .map((tag) => String(tag).trim()) + .filter(Boolean); + + return Array.from(new Set(tags)); +}; + +const parseFrontMatter = (raw, filePath) => { + const trimmed = raw.trimStart(); + const usesToml = trimmed.startsWith("+++"); + const options = usesToml + ? { + engines: { toml: toml.parse.bind(toml) }, + language: "toml", + delimiters: "+++", + } + : undefined; + + try { + const { data } = matter(raw, options); + return data || {}; + } catch (error) { + console.error(`Failed to parse frontmatter for ${filePath}:`, error); + return null; + } +}; + +const resolveEntry = (relativePath) => { + const segments = relativePath.split("/"); + const filename = segments[segments.length - 1]; + const slug = path.basename(filename, ".md"); + const section = segments[0]; + + if (EXCLUDED_SLUGS.has(slug)) { + return null; + } + + if (section === "overview") { + const overviewSection = segments[1]; + if (!overviewSection) { + console.warn(`Skipping overview content without subsection: ${relativePath}`); + return null; + } + + const isIntro = slug === "intro"; + const pathSuffix = isIntro + ? `/overview/${overviewSection}` + : `/overview/${overviewSection}/${slug}`; + + return { + path: pathSuffix, + section: "overview", + subsection: overviewSection, + subsectionLabel: toTitleCase(overviewSection), + }; + } + + if (section === "blog") { + return { path: `/blog/${slug}`, section: "blog" }; + } + + if (section === "grants") { + return { path: `/grants/${slug}`, section: "grants" }; + } + + if (section === "events") { + return { path: `/events/${slug}`, section: "events" }; + } + + if (section === "singles") { + return { path: `/${slug}`, section: "pages" }; + } + + if (segments.length === 1) { + return { path: `/${slug}`, section: "pages" }; + } + + return { + path: `/${relativePath.replace(/\.md$/, "")}`, + section: "other", + }; +}; + +const getSectionRank = (section) => { + const index = SECTION_ORDER.indexOf(section); + return index === -1 ? SECTION_ORDER.length : index; +}; + +async function buildSearchIndex() { + console.log("Building search index...\n"); + + if (!fs.existsSync(CONTENT_DIR)) { + console.error(`Content directory not found: ${CONTENT_DIR}`); + process.exit(1); + } + + const outputDir = path.dirname(OUTPUT_PATH); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + const postPaths = await glob(path.join(CONTENT_DIR, "**/*.md")); + const entries = []; + const errors = []; + + for (const filePath of postPaths) { + const relativePath = path + .relative(CONTENT_DIR, filePath) + .replace(/\\/g, "/"); + const filename = path.basename(filePath); + const segments = relativePath.split("/"); + + if (EXCLUDED_FILE_NAMES.has(filename)) { + continue; + } + + if (segments.some((segment) => EXCLUDED_DIRECTORIES.has(segment))) { + continue; + } + + let rawContent; + try { + rawContent = fs.readFileSync(filePath, "utf-8"); + } catch (error) { + console.error(`Failed to read ${filePath}:`, error); + errors.push({ filePath, error }); + continue; + } + + const frontMatter = parseFrontMatter(rawContent, filePath); + if (!frontMatter) { + errors.push({ filePath, error: new Error("Frontmatter parse failed") }); + continue; + } + + const routeInfo = resolveEntry(relativePath); + if (!routeInfo) { + continue; + } + + const title = frontMatter.title || toTitleCase(path.basename(filePath, ".md")); + const description = + frontMatter.description || + frontMatter.summary || + frontMatter.extra?.description || + ""; + const tags = collectTags(frontMatter); + const sectionLabel = SECTION_LABELS[routeInfo.section] || toTitleCase(routeInfo.section); + const searchText = [ + title, + description, + tags.join(" "), + routeInfo.path, + sectionLabel, + routeInfo.subsectionLabel || "", + ] + .join(" ") + .toLowerCase(); + + entries.push({ + title, + description, + tags, + path: routeInfo.path, + section: routeInfo.section, + sectionLabel, + subsection: routeInfo.subsection, + subsectionLabel: routeInfo.subsectionLabel, + searchText, + }); + } + + entries.sort((a, b) => { + const sectionRank = getSectionRank(a.section) - getSectionRank(b.section); + if (sectionRank !== 0) return sectionRank; + return a.title.localeCompare(b.title, undefined, { sensitivity: "base" }); + }); + + const output = { + generatedAt: new Date().toISOString(), + total: entries.length, + entries, + }; + + fs.writeFileSync(OUTPUT_PATH, JSON.stringify(output, null, 2), "utf-8"); + + console.log(`✓ Search index written to ${OUTPUT_PATH}`); + console.log(`✓ Indexed ${entries.length} content entries`); + + if (errors.length > 0) { + console.error(`Search index completed with ${errors.length} errors.`); + process.exitCode = 1; + } +} + +buildSearchIndex().catch((error) => { + console.error("Search index build failed:", error); + process.exit(1); +}); From 8a174691011a8db9bed59b8b7c175e0782bc7572 Mon Sep 17 00:00:00 2001 From: thelifeandtimes Date: Thu, 5 Mar 2026 08:43:21 -0800 Subject: [PATCH 3/4] feat: enhance search ranking and metadata Add search_terms metadata, weighted fuzzy scoring, and mobile search refinements to improve relevance and navigation. --- app/components/ContentBlurbs.js | 3 +- app/components/HeaderNav.js | 38 +- app/components/LayoutFrame.js | 2 + app/components/SearchModal.js | 638 +++++++++++++----- .../contributor-spotlight-litneb-maltyp.md | 14 + scripts/build-search-index.js | 289 +++++++- 6 files changed, 775 insertions(+), 209 deletions(-) diff --git a/app/components/ContentBlurbs.js b/app/components/ContentBlurbs.js index 815664d014..d74cbacd98 100644 --- a/app/components/ContentBlurbs.js +++ b/app/components/ContentBlurbs.js @@ -270,12 +270,13 @@ export const PreviewContentBlurb = ({ id, blurbSlug, title, description, content export const ContentBlurb = ({ id, blurbSlug, title, description, content, references, image, imageDark, ctaButton }) => { const [isDetailsExpanded, setIsDetailsExpanded] = useState(false); const tooltipContext = blurbSlug || id || slugify(title); + const anchorId = id || blurbSlug; // Check if there are any details to show const hasDetails = description || (references && references.some(ref => ref.description)); return ( -
+
{/* Render images if provided */} diff --git a/app/components/HeaderNav.js b/app/components/HeaderNav.js index 9dd088ed78..eecf6270fd 100644 --- a/app/components/HeaderNav.js +++ b/app/components/HeaderNav.js @@ -52,7 +52,7 @@ const SearchIcon = ({ className = "" }) => ( viewBox="0 0 24 24" fill="none" stroke="currentColor" - strokeWidth="1.5" + strokeWidth="2.3" strokeLinecap="round" strokeLinejoin="round" className={className} @@ -66,7 +66,7 @@ const SearchIcon = ({ className = "" }) => ( const getShortcutLabel = () => { if (typeof navigator === "undefined") return null; const platform = navigator.userAgentData?.platform || navigator.platform || ""; - return /mac/i.test(platform) ? "⌘K" : "Ctrl+K"; + return /mac/i.test(platform) ? "⌘K" : "^+K"; }; export const HeaderNav = ({ @@ -78,6 +78,7 @@ export const HeaderNav = ({ urbitExplainedSections, runningUrbitSections, onSearchOpen, + isSearchOpen, }) => { const headerRef = useRef(null); @@ -92,6 +93,7 @@ export const HeaderNav = ({ urbitExplainedSections={urbitExplainedSections} runningUrbitSections={runningUrbitSections} onSearchOpen={onSearchOpen} + isSearchOpen={isSearchOpen} />
{inFrame ? ( - + + ) : (
- +
@@ -124,6 +127,7 @@ const MobileNav = ({ urbitExplainedSections, runningUrbitSections, onSearchOpen, + isSearchOpen, }) => { const [menuIsOpen, setMenuOpen] = useState(false); @@ -204,9 +208,13 @@ const MobileNav = ({ data-umami-event-destination="search-modal" data-umami-event-context={currentRoute} data-umami-event-variant="mobile" - className="flex items-center justify-center text-contrast-2 hover:text-primary transition-colors" + className={`flex items-center justify-center transition-colors duration-200 ${ + isSearchOpen + ? "text-primary" + : "text-contrast-2 hover:text-primary" + }`} > - + )}
diff --git a/app/components/SearchModal.js b/app/components/SearchModal.js index ccb7b94af0..e9cc4ecfcc 100644 --- a/app/components/SearchModal.js +++ b/app/components/SearchModal.js @@ -33,11 +33,185 @@ const normalizeTokens = (value) => .split(/\s+/) .filter(Boolean); -const filterEntries = (entries, tokens) => { +const splitWords = (value) => + value + .toLowerCase() + .split(/[^a-z0-9]+/) + .filter(Boolean); + +const FIELD_WEIGHTS = { + title: 12, + tags: 10, + searchTerms: 9, + description: 6, + authors: 4, + other: 2, +}; + +const SOURCE_BOOSTS = { + overview: 12, + blurbs: 12, + homepage: 8, + blog: 4, + events: 3, + pages: 2, + other: 0, +}; + +const SOURCE_RANKS = { + overview: 0, + blurbs: 0, + homepage: 1, + blog: 2, + events: 3, + pages: 4, + other: 5, +}; + +const scoreFuzzyWord = (token, word) => { + if (!token || !word || token.length > word.length) { + return 0; + } + + let score = 0; + let lastIndex = -1; + let consecutive = 0; + + for (const char of token) { + const nextIndex = word.indexOf(char, lastIndex + 1); + if (nextIndex === -1) { + return 0; + } + + if (nextIndex === lastIndex + 1) { + consecutive += 1; + score += 2 + consecutive; + } else { + consecutive = 0; + score += 1; + } + + lastIndex = nextIndex; + } + + if (word.startsWith(token)) { + score += 6 + token.length; + } + + return score; +}; + +const getBestTokenScore = (token, words) => { + if (!token.length) return 0; + if (token.length <= 2) { + const hasPrefix = words.some((word) => word.startsWith(token)); + return hasPrefix ? 5 + token.length : 0; + } + + let bestScore = 0; + for (const word of words) { + const score = scoreFuzzyWord(token, word); + if (score > bestScore) { + bestScore = score; + } + } + + return bestScore; +}; + +const getEntryWords = (entry) => ({ + title: splitWords(entry.title || ""), + tags: splitWords((entry.tags || []).join(" ")), + searchTerms: splitWords((entry.searchTerms || []).join(" ")), + description: splitWords(entry.description || ""), + authors: splitWords((entry.authors || []).join(" ")), + other: splitWords(entry.searchText || ""), +}); + +const scoreEntry = (entry, tokens, wordsByField) => { + if (!tokens.length) return 0; + + let totalScore = 0; + + for (const token of tokens) { + const tokenScores = { + title: getBestTokenScore(token, wordsByField.title), + tags: getBestTokenScore(token, wordsByField.tags), + searchTerms: getBestTokenScore(token, wordsByField.searchTerms), + description: getBestTokenScore(token, wordsByField.description), + authors: getBestTokenScore(token, wordsByField.authors), + other: getBestTokenScore(token, wordsByField.other), + }; + + const weightedScore = Math.max( + tokenScores.title * FIELD_WEIGHTS.title, + tokenScores.tags * FIELD_WEIGHTS.tags, + tokenScores.searchTerms * FIELD_WEIGHTS.searchTerms, + tokenScores.description * FIELD_WEIGHTS.description, + tokenScores.authors * FIELD_WEIGHTS.authors, + tokenScores.other * FIELD_WEIGHTS.other + ); + + if (!weightedScore) { + return 0; + } + + totalScore += weightedScore; + } + + const sourceKey = entry.source || entry.section || "other"; + totalScore += SOURCE_BOOSTS[sourceKey] || 0; + + return totalScore; +}; + +const getSourceRank = (entry) => { + const sourceKey = entry.source || entry.section || "other"; + return SOURCE_RANKS[sourceKey] ?? SOURCE_RANKS.other; +}; + +const rankEntries = (entries, tokens, wordsByEntry) => { if (!tokens.length) return []; - return entries.filter((entry) => { - const searchText = String(entry.searchText || "").toLowerCase(); - return tokens.every((token) => searchText.includes(token)); + + return entries + .map((entry) => { + const key = entry.id || entry.path || entry.title; + const words = wordsByEntry.get(key) || getEntryWords(entry); + const score = scoreEntry(entry, tokens, words); + if (!score) return null; + return { ...entry, score }; + }) + .filter(Boolean) + .sort((a, b) => { + const scoreDiff = b.score - a.score; + if (scoreDiff !== 0) return scoreDiff; + + const sourceDiff = getSourceRank(a) - getSourceRank(b); + if (sourceDiff !== 0) return sourceDiff; + + const dateDiff = (b.publishedTimestamp || 0) - (a.publishedTimestamp || 0); + if (dateDiff !== 0) return dateDiff; + + return String(a.title || "").localeCompare(String(b.title || ""), undefined, { + sensitivity: "base", + }); + }); +}; + +const dedupeAnchoredResults = (results) => { + const seenAnchors = new Set(); + return results.filter((entry) => { + const entryPath = entry.path || ""; + if (!entryPath.includes("#")) { + return true; + } + + if (seenAnchors.has(entryPath)) { + return false; + } + + seenAnchors.add(entryPath); + return true; }); }; @@ -73,13 +247,16 @@ export function SearchModal({ isOpen, onClose, children }) { const hasRequestedRef = useRef(false); const queryRef = useRef(""); const [query, setQuery] = useState(""); + const [debouncedQuery, setDebouncedQuery] = useState(""); const [indexEntries, setIndexEntries] = useState([]); const [isLoading, setIsLoading] = useState(false); const [errorMessage, setErrorMessage] = useState(""); const [activeIndex, setActiveIndex] = useState(-1); + const [isMobile, setIsMobile] = useState(false); const resetSearch = useCallback(() => { setQuery(""); + setDebouncedQuery(""); queryRef.current = ""; setActiveIndex(-1); setErrorMessage(""); @@ -114,12 +291,6 @@ export function SearchModal({ isOpen, onClose, children }) { console.info(`Search index loaded (${entries.length} entries).`); } setIndexEntries(entries); - - const tokens = normalizeTokens(queryRef.current); - if (tokens.length) { - const nextResults = filterEntries(entries, tokens); - setActiveIndex(nextResults.length ? 0 : -1); - } }) .catch((error) => { console.error("Failed to load search index:", error); @@ -131,22 +302,75 @@ export function SearchModal({ isOpen, onClose, children }) { }); }, [indexEntries.length, isLoading]); + useEffect(() => { + if (typeof window === "undefined") return undefined; + const mediaQuery = window.matchMedia("(max-width: 767px)"); + + const updateIsMobile = () => { + setIsMobile(mediaQuery.matches); + }; + + updateIsMobile(); + mediaQuery.addEventListener("change", updateIsMobile); + return () => mediaQuery.removeEventListener("change", updateIsMobile); + }, []); + + useEffect(() => { + const timeout = setTimeout(() => { + setDebouncedQuery(query); + }, 160); + + return () => clearTimeout(timeout); + }, [query]); + useEffect(() => { if (!isOpen) return; inputRef.current?.focus(); inputRef.current?.select(); }, [isOpen]); + useEffect(() => { + if (!isOpen || !isMobile || typeof document === "undefined") { + return undefined; + } + + const handleEscape = (event) => { + if (event.key === "Escape") { + handleClose(); + } + }; + + document.documentElement.style.overflow = "hidden"; + document.body.style.overflow = "hidden"; + document.addEventListener("keydown", handleEscape); + + return () => { + document.documentElement.style.overflow = ""; + document.body.style.overflow = ""; + document.removeEventListener("keydown", handleEscape); + }; + }, [isOpen, isMobile, handleClose]); - const queryTokens = useMemo(() => normalizeTokens(query), [query]); + const queryTokens = useMemo(() => normalizeTokens(debouncedQuery), [debouncedQuery]); + const highlightTokens = useMemo(() => normalizeTokens(query), [query]); const highlightText = useCallback( - (text) => highlightMatches(text, queryTokens), - [queryTokens] + (text) => highlightMatches(text, highlightTokens), + [highlightTokens] ); + const entryWords = useMemo(() => { + const map = new Map(); + indexEntries.forEach((entry) => { + const key = entry.id || entry.path || entry.title; + if (!key) return; + map.set(key, getEntryWords(entry)); + }); + return map; + }, [indexEntries]); + const filteredResults = useMemo( - () => filterEntries(indexEntries, queryTokens), - [indexEntries, queryTokens] + () => dedupeAnchoredResults(rankEntries(indexEntries, queryTokens, entryWords)), + [indexEntries, queryTokens, entryWords] ); const groupedResults = useMemo(() => { @@ -169,11 +393,13 @@ export function SearchModal({ isOpen, onClose, children }) { items[0]?.sectionLabel || toTitleCase(section); - const sortedItems = [...items].sort((a, b) => - String(a.title || "").localeCompare(String(b.title || ""), undefined, { + const sortedItems = [...items].sort((a, b) => { + const scoreDiff = (b.score || 0) - (a.score || 0); + if (scoreDiff !== 0) return scoreDiff; + return String(a.title || "").localeCompare(String(b.title || ""), undefined, { sensitivity: "base", - }) - ); + }); + }); return { section, label, items: sortedItems }; }).filter(Boolean); @@ -191,16 +417,27 @@ export function SearchModal({ isOpen, onClose, children }) { [groupedResults] ); - const resultIndexByPath = useMemo(() => { + const resultIndexById = useMemo(() => { const indexMap = new Map(); flatResults.forEach((result, index) => { - if (result.path) { - indexMap.set(result.path, index); + const key = result.id || result.path || result.title; + if (key) { + indexMap.set(key, index); } }); return indexMap; }, [flatResults]); + const querySignature = queryTokens.join(" "); + + useEffect(() => { + if (!querySignature || !flatResults.length) { + setActiveIndex(-1); + return; + } + + setActiveIndex(0); + }, [querySignature, flatResults.length]); useEffect(() => { if (activeIndex < 0) return; @@ -212,19 +449,11 @@ export function SearchModal({ isOpen, onClose, children }) { const nextQuery = event.target.value; queryRef.current = nextQuery; setQuery(nextQuery); + setActiveIndex(-1); if (!indexEntries.length) { ensureIndexLoaded(); } - - const tokens = normalizeTokens(nextQuery); - if (!tokens.length) { - setActiveIndex(-1); - return; - } - - const nextResults = filterEntries(indexEntries, tokens); - setActiveIndex(nextResults.length ? 0 : -1); }; const handleSelect = (item) => { @@ -269,22 +498,21 @@ export function SearchModal({ isOpen, onClose, children }) { }; const activeId = activeIndex >= 0 ? `search-result-${activeIndex}` : undefined; - - return ( - -
+ const resultCountLabel = + queryTokens.length > 0 && !isLoading && !errorMessage + ? `${flatResults.length} results` + : null; + + const searchBody = ( +
+

Search urbit.org

- {queryTokens.length > 0 && !isLoading && !errorMessage && ( + {resultCountLabel && ( - {flatResults.length} results + {resultCountLabel} )}
@@ -297,144 +525,218 @@ export function SearchModal({ isOpen, onClose, children }) { Focus the field to load results. )}
+
-
- - -
- -
- {isLoading && ( -
Loading search index…
- )} - - {errorMessage && ( -
{errorMessage}
+
+

+ Browse site content, guides, grants, and updates. +

+
+ Tap a result to open. + {!indexEntries.length && !isLoading && ( + Focus the field to load results. )} +
+
- {!isLoading && !errorMessage && !queryTokens.length && ( -
- Start typing to see search results. -
- )} +
+ + +
- {!isLoading && !errorMessage && queryTokens.length > 0 && !flatResults.length && ( -
- No results found. Try a different search. -
- )} +
+ {isLoading && ( +
Loading search index…
+ )} + + {errorMessage && ( +
{errorMessage}
+ )} + + {!isLoading && !errorMessage && !queryTokens.length && ( +
+ Start typing to see search results. +
+ )} + + {!isLoading && !errorMessage && queryTokens.length > 0 && !flatResults.length && ( +
+ No results found. Try a different search. +
+ )} {!isLoading && !errorMessage && groupedResults.length > 0 && ( -
- {groupedResults.map((group) => ( -
-
- {group.label} -
-
- {group.items.map((item) => { - const resultIndex = resultIndexByPath.get(item.path); - const isActive = resultIndex === activeIndex; - const resultId = - typeof resultIndex === "number" - ? `search-result-${resultIndex}` - : undefined; - const tags = Array.isArray(item.tags) ? item.tags : []; - const visibleTags = tags.slice(0, 3); - const extraTags = tags.length - visibleTags.length; - - return ( - - ); - })} -
- +
+ )} + + ); + })}
- ))} -
+
+ ))} +
+ )} +
+
+ ); + + if (isMobile) { + if (!isOpen) return null; + + return ( +
+
+
+

+ Search +

+ {resultCountLabel && ( +
+ {resultCountLabel} +
+ )} +
+ +
+
+ {searchBody} + {children && ( +
{children}
)}
+ ); + } + + return ( + + {searchBody} {children && (
{children}
diff --git a/app/content/blog/contributor-spotlight-litneb-maltyp.md b/app/content/blog/contributor-spotlight-litneb-maltyp.md index ebd2248e2e..2a35f56797 100644 --- a/app/content/blog/contributor-spotlight-litneb-maltyp.md +++ b/app/content/blog/contributor-spotlight-litneb-maltyp.md @@ -14,6 +14,20 @@ imageCard = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog+QA+li # imageCardDark = "" # imageIndexDark = "" tags = ["spotlight", "identity", "design"] +search_terms = [ + "contributor spotlight", + "litneb maltyp", + "urbit identity", + "personal server", + "urbit community", + "urbit id", + "azimuth ids", + "sigil design", + "olif", + "assembly conference", + "groundwire", + "forever computer" +] +++ ![~litneb-maltyp contributor spotlight image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog+QA+litneb-maltyp/Blog_QA+litneb-maltyp_no+text_Social16_9.png) diff --git a/scripts/build-search-index.js b/scripts/build-search-index.js index cb870dd73c..10e5748193 100644 --- a/scripts/build-search-index.js +++ b/scripts/build-search-index.js @@ -16,9 +16,8 @@ const toml = require("@iarna/toml"); const CONTENT_DIR = path.join(process.cwd(), "app/content"); const OUTPUT_PATH = path.join(process.cwd(), "public/search-index.json"); +const INCLUDED_DIRECTORIES = new Set(["blog", "blurbs", "homepage", "overview"]); const EXCLUDED_FILE_NAMES = new Set(["config.md", "index.md"]); -const EXCLUDED_SLUGS = new Set(["get-on-the-network"]); -const EXCLUDED_DIRECTORIES = new Set(["blurbs", "homepage"]); const SECTION_ORDER = ["overview", "blog", "grants", "events", "pages", "other"]; const SECTION_LABELS = { overview: "Overview", @@ -54,6 +53,83 @@ const collectTags = (frontMatter) => { return Array.from(new Set(tags)); }; +const collectFrontMatterValues = (value, values = []) => { + if (value === null || value === undefined) { + return values; + } + + if (Array.isArray(value)) { + value.forEach((entry) => collectFrontMatterValues(entry, values)); + return values; + } + + if (typeof value === "object") { + Object.values(value).forEach((entry) => collectFrontMatterValues(entry, values)); + return values; + } + + if (typeof value === "string" || typeof value === "number") { + const stringValue = String(value).trim(); + if (stringValue) { + values.push(stringValue); + } + } + + return values; +}; + +const uniqueStrings = (values) => Array.from(new Set(values.filter(Boolean))); + +const normalizeSearchTerms = (value) => { + if (!value) return []; + + const values = normalizeArray(value).flatMap((entry) => { + if (typeof entry === "string") { + return entry + .split(",") + .map((item) => item.trim()) + .filter(Boolean); + } + + if (typeof entry === "number") { + return [String(entry)]; + } + + return []; + }); + + return uniqueStrings(values); +}; + +const collectAuthors = (frontMatter) => { + const values = [ + ...normalizeArray(frontMatter.author), + ...normalizeArray(frontMatter.authors), + ...normalizeArray(frontMatter.extra?.author), + ...normalizeArray(frontMatter.extra?.authors), + ] + .map((entry) => String(entry || "").trim()) + .filter(Boolean); + + return uniqueStrings(values); +}; + +const parsePublishedTimestamp = (frontMatter) => { + const dateValue = + frontMatter.date || + frontMatter.published || + frontMatter.published_at || + frontMatter.updated || + frontMatter.extra?.date || + frontMatter.extra?.published || + frontMatter.extra?.updated; + + if (!dateValue) return null; + + const parsed = Date.parse(dateValue); + return Number.isNaN(parsed) ? null : parsed; +}; + const parseFrontMatter = (raw, filePath) => { const trimmed = raw.trimStart(); const usesToml = trimmed.startsWith("+++"); @@ -74,38 +150,174 @@ const parseFrontMatter = (raw, filePath) => { } }; -const resolveEntry = (relativePath) => { +const deriveSectionInfoFromPath = (targetPath) => { + const parts = targetPath.split("/").filter(Boolean); + if (!parts.length) { + return { section: "pages" }; + } + + const [root, subsection] = parts; + if (root === "overview") { + return { + section: "overview", + subsection, + subsectionLabel: subsection ? toTitleCase(subsection) : undefined, + }; + } + + if (root === "blog") { + return { section: "blog" }; + } + + if (root === "grants") { + return { section: "grants" }; + } + + if (root === "events") { + return { section: "events" }; + } + + return { section: "pages" }; +}; + +const resolveOverviewEntry = (segments, slug, relativePath) => { + const overviewSection = segments[1]; + if (!overviewSection) { + console.warn(`Skipping overview content without subsection: ${relativePath}`); + return null; + } + + const isIntro = slug === "intro"; + const pathSuffix = isIntro + ? `/overview/${overviewSection}` + : `/overview/${overviewSection}/${slug}`; + + return { + path: pathSuffix, + section: "overview", + subsection: overviewSection, + subsectionLabel: toTitleCase(overviewSection), + }; +}; + +const addBlurbRoute = (map, slug, targetPath, { overwrite = false } = {}) => { + if (!slug || !targetPath) { + return; + } + + if (!overwrite && map.has(slug)) { + return; + } + + if (overwrite && map.has(slug) && map.get(slug) !== targetPath) { + console.warn(`Blurb ${slug} mapped to multiple routes; using ${targetPath}.`); + } + + map.set(slug, targetPath); +}; + +const buildBlurbRouteMap = async () => { + const map = new Map(); + const homepageConfigPath = path.join(CONTENT_DIR, "homepage/config.md"); + + if (fs.existsSync(homepageConfigPath)) { + try { + const rawContent = fs.readFileSync(homepageConfigPath, "utf-8"); + const frontMatter = parseFrontMatter(rawContent, homepageConfigPath); + if (frontMatter) { + const sections = normalizeArray(frontMatter.sections); + sections.forEach((section) => { + if (!section) return; + const sectionBlurb = section["section-blurb"]; + addBlurbRoute(map, sectionBlurb, `/#${sectionBlurb}`); + + const subsectionBlurbs = normalizeArray(section["subsection-blurbs"]); + subsectionBlurbs.forEach((blurbSlug) => { + addBlurbRoute(map, blurbSlug, `/#${blurbSlug}`); + }); + }); + + const sidebarBlurb = frontMatter.sidebar_blurb; + addBlurbRoute(map, sidebarBlurb, `/#${sidebarBlurb}`); + } + } catch (error) { + console.error("Failed to load homepage config for blurbs:", error); + } + } + + const overviewPaths = await glob(path.join(CONTENT_DIR, "overview/**/*.md")); + for (const filePath of overviewPaths) { + const filename = path.basename(filePath); + if (EXCLUDED_FILE_NAMES.has(filename)) { + continue; + } + + let rawContent; + try { + rawContent = fs.readFileSync(filePath, "utf-8"); + } catch (error) { + console.error(`Failed to read ${filePath}:`, error); + continue; + } + + const frontMatter = parseFrontMatter(rawContent, filePath); + if (!frontMatter) { + continue; + } + + const blurbs = normalizeArray(frontMatter.blurbs); + if (!blurbs.length) { + continue; + } + + const relativePath = path + .relative(CONTENT_DIR, filePath) + .replace(/\\/g, "/"); + const segments = relativePath.split("/"); + const slug = path.basename(filename, ".md"); + const routeInfo = resolveOverviewEntry(segments, slug, relativePath); + + if (!routeInfo) { + continue; + } + + blurbs.forEach((blurbSlug) => { + addBlurbRoute(map, blurbSlug, `${routeInfo.path}#${blurbSlug}`, { overwrite: true }); + }); + } + + return map; +}; + +const resolveEntry = (relativePath, blurbRoutes) => { const segments = relativePath.split("/"); const filename = segments[segments.length - 1]; const slug = path.basename(filename, ".md"); const section = segments[0]; - if (EXCLUDED_SLUGS.has(slug)) { - return null; + if (section === "overview") { + return resolveOverviewEntry(segments, slug, relativePath); } - if (section === "overview") { - const overviewSection = segments[1]; - if (!overviewSection) { - console.warn(`Skipping overview content without subsection: ${relativePath}`); - return null; - } + if (section === "blog") { + return { path: `/blog/${slug}`, section: "blog" }; + } - const isIntro = slug === "intro"; - const pathSuffix = isIntro - ? `/overview/${overviewSection}` - : `/overview/${overviewSection}/${slug}`; + if (section === "blurbs") { + const targetPath = blurbRoutes?.get(slug); + if (!targetPath) { + console.warn(`Blurb missing route mapping: ${relativePath}`); + return { path: `/#${slug}`, section: "pages" }; + } return { - path: pathSuffix, - section: "overview", - subsection: overviewSection, - subsectionLabel: toTitleCase(overviewSection), + path: targetPath, + ...deriveSectionInfoFromPath(targetPath), }; } - if (section === "blog") { - return { path: `/blog/${slug}`, section: "blog" }; + if (section === "homepage") { + return { path: `/#${slug}`, section: "pages" }; } if (section === "grants") { @@ -116,10 +328,6 @@ const resolveEntry = (relativePath) => { return { path: `/events/${slug}`, section: "events" }; } - if (section === "singles") { - return { path: `/${slug}`, section: "pages" }; - } - if (segments.length === 1) { return { path: `/${slug}`, section: "pages" }; } @@ -148,7 +356,12 @@ async function buildSearchIndex() { fs.mkdirSync(outputDir, { recursive: true }); } - const postPaths = await glob(path.join(CONTENT_DIR, "**/*.md")); + const blurbRoutes = await buildBlurbRouteMap(); + const contentGlob = path.join( + CONTENT_DIR, + `{${Array.from(INCLUDED_DIRECTORIES).join(",")}}/**/*.md` + ); + const postPaths = await glob(contentGlob); const entries = []; const errors = []; @@ -163,7 +376,7 @@ async function buildSearchIndex() { continue; } - if (segments.some((segment) => EXCLUDED_DIRECTORIES.has(segment))) { + if (!INCLUDED_DIRECTORIES.has(segments[0])) { continue; } @@ -182,7 +395,7 @@ async function buildSearchIndex() { continue; } - const routeInfo = resolveEntry(relativePath); + const routeInfo = resolveEntry(relativePath, blurbRoutes); if (!routeInfo) { continue; } @@ -194,22 +407,38 @@ async function buildSearchIndex() { frontMatter.extra?.description || ""; const tags = collectTags(frontMatter); + const searchTerms = normalizeSearchTerms( + frontMatter.search_terms || frontMatter.searchTerms + ); + const authors = collectAuthors(frontMatter); + const publishedTimestamp = parsePublishedTimestamp(frontMatter); const sectionLabel = SECTION_LABELS[routeInfo.section] || toTitleCase(routeInfo.section); - const searchText = [ + const entryId = relativePath; + const source = segments[0]; + const frontMatterValues = collectFrontMatterValues(frontMatter); + const searchText = uniqueStrings([ title, description, tags.join(" "), + searchTerms.join(" "), + authors.join(" "), routeInfo.path, sectionLabel, routeInfo.subsectionLabel || "", - ] + ...frontMatterValues, + ]) .join(" ") .toLowerCase(); entries.push({ + id: entryId, title, description, tags, + searchTerms, + authors, + publishedTimestamp, + source, path: routeInfo.path, section: routeInfo.section, sectionLabel, From 96868e322f50865b9df128a944104d19a1effc64 Mon Sep 17 00:00:00 2001 From: thelifeandtimes Date: Thu, 5 Mar 2026 12:26:39 -0800 Subject: [PATCH 4/4] docs: backfill search terms Improve urbit.org search relevance by adding search_terms frontmatter. --- app/content/blog/2019-10-3-roadmap.md | 13 +++++++++++++ app/content/blog/2019-5-roadmap.md | 13 +++++++++++++ app/content/blog/2020-to-2021.md | 14 ++++++++++++++ app/content/blog/20200929-state-of-urbit.md | 14 ++++++++++++++ app/content/blog/20201119-models-of-society.md | 14 ++++++++++++++ .../blog/2021-11-18-report-from-the-field.md | 12 ++++++++++++ ...-the-promise-and-paradox-of-decentralization.md | 12 ++++++++++++ .../2025-a-new-epoch-for-the-forever-computer.md | 12 ++++++++++++ app/content/blog/a-founders-farewell.md | 13 +++++++++++++ app/content/blog/a-topiary.md | 14 ++++++++++++++ app/content/blog/aesthetic-culture-1.md | 13 +++++++++++++ app/content/blog/after-machine-war.md | 14 ++++++++++++++ app/content/blog/agency-daos.md | 12 ++++++++++++ app/content/blog/an-email.md | 14 ++++++++++++++ app/content/blog/an-urbit-overview.md | 13 +++++++++++++ app/content/blog/announcing-urbit-grants.md | 12 ++++++++++++ app/content/blog/ares.md | 12 ++++++++++++ app/content/blog/august-2022-grants-program.md | 12 ++++++++++++ app/content/blog/azimuth-as-multipass.md | 12 ++++++++++++ app/content/blog/azimuth-is-on-chain.md | 14 ++++++++++++++ .../blog/azimuth-security-bounty-program.md | 12 ++++++++++++ app/content/blog/beliefs-and-principles.md | 12 ++++++++++++ .../blog/bootstrapping-urbit-from-ethereum.md | 13 +++++++++++++ .../blog/building-beyond-beginner-guitar.md | 13 +++++++++++++ app/content/blog/common-objections-to-urbit.md | 12 ++++++++++++ .../blog/community-spotlight-the-portico.md | 13 +++++++++++++ .../blog/contributor-spotlight-dozreg-toplud.md | 13 +++++++++++++ .../blog/contributor-spotlight-mastyr-bottec.md | 13 +++++++++++++ ...or-spotlight-niblyx-malnus-and-bonbud-macryg.md | 13 +++++++++++++ .../blog/contributor-spotlight-nordus-mocwyl.md | 13 +++++++++++++ app/content/blog/convivial-networks.md | 12 ++++++++++++ app/content/blog/creating-sigils.md | 13 +++++++++++++ app/content/blog/desire-lines.md | 12 ++++++++++++ app/content/blog/developer-preview-vere64.md | 12 ++++++++++++ app/content/blog/eliza.md | 14 ++++++++++++++ app/content/blog/events-series.md | 13 +++++++++++++ app/content/blog/first-contract.md | 14 ++++++++++++++ app/content/blog/first-steps-towards-urbit-org.md | 13 +++++++++++++ app/content/blog/ford-fusion.md | 13 +++++++++++++ app/content/blog/foss-1.md | 12 ++++++++++++ app/content/blog/foss-2.md | 12 ++++++++++++ app/content/blog/gifts-q3-2020.md | 12 ++++++++++++ app/content/blog/governance-of-urbit.md | 12 ++++++++++++ app/content/blog/hackathon-2023.md | 14 ++++++++++++++ app/content/blog/hackathon-results.md | 12 ++++++++++++ app/content/blog/haleek-maul-interview.md | 14 ++++++++++++++ app/content/blog/hoon-4-lispers.md | 13 +++++++++++++ app/content/blog/hosting-the-future.md | 13 +++++++++++++ .../blog/immunology-for-the-internet-age.md | 12 ++++++++++++ app/content/blog/infrastructural.md | 13 +++++++++++++ app/content/blog/interim-constitution.md | 12 ++++++++++++ app/content/blog/interplanetary_commerce.md | 14 ++++++++++++++ app/content/blog/introducing-os1.md | 13 +++++++++++++ .../blog/introduction-to-the-combine-dao.md | 12 ++++++++++++ app/content/blog/io-in-hoon.md | 14 ++++++++++++++ app/content/blog/iot.md | 14 ++++++++++++++ app/content/blog/landscape-a-portrait.md | 13 +++++++++++++ app/content/blog/layer-2-faq.md | 12 ++++++++++++ app/content/blog/llms-on-urbit.md | 14 ++++++++++++++ app/content/blog/magic.md | 12 ++++++++++++ app/content/blog/metaphase.md | 14 ++++++++++++++ app/content/blog/nockmas-2025-day-1.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-10.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-11.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-12.md | 12 ++++++++++++ app/content/blog/nockmas-2025-day-2.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-3.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-4.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-5.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-6.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-7.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-8.md | 11 +++++++++++ app/content/blog/nockmas-2025-day-9.md | 11 +++++++++++ app/content/blog/nockmas-2025-welcome.md | 11 +++++++++++ app/content/blog/nockpu.md | 11 +++++++++++ app/content/blog/olif-and-urbit-ids.md | 14 ++++++++++++++ app/content/blog/on-christopher-alexander.md | 14 ++++++++++++++ .../pin-the-face-that-launches-a-thousand-ships.md | 12 ++++++++++++ app/content/blog/pki-maze.md | 13 +++++++++++++ app/content/blog/platform-decay.md | 13 +++++++++++++ app/content/blog/precepts-discussion.md | 13 +++++++++++++ app/content/blog/precepts.md | 14 ++++++++++++++ app/content/blog/providers.md | 13 +++++++++++++ app/content/blog/pseudonymous-reputation.md | 12 ++++++++++++ app/content/blog/rollups.md | 14 ++++++++++++++ app/content/blog/security-and-continuity.md | 14 ++++++++++++++ app/content/blog/security-audit.md | 14 ++++++++++++++ app/content/blog/simple-durable-yours.md | 12 ++++++++++++ app/content/blog/smart-home-of-the-future.md | 12 ++++++++++++ app/content/blog/sovereign-intelligence.md | 13 +++++++++++++ app/content/blog/stable-arvo.md | 13 +++++++++++++ app/content/blog/state-of-urbit.md | 14 ++++++++++++++ app/content/blog/subassembly-hackathon-2024.md | 12 ++++++++++++ app/content/blog/the-100-year-computer.md | 12 ++++++++++++ ...-dao-as-a-lesson-in-decentralized-governance.md | 12 ++++++++++++ app/content/blog/the-missing-middle.md | 13 +++++++++++++ .../blog/the-shape-of-dao-governance-to-come.md | 12 ++++++++++++ app/content/blog/the-state-of-landscape.md | 12 ++++++++++++ .../blog/the-understanding-urbit-podcast.md | 12 ++++++++++++ app/content/blog/the-urbit-address-space.md | 12 ++++++++++++ app/content/blog/tools-of-our-own.md | 13 +++++++++++++ .../blog/toward-a-frozen-operating-system.md | 12 ++++++++++++ app/content/blog/toward-a-new-clay.md | 12 ++++++++++++ app/content/blog/urbit-and-bitcoin.md | 12 ++++++++++++ app/content/blog/urbit-and-the-blockchain.md | 12 ++++++++++++ app/content/blog/urbit-creator-daos.md | 12 ++++++++++++ app/content/blog/urbit-for-creators.md | 12 ++++++++++++ app/content/blog/urbit-for-normies.md | 13 +++++++++++++ .../blog/urbit-grants-and-mid-2019-gifts.md | 11 +++++++++++ app/content/blog/urbit-is-for-communities.md | 13 +++++++++++++ app/content/blog/urbithost-interview.md | 14 ++++++++++++++ app/content/blog/using-urbit-in-2023.md | 12 ++++++++++++ app/content/blog/value-of-address-space-pt1.md | 13 +++++++++++++ app/content/blog/value-of-address-space-pt2.md | 14 ++++++++++++++ app/content/blog/value-of-address-space-pt3.md | 13 +++++++++++++ app/content/blog/what-is-urbit-for.md | 12 ++++++++++++ app/content/blog/why-hoon.md | 13 +++++++++++++ ...hy-urbit-probably-does-not-need-a-blockchain.md | 12 ++++++++++++ app/content/blog/your-last-computer.md | 12 ++++++++++++ app/content/blurbs/add-and-remove-applications.md | 12 ++++++++++++ app/content/blurbs/azimuth-based-urbit-ids.md | 13 +++++++++++++ app/content/blurbs/build-out-your-urbit.md | 13 +++++++++++++ app/content/blurbs/buy-an-urbit-id.md | 14 ++++++++++++++ .../blurbs/check-and-reduce-memory-usage.md | 12 ++++++++++++ app/content/blurbs/check-application-status.md | 12 ++++++++++++ app/content/blurbs/check-your-sponsor.md | 11 +++++++++++ .../blurbs/checking-and-fixing-azimuth-state.md | 12 ++++++++++++ .../blurbs/common-pitfalls-of-running-urbit.md | 11 +++++++++++ app/content/blurbs/create-a-moon-identity.md | 12 ++++++++++++ .../blurbs/directly-contact-another-urbit.md | 11 +++++++++++ app/content/blurbs/docking-your-urbit.md | 11 +++++++++++ app/content/blurbs/docs-for-self-hosting-urbit.md | 12 ++++++++++++ app/content/blurbs/get-access-code.md | 11 +++++++++++ .../blurbs/get-started-with-cloud-server.md | 12 ++++++++++++ .../blurbs/get-started-with-command-line.md | 12 ++++++++++++ .../blurbs/get-started-with-native-planet.md | 12 ++++++++++++ .../blurbs/get-started-with-tlon-hosting.md | 12 ++++++++++++ app/content/blurbs/getting-started-with-urbit.md | 12 ++++++++++++ app/content/blurbs/groundwire-based-urbit-ids.md | 12 ++++++++++++ app/content/blurbs/homepage-go-deeper.md | 11 +++++++++++ app/content/blurbs/homepage-hosting-providers.md | 11 +++++++++++ app/content/blurbs/homepage-self-hosting.md | 11 +++++++++++ app/content/blurbs/learn-to-hoon.md | 12 ++++++++++++ app/content/blurbs/reduce-your-pier-size.md | 12 ++++++++++++ app/content/blurbs/run-urbit-in-a-vps.md | 12 ++++++++++++ app/content/blurbs/run-urbit-locally.md | 12 ++++++++++++ app/content/blurbs/run-urbit-using-groundseg.md | 12 ++++++++++++ .../run-urbit-using-native-planet-hardware.md | 12 ++++++++++++ app/content/blurbs/run-urbit-with-tlon-hosting.md | 12 ++++++++++++ app/content/blurbs/select-available-loom-size.md | 11 +++++++++++ app/content/blurbs/self-custody-your-id.md | 12 ++++++++++++ .../blurbs/shortfalls-of-hosting-providers.md | 11 +++++++++++ app/content/blurbs/shut-down-your-urbit.md | 11 +++++++++++ .../start-and-stop-applications-on-your-urbit.md | 11 +++++++++++ app/content/blurbs/start-up-your-urbit.md | 11 +++++++++++ app/content/blurbs/support-contact-points.md | 11 +++++++++++ app/content/blurbs/troubleshooting-your-urbit.md | 10 ++++++++++ .../blurbs/update-commands-for-your-urbit.md | 11 +++++++++++ app/content/blurbs/update-your-urbit-runtime.md | 11 +++++++++++ app/content/blurbs/urbit-as-overlay-os.md | 12 ++++++++++++ .../blurbs/urbit-id-incentives-for-hosts.md | 12 ++++++++++++ app/content/blurbs/urbit-master-ticket-wallets.md | 12 ++++++++++++ app/content/blurbs/urbit-related-blogs.md | 11 +++++++++++ app/content/blurbs/urbit-support-groups.md | 12 ++++++++++++ .../blurbs/urbit-systems-technical-journal.md | 12 ++++++++++++ app/content/blurbs/why-hosting-providers.md | 12 ++++++++++++ 166 files changed, 2047 insertions(+) diff --git a/app/content/blog/2019-10-3-roadmap.md b/app/content/blog/2019-10-3-roadmap.md index 188e3ceaa2..2397a9d4f7 100644 --- a/app/content/blog/2019-10-3-roadmap.md +++ b/app/content/blog/2019-10-3-roadmap.md @@ -6,6 +6,19 @@ aliases = [ "/posts/essays/2019-10-3-roadmap", "/posts/2019-10-3-roadmap" ] +search_terms = [ + "2019 roadmap", + "urbit roadmap", + "bridge update", + "sigils", + "arvo updates", + "landscape modules", + "hoon school", + "grants program", + "identity stack", + "urbit interface", + "os updates" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/2019-5-roadmap.md b/app/content/blog/2019-5-roadmap.md index bfe7fd1b69..2d729bfe2d 100644 --- a/app/content/blog/2019-5-roadmap.md +++ b/app/content/blog/2019-5-roadmap.md @@ -3,6 +3,19 @@ title = "~2019.5 Roadmap" date = "2019-05-15" description = "Where we are and where we're going as of mid-2019." aliases = [ "/posts/essays/2019-5-roadmap", "/posts/2019-5-roadmap" ] +search_terms = [ + "2019 roadmap", + "azimuth", + "bridge", + "arvo updates", + "landscape modulo", + "hoon school", + "grants program", + "urbit roadmap", + "daemon updates", + "community plans", + "arvo interface" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/2020-to-2021.md b/app/content/blog/2020-to-2021.md index f40db8a6fa..478a228156 100644 --- a/app/content/blog/2020-to-2021.md +++ b/app/content/blog/2020-to-2021.md @@ -2,6 +2,20 @@ title = "2020 -> 2021" description = "Reflecting and looking forward." date = "2021-01-20" +search_terms = [ + "2020 review", + "2021 outlook", + "landscape os1", + "urbit hosting", + "urbit org", + "community growth", + "ota updates", + "developer guides", + "grants program", + "continuity breach", + "urbit roadmap", + "network reset" +] [extra] author = "Josh Lehman" diff --git a/app/content/blog/20200929-state-of-urbit.md b/app/content/blog/20200929-state-of-urbit.md index d245e424fb..76c6df2591 100644 --- a/app/content/blog/20200929-state-of-urbit.md +++ b/app/content/blog/20200929-state-of-urbit.md @@ -2,6 +2,20 @@ title = "Late 2020 Progress Update: OS 1 -> OS 1.N" date = "2020-09-28" description = "When we announced OS 1, in April, we started to disappear into Urbit. Since then, we’ve been living on Urbit like we never have before." +search_terms = [ + "os1 updates", + "state of urbit", + "landscape improvements", + "ota updates", + "graph store", + "performance gains", + "memory usage", + "indigo ui", + "leap omnibox", + "urbit progress", + "network stability", + "community growth" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/20201119-models-of-society.md b/app/content/blog/20201119-models-of-society.md index d1d6b38163..ac8ddbcf8e 100644 --- a/app/content/blog/20201119-models-of-society.md +++ b/app/content/blog/20201119-models-of-society.md @@ -2,6 +2,20 @@ title = "Models of Society" description = "Conversations compose society. What composes conversation — how do we digitize it in a way that enhances society without imposing upon it? How do we form this new medium, both to facilitate natural human behavior and to inspire the best of it?" date = "2020-11-18" +search_terms = [ + "models of society", + "digital messaging", + "conversation forms", + "identity and place", + "digital spaces", + "urbit territory", + "messaging modes", + "hypertext", + "social networks", + "urbit identity", + "digital city", + "community spaces" +] [extra] author = "Tyler Shuster" diff --git a/app/content/blog/2021-11-18-report-from-the-field.md b/app/content/blog/2021-11-18-report-from-the-field.md index 25f975db84..bba21161f8 100644 --- a/app/content/blog/2021-11-18-report-from-the-field.md +++ b/app/content/blog/2021-11-18-report-from-the-field.md @@ -2,6 +2,18 @@ title = "Report from the field: Assembly 2021" date = "2021-11-18" description = "The system builds the community and the community builds the system." +search_terms = [ + "assembly 2021", + "report from the field", + "urbit assembly", + "new world energy", + "software distribution", + "star market", + "urbit foundation", + "developers.urbit.org", + "operators.urbit.org", + "urbit community" +] [extra] author = "Galen Wolfe-Pauly" ship = "~ravmel-ropdyl" diff --git a/app/content/blog/2021-11-18-the-promise-and-paradox-of-decentralization.md b/app/content/blog/2021-11-18-the-promise-and-paradox-of-decentralization.md index 6f07014d01..cec374fc3b 100644 --- a/app/content/blog/2021-11-18-the-promise-and-paradox-of-decentralization.md +++ b/app/content/blog/2021-11-18-the-promise-and-paradox-of-decentralization.md @@ -2,6 +2,18 @@ title = "The Promise and Paradox of Decentralization" date = "2021-11-17" description = "Is centralization just a natural tendency of all networks? Are we destined to have a 'decentralization sandwich?'" +search_terms = [ + "decentralization paradox", + "centralization", + "onramps", + "ownership of data", + "open protocols", + "decentralization sandwich", + "urbit identity", + "centralized platforms", + "norms", + "protocol governance" +] [extra] author = "" ship = "~lableg-tadrex" diff --git a/app/content/blog/2025-a-new-epoch-for-the-forever-computer.md b/app/content/blog/2025-a-new-epoch-for-the-forever-computer.md index 6d32d4b36a..bf45a19efc 100644 --- a/app/content/blog/2025-a-new-epoch-for-the-forever-computer.md +++ b/app/content/blog/2025-a-new-epoch-for-the-forever-computer.md @@ -3,6 +3,18 @@ title = "A New Epoch for The Forever Computer" date = "2025-10-9" description = "On the further decentralization of Urbit and the next era of the Urbit Foundation" # aliases = [] +search_terms = [ + "urbit foundation", + "new epoch", + "forever computer", + "decentralization", + "galactic senate", + "governance", + "board of directors", + "executive director", + "urbit community", + "public goods" +] [extra] author = "The Urbit Foundation" diff --git a/app/content/blog/a-founders-farewell.md b/app/content/blog/a-founders-farewell.md index 04b91ab45a..37c213e5be 100644 --- a/app/content/blog/a-founders-farewell.md +++ b/app/content/blog/a-founders-farewell.md @@ -6,6 +6,19 @@ aliases = [ "/posts/essays/a-founders-farewell", "/posts/a-founders-farewell" ] +search_terms = [ + "founders farewell", + "curtis yarvin", + "urbit founder", + "project handoff", + "tlon", + "galaxy distribution", + "urbit history", + "open source", + "urbit governance", + "technical report", + "urbit transition" +] [extra] author = "Curtis Yarvin" diff --git a/app/content/blog/a-topiary.md b/app/content/blog/a-topiary.md index 70e040ba49..4dca0b45f4 100644 --- a/app/content/blog/a-topiary.md +++ b/app/content/blog/a-topiary.md @@ -2,6 +2,20 @@ title = "A Topiary: Hypertext and Urbit" date = "2021-06-13" description = "A brief history of hypertext and Urbit networking" +search_terms = [ + "hypertext history", + "urbit networking", + "graph store", + "linked data", + "project xanadu", + "world wide web", + "social networks", + "peer to peer", + "graph databases", + "urbit graph", + "digital hypertext", + "network protocols" +] [extra] author = "Reid Scoggin" diff --git a/app/content/blog/aesthetic-culture-1.md b/app/content/blog/aesthetic-culture-1.md index d69cdec5c8..9c447e227e 100644 --- a/app/content/blog/aesthetic-culture-1.md +++ b/app/content/blog/aesthetic-culture-1.md @@ -2,6 +2,19 @@ title = "Aesthetic Culture #1" description = "One of the most exciting things about Urbit is the aesthetic and design around it, developed partly by Tlon (through the design of Urbit itself) and partly by the community (by producing great Urbit art)." date = "2020-11-11" +search_terms = [ + "urbit art", + "aesthetic culture", + "sigil art", + "community art", + "art digest", + "urbit design", + "urbit memes", + "landscape themes", + "urbit creators", + "visual culture", + "urbit aesthetics" +] [extra] description = "One of the most exciting things about Urbit is the aesthetic and design around it, developed partly by Tlon (through the design of Urbit itself) and partly by the community (by producing great Urbit art)." diff --git a/app/content/blog/after-machine-war.md b/app/content/blog/after-machine-war.md index e309381ffb..0196430eee 100644 --- a/app/content/blog/after-machine-war.md +++ b/app/content/blog/after-machine-war.md @@ -2,6 +2,20 @@ title = "After the Machine War" description = "The date is January 1, 2050. The place, New York City. The vibe...subdued." date = "2021-03-14" +search_terms = [ + "after machine war", + "speculative fiction", + "digital dystopia", + "urbit future", + "permanent identities", + "peer to peer", + "2050 future", + "content moderation", + "megacorp world", + "surveillance tech", + "urbit optimism", + "future internet" +] [extra] author = "Simon Kovacs" diff --git a/app/content/blog/agency-daos.md b/app/content/blog/agency-daos.md index a9f7876c9e..c50ab316fa 100644 --- a/app/content/blog/agency-daos.md +++ b/app/content/blog/agency-daos.md @@ -2,6 +2,18 @@ title = "The Dream of the Agency DAO" date = "2022-11-04" 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." +search_terms = [ + "agency dao", + "creative agency", + "tokenization", + "branding industry", + "decentralized marketing", + "creative bounties", + "talent retention", + "idea valuation", + "urbit ids", + "creative reputation" +] [extra] author = "Isaac Simpson" diff --git a/app/content/blog/an-email.md b/app/content/blog/an-email.md index b91549af46..2c367097ba 100644 --- a/app/content/blog/an-email.md +++ b/app/content/blog/an-email.md @@ -2,6 +2,20 @@ title = "An Email from the Archive" description = "I found this email in my archives recently and thought it might be fun to share publicly." date = "2020-11-29" +search_terms = [ + "email from archive", + "simplicity", + "durability", + "ownership", + "urbit philosophy", + "digital tools", + "personal computing", + "decentralized network", + "software craftsmanship", + "christopher alexander", + "future vision", + "network institutions" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/an-urbit-overview.md b/app/content/blog/an-urbit-overview.md index 626c899227..bdab0499bb 100644 --- a/app/content/blog/an-urbit-overview.md +++ b/app/content/blog/an-urbit-overview.md @@ -2,6 +2,19 @@ title = "An Urbit Overview" date = "2016-05-10" description = "A high-level overview of Urbit." +search_terms = [ + "urbit overview", + "personal server", + "urbit os", + "digital independence", + "urbit address space", + "urbit identity", + "nock hoon arvo", + "encrypted p2p", + "urbit network", + "clean slate stack", + "virtual city" +] aliases = [ "/posts/essays/an-urbit-overview", "/posts/an-urbit-overview" diff --git a/app/content/blog/announcing-urbit-grants.md b/app/content/blog/announcing-urbit-grants.md index 4c1a2c8f61..2a2fa8c866 100644 --- a/app/content/blog/announcing-urbit-grants.md +++ b/app/content/blog/announcing-urbit-grants.md @@ -6,6 +6,18 @@ aliases = [ "/posts/essays/announcing-urbit-grants", "/posts/announcing-urbit-grants" ] +search_terms = [ + "urbit grants", + "grants program", + "bounties", + "gifts", + "proposals", + "azimuth stars", + "contributor rewards", + "grants website", + "community funding", + "urbit bounties" +] [extra] author = "Robert Mariani" diff --git a/app/content/blog/ares.md b/app/content/blog/ares.md index 30d095319d..292042f2b6 100644 --- a/app/content/blog/ares.md +++ b/app/content/blog/ares.md @@ -2,6 +2,18 @@ title = "Ares" date = "2023-06-26" description = "A light technical description of Ares, the new Urbit runtime" +search_terms = [ + "ares runtime", + "urbit runtime", + "subject knowledge analysis", + "2stackz", + "persistent memory arena", + "nock codegen", + "single level store", + "runtime performance", + "large data", + "ares release" +] [extra] author = "Noah Kumin" diff --git a/app/content/blog/august-2022-grants-program.md b/app/content/blog/august-2022-grants-program.md index 6bba1d1bca..1207bcde2f 100644 --- a/app/content/blog/august-2022-grants-program.md +++ b/app/content/blog/august-2022-grants-program.md @@ -2,6 +2,18 @@ title = "August Grants Program Review" date = "2022-08-30" 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." +search_terms = [ + "grants program", + "hoon school", + "app school", + "grant review", + "bounties", + "apprenticeships", + "urbit foundation grants", + "completed grants", + "proposals", + "assembly 2022" +] [extra] author = "" ship = "~sarlev-sarsen" diff --git a/app/content/blog/azimuth-as-multipass.md b/app/content/blog/azimuth-as-multipass.md index 928e60d7d4..b8d283b080 100644 --- a/app/content/blog/azimuth-as-multipass.md +++ b/app/content/blog/azimuth-as-multipass.md @@ -6,6 +6,18 @@ aliases = [ "/posts/essays/azimuth-as-multipass/", "/posts/azimuth-as-multipass" ] +search_terms = [ + "azimuth multipass", + "civilizational key", + "azimuth identity", + "single login", + "urbit wallet", + "digital identity", + "multipass", + "azimuth point", + "urbit access", + "identity card" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/azimuth-is-on-chain.md b/app/content/blog/azimuth-is-on-chain.md index c10d275ae5..499be64cf7 100644 --- a/app/content/blog/azimuth-is-on-chain.md +++ b/app/content/blog/azimuth-is-on-chain.md @@ -2,6 +2,20 @@ title = "Azimuth is On-Chain" date = "2019-01-13" description = "The Urbit address space, now called Azimuth, is on the blockchain. And too many other things to fit into a single post." +search_terms = [ + "azimuth on chain", + "urbit address space", + "ethereum contracts", + "urbit identity", + "azimuth pki", + "ecliptic contract", + "erc-721 points", + "bridge interface", + "urbit os arvo", + "landscape cities", + "urbit pki", + "azimuth points" +] aliases = [ "/posts/essays/azimuth-is-on-chain", "/posts/azimuth-is-on-chain" diff --git a/app/content/blog/azimuth-security-bounty-program.md b/app/content/blog/azimuth-security-bounty-program.md index 48f5040fcf..8d43ec9d2b 100644 --- a/app/content/blog/azimuth-security-bounty-program.md +++ b/app/content/blog/azimuth-security-bounty-program.md @@ -6,6 +6,18 @@ aliases = [ "/posts/essays/azimuth-security-bounty-program", "/posts/azimuth-security-bounty-program" ] +search_terms = [ + "azimuth security", + "bounty program", + "hackerone", + "smart contracts", + "urbit pki", + "security audit", + "bridge testing", + "vulnerability report", + "security bounties", + "azimuth contracts" +] [extra] author = "Anthony Arroyo" diff --git a/app/content/blog/beliefs-and-principles.md b/app/content/blog/beliefs-and-principles.md index 4b1519779a..35a5cb337f 100644 --- a/app/content/blog/beliefs-and-principles.md +++ b/app/content/blog/beliefs-and-principles.md @@ -2,6 +2,18 @@ title = "Beliefs and Principles Guiding the Urbit Project" date = "2016-05-10" description = "We believe." +search_terms = [ + "urbit principles", + "urbit beliefs", + "digital independence", + "code is law", + "decentralized control", + "property rights", + "governance by stake", + "content neutrality", + "urbit republic", + "network governance" +] aliases = [ "/posts/essays/beliefs-and-principles", "/posts/beliefs-and-principles", diff --git a/app/content/blog/bootstrapping-urbit-from-ethereum.md b/app/content/blog/bootstrapping-urbit-from-ethereum.md index af4386b7e9..253e8ec5e1 100644 --- a/app/content/blog/bootstrapping-urbit-from-ethereum.md +++ b/app/content/blog/bootstrapping-urbit-from-ethereum.md @@ -2,6 +2,19 @@ title = "Bootstrapping Urbit from Ethereum" date = "2017-09-19" description = "We've decided to launch Urbit's constitution as a system of Ethereum contracts." +search_terms = [ + "bootstrapping urbit", + "ethereum contracts", + "urbit constitution", + "azimuth pki", + "urbit address space", + "spark token", + "galaxy governance", + "on chain registry", + "urbit on ethereum", + "urbit land registry", + "planet sales" +] aliases = [ "/posts/essays/bootstrapping-urbit-from-ethereum", "/posts/bootstrapping-urbit-from-ethereum", diff --git a/app/content/blog/building-beyond-beginner-guitar.md b/app/content/blog/building-beyond-beginner-guitar.md index 4b098dfc91..dbf6c88b60 100644 --- a/app/content/blog/building-beyond-beginner-guitar.md +++ b/app/content/blog/building-beyond-beginner-guitar.md @@ -14,6 +14,19 @@ imageIndex = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog_Buil # imageCardDark = # imageIndexDark = tags = ["courseware", "hawk", "userspace"] +search_terms = [ + "beyond beginner guitar", + "hawk courseware", + "urbit business", + "guitar course", + "urbit hosting", + "stripe payments", + "crypto payments", + "access control", + "urbit userspace", + "course community", + "self sovereign" +] +++ diff --git a/app/content/blog/common-objections-to-urbit.md b/app/content/blog/common-objections-to-urbit.md index e172f94a85..b4e4331ec0 100644 --- a/app/content/blog/common-objections-to-urbit.md +++ b/app/content/blog/common-objections-to-urbit.md @@ -2,6 +2,18 @@ title = "Common Objections to Urbit" date = "2016-06-27" description = "Some common objections to Urbit, discussed." +search_terms = [ + "urbit objections", + "urbit critiques", + "urbit decentralization", + "urbit governance", + "hoon language", + "nock jets", + "urbit adoption", + "urbit scalability", + "urbit security", + "personal server concerns" +] aliases = [ "/posts/essays/common-objections-to-urbit", "/posts/common-objections-to-urbit", diff --git a/app/content/blog/community-spotlight-the-portico.md b/app/content/blog/community-spotlight-the-portico.md index c1fb32e426..d3a4ecbd7c 100644 --- a/app/content/blog/community-spotlight-the-portico.md +++ b/app/content/blog/community-spotlight-the-portico.md @@ -2,6 +2,19 @@ title = "Community Spotlight: The Portico" date = "2021-05-03" description = "Interview with The Portico founder Josh Reagan" +search_terms = [ + "portico community", + "orthodox christian", + "community spotlight", + "urbit groups", + "theology and logic", + "religious community", + "eternal september", + "decentralized communities", + "urbit culture", + "philosophy of religion", + "niche communities" +] [extra] author = "Matt" diff --git a/app/content/blog/contributor-spotlight-dozreg-toplud.md b/app/content/blog/contributor-spotlight-dozreg-toplud.md index f3706ce9e9..660351caab 100644 --- a/app/content/blog/contributor-spotlight-dozreg-toplud.md +++ b/app/content/blog/contributor-spotlight-dozreg-toplud.md @@ -8,6 +8,19 @@ description = "A peek into the mind behind UrWASM, and the undertaking to make U ship = "~sarlev-sarsen" image = "/images/dozreg-toplud-spotlight.png" tags = ["spotlight", "UrWASM", "subject-knowledge analysis"] +search_terms = [ + "contributor spotlight", + "dozreg toplud", + "urwasm", + "subject knowledge analysis", + "ford build system", + "nock speed", + "runtime performance", + "urbit simplicity", + "security permissions", + "gall tooling", + "directed messaging" +] +++ > **\~sarlev:** What about Urbit drew you in and captured your attention? diff --git a/app/content/blog/contributor-spotlight-mastyr-bottec.md b/app/content/blog/contributor-spotlight-mastyr-bottec.md index 28dfd148b8..baccc09c62 100644 --- a/app/content/blog/contributor-spotlight-mastyr-bottec.md +++ b/app/content/blog/contributor-spotlight-mastyr-bottec.md @@ -14,6 +14,19 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog_QA+mastyr # imageCardDark = # imageIndexDark = tags = ["spotlight", "vere64", "runtime"] +search_terms = [ + "contributor spotlight", + "mastyr bottec", + "vere64", + "runtime developer", + "large data", + "loom size", + "runtime migration", + "directed messaging", + "nock runtime", + "storage scaling", + "urbit runtime" +] +++ > **\~sarlev:** So, starting at the top, what's the first thing that drew you into the idea that we needed to throw away and rewrite the entire network computing stack? Or are you even sold on that? diff --git a/app/content/blog/contributor-spotlight-niblyx-malnus-and-bonbud-macryg.md b/app/content/blog/contributor-spotlight-niblyx-malnus-and-bonbud-macryg.md index 3c7375182a..e291a527e5 100644 --- a/app/content/blog/contributor-spotlight-niblyx-malnus-and-bonbud-macryg.md +++ b/app/content/blog/contributor-spotlight-niblyx-malnus-and-bonbud-macryg.md @@ -14,6 +14,19 @@ imageCard = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog+QA+~n # imageCardDark = # imageIndexDark = tags = ["AI", "design", "architecture"] +search_terms = [ + "contributor spotlight", + "groundwire", + "bonbud macryg", + "niblyx malnus", + "urbit ai", + "llm tools", + "christopher alexander", + "mcp server", + "urbit master", + "architecture design", + "hoon" +] +++ > **\~sarlev:** This is our first two-person spotlight interview, so we'll see how it goes and adapt accordingly. I generally like to start by just asking, what first drew you into the idea that we needed to throw away and rewrite the entire networked computing stack? diff --git a/app/content/blog/contributor-spotlight-nordus-mocwyl.md b/app/content/blog/contributor-spotlight-nordus-mocwyl.md index 780ada937a..c58f7099eb 100644 --- a/app/content/blog/contributor-spotlight-nordus-mocwyl.md +++ b/app/content/blog/contributor-spotlight-nordus-mocwyl.md @@ -14,6 +14,19 @@ imageCard = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog_QA+no # imageCardDark = # imageIndexDark = tags = ["spotlight", "userspace", "community"] +search_terms = [ + "contributor spotlight", + "nordus mocwyl", + "independent music", + "musician", + "urbit for creators", + "hawk website", + "guitar course", + "direct charity", + "personal server", + "hoon learning", + "sovereign web" +] +++ > **\~sarlev:** What drew you into the idea that we needed to throw away and rewrite the entire network computing stack? diff --git a/app/content/blog/convivial-networks.md b/app/content/blog/convivial-networks.md index b58ec630d2..061a1a728f 100644 --- a/app/content/blog/convivial-networks.md +++ b/app/content/blog/convivial-networks.md @@ -2,6 +2,18 @@ title = "Convivial Networks" date = "2022-05-27" 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." +search_terms = [ + "convivial networks", + "convivial tools", + "ivan illich", + "human scale tech", + "attention economy", + "community building", + "personal computing", + "urbit community", + "peer to peer", + "ownership" +] [extra] author = "" ship = "~witwyt-widlyr" diff --git a/app/content/blog/creating-sigils.md b/app/content/blog/creating-sigils.md index 8bdf2e36eb..66f8d9d737 100644 --- a/app/content/blog/creating-sigils.md +++ b/app/content/blog/creating-sigils.md @@ -2,6 +2,19 @@ title = "Creating Sigils" date = "2020-02-03" description = "The origin and design process informing Urbit's generative user avatar system, Sigils." +search_terms = [ + "creating sigils", + "urbit sigils", + "visual identity", + "urbit id", + "sigil design", + "generative avatars", + "phonemes", + "sigil js", + "design process", + "identity system", + "urbit names" +] [extra] author = "Gavin Atkinson" diff --git a/app/content/blog/desire-lines.md b/app/content/blog/desire-lines.md index 5f3418d398..c825d6bdda 100644 --- a/app/content/blog/desire-lines.md +++ b/app/content/blog/desire-lines.md @@ -2,6 +2,18 @@ title = "Desire Lines to a New Internet" date = "2022-05-06" 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." +search_terms = [ + "desire lines", + "web3 communities", + "dao migration", + "urbit adoption", + "token gating", + "planet distribution", + "holium ballot", + "pointdao", + "urbit for creators", + "decentralized networks" +] [extra] author = "" ship = "~dalwes-migdec" diff --git a/app/content/blog/developer-preview-vere64.md b/app/content/blog/developer-preview-vere64.md index 390ccaf4d2..86484622d7 100644 --- a/app/content/blog/developer-preview-vere64.md +++ b/app/content/blog/developer-preview-vere64.md @@ -14,6 +14,18 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog_Vere64+DP # imageCardDark = # imageIndexDark = tags = ["developer preview", "vere64", "runtime"] +search_terms = [ + "vere64 preview", + "developer preview", + "unlimited loom", + "build from source", + "loom size", + "runtime 64-bit", + "demand paging", + "loom constraints", + "file size limit", + "runtime preview" +] +++ Urbit has long been practically and conceptually constrained in its application by the limitation in the ["loom"](https://docs.urbit.org/build-on-urbit/core-academy/ca06#the-loom) size. Initially the Vere runtime could provide only a mere 2GB in available memory, but over the years that has been increased to 4GB, 8GB, and most recently 16GB with the recent [Vere 4.0 release](https://github.com/urbit/vere/releases/tag/vere-v4.0). These improvements have come from various projects, such as pointer compression in the allocator making 16GB loom possible in Vere 4.0, or [demand paging](https://docs.urbit.org/build-on-urbit/core-academy/ca06#demand-paging) which makes it possible to not require the entire loom to live in RAM, making it viable to run a larger loom on reasonable underlying hardware. diff --git a/app/content/blog/eliza.md b/app/content/blog/eliza.md index acf1d8229f..01c310c4f9 100644 --- a/app/content/blog/eliza.md +++ b/app/content/blog/eliza.md @@ -2,6 +2,20 @@ title = "Eliza" date = "2021-02-22" description = "Building things, even Calm™ things, makes noise." +search_terms = [ + "eliza bot", + "urbit chatbot", + "landscape feedback", + "data collection", + "calm bot", + "urbit surveys", + "open source bot", + "urbit automation", + "anti spam", + "urbit agents", + "network economics", + "tlon bot" +] [extra] author = "Christian Langalis" diff --git a/app/content/blog/events-series.md b/app/content/blog/events-series.md index bdecf7a593..bd5a9818a4 100644 --- a/app/content/blog/events-series.md +++ b/app/content/blog/events-series.md @@ -2,6 +2,19 @@ title = "Urbit Events Series" description = "These events are an opportunity for Urbit contributors to share real-time updates that don’t make it into this blog, and for the community to get to know the contributors (and one another)." date = "2020-10-29" +search_terms = [ + "urbit events", + "developer calls", + "community series", + "town hall", + "urbitcon", + "community building", + "urbit community", + "event series", + "grants program", + "knowledge sharing", + "developer talks" +] [extra] description = "These events are an opportunity for Urbit contributors to share real-time updates that don’t make it into this blog, and for the community to get to know the contributors (and one another)." diff --git a/app/content/blog/first-contract.md b/app/content/blog/first-contract.md index ce2972cb48..284baf579f 100644 --- a/app/content/blog/first-contract.md +++ b/app/content/blog/first-contract.md @@ -2,6 +2,20 @@ title = "Azimuth’s First Contract Upgrade" date = "2021-06-04" description = "Galactic Senate makes first concrete action" +search_terms = [ + "azimuth upgrade", + "first contract", + "galactic senate", + "ecliptic changes", + "erc721 fix", + "claims contract", + "proxy addresses", + "urbit governance", + "doc vote", + "address space", + "azimuth vote", + "senate proposals" +] [extra] author = "Jonathan Paprocki and Mark" diff --git a/app/content/blog/first-steps-towards-urbit-org.md b/app/content/blog/first-steps-towards-urbit-org.md index 2fca30ec11..bdb2605ef3 100644 --- a/app/content/blog/first-steps-towards-urbit-org.md +++ b/app/content/blog/first-steps-towards-urbit-org.md @@ -2,6 +2,19 @@ title = "First Steps Towards urbit.org" date = "2020-08-11" description = "With a stable platform taking shape and a strong community forming that wants to help build Urbit, it’s time to make urbit.org real." +search_terms = [ + "urbit.org", + "urbit foundation", + "address space", + "grants program", + "interim director", + "community builders", + "governance", + "airlock", + "urbit roadmap", + "protocol stewardship", + "platform maturity" +] [extra] author = "Josh Lehman" diff --git a/app/content/blog/ford-fusion.md b/app/content/blog/ford-fusion.md index 632b9e6f82..80a76628a4 100644 --- a/app/content/blog/ford-fusion.md +++ b/app/content/blog/ford-fusion.md @@ -2,6 +2,19 @@ title = "Ford Fusion" date = "2020-07-14" description = "Ford Fusion was an overhaul of Urbit's over-the-air upgrade process and a rewrite of its build system. The new update system corrects a few long-standing bugs with the previous one, and the new build system is simpler, smaller (by around 5,000 lines), and easier to manage." +search_terms = [ + "ford fusion", + "ota updates", + "build system", + "urbit upgrades", + "clay", + "hoon compiler", + "arvo kernel", + "atomic updates", + "ordered updates", + "self contained builds", + "urbit tooling" +] [extra] author = "Ted Blackman" diff --git a/app/content/blog/foss-1.md b/app/content/blog/foss-1.md index 50e281868f..cddfb81e0f 100644 --- a/app/content/blog/foss-1.md +++ b/app/content/blog/foss-1.md @@ -2,6 +2,18 @@ title = "Urbit's Open Source Culture, Part I" date = "2023-05-31" 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." +search_terms = [ + "open source culture", + "urbit history", + "skunkworks", + "developer community", + "hoon education", + "third party distribution", + "urbit foundation", + "assembly events", + "grants program", + "urbit open source" +] [extra] author = "N E Davis" diff --git a/app/content/blog/foss-2.md b/app/content/blog/foss-2.md index d08fc99b44..3f92ad9544 100644 --- a/app/content/blog/foss-2.md +++ b/app/content/blog/foss-2.md @@ -2,6 +2,18 @@ title = "Urbit's Open Source Culture, Part II" date = "2023-06-13" description = "How will Urbit continue to foster its innovative open source software culture?" +search_terms = [ + "open source culture", + "urbit foundation", + "developer experience", + "hoon prime", + "documentation", + "grants program", + "build parties", + "developer tooling", + "open source strategy", + "community" +] [extra] author = "N E Davis" diff --git a/app/content/blog/gifts-q3-2020.md b/app/content/blog/gifts-q3-2020.md index 717f8b2989..3e6967bd53 100644 --- a/app/content/blog/gifts-q3-2020.md +++ b/app/content/blog/gifts-q3-2020.md @@ -2,6 +2,18 @@ title = "Gifts Q3 2020" date = "2020-09-22" description = "Twice a year we distribute address space to those that have made valuable contributions to Urbit. Now called our Gifts program, the gifting of address space has been part of Urbit long before we had a grants program." +search_terms = [ + "gifts program", + "address space", + "urbit gifts", + "community contributors", + "grants program", + "galaxy gifts", + "star awards", + "urbit foundation", + "network growth", + "urbit rewards" +] [taxonomies] grant_type = [ "Gift" ] diff --git a/app/content/blog/governance-of-urbit.md b/app/content/blog/governance-of-urbit.md index 1260e18ac6..e96aa0437b 100644 --- a/app/content/blog/governance-of-urbit.md +++ b/app/content/blog/governance-of-urbit.md @@ -2,6 +2,18 @@ title = "Governance of urbit.org" date = "2019-01-10" description = "Stewardship of the Urbit Project." +search_terms = [ + "urbit governance", + "urbit.org assets", + "urbit address space", + "azimuth property", + "galaxy grants", + "tlon stewardship", + "board of advisors", + "platform development", + "urbit foundation", + "address space pool" +] aliases = [ "/posts/essays/governance-of-urbit", "/posts/governance-of-urbit" diff --git a/app/content/blog/hackathon-2023.md b/app/content/blog/hackathon-2023.md index d8fe839ed4..54e29612b6 100644 --- a/app/content/blog/hackathon-2023.md +++ b/app/content/blog/hackathon-2023.md @@ -2,6 +2,20 @@ title = "Assembly Hackathon 2023" date = "2023-12-05" description = "The Assembly 2023 Hackathon was the most successful Urbit Hackathon we've had. Get a taste of Demo Day in Lisbon and check out the projects they made." +search_terms = [ + "assembly hackathon", + "demo day", + "urbit hackathon", + "%eyas", + "urwasm", + "pharos", + "%yijing", + "%bizbaz", + "mentat", + "seax", + "urbit apps", + "lisbon" +] [extra] author = "Jack Wang" diff --git a/app/content/blog/hackathon-results.md b/app/content/blog/hackathon-results.md index 40249a3281..b6634a25bd 100644 --- a/app/content/blog/hackathon-results.md +++ b/app/content/blog/hackathon-results.md @@ -2,6 +2,18 @@ title = "Hackathon Results" date = "2020-06-11" description = "We recently held an invite-only Urbit Hackathon for graduates of our Hoon School program, and the submissions really impressed us across the board. Submissions were judged on several criteria: creativity, usefulness, and code quality." +search_terms = [ + "urbit hackathon", + "hoon school", + "hackathon results", + "landscape apps", + "canvas app", + "rote flashcards", + "community projects", + "urbit prizes", + "developer competition", + "urbit builders" +] [extra] author = "Robert Mariani" diff --git a/app/content/blog/haleek-maul-interview.md b/app/content/blog/haleek-maul-interview.md index 29115e9282..e625ac2e7e 100644 --- a/app/content/blog/haleek-maul-interview.md +++ b/app/content/blog/haleek-maul-interview.md @@ -2,6 +2,20 @@ title = "NFTs, Urbit IDs, and Communities w/ Haleek Maul" date = "2021-09-09" description = "An interview with the founder of Holdersland" +search_terms = [ + "haleek maul", + "holdersland", + "urbit ids", + "nfts", + "sigil art", + "digital communities", + "caribbean artists", + "assembly 2021", + "urbit dao", + "nft auction", + "urbit identity", + "crypto communities" +] [extra] author = "Matt" ship = "~tirwyd-sarmes" diff --git a/app/content/blog/hoon-4-lispers.md b/app/content/blog/hoon-4-lispers.md index 3425ad90bb..ac35717692 100644 --- a/app/content/blog/hoon-4-lispers.md +++ b/app/content/blog/hoon-4-lispers.md @@ -2,6 +2,19 @@ title = "A Perspective on Lisp and Hoon" date = "2023-06-15" description = "Lisp is an éminence grise of programming. How does Hoon compare?" +search_terms = [ + "hoon vs lisp", + "lisp comparison", + "hoon language", + "nock", + "runes", + "homoiconic", + "metaprogramming", + "functional programming", + "hoon types", + "lisp macros", + "urbit programming" +] [extra] author = "N E Davis" diff --git a/app/content/blog/hosting-the-future.md b/app/content/blog/hosting-the-future.md index d9538a081f..1a2fc77899 100644 --- a/app/content/blog/hosting-the-future.md +++ b/app/content/blog/hosting-the-future.md @@ -2,6 +2,19 @@ title = "Hosting the Future" date = "2020-09-30" description = "The way we see it, hosting is the most important thing, next to Landscape, that Tlon can do to help Urbit continue toward widespread adoption." +search_terms = [ + "hosting service", + "tlon hosting", + "urbit hosting", + "onboarding", + "landscape", + "hosting providers", + "tlon.io", + "self hosting", + "urbit adoption", + "urbit foundation", + "planet hosting" +] [extra] author = "Nick Simmons" diff --git a/app/content/blog/immunology-for-the-internet-age.md b/app/content/blog/immunology-for-the-internet-age.md index e0dbe48f3b..149681eb43 100644 --- a/app/content/blog/immunology-for-the-internet-age.md +++ b/app/content/blog/immunology-for-the-internet-age.md @@ -2,6 +2,18 @@ title = "Immunology for the Internet Age" date = "2022-04-07" 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." +search_terms = [ + "internet immune system", + "decentralization", + "daos", + "pseudonymity", + "megacorp", + "privacy", + "cyberpunk", + "ownership", + "urbit", + "zero trust" +] [extra] author = "" ship = "~lagrev-nocfep" diff --git a/app/content/blog/infrastructural.md b/app/content/blog/infrastructural.md index 7d23c7e6e9..e0edd27051 100644 --- a/app/content/blog/infrastructural.md +++ b/app/content/blog/infrastructural.md @@ -2,6 +2,19 @@ title = "Infrastructural" date = "2020-04-09" description = "A reflection–meditation on OS 1’s initial form development, and the attitude we brought to bear in designing it." +search_terms = [ + "infrastructural", + "os1 design", + "human shaped infrastructure", + "interface design", + "beautiful infrastructure", + "digital spaces", + "os0", + "os1", + "communal computing", + "urbit interface", + "design philosophy" +] [extra] author = "É. Urcades" diff --git a/app/content/blog/interim-constitution.md b/app/content/blog/interim-constitution.md index 47ebb89319..d9a9f4c3e1 100644 --- a/app/content/blog/interim-constitution.md +++ b/app/content/blog/interim-constitution.md @@ -2,6 +2,18 @@ title = "Interim Constitution" date = "2016-05-15" description = "The governing rules for the early days of the Urbit network." +search_terms = [ + "interim constitution", + "urbit governance", + "galaxy senate", + "stellar congress", + "planetary assembly", + "consulate rules", + "urbit republic", + "address space presale", + "urbit foundation", + "galaxy table" +] aliases = [ "/posts/essays/interim-constitution", "/posts/constitution" ] [extra] diff --git a/app/content/blog/interplanetary_commerce.md b/app/content/blog/interplanetary_commerce.md index da10152ded..92dd611664 100644 --- a/app/content/blog/interplanetary_commerce.md +++ b/app/content/blog/interplanetary_commerce.md @@ -3,6 +3,20 @@ title = "Interplanetary Commerce" date = "2021-04-08" description = "OS-level commercial primitives." tags = ["bitcoin"] +search_terms = [ + "interplanetary commerce", + "urbit payments", + "bitcoin wallet", + "lightning network", + "ship payments", + "urbit hosting", + "creator economy", + "p2p commerce", + "urbit services", + "paywalls", + "urbit bitcoin", + "commercial primitives" +] [extra] author = "Christian Langalis" diff --git a/app/content/blog/introducing-os1.md b/app/content/blog/introducing-os1.md index 439d5fceed..fa53557525 100644 --- a/app/content/blog/introducing-os1.md +++ b/app/content/blog/introducing-os1.md @@ -2,6 +2,19 @@ title = "Introducing OS 1" date = "2020-04-29" description = "OS 1 is somewhere between ‘productivity software’ and a ‘social network’. We think it’s the beginning of an altogether new breed of social computing." +search_terms = [ + "os1", + "introducing os1", + "landscape", + "social computing", + "urbit groups", + "chat modules", + "links module", + "publish notebook", + "urbit interface", + "community grants", + "urbit os" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/introduction-to-the-combine-dao.md b/app/content/blog/introduction-to-the-combine-dao.md index 5673d211e1..e8d9d78692 100644 --- a/app/content/blog/introduction-to-the-combine-dao.md +++ b/app/content/blog/introduction-to-the-combine-dao.md @@ -2,6 +2,18 @@ title = "Introduction to the Combine DAO" date = "2022-07-01" description = "Inside the mind of the Combine" +search_terms = [ + "combine dao", + "urbit foundation", + "dao on urbit", + "ballot app", + "uqbar", + "urbit investing", + "dao membership", + "urbit projects", + "grants pipeline", + "dao investors" +] [extra] author = "Anthony Arroyo" diff --git a/app/content/blog/io-in-hoon.md b/app/content/blog/io-in-hoon.md index e935ef3a85..deee6922ea 100644 --- a/app/content/blog/io-in-hoon.md +++ b/app/content/blog/io-in-hoon.md @@ -2,6 +2,20 @@ title = "Input and Output in Hoon" description = "Let's talk about IO in Urbit." date = "2020-12-15" +search_terms = [ + "hoon io", + "input output", + "state machines", + "monadic io", + "urbit threads", + "urbit agents", + "arvo vanes", + "functional io", + "imperative io", + "io patterns", + "hoon programming", + "state machine io" +] [extra] author = "Philip Monk" diff --git a/app/content/blog/iot.md b/app/content/blog/iot.md index 34f0b77042..5145cec745 100644 --- a/app/content/blog/iot.md +++ b/app/content/blog/iot.md @@ -2,6 +2,20 @@ title = "Lunar Urbit and the Internet of Things" date = "2021-04-29" description = "Potential future use cases of moons for industry and consumers" +search_terms = [ + "lunar urbit", + "internet of things", + "urbit moons", + "iot security", + "solid state interpreter", + "self authenticating ids", + "industrial iot", + "agriculture data", + "p2p data markets", + "device identity", + "urbit ids", + "moon identities" +] [extra] author = "Jonathan Paprocki" diff --git a/app/content/blog/landscape-a-portrait.md b/app/content/blog/landscape-a-portrait.md index 5e9f5ca86d..e6b1a03214 100644 --- a/app/content/blog/landscape-a-portrait.md +++ b/app/content/blog/landscape-a-portrait.md @@ -6,6 +6,19 @@ aliases = [ "/posts/essays/landscape-a-portrait/", "/posts/landscape-a-portrait" ] +search_terms = [ + "landscape ui", + "urbit interface", + "modulo", + "userspace", + "indigo", + "chat publish", + "urbit apps", + "eyre vane", + "create landscape app", + "interface roadmap", + "urbit design" +] [extra] author = "Matilde Park" diff --git a/app/content/blog/layer-2-faq.md b/app/content/blog/layer-2-faq.md index 0eacfc4b50..5b4d33288c 100644 --- a/app/content/blog/layer-2-faq.md +++ b/app/content/blog/layer-2-faq.md @@ -2,6 +2,18 @@ title = "Layer 2 FAQ" date = "2022-03-01" description = "Answers to all your lingering L2 questions." +search_terms = [ + "layer 2 faq", + "l2 planets", + "rollup", + "bridge", + "planet custody", + "migrate l1 to l2", + "naive rollup", + "metamask", + "buy planet", + "hosting provider" +] [extra] image = "https://media.urbit.org/site/posts/essays/l2-faq-artwork.jpg" +++ diff --git a/app/content/blog/llms-on-urbit.md b/app/content/blog/llms-on-urbit.md index af75e1958e..7b65034a73 100644 --- a/app/content/blog/llms-on-urbit.md +++ b/app/content/blog/llms-on-urbit.md @@ -14,6 +14,20 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog_LLMs+on+U # imageCardDark = # imageIndexDark = tags = ["AI", "guides"] +search_terms = [ + "llms on urbit", + "clurd", + "urbit master", + "claude code", + "dojo access", + "llm tooling", + "mcp server", + "sailbox", + "tarball", + "agentic assistants", + "groundwire", + "llm setup" +] +++ ![llms on urbit image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog_LLMs+on+Urbit_Social+16x9.png ) diff --git a/app/content/blog/magic.md b/app/content/blog/magic.md index c3833ccf6f..9fb94167cb 100644 --- a/app/content/blog/magic.md +++ b/app/content/blog/magic.md @@ -2,6 +2,18 @@ title = "Magic" date = "2016-05-15" description = "A thought-experiment to explain the Urbit user experience." +search_terms = [ + "urbit user experience", + "personal server vision", + "magic thought experiment", + "free your data", + "self hosted identity", + "urbit platform", + "digital freedom", + "personal cloud", + "agent software", + "urbit metaphor" +] aliases = [ "/posts/essays/magic", "/posts/magic" ] [extra] diff --git a/app/content/blog/metaphase.md b/app/content/blog/metaphase.md index 6a3a5ca5db..9e17f76a99 100644 --- a/app/content/blog/metaphase.md +++ b/app/content/blog/metaphase.md @@ -2,6 +2,20 @@ title = "Metaphase" date = "2020-12-08" description = "On the upcoming and foregoing Landscape lifecycles, and other forms of mitosis across the Urbit project." +search_terms = [ + "landscape lifecycle", + "release streams", + "graph store", + "notifications", + "stable stream", + "dev stream", + "landscape roadmap", + "userspace apps", + "urbit foundation", + "product process", + "ota updates", + "landscape teams" +] [extra] author = "Matilde Park" diff --git a/app/content/blog/nockmas-2025-day-1.md b/app/content/blog/nockmas-2025-day-1.md index 6c84413f1e..1c676f6ab6 100644 --- a/app/content/blog/nockmas-2025-day-1.md +++ b/app/content/blog/nockmas-2025-day-1.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+1/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 1", + "opcode 0", + "address opcode", + "slot operator", + "tree addressing", + "nock nouns", + "binary tree", + "nock address", + "nock tutorial" +] +++ ![nockmas day 1 tree addressing image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+1/nockmas-day-1-tree-addressing-Social.png) diff --git a/app/content/blog/nockmas-2025-day-10.md b/app/content/blog/nockmas-2025-day-10.md index e5c9e76479..6b3453bd6d 100644 --- a/app/content/blog/nockmas-2025-day-10.md +++ b/app/content/blog/nockmas-2025-day-10.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+10/nockmas # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 10", + "opcode 9", + "invoke opcode", + "core arms", + "battery payload", + "nock invoke", + "nock isa", + "core call", + "nock tutorial" +] +++ ![nockmas day 10 invoke image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+10/nockmas-day-10-invoke-social.png) diff --git a/app/content/blog/nockmas-2025-day-11.md b/app/content/blog/nockmas-2025-day-11.md index bcf30e2dd7..8bb7b11f19 100644 --- a/app/content/blog/nockmas-2025-day-11.md +++ b/app/content/blog/nockmas-2025-day-11.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+11/nockmas # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 11", + "opcode 10", + "edit opcode", + "hax edit", + "nock edit", + "gate calls", + "nock isa", + "in place edit", + "nock tutorial" +] +++ ![nockmas day 11 edit image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+11/nockmas-day-11-edit-social.png) diff --git a/app/content/blog/nockmas-2025-day-12.md b/app/content/blog/nockmas-2025-day-12.md index 0f68a8ffa2..2f7b022c88 100644 --- a/app/content/blog/nockmas-2025-day-12.md +++ b/app/content/blog/nockmas-2025-day-12.md @@ -14,6 +14,18 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+12/nockmas # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 12", + "opcode 11", + "hint opcode", + "static hint", + "dynamic hint", + "nock metadata", + "hints and jetting", + "nock isa", + "runtime hints", + "nock tutorial" +] +++ ![nockmas day 12 hint image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+12/nockmas-day-12-hint-social.png) diff --git a/app/content/blog/nockmas-2025-day-2.md b/app/content/blog/nockmas-2025-day-2.md index 39364782d3..164237c0a9 100644 --- a/app/content/blog/nockmas-2025-day-2.md +++ b/app/content/blog/nockmas-2025-day-2.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+2/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 2", + "opcode 1", + "constant opcode", + "nock constant", + "store data", + "return constant", + "nock isa", + "nock tutorial", + "stored code" +] +++ ![nockmas day 2 constants image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+2/nockmas-day-2-constants-Social.png) diff --git a/app/content/blog/nockmas-2025-day-3.md b/app/content/blog/nockmas-2025-day-3.md index 88ae7e12f4..24179d100a 100644 --- a/app/content/blog/nockmas-2025-day-3.md +++ b/app/content/blog/nockmas-2025-day-3.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Day+3/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 3", + "opcode 2", + "evaluate opcode", + "tar operator", + "dynamic eval", + "nock evaluate", + "metaprogramming", + "nock isa", + "nock tutorial" +] +++ ![nockmas day 3 evaluate image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Day+3/nockmas-day-3-Evaluate-Social.png) diff --git a/app/content/blog/nockmas-2025-day-4.md b/app/content/blog/nockmas-2025-day-4.md index 95b00e1f43..85fb62daa1 100644 --- a/app/content/blog/nockmas-2025-day-4.md +++ b/app/content/blog/nockmas-2025-day-4.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+4/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 4", + "opcode 3", + "cell check", + "wut operator", + "nock cell", + "atom vs cell", + "loobean", + "nock isa", + "nock tutorial" +] +++ ![nockmas day 4 cell check image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+4/nockmas-day-4-cell-check-Social.png) diff --git a/app/content/blog/nockmas-2025-day-5.md b/app/content/blog/nockmas-2025-day-5.md index 35b72e3952..e4e859ebd7 100644 --- a/app/content/blog/nockmas-2025-day-5.md +++ b/app/content/blog/nockmas-2025-day-5.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+5/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 5", + "opcode 4", + "increment opcode", + "lus operator", + "nock increment", + "arithmetic primitive", + "jetting", + "nock isa", + "nock tutorial" +] +++ ![nockmas day 5 increment image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+5/nockmas-day-5-increment-social.png) diff --git a/app/content/blog/nockmas-2025-day-6.md b/app/content/blog/nockmas-2025-day-6.md index 6c941107de..a9a79c4cd6 100644 --- a/app/content/blog/nockmas-2025-day-6.md +++ b/app/content/blog/nockmas-2025-day-6.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+6/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 6", + "opcode 5", + "equality check", + "tis operator", + "nock equality", + "deep equality", + "loobean", + "nock isa", + "nock tutorial" +] +++ ![nockmas day 6 equal image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+6/nockmas-day-6-equal-social.png) diff --git a/app/content/blog/nockmas-2025-day-7.md b/app/content/blog/nockmas-2025-day-7.md index 10efc34d53..6e9327d65b 100644 --- a/app/content/blog/nockmas-2025-day-7.md +++ b/app/content/blog/nockmas-2025-day-7.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+7/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 7", + "opcode 6", + "conditional opcode", + "if then else", + "nock conditional", + "loobean", + "composite opcode", + "nock isa", + "nock tutorial" +] +++ ![nockmas day 7 conditional image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+7/nockmas-day-7-conditional-social.png) diff --git a/app/content/blog/nockmas-2025-day-8.md b/app/content/blog/nockmas-2025-day-8.md index fbba70659b..af0218e1c6 100644 --- a/app/content/blog/nockmas-2025-day-8.md +++ b/app/content/blog/nockmas-2025-day-8.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+8/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 8", + "opcode 7", + "compose opcode", + "function composition", + "nock compose", + "pipe pattern", + "subject transform", + "nock isa", + "nock tutorial" +] +++ ![nockmas day 8 compose image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+8/nockmas-day-8-compose-social.png) diff --git a/app/content/blog/nockmas-2025-day-9.md b/app/content/blog/nockmas-2025-day-9.md index 49aaeb0799..e99f1a1d11 100644 --- a/app/content/blog/nockmas-2025-day-9.md +++ b/app/content/blog/nockmas-2025-day-9.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+9/nockmas- # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", ""] +search_terms = [ + "nockmas day 9", + "opcode 8", + "extend opcode", + "variable binding", + "nock extend", + "pin value", + "subject extension", + "nock isa", + "nock tutorial" +] +++ ![nockmas day 9 extend image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/day+9/nockmas-day-9-extend-social.png) diff --git a/app/content/blog/nockmas-2025-welcome.md b/app/content/blog/nockmas-2025-welcome.md index 0564f09395..d6b53fec01 100644 --- a/app/content/blog/nockmas-2025-welcome.md +++ b/app/content/blog/nockmas-2025-welcome.md @@ -14,6 +14,17 @@ image = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/nockmas-day-mi # imageCardDark = # imageIndexDark = tags = ["nock", "nockmas", "autocons"] +search_terms = [ + "nockmas day 0", + "autocons", + "nock evaluation", + "cell construction", + "nock intro", + "formula cell", + "nock basics", + "nock isa", + "nock tutorial" +] +++ ![nockmas day minus 1 autocons image](https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/nockmas-day-minus-1-autocons.png) diff --git a/app/content/blog/nockpu.md b/app/content/blog/nockpu.md index aff38dfd7b..53f14a8d9a 100644 --- a/app/content/blog/nockpu.md +++ b/app/content/blog/nockpu.md @@ -2,6 +2,17 @@ title = "NockPU" date = "2023-08-02" description = "A light technical description of NockPU, a hardware system for running Nock" +search_terms = [ + "nockpu", + "nock hardware", + "nock processing unit", + "bare metal nock", + "hardware jets", + "tree traversal", + "binary tree", + "urbit hardware", + "mopfel winrux" +] [extra] author = "Noah Kumin" diff --git a/app/content/blog/olif-and-urbit-ids.md b/app/content/blog/olif-and-urbit-ids.md index 8691391de6..41c114b529 100644 --- a/app/content/blog/olif-and-urbit-ids.md +++ b/app/content/blog/olif-and-urbit-ids.md @@ -14,6 +14,20 @@ imageCard = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog_Olif+ # imageCardDark = "" # imageIndexDark = "" tags = ["olif", "identity", "design"] +search_terms = [ + "olif", + "urbit ids", + "sigils", + "@p names", + "fragrance rendering", + "olfactive identity", + "address space", + "scent mapping", + "urbit address", + "fragrance project", + "olfactory sigil", + "olif perfume" +] +++ My introduction to Urbit came through its identity system. In particular, [sigils](./creating-sigils) and `@p` names. Each Urbit ID is fundamentally a large number, but the system derives two practical representations from it. A `@p` is a pronounceable name generated from a phonetic base. The number is mapped to a selection from 512 predefined three-letter syllables or phonemes (256 prefixes and 256 suffixes). This produces a readable string like `~sampel-palnet` for a planet. The sigil is generated in parallel as a visual shape assembled from a fixed set of foundational glyphs. Each glyph corresponds directly to one of those syllables. The mapping is fully deterministic. The same address always produces the same `@p` and sigil. This keeps the core components simple and consistent across billions of possible IDs. diff --git a/app/content/blog/on-christopher-alexander.md b/app/content/blog/on-christopher-alexander.md index ba7da75935..659f3546c7 100644 --- a/app/content/blog/on-christopher-alexander.md +++ b/app/content/blog/on-christopher-alexander.md @@ -2,6 +2,20 @@ title = "On Christopher Alexander" date = "2021-07-19" description = "An overview of his writing and relevance" +search_terms = [ + "christopher alexander", + "pattern language", + "timeless way", + "nature of order", + "design philosophy", + "architecture theory", + "quality without name", + "living structure", + "software design", + "urbit design", + "pattern languages", + "alexander influence" +] [extra] author = "Matt" diff --git a/app/content/blog/pin-the-face-that-launches-a-thousand-ships.md b/app/content/blog/pin-the-face-that-launches-a-thousand-ships.md index c57c9bcd92..47976340e5 100644 --- a/app/content/blog/pin-the-face-that-launches-a-thousand-ships.md +++ b/app/content/blog/pin-the-face-that-launches-a-thousand-ships.md @@ -2,6 +2,18 @@ title = "Pin the Face that Launches a Thousand Ships" date = "2023-04-07" description = "A guest post by ~nospex-larsut" +search_terms = [ + "learn hoon", + "hoon hesitations", + "pin the face", + "urbit apps", + "onboarding", + "hosting providers", + "hoon school", + "urbit adoption", + "runes", + "hoon community" +] [extra] image = "https://storage.googleapis.com/media.urbit.org/blog/6a0120a85dcdae970b016766c94c14970b-800wi.jpg" author = "" diff --git a/app/content/blog/pki-maze.md b/app/content/blog/pki-maze.md index 2ef6977ea1..e087e470e8 100644 --- a/app/content/blog/pki-maze.md +++ b/app/content/blog/pki-maze.md @@ -2,6 +2,19 @@ title = "Designing a Permanent Personal Identity" date = "2019-11-26" description = "A public key infrastructure (PKI) is a system for binding a set of keys to a name. Sometimes a small amount of metadata is included." +search_terms = [ + "permanent identity", + "urbit pki", + "public key infrastructure", + "comets planets moons", + "key rotation", + "blockchain pki", + "self sovereign identity", + "urbit ids", + "idea maze", + "global consistency", + "key revocation" +] [extra] author = "Philip Monk" diff --git a/app/content/blog/platform-decay.md b/app/content/blog/platform-decay.md index f07a4232b0..47b47d2a59 100644 --- a/app/content/blog/platform-decay.md +++ b/app/content/blog/platform-decay.md @@ -2,6 +2,19 @@ title = "Platform Decay, Decentralized Marketplaces, and Urbit" date = "2020-05-07" description = "Urbit is calm computing. Calm commerce follows naturally. " +search_terms = [ + "platform decay", + "decentralized marketplaces", + "calm commerce", + "data ownership", + "urbit commerce", + "reputation systems", + "ecommerce platforms", + "marketplace protocols", + "urbit id", + "micropayments", + "privacy markets" +] [extra] author = "Nicholas Simmons" diff --git a/app/content/blog/precepts-discussion.md b/app/content/blog/precepts-discussion.md index 671d181291..be3b8661d0 100644 --- a/app/content/blog/precepts-discussion.md +++ b/app/content/blog/precepts-discussion.md @@ -2,6 +2,19 @@ title = "Precepts: Discussion" date = "2020-03-17" description = "The precepts aren’t arguments. We discuss and justify them here." +search_terms = [ + "precepts discussion", + "urbit principles", + "design rationale", + "mechanical simplicity", + "code discipline", + "system design", + "real software", + "engineering attitude", + "theory and practice", + "urbit philosophy", + "abstractions" +] [extra] author = "Philip Monk" diff --git a/app/content/blog/precepts.md b/app/content/blog/precepts.md index 5baf6f7f74..ea4ce61e2e 100644 --- a/app/content/blog/precepts.md +++ b/app/content/blog/precepts.md @@ -2,6 +2,20 @@ title = "Precepts" date = "2020-03-17" description = "Technical maxims that define Urbit's approach to engineering." +search_terms = [ + "urbit precepts", + "engineering principles", + "system design", + "technical maxims", + "data over code", + "cqrs", + "pubsub", + "determinism", + "timeless software", + "hoon principles", + "urbit architecture", + "software discipline" +] [extra] author = "Philip Monk" diff --git a/app/content/blog/providers.md b/app/content/blog/providers.md index 18d823ef1a..6ecf83dbec 100644 --- a/app/content/blog/providers.md +++ b/app/content/blog/providers.md @@ -2,6 +2,19 @@ title = "Providers" date = "2020-08-17" description = "We’ve always assumed that providers would have to come into existence sooner or later. By the look of it, that time is now. Tlon and a few others have provider-like services in the works." +search_terms = [ + "urbit providers", + "hosting providers", + "onboarding", + "planet hosting", + "urbit service", + "address space", + "provider business", + "urbit hosting", + "community access", + "provider examples", + "tlon provider" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/pseudonymous-reputation.md b/app/content/blog/pseudonymous-reputation.md index 0b30e4496f..78f3f4f29b 100644 --- a/app/content/blog/pseudonymous-reputation.md +++ b/app/content/blog/pseudonymous-reputation.md @@ -2,6 +2,18 @@ title = "Building Your DAO with Pseudonymous Reputation on Urbit" date = "2022-07-19" description = "Using Urbit ID’s pseudonymous reputation model, DAO participants know Urbit ID holders’ past behavior before relying on them, and without sacrificing anonymity." +search_terms = [ + "pseudonymous reputation", + "urbit id", + "dao membership", + "combine dao", + "token gated", + "trust and anonymity", + "urbit ids", + "dao governance", + "crypto identity", + "reputation" +] [extra] author = "Anthony Arroyo" diff --git a/app/content/blog/rollups.md b/app/content/blog/rollups.md index b166a0b55d..11ad967af3 100644 --- a/app/content/blog/rollups.md +++ b/app/content/blog/rollups.md @@ -2,6 +2,20 @@ title = "The Gang Solves the Gas Crisis" date = "2021-05-13" description = "How we're making Urbit ID affordable again" +search_terms = [ + "gas crisis", + "layer 2", + "naive rollups", + "urbit id fees", + "ethereum gas", + "bridge update", + "roller node", + "layer 2 planets", + "layer 1 vs 2", + "azimuth changes", + "star owners", + "rollup security" +] [extra] author = "Jonathan Paprocki" diff --git a/app/content/blog/security-and-continuity.md b/app/content/blog/security-and-continuity.md index 0ee183db60..eeb55a370b 100644 --- a/app/content/blog/security-and-continuity.md +++ b/app/content/blog/security-and-continuity.md @@ -2,6 +2,20 @@ title = "Security and Continuity" description = "An update on our primary infrastructure milestones for 2020." date = "2020-11-30" +search_terms = [ + "security continuity", + "ames audit", + "network breaches", + "continuity breach", + "version negotiation", + "data migration", + "urbit uptime", + "azimuth vote", + "galaxy vote", + "urbit security", + "protocol milestones", + "infrastructure goals" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/security-audit.md b/app/content/blog/security-audit.md index 46416f92e3..d8d277f7de 100644 --- a/app/content/blog/security-audit.md +++ b/app/content/blog/security-audit.md @@ -2,6 +2,20 @@ title = "Ames Security Audit and the Future of the Protocol" description = "Ames’ design has unparalleled potential to deter, mitigate, and recover from attacks, since every packet is authenticated and encrypted and backed by a stable, decentralized PKI." date = "2020-12-17" +search_terms = [ + "ames security", + "protocol audit", + "urbit security", + "forward secrecy", + "dos attacks", + "ddos mitigation", + "ames protocol", + "urbit pki", + "networking keys", + "cryptographic audit", + "social boundaries", + "security roadmap" +] [extra] author = "Ted Blackman + Anthony Arroyo" diff --git a/app/content/blog/simple-durable-yours.md b/app/content/blog/simple-durable-yours.md index fcebab81be..ddaa27adbf 100644 --- a/app/content/blog/simple-durable-yours.md +++ b/app/content/blog/simple-durable-yours.md @@ -2,6 +2,18 @@ title = "Simple, Durable, Yours" date = "2019-10-16" description = "We built Urbit from scratch to be a system that’s simple, durable, and yours. Everything that computing today is not — but should be." +search_terms = [ + "simple durable yours", + "urbit overview", + "digital home", + "personal computing", + "urbit os", + "urbit id", + "calm computing", + "durable software", + "own your data", + "decentralized system" +] extra = { } +++ diff --git a/app/content/blog/smart-home-of-the-future.md b/app/content/blog/smart-home-of-the-future.md index f256633574..22a2124550 100644 --- a/app/content/blog/smart-home-of-the-future.md +++ b/app/content/blog/smart-home-of-the-future.md @@ -2,6 +2,18 @@ title = "The Smart Home of the Future" date = "2022-08-04" 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?" +search_terms = [ + "smart home", + "communal computing", + "iot", + "urbit identity", + "privacy", + "contextual integrity", + "home data", + "smart devices", + "gall app", + "communal computing grant" +] [extra] author = "" ship = "~pilwyc-fastec" diff --git a/app/content/blog/sovereign-intelligence.md b/app/content/blog/sovereign-intelligence.md index 72e33f5b62..4f04872264 100644 --- a/app/content/blog/sovereign-intelligence.md +++ b/app/content/blog/sovereign-intelligence.md @@ -14,6 +14,19 @@ imageIndex = "https://s3.us-east-1.amazonaws.com/urbit.orgcontent/Blog/Blog_Sove # imageCardDark = # imageIndexDark = tags = ["AI", "privacy", "sovereignty"] +search_terms = [ + "sovereign intelligence", + "personal ai", + "urbit ai", + "sidecar", + "data sovereignty", + "urbit id", + "urwasm", + "ai agents", + "bicameral mind", + "identity and memory", + "context without custody" +] +++ diff --git a/app/content/blog/stable-arvo.md b/app/content/blog/stable-arvo.md index 64376835ba..8883f98fc7 100644 --- a/app/content/blog/stable-arvo.md +++ b/app/content/blog/stable-arvo.md @@ -2,6 +2,19 @@ title = "Stable Arvo" date = "2019-11-19" description = "This year we set out to get Arvo to a point that we can credibly call ‘stable.' " +search_terms = [ + "stable arvo", + "kernel stability", + "ames rewrite", + "continuity breach", + "kelvin versioning", + "upgrade mechanics", + "urbit resilience", + "network protocol", + "error recovery", + "crud events", + "arvo upgrades" +] [extra] author = "Anthony Arroyo" diff --git a/app/content/blog/state-of-urbit.md b/app/content/blog/state-of-urbit.md index 1a20b90d67..8b5bd24625 100644 --- a/app/content/blog/state-of-urbit.md +++ b/app/content/blog/state-of-urbit.md @@ -2,6 +2,20 @@ title = "State of Urbit" date = "2021-08-24" description = "A year in review" +search_terms = [ + "state of urbit", + "urbit year review", + "landscape app", + "os1 landscape", + "urbit hosting", + "urbit onboarding", + "urbit id fees", + "naive rollups", + "grid interface", + "software distribution", + "assembly 2021", + "urbit roadmap" +] [extra] author = "Galen Wolfe-Pauly" ship = "~ravmel-ropdyl" diff --git a/app/content/blog/subassembly-hackathon-2024.md b/app/content/blog/subassembly-hackathon-2024.md index e8c1e3fa6f..0a7b008f49 100644 --- a/app/content/blog/subassembly-hackathon-2024.md +++ b/app/content/blog/subassembly-hackathon-2024.md @@ -2,6 +2,18 @@ title = "Subssembly Hackathon 2024" date = "2024-09-16" description = "Use Login with Urbit ID in your app and win Urbit Stars" +search_terms = [ + "subassembly hackathon", + "login with urbit id", + "urbit stars", + "hackathon 2024", + "azimake", + "create react azimuth app", + "identity authentication", + "urbit id login", + "subassembly event", + "azimuth app" +] [extra] ship = "~sarlev-sarsen" diff --git a/app/content/blog/the-100-year-computer.md b/app/content/blog/the-100-year-computer.md index f4de15ff6a..e736ebee4e 100644 --- a/app/content/blog/the-100-year-computer.md +++ b/app/content/blog/the-100-year-computer.md @@ -6,6 +6,18 @@ aliases = [ "/posts/essays/the-100-year-computer/", "/posts/the-100-year-computer" ] +search_terms = [ + "100 year computer", + "durable computing", + "personal server", + "permanent data", + "urbit overview", + "long term computing", + "reliable computer", + "continuous updates", + "future proof", + "urbit vision" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/the-dao-as-a-lesson-in-decentralized-governance.md b/app/content/blog/the-dao-as-a-lesson-in-decentralized-governance.md index 7705efcb2f..0dfa5d4489 100644 --- a/app/content/blog/the-dao-as-a-lesson-in-decentralized-governance.md +++ b/app/content/blog/the-dao-as-a-lesson-in-decentralized-governance.md @@ -2,6 +2,18 @@ title = "The DAO as a Lesson in Decentralized Governance" date = "2016-06-23" description = "What's the right lesson for the decentralization community to learn from the collapse of the DAO?" +search_terms = [ + "dao collapse", + "decentralized governance", + "blockchain governance", + "decentralization theater", + "ethereum fork", + "code is law", + "sovereignty conserved", + "dao rollback", + "governance institutions", + "urbit governance" +] aliases = [ "/posts/essays/the-dao-as-a-lesson-in-decentralized-governance", "/posts/the-dao-as-a-lesson-in-decentralized-governance", diff --git a/app/content/blog/the-missing-middle.md b/app/content/blog/the-missing-middle.md index 785b75ff5b..d820476f63 100644 --- a/app/content/blog/the-missing-middle.md +++ b/app/content/blog/the-missing-middle.md @@ -2,6 +2,19 @@ title = "The Missing Middle" date = "2020-05-25" description = "Urbit stars can facilitate a flexible continuum of community norms." +search_terms = [ + "missing middle", + "urbit stars", + "community norms", + "network governance", + "star providers", + "decentralized communities", + "urbit infrastructure", + "routing hubs", + "social technology", + "community governance", + "digital commons" +] [extra] author = "Nicholas Simmons" diff --git a/app/content/blog/the-shape-of-dao-governance-to-come.md b/app/content/blog/the-shape-of-dao-governance-to-come.md index e36c5486e8..cc7736d1b7 100644 --- a/app/content/blog/the-shape-of-dao-governance-to-come.md +++ b/app/content/blog/the-shape-of-dao-governance-to-come.md @@ -2,6 +2,18 @@ title = "The Shape of DAO Governance to Come" date = "2022-08-17" 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." +search_terms = [ + "dao governance", + "combine dao", + "ballot app", + "custom actions", + "pseudonymous reputation", + "governance attacks", + "moloch dao", + "snapshot voting", + "urbit dao tools", + "ragequit" +] [extra] author = "Anthony Arroyo" diff --git a/app/content/blog/the-state-of-landscape.md b/app/content/blog/the-state-of-landscape.md index 2925bef974..7ec2af4491 100644 --- a/app/content/blog/the-state-of-landscape.md +++ b/app/content/blog/the-state-of-landscape.md @@ -6,6 +6,18 @@ aliases = [ "/posts/essays/the-state-of-landscape", "/posts/the-state-of-landscape" ] +search_terms = [ + "state of landscape", + "landscape update", + "chat interface", + "urbit ui", + "arvo network", + "landscape bugs", + "ios app", + "community chats", + "urbit help", + "modulo roadmap" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/the-understanding-urbit-podcast.md b/app/content/blog/the-understanding-urbit-podcast.md index f28ebf1945..8e4e3d677d 100644 --- a/app/content/blog/the-understanding-urbit-podcast.md +++ b/app/content/blog/the-understanding-urbit-podcast.md @@ -2,6 +2,18 @@ title = "The Understanding Urbit Podcast" date = "2020-04-02" description = "An interview-based podcast series about the Urbit project, as told by those working on it." +search_terms = [ + "understanding urbit podcast", + "urbit podcast", + "interviews", + "tlon team", + "urbit philosophy", + "nock performance", + "technology talks", + "podcast series", + "urbit interviews", + "streaming platforms" +] [extra] author = "Arthur Falls" diff --git a/app/content/blog/the-urbit-address-space.md b/app/content/blog/the-urbit-address-space.md index 187e6b86c1..dabd2910c6 100644 --- a/app/content/blog/the-urbit-address-space.md +++ b/app/content/blog/the-urbit-address-space.md @@ -2,6 +2,18 @@ title = "The Urbit Address Space" date = "2016-05-15" description = "An overview of Urbit's cryptographic address space." +search_terms = [ + "urbit address space", + "urbit ships", + "galaxies stars planets", + "urbit identity", + "urbit pki", + "ship hierarchy", + "urbit governance", + "digital land", + "ship scarcity", + "urbit naming" +] aliases = [ "/posts/essays/the-urbit-address-space", "/posts/the-urbit-address-space" diff --git a/app/content/blog/tools-of-our-own.md b/app/content/blog/tools-of-our-own.md index f7f430014f..5289896666 100644 --- a/app/content/blog/tools-of-our-own.md +++ b/app/content/blog/tools-of-our-own.md @@ -2,6 +2,19 @@ title = "Tools of Our Own" date = "2020-05-12" description = "What is a digital environment? What does it mean to shape your own digital environment?" +search_terms = [ + "tools of our own", + "digital environment", + "conversational tools", + "urbit philosophy", + "social graph", + "collective tools", + "convivial tools", + "personal computing", + "system control", + "urbit communities", + "digital autonomy" +] [extra] author = "Matilde Park" diff --git a/app/content/blog/toward-a-frozen-operating-system.md b/app/content/blog/toward-a-frozen-operating-system.md index 928666c233..1f0eead833 100644 --- a/app/content/blog/toward-a-frozen-operating-system.md +++ b/app/content/blog/toward-a-frozen-operating-system.md @@ -2,6 +2,18 @@ title = "Toward a Frozen Operating System" date = "2017-05-09" description = "Is it possible to freeze an entire OS?" +search_terms = [ + "frozen operating system", + "kelvin versioning", + "urbit os design", + "freezable os", + "nock hoon arvo", + "telescoping kelvins", + "palm tree model", + "system stability", + "urbit platform", + "infinite maturity" +] aliases = [ "/posts/essays/toward-a-frozen-operating-system", "/posts/toward-a-frozen-operating-system", diff --git a/app/content/blog/toward-a-new-clay.md b/app/content/blog/toward-a-new-clay.md index c9086ab265..087800fdca 100644 --- a/app/content/blog/toward-a-new-clay.md +++ b/app/content/blog/toward-a-new-clay.md @@ -2,6 +2,18 @@ title = "Toward a New %clay" date = "2016-07-13" description = "Urbit's revision-control system, %clay, is itself due for a (medium-sized) revision!" +search_terms = [ + "clay revision control", + "urbit filesystem", + "%clay redesign", + "urbit dvcs", + "desk mounting", + "urbit namespace", + "mark system", + "clay storage", + "urbit version control", + "clay community" +] aliases = [ "/posts/essays/toward-a-new-clay", "/posts/toward-a-new-clay", diff --git a/app/content/blog/urbit-and-bitcoin.md b/app/content/blog/urbit-and-bitcoin.md index c7252c9b3f..c94a7613d1 100644 --- a/app/content/blog/urbit-and-bitcoin.md +++ b/app/content/blog/urbit-and-bitcoin.md @@ -3,6 +3,18 @@ title = "Urbit and Bitcoin" description = "A sound money deserves a sound computer." date = "2019-10-16" tags = ["bitcoin"] +search_terms = [ + "urbit and bitcoin", + "sound money", + "bitcoin integration", + "urbit wallet", + "bitcoin grants", + "urbit os", + "peer to peer", + "sound computer", + "btc bounties", + "crypto payments" +] [extra] author = "Christian Langalis" ship = "~pindet-timmut" diff --git a/app/content/blog/urbit-and-the-blockchain.md b/app/content/blog/urbit-and-the-blockchain.md index 86efb1055c..91b3cd99d8 100644 --- a/app/content/blog/urbit-and-the-blockchain.md +++ b/app/content/blog/urbit-and-the-blockchain.md @@ -2,6 +2,18 @@ title = "Urbit and the Blockchain Wars" date = "2017-09-24" description = "A bit about the 'idea maze' of choosing to bootstrap from Ethereum." +search_terms = [ + "urbit blockchain", + "ethereum bootstrap", + "urbit pki", + "blockchain wars", + "urbit land registry", + "on chain governance", + "ethereum critique", + "consensus engine", + "urbit on ethereum", + "chain migration" +] aliases = [ "/posts/essays/urbit-and-the-blockchain", "/posts/urbit-and-the-blockchain", diff --git a/app/content/blog/urbit-creator-daos.md b/app/content/blog/urbit-creator-daos.md index 0f594492cc..cae9ad5601 100644 --- a/app/content/blog/urbit-creator-daos.md +++ b/app/content/blog/urbit-creator-daos.md @@ -2,6 +2,18 @@ title = "Urbit + Creator DAOs with Justin Murphy" date = "2022-10-05" 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." +search_terms = [ + "creator dao", + "justin murphy", + "other life", + "urbit groups", + "straw app", + "ballot", + "creator economy", + "dao governance", + "p2p community", + "urbit id" +] [extra] author = "Isaac Simpson" diff --git a/app/content/blog/urbit-for-creators.md b/app/content/blog/urbit-for-creators.md index 350cd63b29..b8935e7114 100644 --- a/app/content/blog/urbit-for-creators.md +++ b/app/content/blog/urbit-for-creators.md @@ -2,6 +2,18 @@ title = "Urbit Is for Creators" date = "2021-12-09" description = "Urbit is for creators who are ready to wake up from this bad dream." +search_terms = [ + "urbit for creators", + "creator economy", + "p2p creators", + "content ownership", + "1000 true fans", + "creator community", + "peer to peer payments", + "no middlemen", + "urbit creators", + "digital sovereignty" +] [extra] author = "Noah Kumin" ship = "~librex-dozryc" diff --git a/app/content/blog/urbit-for-normies.md b/app/content/blog/urbit-for-normies.md index 1c6ffe2d99..10ae9b165a 100644 --- a/app/content/blog/urbit-for-normies.md +++ b/app/content/blog/urbit-for-normies.md @@ -2,6 +2,19 @@ title = "Urbit for Normies" date = "2020-02-11" description = "A layperson’s guide to the coming new internet." +search_terms = [ + "urbit for normies", + "layperson guide", + "new internet", + "peer to peer", + "privacy", + "personal server", + "urbit ids", + "calm computing", + "digital autonomy", + "urbit overview", + "decentralized web" +] [extra] author = "Erik Newton" diff --git a/app/content/blog/urbit-grants-and-mid-2019-gifts.md b/app/content/blog/urbit-grants-and-mid-2019-gifts.md index 976fe6cc71..d5b93ab1e0 100644 --- a/app/content/blog/urbit-grants-and-mid-2019-gifts.md +++ b/app/content/blog/urbit-grants-and-mid-2019-gifts.md @@ -6,6 +6,17 @@ aliases = [ "/posts/essays/urbit-grants-and-mid-2019-gifts", "/posts/urbit-grants-and-mid-2019-gifts" ] +search_terms = [ + "urbit grants", + "mid 2019 gifts", + "star gifts", + "developer rewards", + "grants program", + "azimuth stars", + "community contributors", + "gift program", + "urbit awards" +] [taxonomies] grant_type = [ "Gift" ] diff --git a/app/content/blog/urbit-is-for-communities.md b/app/content/blog/urbit-is-for-communities.md index 7d10f45104..87a96be784 100644 --- a/app/content/blog/urbit-is-for-communities.md +++ b/app/content/blog/urbit-is-for-communities.md @@ -2,6 +2,19 @@ title = "Urbit is for Communities" date = "2020-03-22" description = "Urbit is for giving communities the tools to shape their own environments; for us all to feel a sense of life and self-directedness in the digital world." +search_terms = [ + "urbit for communities", + "community tools", + "digital homesteading", + "os1", + "high trust", + "digital environment", + "self hosting", + "community software", + "urbit philosophy", + "community modules", + "digital commons" +] [extra] author = "Galen Wolfe-Pauly" diff --git a/app/content/blog/urbithost-interview.md b/app/content/blog/urbithost-interview.md index 8c3bf23773..d9fea8aad8 100644 --- a/app/content/blog/urbithost-interview.md +++ b/app/content/blog/urbithost-interview.md @@ -2,6 +2,20 @@ title = "An Interview with UrbitHost" date = "2021-08-19" description = "Interview with the founder of UrbitHost ~lavlyn-litmeg" +search_terms = [ + "urbithost", + "hosting provider", + "urbit hosting", + "landscape access", + "kubernetes", + "automated hosting", + "layer 2", + "khan vane", + "software distribution", + "hosted urbit", + "onboarding", + "commercial providers" +] [extra] author = "Matt" ship = "~tirwyd-sarmes" diff --git a/app/content/blog/using-urbit-in-2023.md b/app/content/blog/using-urbit-in-2023.md index 3f5a50bc04..b10b1d5640 100644 --- a/app/content/blog/using-urbit-in-2023.md +++ b/app/content/blog/using-urbit-in-2023.md @@ -2,6 +2,18 @@ title = "Using Urbit in 2023" date = "2023-02-06" description = "There are more ways to run Urbit than ever, and more options coming soon." +search_terms = [ + "using urbit 2023", + "hosting providers", + "command line", + "cloud hosting", + "port app", + "windows binary", + "native planet", + "tlon hosting", + "run urbit", + "vps" +] [extra] image = "https://storage.googleapis.com/media.urbit.org/blog/usingurbit-2023.jpg" author = "Josh Lehman" diff --git a/app/content/blog/value-of-address-space-pt1.md b/app/content/blog/value-of-address-space-pt1.md index 011d0d9165..23da085fb1 100644 --- a/app/content/blog/value-of-address-space-pt1.md +++ b/app/content/blog/value-of-address-space-pt1.md @@ -2,6 +2,19 @@ title = "The Value of Urbit Address Space (1 of 3)" date = "2020-04-06" description = "An expansion of our position on Urbit's address space value." +search_terms = [ + "address space value", + "urbit ids", + "azimuth", + "digital asset", + "scarce ids", + "network structure", + "galaxies stars planets", + "address space history", + "urbit land", + "identity system", + "decentralized web" +] [extra] author = "Erik Newton + Galen Wolfe-Pauly" diff --git a/app/content/blog/value-of-address-space-pt2.md b/app/content/blog/value-of-address-space-pt2.md index 1550b5582f..3f90eb8c2b 100644 --- a/app/content/blog/value-of-address-space-pt2.md +++ b/app/content/blog/value-of-address-space-pt2.md @@ -2,6 +2,20 @@ title = "The Value of Urbit Address Space (2 of 3)" date = "2020-04-12" description = "Scarcity, utility, liquidity, and network effect." +search_terms = [ + "address space value", + "scarcity", + "utility", + "liquidity", + "network effect", + "urbit ids", + "planet prices", + "star prices", + "address space trading", + "urbit scarcity", + "network laws", + "urbit tokens" +] [extra] author = "Erik Newton + Galen Wolfe-Pauly" diff --git a/app/content/blog/value-of-address-space-pt3.md b/app/content/blog/value-of-address-space-pt3.md index 68fd1ed99a..320c877751 100644 --- a/app/content/blog/value-of-address-space-pt3.md +++ b/app/content/blog/value-of-address-space-pt3.md @@ -2,6 +2,19 @@ title = "The Value of Urbit Address Space (3 of 3)" date = "2020-07-09" description = "" +search_terms = [ + "address space value", + "urbit ids", + "lockups", + "spawning limits", + "galaxy distribution", + "star unlocks", + "network effects", + "urbit scarcity", + "usage metrics", + "network explorer", + "address space trade" +] [extra] author = "Erik Newton + Galen Wolfe-Pauly" diff --git a/app/content/blog/what-is-urbit-for.md b/app/content/blog/what-is-urbit-for.md index 15be9dad10..562c183e15 100644 --- a/app/content/blog/what-is-urbit-for.md +++ b/app/content/blog/what-is-urbit-for.md @@ -2,6 +2,18 @@ title = "What is Urbit For?" date = "2016-05-10" description = "A vision of the Urbit-powered future." +search_terms = [ + "what is urbit for", + "urbit future", + "personal server vision", + "cryptographic identity", + "self hosted publishing", + "web programmable", + "blockchain complement", + "data permanence", + "reputation systems", + "urbit iot" +] aliases = [ "/posts/essays/what-is-urbit-for", "/posts/what-is-urbit-for" diff --git a/app/content/blog/why-hoon.md b/app/content/blog/why-hoon.md index e58376c068..c31bf943db 100644 --- a/app/content/blog/why-hoon.md +++ b/app/content/blog/why-hoon.md @@ -2,6 +2,19 @@ title = "Why Hoon?" date = "2019-11-13" description = "The promise of Urbit lies in its reimagination of the digital world using components that are as constrained and limited as possible." +search_terms = [ + "why hoon", + "hoon language", + "nock vm", + "functional os", + "hot code reload", + "metaprogramming", + "urbit stack", + "axiomatic", + "purely functional", + "urbit compiler", + "minimalism" +] [extra] author = "Ted Blackman" diff --git a/app/content/blog/why-urbit-probably-does-not-need-a-blockchain.md b/app/content/blog/why-urbit-probably-does-not-need-a-blockchain.md index 19009cb08f..5f86f25ac7 100644 --- a/app/content/blog/why-urbit-probably-does-not-need-a-blockchain.md +++ b/app/content/blog/why-urbit-probably-does-not-need-a-blockchain.md @@ -2,6 +2,18 @@ title = "Why Urbit Probably Doesn't Need a Blockchain" date = "2016-07-13" description = "Urbit (probably) doesn't need a blockchain, because the Urbit address-space PKI is a special case of a consensus ledger." +search_terms = [ + "urbit blockchain", + "urbit pki", + "address space ledger", + "worse is better", + "double sell problem", + "urbit consensus", + "urbit governance", + "ships and wills", + "gossip propagation", + "urbit without blockchain" +] aliases = [ "/posts/essays/why-urbit-probably-does-not-need-a-blockchain/", "/posts/why-urbit-probably-does-not-need-a-blockchain/", diff --git a/app/content/blog/your-last-computer.md b/app/content/blog/your-last-computer.md index 518976645e..da9b0490f1 100644 --- a/app/content/blog/your-last-computer.md +++ b/app/content/blog/your-last-computer.md @@ -2,6 +2,18 @@ title = "Your Last Computer" date = "2019-10-16" description = "Your 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." +search_terms = [ + "your last computer", + "urbit os", + "digital life", + "social computing", + "sealed system", + "private computer", + "urbit communities", + "personal server", + "calm computing", + "future computing" +] [extra] image = "https://media.urbit.org/site/understanding-urbit/your-last-computer/your-last-computer-waves%402x.png" diff --git a/app/content/blurbs/add-and-remove-applications.md b/app/content/blurbs/add-and-remove-applications.md index 5e19c43b8d..8ec43f7ad7 100644 --- a/app/content/blurbs/add-and-remove-applications.md +++ b/app/content/blurbs/add-and-remove-applications.md @@ -2,6 +2,18 @@ title = "Add and remove applications" description = "3rd-party software distribution enables any urbit node to distribute software to the network, these commands help you manage your installed apps." tags = ["dojo"] +search_terms = [ + "install apps", + "uninstall apps", + "nuke app data", + "urbit applications", + "dojo commands", + "app distribution", + "landscape get apps", + "desk management", + "remove app state", + "app recovery" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/azimuth-based-urbit-ids.md b/app/content/blurbs/azimuth-based-urbit-ids.md index 446aa69740..3d9d194a7f 100644 --- a/app/content/blurbs/azimuth-based-urbit-ids.md +++ b/app/content/blurbs/azimuth-based-urbit-ids.md @@ -2,6 +2,19 @@ title = "Azimuth-based Urbit IDs" description = "Azimuth identities are cryptographically owned Urbit address space on the Ethereum blockchain" tags = ["ethereum", "layer 1", "layer 2", "urbit id", "nft"] +search_terms = [ + "azimuth ids", + "urbit id nft", + "ethereum address space", + "bridge login", + "buy urbit id", + "galaxy star planet", + "layer 2 rollup", + "ecliptic contracts", + "ownership ledger", + "web3 wallet", + "network explorer" +] lastest-update ="" image = "" imageDark = "" diff --git a/app/content/blurbs/build-out-your-urbit.md b/app/content/blurbs/build-out-your-urbit.md index 719308f62b..b7991422d2 100644 --- a/app/content/blurbs/build-out-your-urbit.md +++ b/app/content/blurbs/build-out-your-urbit.md @@ -2,6 +2,19 @@ title = "Running your Urbit" description = "" tags = ["configuration", "apps", "urbit-os"] +search_terms = [ + "run urbit", + "urbit os", + "urbit configuration", + "urbit apps", + "urbit id options", + "layer 1 azimuth", + "layer 2 azimuth", + "self hosting", + "private messaging", + "distributed systems", + "bitcoin compatible" +] lastest-update = "" image = "/images/urbit-dither-placeholder.png" imageDark = "" diff --git a/app/content/blurbs/buy-an-urbit-id.md b/app/content/blurbs/buy-an-urbit-id.md index b9480e6438..87ade928ee 100644 --- a/app/content/blurbs/buy-an-urbit-id.md +++ b/app/content/blurbs/buy-an-urbit-id.md @@ -2,6 +2,20 @@ title = "Buy an Urbit ID" description = "Learn how to acquire your own self-sovereign digital identity" tags = ["urbit-id"] +search_terms = [ + "buy urbit id", + "urbit planet", + "azimuth identity", + "layer 1 nft", + "layer 2 rollup", + "opensea marketplace", + "subject network", + "pocwet store", + "bitcoin planet", + "credit card planet", + "galaxy star ids", + "self sovereign identity" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/check-and-reduce-memory-usage.md b/app/content/blurbs/check-and-reduce-memory-usage.md index 45ff1bbf36..3e96172830 100644 --- a/app/content/blurbs/check-and-reduce-memory-usage.md +++ b/app/content/blurbs/check-and-reduce-memory-usage.md @@ -2,6 +2,18 @@ title = "Check and reduce memory usage" description = "Monitor and optimize your urbit's memory consumption" tags = ["dojo", "runtime"] +search_terms = [ + "memory usage", + "loom size", + "mass report", + "meld command", + "pack command", + "urbit runtime", + "dojo tools", + "deduplicate memory", + "pier storage", + "resource constraints" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/check-application-status.md b/app/content/blurbs/check-application-status.md index b51895dad7..f4556101c4 100644 --- a/app/content/blurbs/check-application-status.md +++ b/app/content/blurbs/check-application-status.md @@ -2,6 +2,18 @@ title = "Check application info and status" description = "Running `+vats` will output the state of your apps and related metadata that can help with troubleshooting" tags = ["dojo"] +search_terms = [ + "vats command", + "app status", + "desk metadata", + "urbit apps", + "cz hash", + "publishing ship", + "pending updates", + "dojo tools", + "troubleshoot apps", + "app version" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/check-your-sponsor.md b/app/content/blurbs/check-your-sponsor.md index 8f96fc9400..382283ce15 100644 --- a/app/content/blurbs/check-your-sponsor.md +++ b/app/content/blurbs/check-your-sponsor.md @@ -2,6 +2,17 @@ title = "Check your current sponsor" description = "Understanding your networking sponsor can help with troubleshooting connectivity issues" tags = ["dojo"] +search_terms = [ + "sponsor command", + "network sponsor", + "sponsor chain", + "urbit connectivity", + "dojo sponsor", + "bridge sponsor", + "network explorer", + "onchain sponsor", + "urbit sponsor" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/checking-and-fixing-azimuth-state.md b/app/content/blurbs/checking-and-fixing-azimuth-state.md index edd54d7ba3..c7b98bd267 100644 --- a/app/content/blurbs/checking-and-fixing-azimuth-state.md +++ b/app/content/blurbs/checking-and-fixing-azimuth-state.md @@ -2,6 +2,18 @@ title = "Checking and fixing Azimuth state" description = "Monitor and repair your PKI state synchronization" tags = ["dojo", "azimuth"] +search_terms = [ + "azimuth state", + "pki sync", + "azimuth block", + "ethereum block", + "azimuth load", + "pki snapshot", + "dojo azimuth", + "state sync", + "azimuth snapshot", + "bridge azimuth" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/common-pitfalls-of-running-urbit.md b/app/content/blurbs/common-pitfalls-of-running-urbit.md index 04261d28ca..863ef2f812 100644 --- a/app/content/blurbs/common-pitfalls-of-running-urbit.md +++ b/app/content/blurbs/common-pitfalls-of-running-urbit.md @@ -2,6 +2,17 @@ title = "Common Pitfalls Of Running Urbit" description = "Placeholder description" tags = [] +search_terms = [ + "urbit pitfalls", + "running urbit issues", + "common mistakes", + "urbit troubleshooting", + "ship errors", + "self hosting problems", + "urbit setup", + "beginner mistakes", + "pier issues" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/create-a-moon-identity.md b/app/content/blurbs/create-a-moon-identity.md index c1160178ac..8115eeba1f 100644 --- a/app/content/blurbs/create-a-moon-identity.md +++ b/app/content/blurbs/create-a-moon-identity.md @@ -2,6 +2,18 @@ title = "Create a moon identity" description = "Spawn subordinate identities tied to your planet" tags = ["dojo", "urbit-id"] +search_terms = [ + "moon identity", + "spawn moon", + "urbit moon", + "moon keyfile", + "moon breach", + "moon cycle keys", + "azimuth moon", + "dojo moon", + "sub identity", + "moon reset" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/directly-contact-another-urbit.md b/app/content/blurbs/directly-contact-another-urbit.md index 036550c1f7..1ec590aa04 100644 --- a/app/content/blurbs/directly-contact-another-urbit.md +++ b/app/content/blurbs/directly-contact-another-urbit.md @@ -2,6 +2,17 @@ title = "Directly contact another urbit" description = "Urbit's most basic messaging protocol can send a quick hi in the dojo" tags = ["dojo"] +search_terms = [ + "hi command", + "dojo hi", + "ping ship", + "direct message", + "urbit p2p", + "neighbor message", + "connect to ship", + "urbit messaging", + "quick hi" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/docking-your-urbit.md b/app/content/blurbs/docking-your-urbit.md index c20f7dbe40..9be67ce121 100644 --- a/app/content/blurbs/docking-your-urbit.md +++ b/app/content/blurbs/docking-your-urbit.md @@ -2,6 +2,17 @@ title = "Docking your urbit" description = "Install a specific runtime version into your pier" tags = ["runtime"] +search_terms = [ + "dock command", + "urbit dock", + "runtime version", + "vere binary", + "pier runtime", + "version pinning", + "docked pier", + "run urbit", + "runtime install" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/docs-for-self-hosting-urbit.md b/app/content/blurbs/docs-for-self-hosting-urbit.md index 3203b28f44..d51d86587d 100644 --- a/app/content/blurbs/docs-for-self-hosting-urbit.md +++ b/app/content/blurbs/docs-for-self-hosting-urbit.md @@ -2,6 +2,18 @@ title = "Documentation for self-hosting urbit" description = "The top guides for learning how to run your own urbit node" tags = [] +search_terms = [ + "self hosting guide", + "run urbit node", + "cloud hosting", + "groundseg guide", + "local setup", + "urbit os", + "hosting docs", + "comet identity", + "native planet", + "cloud server" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/get-access-code.md b/app/content/blurbs/get-access-code.md index e5cd772544..95f58ff70c 100644 --- a/app/content/blurbs/get-access-code.md +++ b/app/content/blurbs/get-access-code.md @@ -2,6 +2,17 @@ title = "Get access code" description = "A secret code for remote access to your instance of Urbit OS" tags = ["dojo"] +search_terms = [ + "access code", + "+code", + "luscode", + "urbit login", + "remote access", + "mobile client", + "web login", + "phenome code", + "urbit secret" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/get-started-with-cloud-server.md b/app/content/blurbs/get-started-with-cloud-server.md index a58a541ac9..a2e11a4b14 100644 --- a/app/content/blurbs/get-started-with-cloud-server.md +++ b/app/content/blurbs/get-started-with-cloud-server.md @@ -2,6 +2,18 @@ title = "Cloud Server" description = "Running in a virtual private server (VPS) affords easy solutions to things like DNS and remote access, at a marginal cost to tangible control of your data" tags = ["vps", "cloud", "self-hosting"] +search_terms = [ + "cloud server", + "vps hosting", + "self host urbit", + "remote access", + "personal server", + "datacenter hosting", + "dns setup", + "cloud hosting guide", + "virtual private server", + "urbit hosting" +] lastest-update = "" image = "/images/cloud-hosting-sigil-dither.png" imageDark = "" diff --git a/app/content/blurbs/get-started-with-command-line.md b/app/content/blurbs/get-started-with-command-line.md index cc32cb7cfa..ee7d7efdc9 100644 --- a/app/content/blurbs/get-started-with-command-line.md +++ b/app/content/blurbs/get-started-with-command-line.md @@ -2,6 +2,18 @@ title = "Command Line" description = "Every Urbit OS server is made unique by its Urbit ID, which others can use to reach you on the network. There are five ranks of Urbit ID, but the one an ordinary user needs is a planet, which has a four-syllable name like \"~sampel-palnet\". Unless you know someone who can gift you one, or you want to get one from hosting provider like Tlon, you'll need to buy one." tags = ["cli", "self-hosting", "command-line"] +search_terms = [ + "command line", + "cli setup", + "run urbit", + "self host", + "terminal boot", + "get urbit id", + "comet identity", + "unix terminal", + "urbit cli", + "boot a ship" +] lastest-update = "" image = "/images/uf-board-sigils-dither.png" imageDark = "" diff --git a/app/content/blurbs/get-started-with-native-planet.md b/app/content/blurbs/get-started-with-native-planet.md index 06f6b9ca85..3fbfa66e28 100644 --- a/app/content/blurbs/get-started-with-native-planet.md +++ b/app/content/blurbs/get-started-with-native-planet.md @@ -2,6 +2,18 @@ title = "Native Planet" description = "Native Planet builds hardware and software for simplified home hosting of your Urbit" tags = ["native-planet", "self-hosting", "hardware"] +search_terms = [ + "native planet", + "urbit hardware", + "groundseg", + "startram", + "home hosting", + "local control", + "device hosting", + "urbit appliance", + "preloaded urbit", + "hardware hosting" +] lastest-update = "" image = "/images/native-planet-callisto-dither.png" imageDark = "" diff --git a/app/content/blurbs/get-started-with-tlon-hosting.md b/app/content/blurbs/get-started-with-tlon-hosting.md index 224a76976f..241dae185e 100644 --- a/app/content/blurbs/get-started-with-tlon-hosting.md +++ b/app/content/blurbs/get-started-with-tlon-hosting.md @@ -2,6 +2,18 @@ title = "Tlon Hosting" description = "Tlon Corporation is the preeminent hosting provider which provides free and seamless onboarding to the Urbit network" tags = ["hosting", "hosting-provider", "urbit-os", "tlon", "layer 2"] +search_terms = [ + "tlon hosting", + "tlon messenger", + "hosted urbit", + "quickstart", + "onboarding", + "layer 2", + "hosting provider", + "phone number signup", + "email signup", + "managed hosting" +] lastest-update ="" image = "/images/tlon-corp-dither.png" imageDark = "" diff --git a/app/content/blurbs/getting-started-with-urbit.md b/app/content/blurbs/getting-started-with-urbit.md index 15f9881c6e..80b7c3a783 100644 --- a/app/content/blurbs/getting-started-with-urbit.md +++ b/app/content/blurbs/getting-started-with-urbit.md @@ -2,6 +2,18 @@ title = "Get Started with Urbit" description = "Ready to join the Urbit network? Get your own Urbit ID and start exploring a new way to compute." tags = ["getting-started", "homepage", "sidebar"] +search_terms = [ + "get started", + "urbit id", + "urbit os", + "join urbit", + "quickstart", + "self sovereign", + "start exploring", + "urbit network", + "buy urbit id", + "learn urbit" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/groundwire-based-urbit-ids.md b/app/content/blurbs/groundwire-based-urbit-ids.md index 66ad2d30e2..cf31803803 100644 --- a/app/content/blurbs/groundwire-based-urbit-ids.md +++ b/app/content/blurbs/groundwire-based-urbit-ids.md @@ -2,6 +2,18 @@ title = "Groundwire-based Urbit IDs" description = "Groundwire identities are cryptographically owned Urbit address space on the Bitcoin blockchain" tags = ["bitcoin", "urbit-id", "ordinal", "comet"] +search_terms = [ + "groundwire ids", + "bitcoin urbit", + "ordinal nft", + "inscription nft", + "comet identity", + "bitcoin address space", + "groundwire network", + "l1 bitcoin fees", + "self issued ids", + "groundwire messenger" +] lastest-update ="" image = "" imageDark = "" diff --git a/app/content/blurbs/homepage-go-deeper.md b/app/content/blurbs/homepage-go-deeper.md index efe3552de6..85a777ba8f 100644 --- a/app/content/blurbs/homepage-go-deeper.md +++ b/app/content/blurbs/homepage-go-deeper.md @@ -2,6 +2,17 @@ title = "Go Deeper" description = "Ready to explore more? Learn about Urbit's architecture, identity system, and the broader ecosystem of applications and tools being built on the network." tags = ["learning", "documentation", "homepage"] +search_terms = [ + "urbit architecture", + "identity system", + "urbit docs", + "urbit overview", + "ecosystem apps", + "learn urbit", + "technical documentation", + "urbit community", + "personal computing" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/homepage-hosting-providers.md b/app/content/blurbs/homepage-hosting-providers.md index 7e05e1c572..903ff58cbb 100644 --- a/app/content/blurbs/homepage-hosting-providers.md +++ b/app/content/blurbs/homepage-hosting-providers.md @@ -2,6 +2,17 @@ title = "Hosting Providers" description = "While urbit is designed to be run by it's users, and so simple that caring for it would be as simple as caring for a cactus, it's not quite there yet. And some people aren't inclined to want to take on the burden of learning how to run their own urbit. If this sound like you, don't worry. Third party hosting providers can run your urbit on your behalf, while still maintaining many of the ownership characteristics that make urbit yours (in stark contrast to legacy cloud software." tags = ["hosting", "hosting-provider", "homepage"] +search_terms = [ + "hosting providers", + "third party hosting", + "managed hosting", + "hosted urbit", + "run urbit for you", + "cloud provider", + "urbit ownership", + "self hosting alternative", + "personal server hosting" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/homepage-self-hosting.md b/app/content/blurbs/homepage-self-hosting.md index 2fbc43c326..0d12819d68 100644 --- a/app/content/blurbs/homepage-self-hosting.md +++ b/app/content/blurbs/homepage-self-hosting.md @@ -2,6 +2,17 @@ title = "Self-Hosting" description = "Urbit is an attempt to build a computer that is truly yours, designed to last a lifetime, with which you can form trustworthy networks free of extractive middlemen. Part of that means a being a networked computer that can be run by it's users. That said, Urbit is still under active development, so self-hosting is currently most apt for users who aren't afraid of a little bit of tinkering. If that's not you, we recommend using a hosting provider instead." tags = ["self-hosting", "homepage"] +search_terms = [ + "self hosting", + "run urbit yourself", + "personal server", + "boot urbit", + "maintain urbit", + "tinkering", + "full control", + "urbit experience", + "caring for cactus" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/learn-to-hoon.md b/app/content/blurbs/learn-to-hoon.md index 8fd615e407..5a304fafbd 100644 --- a/app/content/blurbs/learn-to-hoon.md +++ b/app/content/blurbs/learn-to-hoon.md @@ -2,6 +2,18 @@ title = "Learn To Hoon" description = "Hoon is Urbit's high-level, statically-typed, purely-functional programming language" tags = [] +search_terms = [ + "learn hoon", + "hoon school", + "urbit programming", + "functional language", + "nock hoon", + "runic syntax", + "systems programming", + "hoon docs", + "hoon video", + "hoon source" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/reduce-your-pier-size.md b/app/content/blurbs/reduce-your-pier-size.md index 9c122a504c..d6292cfafc 100644 --- a/app/content/blurbs/reduce-your-pier-size.md +++ b/app/content/blurbs/reduce-your-pier-size.md @@ -2,6 +2,18 @@ title = "Reduce your pier size" description = "Compress and clean up your urbit's disk usage" tags = ["dojo", "runtime"] +search_terms = [ + "reduce pier size", + "roll command", + "chop command", + "urbit disk", + "event log", + "epoch", + "runtime disk", + "pier cleanup", + "truncate events", + "urbit storage" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/run-urbit-in-a-vps.md b/app/content/blurbs/run-urbit-in-a-vps.md index 23b0a0c2e9..b745fe7e9d 100644 --- a/app/content/blurbs/run-urbit-in-a-vps.md +++ b/app/content/blurbs/run-urbit-in-a-vps.md @@ -2,6 +2,18 @@ title = "Run urbit in a virtual server" description = "Urbit runs seamlessly in any cloud server or datacenter you may already be familiar with" tags = [] +search_terms = [ + "cloud server", + "vps urbit", + "run urbit in cloud", + "aws urbit", + "linode urbit", + "server requirements", + "linux hosting", + "datacenter hosting", + "virtual server", + "cloud hosting guide" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/run-urbit-locally.md b/app/content/blurbs/run-urbit-locally.md index 81316b113f..ae89af8dba 100644 --- a/app/content/blurbs/run-urbit-locally.md +++ b/app/content/blurbs/run-urbit-locally.md @@ -2,6 +2,18 @@ title = "Run urbit locally" description = "Quickly and easily run urbit on your laptop, or home desktop computer" tags = [] +search_terms = [ + "run urbit locally", + "laptop urbit", + "home computer", + "local network", + "localhost access", + "ames networking", + "local urbit", + "home hosting", + "fakeship", + "no public domain" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/run-urbit-using-groundseg.md b/app/content/blurbs/run-urbit-using-groundseg.md index 64255e9cd3..0b2e3d5e58 100644 --- a/app/content/blurbs/run-urbit-using-groundseg.md +++ b/app/content/blurbs/run-urbit-using-groundseg.md @@ -2,6 +2,18 @@ title = "Run Urbit Using Groundseg" description = "Groundseg is free and open-source software for running urbits, developed by Native Planet" tags = ["urbit-os", "docker", "native-planet"] +search_terms = [ + "groundseg", + "native planet software", + "urbit gui", + "docker urbit", + "colonyos", + "startram", + "anchor", + "urbit management", + "loom size", + "event log" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/run-urbit-using-native-planet-hardware.md b/app/content/blurbs/run-urbit-using-native-planet-hardware.md index 072e0c85a7..35434051f9 100644 --- a/app/content/blurbs/run-urbit-using-native-planet-hardware.md +++ b/app/content/blurbs/run-urbit-using-native-planet-hardware.md @@ -2,6 +2,18 @@ title = "Run urbit using Native Planet hardware" description = "Placeholder description" tags = [] +search_terms = [ + "native planet hardware", + "urbit appliance", + "colonyos", + "groundseg", + "startram", + "anchor", + "minio setup", + "self hosting device", + "dns service", + "hardware hosting" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/run-urbit-with-tlon-hosting.md b/app/content/blurbs/run-urbit-with-tlon-hosting.md index debb5d0d0d..2a834163a1 100644 --- a/app/content/blurbs/run-urbit-with-tlon-hosting.md +++ b/app/content/blurbs/run-urbit-with-tlon-hosting.md @@ -2,6 +2,18 @@ title = "Tlon hosting services" description = "Tlon Corporation is the preeminent hosting provider which provides free and seamless onboarding to the Urbit network" tags = ["hosting", "hosting-provider", "urbit-os", "tlon", "layer 2"] +search_terms = [ + "tlon hosting", + "tlon messenger", + "hosted urbit", + "layer 2 planet", + "master ticket", + "management proxy", + "urbit foundation group", + "invite friends", + "support email", + "hosted onboarding" +] lastest-update ="" image = "" imageDark = "" diff --git a/app/content/blurbs/select-available-loom-size.md b/app/content/blurbs/select-available-loom-size.md index 21b7734bb9..88d7924a2d 100644 --- a/app/content/blurbs/select-available-loom-size.md +++ b/app/content/blurbs/select-available-loom-size.md @@ -2,6 +2,17 @@ title = "Select available loom size" description = "Configure memory allocation for your urbit" tags = ["runtime"] +search_terms = [ + "loom size", + "--loom", + "memory allocation", + "urbit ram", + "loom exponent", + "loom 32", + "configure runtime", + "run urbit memory", + "loom flag" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/self-custody-your-id.md b/app/content/blurbs/self-custody-your-id.md index 6f48648928..1d40354a58 100644 --- a/app/content/blurbs/self-custody-your-id.md +++ b/app/content/blurbs/self-custody-your-id.md @@ -2,6 +2,18 @@ title = "Self-custody your Urbit ID" description = "As a cryptographic asset, there are many ways to control and secure your Urbit ID" tags = ["wallet", "ledger", "trezor", "metamask", "urbit-id"] +search_terms = [ + "self custody", + "urbit id security", + "hardware wallet", + "software wallet", + "master ticket", + "ledger trezor", + "metamask", + "seed phrase", + "bridge wallet", + "ownership key" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/shortfalls-of-hosting-providers.md b/app/content/blurbs/shortfalls-of-hosting-providers.md index d3e2eac0f2..33909571ba 100644 --- a/app/content/blurbs/shortfalls-of-hosting-providers.md +++ b/app/content/blurbs/shortfalls-of-hosting-providers.md @@ -2,6 +2,17 @@ title = "Shortfalls of hosting providers" description = "Hosting providers are designed to be scalable, not bespoke, operations." tags = ["hosting", "urbit-os"] +search_terms = [ + "hosting drawbacks", + "provider risks", + "encrypted at rest", + "host access data", + "self hosting control", + "dns control", + "ssh access", + "managed hosting limits", + "urbit privacy" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/shut-down-your-urbit.md b/app/content/blurbs/shut-down-your-urbit.md index 12d8e42852..ac3e66f42c 100644 --- a/app/content/blurbs/shut-down-your-urbit.md +++ b/app/content/blurbs/shut-down-your-urbit.md @@ -2,6 +2,17 @@ title = "Shut down your urbit" description = "Gracefully stop your urbit instance" tags = ["dojo", "runtime"] +search_terms = [ + "shutdown urbit", + "exit command", + "ctrl-d", + "graceful shutdown", + "stop urbit", + "dojo exit", + "runtime shutdown", + "solid state", + "power loss recovery" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/start-and-stop-applications-on-your-urbit.md b/app/content/blurbs/start-and-stop-applications-on-your-urbit.md index 0efb12d07f..244e40817f 100644 --- a/app/content/blurbs/start-and-stop-applications-on-your-urbit.md +++ b/app/content/blurbs/start-and-stop-applications-on-your-urbit.md @@ -2,6 +2,17 @@ title = "Start and stop applications on your urbit" description = "Control application lifecycles with dojo commands" tags = ["dojo"] +search_terms = [ + "start app", + "stop app", + "dojo start", + "suspend desk", + "pause desk", + "revive app", + "agent control", + "app lifecycle", + "desk updates" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/start-up-your-urbit.md b/app/content/blurbs/start-up-your-urbit.md index 0b3aed7179..276e6b3f32 100644 --- a/app/content/blurbs/start-up-your-urbit.md +++ b/app/content/blurbs/start-up-your-urbit.md @@ -2,6 +2,17 @@ title = "Restart up your urbit after initial boot" description = "Restarting your urbit after intial boot is straightforward and doesn't require additional cryptographic secrets" tags = ["runtime"] +search_terms = [ + "restart urbit", + "run urbit", + "urbit runtime", + "pier run", + "docked pier", + ".run", + "loom flag", + "boot ship", + "urbit restart" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/support-contact-points.md b/app/content/blurbs/support-contact-points.md index 0f5719a270..048bd836d6 100644 --- a/app/content/blurbs/support-contact-points.md +++ b/app/content/blurbs/support-contact-points.md @@ -2,6 +2,17 @@ title = "Off-network support channels" description = "Not able to get onto the network at all? Here are some off-network channels for getting support" tags = [] +search_terms = [ + "support email", + "off network support", + "urbit support", + "tlon support", + "github issues", + "can't connect", + "help offline", + "support@urbit.org", + "support@tlon.io" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/troubleshooting-your-urbit.md b/app/content/blurbs/troubleshooting-your-urbit.md index 190c79febd..ea09996bca 100644 --- a/app/content/blurbs/troubleshooting-your-urbit.md +++ b/app/content/blurbs/troubleshooting-your-urbit.md @@ -2,6 +2,16 @@ title = "Troubleshooting Your Urbit" description = "Placeholder description" tags = [] +search_terms = [ + "urbit troubleshooting", + "common issues", + "fix urbit", + "ship errors", + "help running urbit", + "urbit support", + "debug urbit", + "network issues" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/update-commands-for-your-urbit.md b/app/content/blurbs/update-commands-for-your-urbit.md index eb0bbd6827..7dd5def80b 100644 --- a/app/content/blurbs/update-commands-for-your-urbit.md +++ b/app/content/blurbs/update-commands-for-your-urbit.md @@ -2,6 +2,17 @@ title = "Update Commands For Your Urbit" description = "Your urbit is generally auto-updating, but in the event of an incompatible application or a kernel update that would conflict with existing apps, you may need to decide which software to run" tags = ["dojo"] +search_terms = [ + "update commands", + "bump", + "ota", + "kernel update", + "app incompatibility", + "suspend desks", + "update provider", + "over the air", + "dojo update" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/update-your-urbit-runtime.md b/app/content/blurbs/update-your-urbit-runtime.md index 5ce43b7de7..37bfaffe8a 100644 --- a/app/content/blurbs/update-your-urbit-runtime.md +++ b/app/content/blurbs/update-your-urbit-runtime.md @@ -2,6 +2,17 @@ title = "Update your urbit runtime" description = "Keep your vere binary up to date" tags = ["runtime"] +search_terms = [ + "update runtime", + "vere next", + "urbit next", + "runtime updates", + "vere binary", + "performance fixes", + "bug fixes", + "networking updates", + "runtime install" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/urbit-as-overlay-os.md b/app/content/blurbs/urbit-as-overlay-os.md index 3539dc951c..cf2bd1e644 100644 --- a/app/content/blurbs/urbit-as-overlay-os.md +++ b/app/content/blurbs/urbit-as-overlay-os.md @@ -2,6 +2,18 @@ title = "Urbit as overlay OS" description = "Urbit OS is a personal server operating system that runs on any Unix box as a self-contained virtual machine" tags = ["urbit-os", "virtual-machine", "runtime"] +search_terms = [ + "overlay os", + "urbit os", + "vere runtime", + "virtual machine", + "portable pier", + "move urbit", + "stateful networking", + "double boot", + "zip pier", + "host os" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/urbit-id-incentives-for-hosts.md b/app/content/blurbs/urbit-id-incentives-for-hosts.md index 753a0d5a0c..0ea65ddb6d 100644 --- a/app/content/blurbs/urbit-id-incentives-for-hosts.md +++ b/app/content/blurbs/urbit-id-incentives-for-hosts.md @@ -2,6 +2,18 @@ title = "Urbit ID incentives for hosts" description = "Cryptographic ownership of Urbit ID helps enforce honest operation of Urbit OS by hosting providers" tags = [] +search_terms = [ + "host incentives", + "urbit id ownership", + "principal agent", + "hosting provider", + "user control", + "cryptographic identity", + "unpersoning", + "host accountability", + "self sovereign", + "bridge" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/urbit-master-ticket-wallets.md b/app/content/blurbs/urbit-master-ticket-wallets.md index 3fd3b4224a..d7311126c6 100644 --- a/app/content/blurbs/urbit-master-ticket-wallets.md +++ b/app/content/blurbs/urbit-master-ticket-wallets.md @@ -2,6 +2,18 @@ title = "Urbit master ticket wallets" description = "Master ticket wallets are an easy and secure way for managing ownership of your Urbit ID" tags = ["ethereum", "wallet", "azimuth"] +search_terms = [ + "master ticket", + "brainwallet", + "hd wallet", + "urbit id wallet", + "bridge", + "cryptographic keys", + "azimuth wallet", + "ledger trezor", + "metamask", + "gnosis safe" +] lastest-update ="" image = "" imageDark = "" diff --git a/app/content/blurbs/urbit-related-blogs.md b/app/content/blurbs/urbit-related-blogs.md index 5cf07db446..273b7c48a8 100644 --- a/app/content/blurbs/urbit-related-blogs.md +++ b/app/content/blurbs/urbit-related-blogs.md @@ -2,6 +2,17 @@ title = "Urbit-related blogs" description = "A collection of written urbit content from the broader community" tags = [] +search_terms = [ + "urbit blogs", + "community writing", + "subject network blog", + "martian computing", + "hawk blog", + "urmanac", + "urbit essays", + "urbit commentary", + "sarlev blog" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/urbit-support-groups.md b/app/content/blurbs/urbit-support-groups.md index 0db6e9e126..ffeed5e2a1 100644 --- a/app/content/blurbs/urbit-support-groups.md +++ b/app/content/blurbs/urbit-support-groups.md @@ -2,6 +2,18 @@ title = "On-network support channels" description = "Need help with something? Give a shout in one of these groups and someone will give you a hand" tags = [] +search_terms = [ + "support groups", + "tlon local", + "battery payload", + "hooniverse", + "urbit community", + "uf public", + "tlon messenger groups", + "get help on urbit", + "support comet", + "join group" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/urbit-systems-technical-journal.md b/app/content/blurbs/urbit-systems-technical-journal.md index d11a8cc0cb..a5c8d5ea74 100644 --- a/app/content/blurbs/urbit-systems-technical-journal.md +++ b/app/content/blurbs/urbit-systems-technical-journal.md @@ -2,6 +2,18 @@ title = "Urbit Systems Technical Journal" description = "Placeholder description" tags = [] +search_terms = [ + "ustj", + "urbit systems journal", + "technical journal", + "solid state computing", + "neo urbit", + "nock performance", + "memory management", + "dynamic linking", + "submit article", + "lagrev nocfep" +] lastest-update = "" image = "" imageDark = "" diff --git a/app/content/blurbs/why-hosting-providers.md b/app/content/blurbs/why-hosting-providers.md index 699ed60d9e..683fe27ce9 100644 --- a/app/content/blurbs/why-hosting-providers.md +++ b/app/content/blurbs/why-hosting-providers.md @@ -2,6 +2,18 @@ title = "Why use a hosting provider?" description = "Urbit is a personal server, yet there are still service providers who will host it for you" tags = ["hosting", "hosting-provider", "urbit-os"] +search_terms = [ + "why hosting", + "hosting provider", + "managed hosting", + "onboarding", + "maintenance support", + "groundseg", + "network effects", + "personal server", + "cactus analogy", + "hosted urbit" +] lastest-update ="" image = "" imageDark = ""