Update and maintain joelclaw.com — the Next.js web app at apps/web/. Use when writing blog posts, editing pages, updating the network page, changing layout/header/footer, adding components, or fixing anything on the site. Hard content triggers: 'write article about X' (draft in Convex), 'publish article <slug>' (set draft=false + revalidate tags/paths). Also triggers on: 'update the site', 'write a post', 'fix the blog', 'joelclaw.com', 'update network page', 'add a page', 'change the header', or any task involving the public-facing web app.
Next.js app at apps/web/ in the joelclaw monorepo (~/Code/joelhooks/joelclaw/).
Deployed to Vercel on push to main. Dark theme, minimal, system-y aesthetic.
Never expose real infrastructure details on public pages.
com.joel. or similar prefixes from service identifiersCurrent King universe mapping (network page):
| Role | Alias | Source |
|---|---|---|
| Mac Mini (control plane) | Overlook | The Shining |
| NAS (archive) | Derry | IT |
| Laptop (dev machine) | Flagg | The Dark Tower |
| Linux server | Blaine | The Dark Tower |
| Router (exit node) | Todash | The Dark Tower |
Canonical runtime content lives in Convex contentResources:
article:<slug> (type = article)adr:<slug> (type = adr)discovery:<slug> (type = discovery)Filesystem content under apps/web/content/ is seed/backfill material, not runtime source.
Runtime read policy:
apps/web/lib/posts.ts → Convex-first articles (article:*)apps/web/lib/adrs.ts → Convex-first ADRs (adr:*)apps/web/lib/discoveries.ts → Convex-first discoveries (discovery:*)JOELCLAW_ALLOW_FILESYSTEM_POSTS_FALLBACK=1 (articles)JOELCLAW_ALLOW_FILESYSTEM_CONTENT_FALLBACK=1 (ADRs/discoveries)Article fields still mirror MDX frontmatter shape:
---
title: "Post Title"
type: "article" | "essay" | "note" | "tutorial"
date: "2026-02-19T11:00:00" # ISO datetime, NOT just date
updated: "2026-02-19T14:30:00" # optional, bumps sort position
description: "One-liner for cards and meta"
tags: ["tag1", "tag2"]
draft: true # optional, hides from prod
source: "https://..." # optional, for video-notes
channel: "Channel Name" # optional, for video-notes
duration: "00:42:02" # optional, for video-notes
---Sorting: Posts sort by updated ?? date descending. Use full ISO datetimes (not bare dates) for deterministic ordering. Setting updated bumps a post to the top without changing its original publish date.
Slugs: Derived from fields.slug in Convex (resourceId = article:<slug>).
write article about XcontentResources with resourceId = article:<slug>, type = "article", full MDX body in fields.content, and fields.draft = true.fields.date to current ISO timestamp./<slug> if draft-visible in dev).publish article <slug>article:<slug> from Convex.fields.draft = false and fields.updated = now.POST /api/revalidate with:
post:<slug>, article:<slug>, articles/, /<slug>, /<slug>.md, /<slug>/md, /feed.xml, /sitemap.md/, /<slug>, /<slug>.md, and /feed.xml include the published post.Always embed YouTube videos in /cool discoveries and articles when they add context. Use the <YouTube id="VIDEO_ID" /> MDX component (available in both .mdx articles and .md discoveries). Extract the video ID from the URL (youtube.com/watch?v=VIDEO_ID). Place embeds near the top of the relevant section, before the prose discussion.
Use the canonical joel-writing-style skill for prose. Key traits: direct, first-person when the claim is actually Joel's, strategic profanity, short paragraphs, bold emphasis, conversational but technical. Never corporate-speak and never fabricate Joel's beliefs or philosophy.
bg-[#0a0a0a]), neutral grays, --color-claw: #ff1493 (hot pink accent)max-w-2xl (672px) — intentionally narrow for reading/), Cool (/cool), ADRs (/adrs), Network (/network)usePathname()MobileNav component| File | Purpose |
|---|---|
app/layout.tsx | Root layout, fonts, metadata, footer |
app/page.tsx | Home page (post list) |
app/[slug]/page.tsx | Post detail pages |
app/adrs/page.tsx | ADR list |
app/adrs/[slug]/page.tsx | ADR detail (strips H1 to avoid duplicate title) |
app/cool/page.tsx | Cool/discoveries list |
app/network/page.tsx | Infrastructure status page |
components/site-header.tsx | Header with active nav (client component) |
components/mobile-nav.tsx | Mobile overlay nav |
components/search-dialog.tsx | ⌘K search |
lib/posts.ts | Article loading from Convex (article:*) |
lib/adrs.ts | ADR loading from Convex (adr:*) |
lib/discoveries.ts | Discovery loading from Convex (discovery:*) |
lib/constants.ts | Site name, URL, tagline |
lib/claw.ts | SVG path for claw icon |
contentResources with resourceId = adr:<slug>)apps/web/content/adrs/bun scripts/seed-adrs-discoveries.tsapp/adrs/[slug]/page.tsx) strips the H1 from markdown content because the page already renders the title with ADR number prefixcontent.replace(/^#\s+(?:ADR-\d+:\s*)?.*$/m, "").trim()contentResources.upsert, resourceId = article:<slug>, draft: true).date field.apps/web/public/images/<slug>/ if needed and reference /images/<slug>/... in MDX.draft: false, then revalidate tags + paths (post:<slug>, article:<slug>, articles, /, /<slug>, /<slug>.md, /<slug>/md, /feed.xml, /sitemap.md).Backfill scripts:
scripts/seed-articles.ts for article resourcesscripts/seed-adrs-discoveries.ts for ADR + discovery resourcesThe network page (app/network/page.tsx) shows real infrastructure with aliased names. When updating:
kubectl get pods, tailscale status, launchctl print, etc.)825972c
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.