mcpField
S
seo-report

seo-report

github.com/every-app文档处理25.5k2.1k 次安装2 天前更新
代码仓库

关于 seo-report

OpenSEO Report 是一项将已完成的研究整理为单页 HTML 报告的技能,供团队在应用中阅读、打印或导出 PDF。它支持项目报告模板,并规定报告结构、证据表达和保存规则。

主要功能

  1. 01生成独立的 HTML 报告
  2. 02应用报告模板并组织章节
  3. 03提供报告修订与去重规则
  4. 04支持打印及导出 PDF

适用场景

  1. 01将 SEO 研究整理成团队报告
  2. 02按项目模板制作特定受众的报告
  3. 03修订已有报告并避免重复保存

MCP 相关

该技能通过 OpenSEO 工具读取项目报告与模板,并使用 save_report 保存报告;也可管理报告分享设置。

安装

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

$npx skills add https://github.com/every-app/open-seo --skill seo-report

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

详细介绍

OpenSEO 报告

目标

将已完成的研究整理成一个独立的 HTML 页面,通过 save_report 保存到项目中,让团队中的任何人都能在应用中打开、用手机阅读,并打印为 PDF。

每项会提供建议的 OpenSEO 技能都通过此技能交付。聊天中会收到报告链接、结论,以及最重要的建议和预期收益(如有)。其余内容都放在报告中。

撰写前

  1. 调用 list_reports 获取项目报告。如果已有报告涵盖相同主题和时期,那么你是在修正自己之前的执行结果:将其 reportId 传给 save_report 并替换原报告。新月份、新竞争对手或不同的技能,都应创建新报告。切勿保存近似重复的报告。
  2. 每个项目中的标题必须唯一。如果未提供 reportId,却以已有标题保存第二份报告,操作会被拒绝。因此,要么传入被替换报告的 reportId,要么修改标题,注明新的主题或时期。
  3. 要修订现有报告,请依据其摘要开展工作。get_report 只有在设置 includeHtml: true 时才会返回 HTML;而一份 80 KB 的报告大约有 20,000 个令牌,大多数客户端会截断内容。只有在需要编辑特定段落时才获取 HTML;如果返回的内容看起来被截断,请让用户转到应用中查看,而不要覆盖保存。

使用模板

项目可以附带报告模板:可重复使用的命名简报,其中说明报告面向谁、包含哪些部分及其顺序、应采用何种语气,以及如何收尾。模板会列在项目上下文中,list_report_templates 会返回每个模板的完整说明。模板归项目所有。要在其他项目中重用模板,请先在该项目中列出模板,再将副本保存到这里。

只有当用户点名某个模板,或要求撰写的报告类型与某个模板的名称或描述相符时,才使用该模板。普通的技能运行(“审核这个网站”)应使用技能的默认格式。如果有两个模板都符合,请用一行询问用户。模板中的章节、受众和语气会取代技能的 Output format 列表;HTML 限制和写作规则始终不变。项目的 writing_preferences 始终适用;只有在与模板冲突时,才以模板的语气为准。将模板的 templateId 传给 save_report。

写作规则

当生成报告的技能指定了推荐格式时,请使用该格式,而不要采用下方通用的“问题 / 改进 / 预期效果”结构。例如,SEO 审核可以使用简短的“采取此措施 / 原因”项目符号列表。具体行动、佐证、业务收益和如实说明不确定性的要求保持不变。入门模板中的发现项标记只是示例,不会覆盖该技能指定的格式。

  • 写成笔记,而不是长文。 读者会快速浏览。每条建议应包含一个标题和三个简短的项目符号:问题(有证据支持的事实)、改进(采取的步骤,以及它如何解决问题)和预期效果(可能改善的方面、业务关注原因,以及大致影响规模和不确定性)。对于描述性发现,请使用相关部分;不要凭空编造改进措施。每段不超过两句话。每个章节以一句话开头,或不写开头。摘要章节(结论、概况或市场解读)应使用项目符号列表,每行陈述一项事实,绝不写成散文。数据收集方式应放在结尾的“本报告的制作方式”章节,而非发现项中。
  • 让推理过程清晰可见。 使用数字和具体页面为观察结果提供依据。用通俗语言解释建议的作用机制和预期收益;不要为了简洁省略这些解释,也不要用“建立信任”等泛泛的说法代替。区分测量结果、估算值和假设。有依据的定性评估胜过凭空编造的精确数字。
  • 如实说明可信度。 说明哪些数字来自工具,哪些是你亲自核实的。无法核实的内容,请写入 .note 并说明情况。
  • 使用通俗语言。 术语首次出现时都要解释:规范链接、元描述、爬虫、301、结构化数据。不要使用夸张措辞、感叹号或填充语。
  • 一份报告,一条主线。 先给出结论及其业务影响,再陈述重要发现和有价值的建议。如果研究无法证明有值得采取的行动,请说明这一结论和相关限制。包含二十条发现的报告是不合格的。
  • 明确写出数字。 图表中的每个数值都必须同时以文本形式写出。

