拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

NewsBlur 功能发布工作流:用 Claude Code 命令同步生产 Features Board 与推文

NewsBlur 功能发布工作流:用 Claude Code 命令同步生产 Features Board 与推文
  • 后端
  • 前端
  • 社交
  • 人工智能

【免费下载链接】NewsBlur

NewsBlur is a personal news reader that brings people together to talk about the world. A new sound of an old instrument.

项目地址:https://gitcode.com/gh_mirrors/ne/NewsBlur
点击查看免费下载

导读

feature.md是 NewsBlur 仓库中为 Claude Code 定制的一条斜杠命令(slash command),它把「发布新功能公告」这件事做成了可复用的 Agent 工作流:自动检索匹配的博客文章、按既有风格生成多个功能描述候选、经用户确认后直接写入生产数据库的 Features Board,并附带 3 至 5 组现成推文。本文结合仓库源码拆解该命令的完整设计:从命令的 frontmatter 声明、上下文注入,到七步执行流程,再到Feature模型的底层实现、权限控制与 Features Board 的前端渲染,让你既能照搬这套发布流程,也能理解它背后的数据链路。

一、命令定位:.claude/commands/feature.md是什么

在 NewsBlur 仓库的.claude/commands/目录下,存放着一批面向 AI 编码助手(Claude Code)的自定义命令,feature.md是其中之一,专门负责「向生产环境的 Features Board 发布一条新功能,并撰写配套推文」。

命令文件采用标准的 YAML frontmatter 声明元信息:

--- description: Post a feature to the Features Board on production and write tweets allowed-tools: Bash, Read, Glob, Grep, AskUserQuestion ---
  • description:描述命令用途,供 Agent 理解何时该调用这条命令;
  • allowed-tools:白名单限定本次任务只允许使用 Bash(执行命令)、Read(读文件)、Glob(文件匹配)、Grep(搜索)和 AskUserQuestion(向用户提问)五类工具,其余能力被显式禁用。

同目录还包含blog-post.md、commit.md、worktree.md等命令,可见该项目把常见的「写博客、提 commit、发布功能」等维护动作全部脚本化成了 Agent 可执行的命令,feature.md就是其中连接「博客内容」与「产品公告」的环节。

二、上下文注入:让 Agent 先「看清现场」

命令正文的开头是 Context(上下文)部分,包含两条动态指令,要求 Agent 在动手前先收集两类现场信息:

# 1. 最近发布的博客文章 !`ls -t blog/_posts/*.md | head -10` # 2. 生产环境当前已上线的功能列表 !`./utils/ssh_hz.sh -n happ-web-01 "docker exec -t newsblur_web python manage.py shell -c \"from apps.reader.models import Feature; [print(f'{f.date.strftime(\\\"%b %d, %Y\\\")}: {f.description}') for f in Feature.objects.all()[:6]]\""`

这两条指令一前一后形成了任务的参照系:

  • 第一条用ls -t按修改时间倒序列出blog/_posts/下最近 10 篇博客文章,用于后续「找一篇与功能主题匹配的文章」;
  • 第二条则是真实的运维链路:通过 utils/ssh_hz.sh 登录到生产应用机(别名happ-web-01),在newsblur_web容器内用 Django shell 查询apps.reader.models.Feature表最近 6 条记录,作为风格模板。

仓库中blog/_posts/目录确实按YYYY-MM-DD-slug.md命名,例如2026-03-25-daily-briefing.md、2026-04-06-premium-pro.md,与命令中推导博客 URL 的规则完全对应。

ssh_hz.sh如何工作

utils/ssh_hz.sh 是整条链路的关键基础设施。它从ansible/inventories/hetzner.ini中按别名解析主机 IP,再以固定密钥发起 SSH:

  • 支持-n|--noninteractive非交互模式,-n后的第一个参数是服务器别名,其余参数全部作为远程命令透传;
  • 别名解析逻辑:先在 ini 中做整行精确匹配(grep "^$1[[:space:]]"),失败则回退到子串匹配,同时跳过以;或#开头的注释行;
  • 连接参数固定为-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /srv/secrets-newsblur/keys/docker.key,登录用户为nb@$HOST;
  • 在仓库中,ansible/inventories/hetzner.ini是一个指向/srv/secrets-newsblur/configs/hetzner.ini的符号链接,实际主机清单存于保密目录;而 ansible/inventories/hetzner.yml 定义了主机分组逻辑,happ-web-01属于django/hdjango组(以happ-web开头),即承载 Django Web 服务的生产实例。

也就是说,这条 Context 指令是经过真实生产环境验证的写法:SSH 进 Django 容器、用manage.py shell -c执行单行查询,全程无人值守。

三、写作风格:拒绝「AI 味」

命令用一节专门约束所有产出的文风(功能描述与推文都要像人写的):

  • 不使用 em dash 或双连字符,甚至「不用破折号做标点」,而是重组句子;
  • 不要过度打磨、不要企业腔,保持直接、自然;
  • 不要套话,例如 "excited to announce"、"we're thrilled"、"game-changer" 这类空泛短语;
  • 写作基调:像开发者向用户介绍自己的产品一样朴实。

