这篇文章记录 HarnessDo.com 从零到上线的过程——由 DeepSeek Harness 搭建部署,我负责决策与验收。既是给自己的备忘,也希望能给想搭同样结构博客的人一点参考。
谁搭的:DeepSeek Harness 与我
这个站点的代码、部署、排障几乎全部由 DeepSeek Harness(DSH)完成——一个 AI 编码代理。我作为人,负责做决定、提供账号与凭证、并在每轮完成后验收和纠偏。把双方分工摊开,既是记录,也方便理解“AI 代理到底替人做了哪些事”。
DeepSeek Harness 做的
- 从零搭建 Astro 7 双语项目:配置文件、i18n 路由、内容集合 schema、布局/组件/样式
- 修复环境问题:npm/pnpm 缓存 EPERM、Astro 遥测沙箱拦截
- 设计双语内容集合,并修复中英同 slug 的 id 冲突 bug
- 撰写首批中英双语文章初稿
- 本地构建、预览、逐路由验证
- 创建 Cloudflare Pages 项目并部署上线
- 用 RDAP/DNS 核查域名归属(发现 harnessgo.com 与 harnessdo.com 的出入)
- 全站改名 harnessgo → harnessdo(含工作目录、Pages 项目)
- 挂载自定义域名、创建 CNAME、跟进 SSL 签发直到 https 可访问
- 给 DSH 自身安装 Cloudflare skills 与 MCP 服务器,并重启服务
- 品牌改名 HarnessDo.com(读者可见文案)并重新部署
- Git 初始化与首次提交
我(人)做的
- 注册域名(harnessdo.com,Cloudflare)
- 技术选型拍板:Astro、中英双语、部署到 Cloudflare Pages
- 在浏览器完成 Cloudflare OAuth 授权
- 创建并配置 Cloudflare API Token(含 DNS 编辑权限)
- 逐轮纠偏:确认域名是 harnessdo、要求全部改名 harnessdo、品牌用 HarnessDo
- 提供启动命令并确认重启 DSH
- 之后:持续写文章、审阅内容、维护站点
一句话:DSH 承担了几乎全部“动手执行”,我承担了“决策、授权、验收”——这正是本博客要追踪的 DeepSeek Harness 的日常用法之一。
技术选型
| 需求 | 选择 | 理由 |
|---|---|---|
| 静态站点框架 | Astro | 为内容型网站设计,Markdown 一等公民,输出纯静态页面,零 JS 默认 |
| 托管 | Cloudflare Pages | 免费、全球 CDN、与域名同账户、免备案 |
| 写作语言 | Markdown | 内容集合 + schema 校验,长期维护成本最低 |
选 Astro 而不是 Next.js 或 Hugo,核心原因是内容模型:Astro 的内容集合(content collections)自带 schema 校验,写错了 frontmatter 构建直接报错,这对一个要长期更新、跨中英双语的博客非常重要。
项目结构
HarnessDo.com/
├── astro.config.mjs # site 配置 + sitemap 集成
├── src/
│ ├── content.config.ts # 内容集合 schema(Astro 5+ 的写法)
│ ├── content/blog/
│ │ ├── zh/*.md # 中文文章
│ │ └── en/*.md # 英文文章
│ ├── i18n/ui.ts # 中英文案字典
│ ├── layouts/ # Base / PostLayout
│ ├── components/ # Header / Footer
│ └── pages/
│ ├── index.astro # 根路径,按浏览器语言跳转
│ ├── [lang]/ # /zh/ /en/ 首页
│ │ ├── blog/ # 文章列表 + [...slug] 文章页
│ │ ├── about.astro
│ │ └── rss.xml.ts # 每语言一个 RSS
│ └── 404.astro
└── public/ # favicon、robots.txt
双语怎么做
- 路由是
/zh/...和/en/...,根路径/根据浏览器navigator.language客户端跳转(默认中文)。 - 文章用同一个 slug 写两份,
src/content/blog/zh/<slug>.md和src/content/blog/en/<slug>.md,frontmatter 里声明lang。 - 内容集合里每份文件的 id 保留语言前缀(如
zh/2025-08-15-welcome),避免中英同 slug 冲突;URL 里的 slug 在路由层剥离前缀(src/lib/posts.ts的slugOf)。 - 页面文案(导航、按钮、关于页)放在
src/i18n/ui.ts字典里,按lang取用。
部署
构建产物是 dist/,用 wrangler 推送到 Cloudflare Pages:
pnpm build
wrangler pages deploy dist --project-name=harnessdo
域名绑定:Cloudflare 控制台 → Pages → 项目 → Custom domains 添加 HarnessDo.com,再在 DNS 里加一条 CNAME(@ → harnessdo.pages.dev,Proxied)。域名注册在 Cloudflare,无需备案。
以后怎么发新文章
- 在
src/content/blog/zh/写<日期>-<slug>.md,英文版写到en/,两份文件的 slug 保持一致。 - frontmatter 必填:
lang、title、description、pubDate;可选tags、draft、dshVersion、series。 - 本地预览:
pnpm dev,然后pnpm build && wrangler pages deploy dist --project-name=harnessdo上线。
内容 schema 在 src/content.config.ts 里,加字段也在这里改。
踩过的坑
- npm 缓存目录损坏。 这台机器上
~/.npm缓存有 root 所有权的文件,npm 直接 EPERM。解决:项目里.npmrc把cache指到项目目录,命令里用npm_config_cache覆盖环境变量(环境变量优先级高于项目配置)。 - pnpm 的 dlx 缓存也在家目录。
pnpm create astro的临时缓存同样被沙箱拦了,干脆手写全部文件,反而更清楚每一处配置在干什么。
以上。接下来就该写正文了。