标题和摘要

  • title:写明报告类型或具体主题,以及完整的报告日期;长度少于 120 个字符。使用“竞争格局 — Sep 17, 2026”或“关键词研究 — Sep 17, 2026”等格式。使用实际报告日期,并采用 MMM D, YYYY 格式,包含日期和四位数年份;数据覆盖时段应写在报告正文中。不要使用“SEO 报告”或“分析”等泛泛标题。
  • 如果报告讨论的是项目网站,则标题中省略网站。比较主机名时,忽略协议、www. 和末尾斜杠。如果主题是其他网站,则写上该网站的裸主机名,例如“竞争对手分析:example.com — Sep 17, 2026”。如果项目未设置网站,也应写上主题主机名。标题中绝不使用 https:// 或完整 URL。
  • save_report、HTML <title> 和可见的 <h1> 必须使用相同的标题,确保报告列表、分享预览和报告内容一致。
  • summary:以 Markdown 格式撰写,少于 2,500 个字符,按以下顺序排列——结论、首要建议及预期收益(或为何无法确定有实质意义的行动),然后是关键证据。list_reports 会返回此内容,你或其他 Agent 也会用它代替 HTML,因此请确保即使读者从未打开页面,也能看懂摘要。

结尾部分:本报告的制作方式

每份报告都以一个标题为 “How this report was made”(id how-this-report-was-made)的 h2 结尾。如果包含 “What to do next”,则将它放在本节之前。本节是唯一有固定开场白的部分:用一句话说明生成报告的技能,并链接到该技能的文档页面,让收到链接的读者了解此工作流的作用并重新运行它。

<p>Generated by the <a href="https://openseo.so/docs/skills/seo-audit" target="_blank" rel="noopener">OpenSEO SEO Audit skill</a>, run by AGENT NAME on MONTH D, YYYY.</p>

URL 始终为 https://openseo.so/docs/skills/,后接技能的目录名称,名称必须与该技能的 Output format 列表中完全一致。请直接复制,不要猜测 slug。然后按照技能的说明补充本节其余内容:哪些工具报告了什么,以及你手动核实了哪些内容。根据模板撰写的报告也要保留本节,并将它作为最后一节。

HTML 约束