这节是命令的灵魂:Features Board 和推文都是面向真实用户的内容,一旦写得像模板生成的营销文案,功能公告的可信度与可读性都会下降。

四、七步执行流程

命令将整个任务拆成 7 个明确步骤,每一步都有可验证的产出物。

Step 1:定位匹配的博客文章

在blog/_posts/中搜索与主题(命令参数{{ arguments }})匹配的博文并通读全文,重点提取:

  • 功能做什么;
  • 关键能力与亮点;
  • 哪些订阅套餐(tier)可使用;
  • 博文日期与 URL slug。

博客 URL 由文件名推导,规则为https://blog.newsblur.com/YYYY/MM/DD/slug-from-filename/,例如blog/_posts/2026-03-25-daily-briefing.md对应https://blog.newsblur.com/2026/03/25/daily-briefing/。这条规则与仓库中博客文件的命名习惯(如2026-04-01-mcp-server-and-cli.md、2026-07-17-good-reads-and-a-redesigned-global-shared-stories.md)一一对应。

Step 2:研究现有功能的风格基线

以 Context 部分取回的 6 条生产记录为样本,归纳出 Features Board 条目的格式规范:

  • 长度:1 至 3 句,精炼有力;
  • 语气:产品导向,突出「新在哪、有什么用」;
  • 结构:功能描述正文 +<a href="...">Read the blog post</a>;
  • 内容:先讲功能做什么,再压缩关键细节,偶尔提及套餐可用性;
  • 字段性质:description字段存放的是原始 HTML,博客链接是其中的<a>锚点标签。

这一点在源码中能得到印证:templates/reader/features_module.xhtml 直接以{{ feature.description|typogrify }}渲染该字段,说明描述内嵌 HTML 是设计使然,前端会原样输出。

Step 3:产出 4 至 5 个候选描述

在既有风格内做多角度变体,差异点包括:突出功能的广度还是深度、长度(短 vs 略长)、纳入哪些细节(分节、投递方式、自定义选项、套餐信息)。所有候选以纯文本形式呈现在对话中,避免使用 AskUserQuestion 的预览框(预览会截断 HTML)。

Step 4:让用户拍板

用 AskUserQuestion 单选(不带预览)让用户选择,选项标签要能体现每个候选的角度差异(例如 "Balanced, both features" 或 "Problem-first framing")。

Step 5:写入生产数据库(核心命令)

用户选定后,通过以下命令在happ-web-01的生产环境创建 Feature 记录:

./utils/ssh_hz.sh -n happ-web-01 "docker exec -t newsblur_web python manage.py shell -c \" from apps.reader.models import Feature import datetime f = Feature( description='<THE CHOSEN DESCRIPTION WITH HTML LINK>', date=datetime.datetime.utcnow() + datetime.timedelta(minutes=1) ) f.save() print(f'Created Feature #{f.id}: {f}') \""

这条命令的要点:

  • 通过ssh_hz.sh直达生产机,再docker exec进入newsblur_web容器;
  • 直接以 ORM 方式构造Feature对象并save(),不经过任何 HTTP 接口;
  • 日期刻意设为「当前 UTC 时间 + 1 分钟」,避免因时钟偏差导致记录时间戳早于当前时刻;
  • 命令结束后打印Feature #<id>用于回执。

命令末尾特别强调:嵌套 shell 命令中必须正确转义描述内容里的引号。因为描述字段含 HTML 锚点(本身就有引号),而整段代码又经过 bash → ssh → docker exec → python shell 四级嵌套,引号层级稍有错乱就会导致命令中断或字段截断。

Step 6:确认上线

向用户回报生成的 Feature ID,并确认该条目已在生产环境生效。

Step 7:撰写推文集

产出 3 至 5 组推文(每组 2 至 3 条,可作为一条 Thread 或独立发布),每条的硬性要求:

  • 长度在 280 字符以内(URL 不计入,Twitter 会自动缩短);
  • 以博客 URL 独占一行结尾;
  • 遵守上文写作风格(不用破折号、不写 AI 套话)。

各组从不同角度切入:有的同时覆盖两个功能、有的聚焦单一功能、有的给出具体示例、有的短小精悍。推文候选直接在对话中以纯文本、编号形式展示,方便用户直接复制,不再走 AskUserQuestion(与 Step 4 刻意形成差异化交互)。

五、底层支撑:Features Board 的数据链路

feature.md命令写入的其实是 NewsBlur 首页 Dashboard 上的一块「类博客功能公告板」,它的完整数据链路如下:

1. 模型层

apps/reader/models.py 第 3196 至 3208 行定义了极简的Feature模型:

class Feature(models.Model): """ Simple blog-like feature board shown to all users on the home page. """ description = models.TextField(default="") date = models.DateTimeField(default=datetime.datetime.now) def __str__(self): return "[%s] %s" % (self.date, self.description[:50]) class Meta: ordering = ["-date"]
  • description:公告正文(含 HTML 博客链接);
  • date:发布时间,模型默认datetime.datetime.now(命令则显式改为 UTC 时间并加 1 分钟);
  • Meta.ordering = ["-date"]:查询结果默认按日期倒序,最新公告排在最前。

配套测试工厂 apps/reader/factories.py 中的FeatureFactory用 Faker 生成description与date,方便在测试环境复现公告数据。

2. 表单层

apps/reader/forms.py 的FeatureForm复刻了命令的日期逻辑:

class FeatureForm(forms.Form): use_required_attribute = False description = forms.CharField(required=True) def save(self): feature = Feature( description=self.cleaned_data["description"], date=datetime.datetime.utcnow() + datetime.timedelta(minutes=1), ) feature.save() return feature

可见「utcnow + 1 分钟」并非命令独有,而是 Web 端新增公告(Dashboard 上的 Add Feature 表单)与 CLI 命令共用的同一套约定。

3. 视图层与权限

apps/reader/views.py 有两个相关视图:

  • add_feature(第 4602 至 4615 行):处理 Web 表单提交,以request.user.is_staff校验管理员权限,非 staff 直接返回HttpResponseForbidden()。生产运维走命令行的原因也与此一致:命令行方式天然绕过了 Web 表单,需要操作者掌握 SSH 与容器权限;
  • load_features(第 4618 至 4632 行):对外提供 JSON 接口,按[page * 3 : (page + 1) * 3 + 1]分页,即每页取 4 条(其中第 4 条用于判断是否还有下一页),并把日期按用户时区格式化为"%b %d, %Y"。

两条路由注册在 apps/reader/urls.py:^add_feature(name 为add-feature)与^features(name 为load-features)。

4. 展示层

templates/reader/features_module.xhtml 渲染公告板表格:

{% for feature in features %} <tr class="NB-module-feature {% if forloop.last %}last{% endif %} {% if feature.date > user.profile.last_seen_on %}NB-module-feature-new{% endif %}"> <td class="NB-module-feature-date">{% localdatetime feature.date "%b %d, %Y" %}</td> <td class="NB-module-feature-description">{{ feature.description|typogrify }}</td>
  • 日期以本地化格式显示;
  • 描述经typogrify过滤器做排版优化(正确处理智能标点等);
  • 若公告日期晚于用户上次访问时间(user.profile.last_seen_on),自动加NB-module-feature-new类做「新公告」视觉高亮。

该模块被嵌入首页仪表盘 templates/reader/dashboard.xhtml,并配合一段 JS($('#add-feature-button').click(...))控制「Add」表单的显隐。也就是说,用户在首页看到的每一条功能公告,都对应着Feature表里的一行记录,而这正是feature.md命令直接操作的对象。

六、实战要点与注意事项

把feature.md的工作流搬到自己的发布流程中时,有几处细节值得留意:

  1. 引号转义是最大的坑:描述中的 HTML 链接(<a href="...">)带双引号,整条命令要穿透 bash、ssh、docker exec、python shell 四层解释器,建议先在本地用单层python -c验证描述字符串,再套进完整命令。
  2. 时间戳策略:date使用utcnow + timedelta(minutes=1),既保证记录出现在「现在」之后,又能容忍一定时钟偏差;前端正是依据这个时间戳做「新功能」高亮。
  3. 权限边界:Web 端的add_feature视图受is_staff保护;命令行发布依赖ssh_hz.sh的密钥(/srv/secrets-newsblur/keys/docker.key)与容器访问权,两条路径的权限模型不同,生产操作前应确认具备对应凭据。
  4. 风格一致性:Features Board 与推文都面向真实用户,命令用「长度 1 至 3 句、产品导向、含博客链接、避免 AI 套话」四条基线约束全部产出,保证任何 Agent 生成的内容都与历史公告同源同质。
  5. 可回滚与可验证:save()后打印Feature #<id>作为回执;也可以随时用 Context 中的查询命令复核最新 6 条记录,确认公告已生效。

七、总结

feature.md完整展示了 NewsBlur 团队如何把「内容运营」也纳入自动化:它一端连接blog/_posts/的写作产出,一端连接生产库Feature表的写入,中间用「风格基线 + 用户确认 + 多角度候选」三件套保证输出质量。理解这条命令,不仅能用它发布公告,更能看到 NewsBlur 首页 Features Board 从模型、表单、视图到模板的完整实现链路。如果你也在维护一个带公告板或 Changelog 的产品,这套「命令定义 + 动态上下文 + 生产直写」的范式值得直接借鉴。

  • 后端
  • 前端
  • 社交
  • 人工智能

【免费下载链接】NewsBlur

NewsBlur is a personal news reader that brings people together to talk about the world. A new sound of an old instrument.

项目地址:https://gitcode.com/gh_mirrors/ne/NewsBlur
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表