Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
joelhooks avatar

Joelclaw Web

  • 33 installs
  • 61 repo stars
  • Updated August 4, 2026
  • joelhooks/joelclaw

Update and maintain joelclaw.com, the Next.js app at apps/web, including pages, layout, components, and Convex-backed blog content.

About

Covers editing the public joelclaw.com Next.js app and its Convex-first content model, with OPSEC rules for hiding real infra. A developer uses it to write posts, edit pages, or fix the site.

  • OPSEC: never expose real hostnames, ports, IPs; use King-universe aliases
  • Convex contentResources is runtime source; filesystem content is seed material

Joelclaw Web by the numbers

  • 33 all-time installs (skills.sh)
  • Ranked #1,438 of 2,245 Frontend Development skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/joelhooks/joelclaw --skill joelclaw-web

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs33
repo stars61
Last updatedAugust 4, 2026
Repositoryjoelhooks/joelclaw

What it does

Update and maintain joelclaw.com, the Next.js app at apps/web, including pages, layout, components, and Convex-backed blog content.

Files

SKILL.mdMarkdownGitHub ↗

joelclaw.com 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.

OPSEC Rules

Never expose real infrastructure details on public pages.

  • Node/host names: Use Stephen King universe aliases, never real tailnet hostnames
  • Ports: Do not publish port numbers for any service
  • Usernames: Strip com.joel. or similar prefixes from service identifiers
  • IPs/subnets: Never show real IP addresses or CIDR ranges
  • Brands/models of network gear: Generalize (e.g. "NAS" not "Synology DS1821+")
  • Tailscale: OK to mention as the mesh VPN product, but no tailnet name or node IPs

Current King universe mapping (network page):

RoleAliasSource
Mac Mini (control plane)OverlookThe Shining
NAS (archive)DerryIT
Laptop (dev machine)FlaggThe Dark Tower
Linux serverBlaineThe Dark Tower
Router (exit node)TodashThe Dark Tower

Content Model (Convex-first)

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:*)
  • Optional local escape hatches (non-production only):
  • 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>).

Hard Trigger Workflow

write article about X

1. Generate slug from title/topic. 2. Upsert contentResources with resourceId = article:<slug>, type = "article", full MDX body in fields.content, and fields.draft = true. 3. Set fields.date to current ISO timestamp. 4. Return slug + draft preview link (/<slug> if draft-visible in dev).

publish article <slug>

1. Read article:<slug> from Convex. 2. Patch/upsert with fields.draft = false and fields.updated = now. 3. Revalidate all affected surfaces via POST /api/revalidate with:

  • tags: post:<slug>, article:<slug>, articles
  • paths: /, /<slug>, /<slug>.md, /<slug>/md, /feed.xml, /sitemap.md

4. Verify /, /<slug>, /<slug>.md, and /feed.xml include the published post.

Media Embeds

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.

Writing Voice

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.

Design System

  • Theme: Dark (bg-[#0a0a0a]), neutral grays, --color-claw: #ff1493 (hot pink accent)
  • Fonts: Geist Sans (body), Geist Mono (code/data), Dank Mono (code blocks with ligatures)
  • Content width: max-w-2xl (672px) — intentionally narrow for reading
  • Header: Single row — claw icon + "JoelClaw" left, nav links + search right. No tagline in header.
  • Nav items: Writing (/), Cool (/cool), ADRs (/adrs), Network (/network)
  • Active nav: White text vs neutral-500 for inactive, detected via usePathname()
  • Search: ⌘K dialog using pagefind, type-based icons/badges
  • Mobile: Full-screen overlay nav via MobileNav component
  • Code blocks: Catppuccin Macchiato theme, rehype-pretty-code
  • Sidenotes: Tufte-style CSS sidenotes (pure CSS, no JS)

Key Files

FilePurpose
app/layout.tsxRoot layout, fonts, metadata, footer
app/page.tsxHome page (post list)
app/[slug]/page.tsxPost detail pages
app/adrs/page.tsxADR list
app/adrs/[slug]/page.tsxADR detail (strips H1 to avoid duplicate title)
app/cool/page.tsxCool/discoveries list
app/network/page.tsxInfrastructure status page
components/site-header.tsxHeader with active nav (client component)
components/mobile-nav.tsxMobile overlay nav
components/search-dialog.tsx⌘K search
lib/posts.tsArticle loading from Convex (article:*)
lib/adrs.tsADR loading from Convex (adr:*)
lib/discoveries.tsDiscovery loading from Convex (discovery:*)
lib/constants.tsSite name, URL, tagline
lib/claw.tsSVG path for claw icon

ADR Display Rules

  • ADR runtime source is Convex (contentResources with resourceId = adr:<slug>)
  • Vault sync still updates repo snapshots under apps/web/content/adrs/
  • Project snapshots into Convex with: bun scripts/seed-adrs-discoveries.ts
  • The detail page (app/adrs/[slug]/page.tsx) strips the H1 from markdown content because the page already renders the title with ADR number prefix
  • Regex: content.replace(/^#\s+(?:ADR-\d+:\s*)?.*$/m, "").trim()

Adding a New Post

1. Draft in Convex (contentResources.upsert, resourceId = article:<slug>, draft: true). 2. Use ISO datetime in date field. 3. Add images to apps/web/public/images/<slug>/ if needed and reference /images/<slug>/... in MDX. 4. Publish by setting draft: false, then revalidate tags + paths (post:<slug>, article:<slug>, articles, /, /<slug>, /<slug>.md, /<slug>/md, /feed.xml, /sitemap.md). 5. Verify route + markdown twin + homepage + feed consistency.

Backfill scripts:

  • scripts/seed-articles.ts for article resources
  • scripts/seed-adrs-discoveries.ts for ADR + discovery resources

Network Page

The network page (app/network/page.tsx) shows real infrastructure with aliased names. When updating:

1. Check actual system state (kubectl get pods, tailscale status, launchctl print, etc.) 2. Apply OPSEC rules — alias all hostnames, strip ports/IPs/usernames 3. Keep data arrays at top of file for easy updates 4. Status dots: green (Online) with ping animation, yellow (Idle), gray (Offline)

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.