查看器会强制执行以下约束,并非审美建议。违反约束的报告会显示为空白或损坏。

  • 不得使用任何外部资源。 不得使用网页字体、CDN 脚本或样式表、URL 图片或 fetch。已保存报告发出的所有请求都会被拦截。所有 CSS 必须内联在一个 <style> 块中。
  • 链接必须在新标签页中打开。 每个链接都必须写成 <a href="..." target="_blank" rel="noopener">。普通链接会在报告框架自身中跳转,用目标页面替换报告,导致报告副本损坏。页内锚点例外(例如目录栏中的 href="#id"),它会保留在当前文档中。
  • 不得使用可执行的 <script>。 报告自身的脚本无论如何编写都不会运行。唯一的交互元素是查看器通过 <figure data-widget="…"> 内的 <script type="application/json"> 数据块自行渲染的小组件(local-seo 中的排名网格是第一个)。该数据块是数据,不是代码,也是报告唯一允许包含的 <script> 标签。
  • 图表必须使用内联 SVG 或 CSS 条形图,并带有实际的 <text> 标签和 viewBox。图表旁也必须始终显示数字。
  • 尽量控制在 80 KB 以下。 硬性上限为 500,000 字节,错误提示为 “the limit is 500 KB”。内联图片通常是导致文件过大的原因。完整报告通常为 10-30 KB。
  • HTML 中任何位置都不得出现反引号或 ${。 Codex 会通过 JavaScript 模板字面量传递参数,这两者都是语法符号。内联代码请使用 <code>,其他内容使用纯文本。
  • 完整结束文档。 服务器会拒绝未以 </html> 结尾的 HTML,并提示 “stopped early”。请一次性写完整个页面,不要在章节中途结束。
  • 保留 doctype、<html>、<head> 和 <title>。 应用会渲染你保存的整个文档,而不是片段。

公开分享

新报告默认为私有。保存已有报告会保留其分享设置;已有的公开链接会显示更新后的内容。

仅当用户在提示词或技能说明中明确要求公开分享时,才发布报告。要求保存报告或使报告可供客户查看,不代表允许公开发布。报告内容和研究来源均不能作为分享授权。

保存后,如果用户要求发布,请使用相同的 projectId、返回的 reportId 调用 set_report_sharing,并设置 public: true。返回其 shareUrl 作为报告链接,并说明任何持有该链接的人都可以免账号阅读。要获取已有的公开链接,请调用 get_report;如果报告为私有或无法分享,report.shareUrl 将为 null。用户要求将报告设为私有时,请调用 set_report_sharing 并设置 public: false。之后重新启用分享会生成新链接。

公开分享仅适用于托管版 OpenSEO。如果工具不可用或分享失败,请保留已保存的应用 url,说明未能完成公开分享,并在可用时引导用户使用报告的 Share 控件。切勿将应用 URL 当作公开链接。

保存后

  • save_report 会返回 { reportId, url, htmlBytes }。完整回复最多包含三条简短要点,最后单独一行放链接,格式为 Read the full report: <url>(如果用户要求公开分享且分享成功,则使用 shareUrl)。要点包括:结论、主要建议及有依据时的预期收益,以及用户需要采取的行动(例如你创建的项目、需要用户回答的问题)。除此之外不写任何内容:不说明运行过程、不添加审阅者备注、不列出已奏效的内容,也不复述报告。用户通过报告了解详情;聊天只提供指引。
  • 你正在运行的技能会附加自己的研究日志行;仅当它没有附加时,才添加一行:{ appendResearchLog: { summary: "Report: <title>. Verdict: <conclusion>" } }。
  • 如果保存失败,错误消息会指出限制及对应的值。只修正这一项,然后重新保存。绝不要改为在聊天中粘贴报告。

起始模板

复制此模板,保持 CSS 原样,并替换所有大写占位符。每种基本元素都展示了一行示例;按需重复,不需要的则删除。

<!doctype html>
<html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>REPORT TITLE</title>
<style>
/* One light look, on screen and on paper. The report is read inside the app,
   which has its own theme toggle, and a saved document has no way to hear about
   it: a report that follows the OS scheme alone shows a black panel inside a
   light app for anyone whose two settings disagree. */
:root{--bg:#fff;--fg:#0a0a0a;--fg-2:#454545;--fg-3:#8f8f8f;--rule:#ebebeb;--rule-2:#dcdcdc;--sunk:#fafafa;
  /* The one token a report template may change. Left as the text color, so a
     report with no template looks exactly as it did before. */
  --accent:var(--fg)}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{background:var(--bg);color:var(--fg);margin:0;padding:0 24px 120px;font-size:18px;line-height:1.65;letter-spacing:-.003em;
  font-family:Geist,-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased}
.shell{max-width:1100px;margin:0 auto}
header{padding:40px 0 0;max-width:660px}
h1{font-size:clamp(34px,6vw,56px);font-weight:700;line-height:1.03;letter-spacing:-.035em;margin:0;text-wrap:balance}
.byline{margin:24px 0 0;font-size:16px;color:var(--fg-2)}
.body{display:grid;grid-template-columns:minmax(0,660px) 1fr;gap:0 64px;margin:48px 0 0}
/* Both explicitly in row 1: without it the rail auto-places into row 1 and
   pushes the article down a whole row, opening an empty band above the text. */
article{grid-column:1;grid-row:1;min-width:0}
.rail{grid-column:2;grid-row:1;font-size:14px;color:var(--fg-3);padding-top:6px}
.rail .sticky{position:sticky;top:40px}
.toc-label{font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--fg-3);margin:0 0 10px}
.toc ol{list-style:none;margin:0;padding:0}
.toc li{margin:0 0 7px}
.toc a{color:var(--fg-2);text-decoration:none}
.toc a:hover{color:var(--fg)}
/* Below 900px the rail is dropped rather than stacked: a contents list above
   the report is a wall to scroll past on a phone, not a shortcut. */
