mcpField
J
joelclaw-web

joelclaw-web

github.com/joelhooks开发6535 次安装1 天前更新
代码仓库

关于 joelclaw-web

joelclaw-web 是 joelclaw.com Next.js 应用的维护指南,涵盖内容管理、发布、设计和基础设施页面的安全要求,供网站贡献者使用。它以 Convex 作为运行时内容来源,并强调谨慎处理公开页面中的基础设施信息。

主要功能

  1. 01以 Convex 为首要内容来源
  2. 02文章草稿与发布流程
  3. 03内容重新验证与检查
  4. 04网站设计和导航规范
  5. 05隐藏基础设施敏感信息

适用场景

  1. 01撰写或发布文章
  2. 02更新 ADR 和发现内容
  3. 03维护网络状态页并避免泄露私密信息

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/joelhooks/joelclaw --skill joelclaw-web

安装后在 Claude Code 中输入/joelclaw-web确认已加载。

附带文件agents/openai.yamlassets/small-logo.svg

详细介绍

joelclaw.com Web 应用

apps/web/ 中的 Next.js 应用,位于 joelclaw monorepo(~/Code/joelhooks/joelclaw/)内。 推送到 main 时部署到 Vercel。深色主题,简约、偏系统风格的美学。

OPSEC 规则

绝不要在公开页面上暴露真实基础设施详情。

  • 节点/主机名:使用 Stephen King 宇宙中的别名,绝不要使用真实的 tailnet 主机名
  • 端口:不要公开任何服务的端口号
  • 用户名:从服务标识符中移除 com.joel. 或类似前缀
  • IP/子网:绝不显示真实 IP 地址或 CIDR 范围
  • 网络设备品牌/型号:使用泛称(例如“NAS”,而不是“Synology DS1821+”)
  • Tailscale:可以提及它是网状 VPN 产品,但不要透露 tailnet 名称或节点 IP

公开图表使用通用角色名称,例如控制平面、归档、开发客户端、中继和路由器。不要将真实主机名伪装成虚构别名后公开;私有拓扑边界仍然适用。

内容模型(Convex 优先)

规范的运行时内容存储在 Convex contentResources 中:

  • article:<slug>(type = article)
  • adr:<slug>(type = adr)
  • discovery:<slug>(type = discovery)

apps/web/content/ 下的文件系统内容仅用于播种/回填,并非运行时数据源。

运行时读取策略:

  • apps/web/lib/posts.ts → Convex 优先的文章(article:*)
  • apps/web/lib/adrs.ts → Convex 优先的 ADR(adr:*)
  • apps/web/lib/discoveries.ts → Convex 优先的发现内容(discovery:*)
  • apps/web/lib/convex-api.ts → 已检查的面向 Web 的 Convex 函数契约,以及运行时 anyApi 代理
  • 绝不要添加指向同级私有 joelclaw-api 检出目录的 link: 依赖。Vercel 只会克隆此仓库。
  • 可选的本地备用方案(仅限非生产环境):
    • JOELCLAW_ALLOW_FILESYSTEM_POSTS_FALLBACK=1(文章)
    • JOELCLAW_ALLOW_FILESYSTEM_CONTENT_FALLBACK=1(ADR/发现内容)

文章字段仍与 MDX frontmatter 结构保持一致:

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

排序:文章按 updated ?? date 降序排列。使用完整的 ISO 日期时间(而非单独的日期),以确保排序确定。设置 updated 会将文章移至顶部,但不会更改其原始发布日期。

Slug:根据 Convex 中的 fields.slug 派生(resourceId = article:<slug>)。

硬触发工作流

write article about X
  1. 根据标题/主题生成 slug。
  2. Upsert contentResources,设置 resourceId = article:<slug>、type = "article",将完整 MDX 正文写入 fields.content,并设置 fields.draft = true。
  3. 将 fields.date 设为当前 ISO 时间戳。
  4. 返回 slug 和草稿预览链接(如果开发环境中草稿可见,则链接为 /<slug>)。
publish article <slug>
  1. 从 Convex 读取 article:<slug>。
  2. Patch/upsert,设置 fields.draft = false 和 fields.updated = now。
  3. 通过 POST /api/revalidate 重新验证所有受影响的页面:
    • 标签:post:<slug>、article:<slug>、articles
    • 路径:/、/<slug>、/<slug>.md、/<slug>/md、/feed.xml、/sitemap.md
  4. 验证 /、/<slug>、/<slug>.md 和 /feed.xml 均包含已发布的文章。

媒体嵌入

