English | 简体中文 | 繁體中文 | 한국어 | Français | Deutsch | Italiano | Español | Русский | Bahasa Indonesia | Português (BR)
一个围绕优美文字构建的 AI 原生 Astro 主题。✍️
面向人类读者强调排版,面向 AI 智能体提供机器可读端点。
Aither 是一个多语言发布主题,把两种表面都当作一等产品能力来设计:对人类,是安静、克制、可读的页面;对智能体,是公开、明确、可抓取的协议文档和 Markdown 端点。它不是一个后来才补上 AI 标签的通用博客模板。
读者指阅读 HTML 站点的人类用户:首页卡片、文章页、About 页、评论和主题切换都属于这一侧。智能体指消费公开机器可读端点的软件客户端:protocol.json、skill.md、按 locale 的agent/home.json、llms.txt、api/posts.json以及单篇文章 Markdown。只读表示当前支持发现、抓取、索引和监控;不提供发布、评论或认证写入能力。
flowchart LR
A["Aither"] --> B["读者界面<br/>HTML 页面"]
A --> C["智能体界面<br/>JSON / Markdown"]
B --> D["规范文章 URL"]
C --> E["protocol.json -> skill.md -> agent/home.json"]
C --> F["llms.txt / api/posts.json / posts/{slug}.md"]
大多数博客主题优先堆 hero、动画和 UI 装饰。Aither 优先的是阅读节奏、排版克制和信息密度,让文字本身成为设计。
同时,它默认你的站点会被软件读取,就像会被人类阅读一样。因此仓库直接内置了一套真实协议表面:protocol.json、skill.md、本地化机器文档、llms.txt、Markdown 正文端点、JSON Schema,以及跨语言文章 API。
- 以排版为中心的阅读体验 -- Bricolage Grotesque 标题、系统字体正文、CJK 友好回退,以及本地打包字体资源,不依赖远程字体 CDN 也能保持质感
- 首页双入口 -- 首页同时提供读者视图和智能体视图;人类看到文章卡片,智能体直接看到 Markdown 入口,
/for-agents/则用自然语言解释协议 - 41 套主题 -- 除 Light / Dark / System 外,还内置 41 个命名主题,定义在
src/config/themes.ts中;如果你想保留模式切换但隐藏完整主题菜单,也可以直接配置 - AI 原生协议 --
/protocol.json、/skill.md、本地化/agent/home.json、/policy.md、/reading.md、/subscribe.md、/auth.md、/llms.txt、/llms-full.txt、/api/posts.json、每篇文章的.md、About Markdown、JSON Schema,以及/.well-known/ai-plugin.json - 默认只读 -- 智能体可以发现、抓取、索引、总结、轮询和引用内容,但当前没有一方写入 API、评论 API,也没有智能体身份认证写操作
- 11 语言发布 -- English、简体中文、繁體中文、한국어、Français、Deutsch、Italiano、Español、Русский、Bahasa Indonesia、Português (BR),包含本地化 UI、hreflang、路由和 RSS
- 66 篇本地化 sample -- 6 个示例 slug 在 11 个 locale 中全部镜像,
11 x 6 = 66,并由pnpm check:post-coverage强制校验 - 完整发布能力 -- 动态 OG 图片、RSS、站点地图、JSON-LD、规范 URL、标签、置顶、分页、目录,以及可选的 Giscus / Crisp / Google Analytics
- 不仅限于 posts -- 路由系统已经支持通过 Astro Content Collections 和
siteConfig.sections扩展更多内容集合,不只是默认的posts - 现代 Astro 栈 -- Astro 6、MDX、按需使用的 React 19、Tailwind CSS v4 tokens,以及在部署前同时校验内容覆盖、构建产物和协议产物的验证流水线
- Node.js -- 推荐
22 LTS。最低支持版本为20.19.1+或22.12.0+ - pnpm -- 仓库通过
packageManager固定pnpm@10.32.1 - Corepack -- 先执行一次
corepack enable,自动使用固定的 pnpm 版本 - Cloudflare Pages -- 仅在你要使用内置 GitHub Actions 部署工作流时需要
- 在 GitHub 上点击 "Use this template"
- 克隆你的新仓库:
git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git
cd YOUR_REPO- 启用 Corepack 并安装依赖:
corepack enable
pnpm install- 配置站点:
# astro.config.mjs -- 设置你的站点 URL(唯一需要设置 URL 的地方)
site: 'https://your-domain.com'
# src/config/site.ts -- 设置站点名称、描述、社交链接、导航、页脚
# url 会自动从 astro.config.mjs 读取- 配置环境变量(可选):
cp .env.example .env
# 按需填写 GA、Giscus、Crisp 等配置- 在开始大改之前,先验证 starter:
pnpm validate- 启动本地开发:
pnpm dev- 准备部署时,如果你要使用内置 Cloudflare Pages 工作流,请先完成部署章节里的设置,再推送到
main
git clone https://github.com/justinhuangcode/astro-theme-aither.git my-blog
cd my-blog
corepack enable
pnpm install
pnpm validate
pnpm dev最佳实践:新站点优先使用 GitHub Template。若你是手动克隆上游仓库,先确认本地运行正常,再创建自己的仓库或导入到新仓库,不要在还没验证成功前就删掉 .git。
Aither 当前是 starter-first 主题,不是可直接安装并通过 pnpm up 升级的 Astro integration 包。已经基于它建站的项目,应按 release 用 Git 升级;如果你有一份干净的上游克隆,也可以先运行 pnpm upgrade:diff -- --from <旧 tag> --to <新 tag> 看分类后的差异。完整流程见 UPGRADING.md。
在 src/content/posts/{locale}/ 中创建 MDX 文件:
---
title: 示例文章标题
date: "2026-01-01T16:00:00+08:00"
description: 可选的 SEO 描述
category: Technology
tags: [可选, 标签]
pinned: false
image: ./optional-cover.jpg
---
在这里写正文内容。| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
title |
string | 是 | -- | 文章标题 |
date |
date | 是 | -- | 发布时间,建议使用带时区的 ISO 8601 |
description |
string | 否 | -- | 用于 RSS 和 meta 标签 |
category |
string | 否 | "General" |
分类 |
tags |
string[] | 否 | -- | 标签 |
pinned |
boolean | 否 | false |
设为 true 后置顶 |
image |
image | 否 | -- | 封面图,可用相对路径或导入 |
最佳实践:
- 尽量使用完整的带时区 ISO 8601 时间,例如
2026-03-19T16:27:43+08:00 - 每个 locale 保持相同 slug,方便
pnpm check:post-coverage以英文基线校验覆盖率 - 把英文作为基准集合,本地化时在各语言目录下使用相同文件名
| 命令 | 说明 |
|---|---|
pnpm dev |
启动本地开发服务器 |
pnpm check |
运行 Astro 类型与内容校验 |
pnpm check:post-coverage |
校验所有 locale 是否拥有相同 slug |
pnpm build |
构建静态站点到 dist/ |
pnpm smoke:package |
校验 @aither/astro 包层接口和导出映射 |
pnpm smoke |
运行包层与 AI 协议构建产物的冒烟测试 |
pnpm preview |
本地预览生产构建 |
pnpm validate |
推荐的推送前检查:串行执行 check、check:post-coverage、build 以及两套冒烟测试 |
/for-agents/ 是给人看的说明页,但真正的机器契约如下:
| 端点 | 范围 | 用途 |
|---|---|---|
/protocol.json |
全局 | 轻量清单和 schema 链接 |
/skill.md |
全局 | 智能体的规范叙事入口 |
/{locale}/agent/home.json |
每个 locale | 当前站点状态和最新文章 |
/{locale}/policy.md |
每个 locale | 规则、发现顺序和安全边界 |
/{locale}/reading.md |
每个 locale | 推荐读取流程 |
/{locale}/subscribe.md |
每个 locale | 轮询和订阅建议 |
/{locale}/auth.md |
每个 locale | 预留的认证契约;当前仍是只读 |
/{locale}/llms.txt |
每个 locale | 给 LLM 的轻量索引 |
/{locale}/llms-full.txt |
每个 locale | 给批量 LLM 工作流的完整内联内容 |
/api/posts.json |
全部 locale | 跨语言结构化文章元数据 |
/{locale}/posts/{slug}.md |
每个 locale | 单篇文章的规范 Markdown 正文 |
/{locale}/about.md |
每个 locale | About 页面 Markdown |
/.well-known/ai-plugin.json |
全局 | 轻量机器发现元数据 |
/schemas/agent-protocol.schema.json |
全局 | protocol.json 的 JSON Schema |
/schemas/agent-home.schema.json |
全局 | agent/home.json 的 JSON Schema |
默认 locale en 不带前缀。例如英文文章 Markdown 是 /posts/{slug}.md,简体中文则是 /zh-hans/posts/{slug}.md。
最佳实践:
- 先读
/protocol.json,再读/skill.md,再获取对应 locale 的agent/home.json - 跨语言发现用
/api/posts.json,最终抓正文用单篇.md端点 - 回链给人类时引用规范 HTML 页面,不要引用 Markdown 端点
- 如果信息新鲜度重要,就重新抓取,不要假设缓存永远正确
- 只要改动了
protocol.json、skill.md、agent/home.json或任一面向智能体的 Markdown 文档,最低也应跑一次pnpm smoke
主要配置入口如下:
astro.config.mjs-- 生产站点 URL,以及共享的@aither/astro集成、Vite 与 locale 路由默认值src/config/site.ts-- 站点元信息、导航、页脚、分页、时区、主题控制、社交链接,以及可选内容 sectionssrc/config/themes.ts-- 41 套主题目录和本地化主题标签src/content.config.ts-- Zod 内容 schema 与 collection 注册src/i18n/index.ts与src/i18n/messages/*.ts-- locale 定义、路由 helper 和翻译文案.env-- 可选的 Google Analytics、Crisp 与 Giscus 配置
export const siteConfig = {
name: 'Aither',
title: 'An AI-native Astro theme built around beautiful text.',
description: '...',
author: {
name: 'Aither',
avatar: '', // 可从 src/assets/ 导入,也可直接使用 URL
},
// url 会自动从 astro.config.mjs 读取,无需在这里重复设置
social: [
{ title: 'GitHub', href: 'https://github.com/...', icon: 'github' },
{ title: 'Twitter', href: '', icon: 'x' },
],
blog: { paginationSize: 20, timeZone: 'Asia/Shanghai' },
analytics: { googleAnalyticsId: import.meta.env.PUBLIC_GA_ID || '' },
crisp: { websiteId: import.meta.env.PUBLIC_CRISP_WEBSITE_ID || '' },
ui: {
defaultMode: 'system',
defaultStyle: 'default',
enableModeSwitch: true,
showMoreThemesMenu: true,
},
sections: [
// 可选:除 posts 外的其他内容集合
// { id: 'translations', labelKey: 'translations' },
],
giscus: { repo: '...', repoId: '...', category: '...', categoryId: '...' },
nav: [
{ labelKey: 'blog', href: '/' },
{ labelKey: 'about', href: '/about' },
],
footer: { copyrightYear: 'auto', sections: [/* ... */] },
};如果你希望保留 Light / Dark / System 切换,但不想展示完整主题菜单,可以把 ui.showMoreThemesMenu 设为 false。
项目已经支持不止一个 collection。新增 section 的方式如下:
// src/config/site.ts
sections: [{ id: 'translations', labelKey: 'translations' }]
// src/content.config.ts
const translations = defineCollection({
loader: glob({ pattern: '**/*.mdx', base: './src/content/translations' }),
schema: contentSchema,
});
export const collections = { posts, translations };然后在 src/content/translations/{locale}/ 下创建内容。列表页和详情页会自动生成到 /translations/、/{locale}/translations/ 及其 slug 路由。
import { defineConfig } from 'astro/config';
import aither from '@aither/astro';
export default defineConfig({
site: 'https://your-domain.com',
integrations: [aither()],
});# Google Analytics(留空则关闭)
PUBLIC_GA_ID=
# Crisp Chat(留空则关闭)
PUBLIC_CRISP_WEBSITE_ID=
# Giscus Comments(全部留空则关闭)
PUBLIC_GISCUS_REPO=
PUBLIC_GISCUS_REPO_ID=
PUBLIC_GISCUS_CATEGORY=
PUBLIC_GISCUS_CATEGORY_ID=语言配置在 src/i18n/index.ts,翻译文案在 src/i18n/messages/*.ts。
| 代码 | 语言 |
|---|---|
en |
English(默认) |
zh-hans |
简体中文 |
zh-hant |
繁體中文 |
ko |
한국어 |
fr |
Français |
de |
Deutsch |
it |
Italiano |
es |
Español |
ru |
Русский |
id |
Bahasa Indonesia |
pt-br |
Português (BR) |
默认 locale en 没有 URL 前缀,其余语言使用各自代码前缀,例如 /zh-hans/、/ko/。
最佳实践:把英文 slug 集合作为规范基线,并在部署前用 pnpm check:post-coverage 抓出缺失的本地化文章。
src/
├── config/
│ ├── site.ts # 站点元信息、导航、页脚、主题控制、可选 sections
│ └── themes.ts # 41 套主题及其本地化标签
├── content.config.ts # Content Collections schema(Zod)
├── content/
│ └── posts/{locale}/*.mdx # 多语言文章内容
├── i18n/
│ ├── index.ts # locale 定义与路由 helper
│ └── messages/*.ts # 各语言 UI 文案
├── components/
│ ├── pages/ # 页面级界面:首页、文章、About、for-agents
│ ├── AIAccessList.astro # 智能体视图下的 Markdown 文章列表
│ ├── Navbar.astro # 导航、语言切换、主题控制
│ ├── ModeSwitcher.astro # Light/Dark/System + 自定义主题选择器
│ ├── TableOfContents.astro # 基于标题生成目录
│ └── Giscus.astro # 可选评论组件
├── lib/
│ ├── agent-protocol.ts # 协议清单与智能体文档生成
│ ├── markdown-endpoint.ts # Markdown 响应辅助工具
│ ├── og-image.ts # 动态 OG 图片生成
│ ├── posts.ts # 按 locale 获取与排序内容
│ ├── site-content.ts # 路径、分页、RSS、llms.txt 等辅助工具
│ └── theme.ts # 主题偏好状态管理
├── layouts/
│ └── Layout.astro # SEO、hreflang、JSON-LD、替代链接与全局壳层
├── pages/
│ ├── index.astro # 默认 locale 首页
│ ├── about.astro # About 页面
│ ├── for-agents.astro # 面向人类的协议说明页
│ ├── page/[num].astro # 首页分页
│ ├── posts/
│ │ ├── [slug].astro # 文章详情页
│ │ └── [slug].md.ts # 单篇 Markdown 端点
│ ├── agent/home.json.ts # 聚合机器可读站点状态
│ ├── protocol.json.ts # 结构化清单
│ ├── skill.md.ts # 规范叙事式协议文档
│ ├── policy.md.ts # 智能体规则与安全约束
│ ├── reading.md.ts # 推荐抓取流程
│ ├── subscribe.md.ts # 监控与订阅建议
│ ├── auth.md.ts # 预留认证契约
│ ├── llms.txt.ts # 紧凑型 LLM 索引
│ ├── llms-full.txt.ts # 全量 LLM 内容聚合
│ ├── api/posts.json.ts # 跨语言文章元数据
│ ├── schemas/*.json.ts # 协议端点 JSON Schema
│ ├── [section]/... # 自动生成的额外 collection 路由
│ └── [locale]/... # 各主要页面的本地化路由
├── styles/
│ ├── fonts.css # 本地 Bricolage Grotesque 字体声明
│ └── global.css # Tailwind v4 设计令牌、排版与主题变量
public/
├── .well-known/ai-plugin.json # 公开机器发现元数据
├── favicon.svg
├── logo.svg / logo-dark.svg
└── og.png
scripts/
├── check-post-coverage.mjs # 校验各 locale slug 一致性
└── smoke-agent-protocol.mjs # 校验生成后的协议产物
内置工作流 .github/workflows/deploy-cloudflare-pages.yml 是一条偏 Cloudflare Pages 的部署路径,并且会在部署前先完成校验。
- 创建一个 Cloudflare Pages 项目。工作流默认使用仓库名;如果需要覆盖,设置仓库变量
CLOUDFLARE_PAGES_PROJECT_NAME - 在 GitHub Secrets 中添加
CLOUDFLARE_API_TOKEN和CLOUDFLARE_ACCOUNT_ID - 在
astro.config.mjs中把site改成你的生产域名 - 运行
pnpm validate - 推送到
main,让 GitHub Actions 自动构建并部署
最佳实践:尽量让仓库名和 Pages 项目名保持一致;如果必须不同,再通过仓库变量 CLOUDFLARE_PAGES_PROJECT_NAME 覆盖。
产物是 dist/ 下的静态 HTML,因此可以部署到任意静态托管平台:
pnpm build
# 将 dist/ 上传到 Netlify、Vercel、GitHub Pages 或任意静态主机- 排版就是界面 -- 好的文字不应该和主题互相抢戏。
- 人类与智能体同样重要 -- 公共协议是产品的一部分,不是后补说明。
- 多语言一致性需要被校验 -- locale 覆盖不是假设,而是显式检查。
- 扩展点应贴近内容层 -- 用 Content Collections 和配置扩展 sections,而不是额外套一层应用系统。
- 保持克制 -- 静态输出、明确文档和清晰契约,比隐藏魔法更可靠。
- 灵感来自 yinwang.org。
- 部分主题系统灵感来自 Raphael Publish 和 EvoMap。
欢迎贡献。请先开 issue 讨论你想修改的内容。