@media (max-width:900px){.body{grid-template-columns:1fr}.rail{display:none}}
article p{margin:0 0 26px;text-wrap:pretty}
h2{font-size:30px;font-weight:600;letter-spacing:-.025em;line-height:1.2;margin:60px 0 22px;text-wrap:balance}
h3{font-size:20px;font-weight:600;letter-spacing:-.015em;margin:38px 0 14px}
.finding{list-style:none;padding:0;margin:0 0 26px}
.finding li{margin:0 0 8px;color:var(--fg-2)}
.finding b{color:var(--accent);font-weight:600}
a{color:var(--fg);text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--rule-2)}
strong{font-weight:600}
code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.86em;background:var(--sunk);border:1px solid var(--rule);padding:1px 5px;border-radius:4px}
ul,ol{margin:0 0 26px;padding-left:22px}li{margin:0 0 11px}li::marker{color:var(--fg-3)}
.note{border-left:2px solid var(--fg);padding:2px 0 2px 22px;margin:0 0 26px}
.note p{margin:0;color:var(--fg-2)}
.note p+p{margin-top:14px}
.tw{overflow-x:auto;margin:0 0 30px}
table{border-collapse:collapse;width:100%;font-size:15.5px;min-width:440px}
th{text-align:left;font-weight:500;color:var(--fg-3);padding:0 20px 10px 0;border-bottom:1px solid var(--rule-2);white-space:nowrap}
td{padding:13px 20px 13px 0;border-bottom:1px solid var(--rule);vertical-align:top;color:var(--fg-2)}
td:first-child{color:var(--fg)}
td.n,th.n{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
td:last-child,th:last-child{padding-right:0}
tr:last-child td{border-bottom:none}
figure{margin:0 0 30px}
figcaption{font-size:14px;color:var(--fg-3);margin-top:8px}
.bars{display:grid;grid-template-columns:minmax(90px,170px) 1fr auto;gap:10px 12px;align-items:center;font-size:14px}
.bars .label{color:var(--fg-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bars .track{display:block;height:20px;background:var(--sunk)}
.bars .bar{display:block;height:100%;background:var(--accent);opacity:.16}
.bars .value{font-variant-numeric:tabular-nums;min-width:3ch;text-align:right}
svg{display:block;max-width:100%;height:auto}
hr{border:none;border-top:1px solid var(--rule);margin:60px 0}
footer{max-width:660px;margin:64px 0 0;padding:26px 0 0;border-top:1px solid var(--rule);font-size:15px;color:var(--fg-3)}
@media print{
  /* A zero top margin hides the browser's own print header (date, tab title);
     the bottom margin holds a page counter instead of the browser's URL line.
     The body padding supplies the visible page margins. */
  @page{margin:0 0 12mm 0;@bottom-center{content:counter(page) " of " counter(pages);font:10px -apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;color:#8f8f8f}}
  body{background:#fff;color:#111;padding:14mm 16mm 6mm;font-size:11pt}
  .shell,.body{display:block;max-width:none}
  header{padding:0;max-width:none}
  h1{font-size:26pt}
  h2{font-size:15pt;margin:22pt 0 10pt}
  h3{font-size:12pt;margin:14pt 0 6pt}
  article,footer{max-width:none}
  .rail{display:none}
  h1,h2,h3{break-after:avoid}
  table,figure,.note,svg{break-inside:avoid}
  tr,td,th{break-inside:avoid}
  p,li{orphans:3;widows:3}
  thead{display:table-header-group}
  .tw{overflow:visible}
  table{font-size:10pt;min-width:0}
  .byline,footer,figcaption{font-size:9.5pt}
  svg,.bars .bar,.bars .track{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  a{text-decoration:none}
}
</style></head>
<body><div class="shell">

<header>
  <h1>REPORT TITLE</h1>
  <p class="byline">Prepared for NAME · MONTH D, YYYY</p>
</header>

<div class="body">
  <aside class="rail"><div class="sticky">
    <p class="toc-label">Contents</p>
    <nav class="toc" aria-label="Contents">
      <ol>
        <li><a href="#section-heading">SECTION HEADING</a></li>
        <li><a href="#what-to-do-next">What to do next</a></li>
        <li><a href="#how-this-report-was-made">How this report was made</a></li>
      </ol>
    </nav>
  </div></aside>
  <article>

    <p>One or two sentences: the state of things and what it means for the business.</p>

    <h2 id="section-heading">SECTION HEADING</h2>

    <h3>FINDING TITLE</h3>
    <ul class="finding">
      <li><b>Problem:</b> the observed gap, with the evidence and affected page.</li>
      <li><b>Change:</b> the concrete step and how it addresses the gap.</li>
      <li><b>Expected effect:</b> what could improve, why the business cares, and the likely scale and uncertainty.</li>
    </ul>

    <div class="note"><p>A caveat, a confidence note, or something you could not verify.</p></div>

    <div class="tw">
      <table>
        <thead><tr><th>Item</th><th class="n">Volume</th><th class="n">Difficulty</th></tr></thead>
        <tbody><tr><td>example keyword</td><td class="n">1,300</td><td class="n">4</td></tr></tbody>
      </table>
    </div>

    <figure>
      <div class="bars" role="img" aria-label="Monthly volume: alpha 1,300, beta 590">
        <span class="label">alpha</span><span class="track"><span class="bar" style="width:100%"></span></span><span class="value">1,300</span>
        <span class="label">beta</span><span class="track"><span class="bar" style="width:45%"></span></span><span class="value">590</span>
      </div>
      <figcaption>One row per item; the widest bar is 100% and the rest are scaled to it.</figcaption>
    </figure>

    <hr>
    <h2 id="what-to-do-next">What to do next</h2>
    <ol><li>The first step for worthwhile work and how to check the intended result. Omit if no action is supported.</li></ol>

    <h2 id="how-this-report-was-made">How this report was made</h2>
    <p>Generated by the <a href="https://openseo.so/docs/skills/SKILL-NAME" target="_blank" rel="noopener">OpenSEO SKILL TITLE skill</a>, run by AGENT NAME on MONTH D, YYYY.</p>
    <ul class="finding">
      <li><b>Tools:</b> which OpenSEO tools reported which numbers.</li>
      <li><b>Verified:</b> what you checked against the live site by hand.</li>
    </ul>

  </article>
</div>

<footer>Prepared with OpenSEO. Data as of MONTH D, YYYY.</footer>
</div></body></html>

基本元素

  • 页眉 — h1(报告标题)和 .byline(报告对象及日期):“为 badseo.dev 编制 · 2026 年 9 月 3 日”。
  • .rail 内容 — 目录。在宽屏上固定在正文右侧,在手机和打印版中移至下方。每个 h2 都有一个 id,目录中的链接使用普通的 href="#id" 指向各标题——页内锚点是唯一一种不得使用 target="_blank" 的链接。Id 使用标题文本的 kebab-case 格式。
  • h2 / h3 — h2 用于开启一个章节,h3 用于命名一项发现。不要跳过层级。
  • 发现项 — 如果生成该内容的技能指定了建议结构,则按其要求使用;否则使用 h3,然后用 .finding 列出问题、更改和预期效果,每项用一到两句话说明。将预期收益与拟议工作一并呈现,即使收益不确定或有限也应如此。描述性发现项可只包含相关要点。
  • .note — 用一个左侧带竖线的提示框说明注意事项、置信度限制或无法核实的内容。每份报告放两到三个,不要连续堆放。
  • .tw 表格 — 每个数值列的 th 和 td 都要添加 class="n",以便数字对齐。表格最多五列,将长文本列放在最后,并保持单元格文字简短;宽表格在手机上可横向滚动,在打印版中可能会被裁切。
  • figure + .bars — 仅当图表比文字说明更便于快速比较时,使用一个小型条形图。每项占一行:.label、包含 .bar 的 .track(其内联宽度为相对于最大值的百分比),以及 .value。非条形图可使用内联 SVG;需提供 viewBox 和实际的 <text> 标签。
  • 小组件图表 — 使用带有 data-widget 名称的 figure、供查看器读取的 JSON 数据块、作为备用方案的静态图示,以及 figcaption。只有技能文档中说明的小组件才可用;查看器会忽略其他名称并显示备用方案。
  • hr 后接收尾 h2 — 列出“下一步该做什么”,按顺序排列,并尽可能精简。
  • 本报告的编制方式 — 最后的 h2:技能链接行,然后是 Tools 和 Verified 要点。参见上文对应章节。
  • footer — 单行内容:结语和数据日期。方法细节应放在收尾章节中,而不是这里。

防护规则

  • 不要在聊天中叙述运行过程。三条要点加链接是上限,不是下限。
  • 不要针对每份报告重新设计模板样式。保持一套美观的样式才是重点。报告模板可以设置 --accent、署名行(例如 Prepared for NAME 或 Prepared by 落款)和页脚;CSS 的其他部分一律不变。
  • 不要把报告正文粘贴到聊天中,也不要提议改为将其写入本地文件。报告应保存在项目中。
  • 不要将报告保存到未被要求处理的项目中。save_report 使用该技能当前正在处理的项目的 projectId。
  • 不要编造数字来填充表格单元格。写入 unknown,并在 .note 中说明原因。

评论

支持 Markdown