当 YouTube 视频能提供背景信息时,务必在 /cool 发现内容和文章中嵌入视频。使用 <YouTube id="VIDEO_ID" /> MDX 组件(.mdx 文章和 .md 发现内容均可使用)。从 URL 中提取视频 ID(youtube.com/watch?v=VIDEO_ID)。将嵌入内容放在相关章节靠前的位置,位于文字讨论之前。

写作风格

撰写正文时使用规范的 joel-writing-style skill。主要特点:直接;只有观点确实属于 Joel 时才使用第一人称;策略性地使用脏话;段落简短;强调内容加粗;对话式但具有技术性。绝不要使用企业套话,也绝不要捏造 Joel 的信念或哲学。

设计系统

  • 主题:深色(bg-[#0a0a0a]),中性灰,--color-claw: #ff1493(亮粉色点缀)
  • 字体:Geist Sans(正文)、Geist Mono(代码/数据)、Dank Mono(带连字的代码块)
  • 内容宽度:max-w-2xl(672px)——特意设得较窄,便于阅读
  • 页眉:单行布局——左侧为爪子图标和“JoelClaw”,右侧为导航链接和搜索。页眉中不显示标语。
  • 导航项:Writing(/)、Cool(/cool)、ADRs(/adrs)、Network(/network)
  • 当前导航项:当前项显示为白色文本,非当前项显示为 neutral-500,通过 usePathname() 检测
  • 搜索:使用 pagefind 的 ⌘K 对话框,带有按类型区分的图标/徽章
  • 移动端:通过 MobileNav 组件显示全屏覆盖式导航
  • 代码块:Catppuccin Macchiato 主题,rehype-pretty-code
  • 边注:Tufte 风格的 CSS 边注(纯 CSS,无 JS)

关键文件

文件用途
app/layout.tsx根布局、字体、元数据、页脚
app/page.tsx首页(文章列表)
app/[slug]/page.tsx文章详情页
app/adrs/page.tsxADR 列表
app/adrs/[slug]/page.tsxADR 详情(移除 H1,避免标题重复)
app/cool/page.tsxCool/发现内容列表
app/network/page.tsx基础设施状态页
components/site-header.tsx带当前导航项标记的页眉(客户端组件)
components/mobile-nav.tsx移动端覆盖式导航
components/search-dialog.tsx⌘K 搜索
lib/posts.ts从 Convex 加载文章(article:*)
lib/adrs.ts从 Convex 加载 ADR(adr:*)
lib/discoveries.ts从 Convex 加载发现内容(discovery:*)
lib/convex-api.ts可部署的运行时代理及类型化的 Convex 公共接口
lib/constants.ts站点名称、URL、标语
lib/claw.ts爪子图标的 SVG 路径

ADR 显示规则

  • ADR 的运行时数据源为 Convex(contentResources,其中 resourceId = adr:<slug>)
  • Vault 同步仍会更新 apps/web/content/adrs/ 下的仓库快照
  • 使用以下命令将项目快照写入 Convex:bun scripts/seed-adrs-discoveries.ts
  • 详情页(app/adrs/[slug]/page.tsx)会移除 Markdown 内容中的 H1,因为页面已带 ADR 编号前缀显示标题
  • 正则表达式:content.replace(/^#\s+(?:ADR-\d+:\s*)?.*$/m, "").trim()

添加新文章

  1. 在 Convex 中起草(contentResources.upsert,resourceId = article:<slug>,draft: true)。
  2. 在 date 字段中使用 ISO 日期时间。
  3. 如需添加图片,将图片放入 apps/web/public/images/<slug>/,并在 MDX 中通过 /images/<slug>/... 引用。
  4. 将 draft 设为 false 以发布,然后重新验证标签和路径(post:<slug>、article:<slug>、articles、/、/<slug>、/<slug>.md、/<slug>/md、/feed.xml、/sitemap.md)。
  5. 验证路由、Markdown 对应页、首页和 Feed 的内容是否一致。

回填脚本:

  • scripts/seed-articles.ts:用于文章资源
  • scripts/seed-adrs-discoveries.ts:用于 ADR 和发现内容资源

Network 页面

Network 页面(app/network/page.tsx)使用别名显示真实基础设施。更新时:

  1. 检查实际系统状态(kubectl get pods、tailscale status、launchctl print 等)
  2. 遵守 OPSEC 规则——为所有主机名设置别名,并移除端口/IP/用户名
  3. 将数据数组放在文件顶部,便于更新
  4. 状态圆点:绿色(Online),带有 ping 动画;黄色(Idle);灰色(Offline)

评论

支持 Markdown