seo-report
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenSEO Report
OpenSEO 报告
Goal
目标
Turn finished research into one self-contained HTML page, saved to the project with , so anyone on the team can open it in the app, read it on a phone, and print it to PDF.
save_reportEvery OpenSEO skill that produces a recommendation delivers through this skill. Chat gets the link, the verdict, and the top action. The report gets everything else.
将已完成的研究整理为单个自包含 HTML 页面,并使用 保存到项目中,以便团队中的任何人都能在应用内打开、在手机上阅读,并打印成 PDF。
save_report每个产出建议的 OpenSEO skill 都通过此 skill 交付。聊天中给出链接、结论和首要行动;报告则承载其他所有内容。
Before you write
写入之前
- Call for the project. If a report already covers the same subject for the same period, you are correcting your own run: pass its
list_reportstoreportIdand replace it. A new month, a new competitor, or a different skill is a new report. Never save a near-duplicate.save_report - Titles are unique within a project. Saving a second report under an existing title with no is rejected, so either pass the
reportIdof the report you are replacing or change the title to name the new subject or period.reportId - To revise an existing report, work from its summary. returns the HTML only with
get_report, and an 80 KB report is roughly 20,000 tokens, which most clients truncate. Fetch the HTML only when you need to edit a specific passage, and if what comes back looks cut off, send the user to the app instead of saving over it.includeHtml: true
- 为项目调用 。如果已有报告覆盖同一主题和同一周期,说明你是在修正自己先前的运行结果:将该报告的
list_reports传给reportId并替换它。新的月份、新的竞品或不同的 skill 都应创建新报告。绝不要保存近乎重复的报告。save_report - 同一项目内的标题必须唯一。在没有 的情况下用已有标题保存第二份报告会被拒绝,因此应传入要替换报告的
reportId,或修改标题以标明新的主题或周期。reportId - 要修订已有报告时,应从其摘要入手。仅在
get_report时返回 HTML,而一份 80 KB 的报告约等于 20,000 个 token,多数客户端会将其截断。仅在需要编辑特定段落时获取 HTML;如果返回内容看起来被截断,应让用户转到应用中查看,而不是覆盖保存。includeHtml: true
Following a template
遵循模板
A project can carry report templates: named, reusable briefs saying who a report is for, which sections it has in what order, how it should sound, and how to sign off. They are listed in project context, and returns the full instructions for each one. Templates belong to a project. To reuse one in another project, list it there and save a copy here.
list_report_templatesUse a template only when the user names it, or asks for the kind of report a template's name or description names. A plain skill run ("audit this site") uses the skill's default format. If two match, ask in one line. A template's sections, audience and tone replace the skill's Output format list; the HTML constraints and writing rules never change. Project writing_preferences always apply; a template's tone wins only where they conflict. Pass its to .
templateIdsave_report项目可以包含报告模板:这些模板是具名、可复用的报告纲要,用于说明报告面向谁、包含哪些章节及其顺序、应采用什么语气,以及如何落款。它们会列在项目上下文中, 则返回每个模板的完整说明。模板归属于项目。若要在另一个项目中复用某个模板,应先在目标项目中列出该模板,然后在这里保存副本。
list_report_templates仅当用户明确指定模板,或要求生成某个模板名称或描述所对应的报告时,才使用该模板。普通的 skill 运行(例如“audit this site”)应采用 skill 的默认格式。如果有两个模板都匹配,用一行询问用户。模板中的章节、受众和语气会取代 skill 的 Output format 列表;HTML 约束和写作规则始终不变。项目的 writing_preferences 始终适用;只有发生冲突时,模板的语气才具有优先权。将模板的 传给 。
templateIdsave_reportWriting rules
写作规则
- Write notes, not essays. The reader scans. A finding is a heading and two or three short bullets: Status (what is true, with the number), Fix (the step), and Why only when it is not obvious. No paragraph runs past two sentences. A section opens with one sentence or none. A summary section (a verdict, a snapshot, a market read) is a bullet list, one fact per line, never prose. How the data was gathered goes in the closing "How this report was made" section, not in the finding.
- Be specific and numeric. "Position 4.6, one click on 1,085 impressions" beats "underperforming". Every claim carries the number, the quoted tag, or the URL that proves it.
- Be honest about confidence. Say which numbers came from a tool and which you verified yourself. When you could not check something, put it in a and say so.
.note - Plain language. Gloss every term of art on first use: canonical, meta description, crawler, 301, structured data. No drama words, no exclamation points, no filler.
- One report, one spine. Lead with the verdict, then the single most important action, then the supporting detail. A report with twenty findings has failed.
- Print the numbers. A chart never carries a value that is not also written out in text.
- 写要点,不写文章。 读者会快速浏览。一个发现项应包含一个标题和两三条简短要点:Status(事实及数字)、Fix(步骤),仅在原因不显而易见时添加 Why。任何段落都不应超过两句。每个章节以一句话开头,或直接省略。摘要章节(结论、概览或市场解读)应使用项目符号列表,每行只写一个事实,绝不写成散文。数据收集方式应放在收尾的“How this report was made”章节,而不是发现项中。
- 具体且量化。 “Position 4.6, one click on 1,085 impressions”优于“underperforming”。每项结论都要带上数字、引用的标签或能够证明它的 URL。
- 诚实说明置信度。 说明哪些数字来自工具,哪些是你自行验证的。无法核查时,将其放入 并明确说明。
.note - 使用通俗语言。 首次出现时解释每个专业术语:canonical、meta description、crawler、301、structured data。不要使用戏剧化词语、感叹号或填充内容。
- 一份报告,一条主线。 先给出结论,再给出唯一最重要的行动,然后是支撑细节。一份包含二十个发现项的报告就失败了。
- 写出数字。 图表中的每个值都必须在正文中同时以文字呈现。
Title and summary
标题与摘要
- : names the subject and the period, under 120 characters. "badseo.dev SEO audit, Sep 2026". Never "SEO Report" or "Analysis".
title - : markdown under 2,500 characters, in this order — the verdict, the single top action, then the key numbers. This is what
summaryreturns and what you or another agent read instead of the HTML, so write it for a reader who will never open the page.list_reports
- :注明主题和周期,少于 120 个字符。例如“badseo.dev SEO audit, Sep 2026”。绝不要使用“SEO Report”或“Analysis”。
title - :少于 2,500 个字符的 Markdown,顺序为:结论、唯一的首要行动、关键数字。
summary会返回此摘要,你或其他 Agent 会读取摘要而不是 HTML,因此应面向永远不会打开页面的读者来编写。list_reports
The closing section: how this report was made
收尾部分:本报告是如何生成的
Every report ends with an titled "How this report was made" (id ), after "What to do next". It is the only section with a fixed opening line: one sentence naming the skill that produced the report and linking its docs page, so a reader who was handed the link can learn what the workflow does and rerun it.
h2how-this-report-was-madehtml
<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>The URL is always followed by the skill's directory name, exactly as written in that skill's Output format list. Copy it; do not guess a slug. Then the rest of the section as the skill describes it: which tools reported what, and what you verified by hand. A report written from a template keeps this section too, as its last one.
https://openseo.so/docs/skills/每份报告都以一个标题为“How this report was made”(id 为 )的 结尾,并放在“What to do next”之后。这是唯一具有固定开头句式的章节:用一句话注明生成报告的 skill,并链接到其文档页面,使收到链接的读者能够了解该工作流的用途并重新运行。
how-this-report-was-madeh2html
<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 始终是 ,后接该 skill 的目录名,并且必须与该 skill 的 Output format 列表中书写的名称完全一致。直接复制,不要猜测 slug。其余部分按 skill 的描述填写:哪些工具提供了哪些信息,以及你手动核实了哪些内容。即使报告基于模板编写,也必须保留这一章节,并将其放在最后。
https://openseo.so/docs/skills/HTML constraints
HTML 约束
These are enforced by the viewer, not by taste. A report that breaks them renders blank or broken.
- No external resources of any kind. No web fonts, no CDN scripts or stylesheets, no images by URL, no . Every request from a saved report is blocked. Inline all CSS in one
fetchblock.<style> - Links open in a new tab. Write every link as . A plain link would navigate the report frame itself, replacing the report with a broken copy of the target. The exception is an in-page anchor (
<a href="..." target="_blank" rel="noopener">, as in the contents rail), which stays in the document.href="#id" - No . Scripts are blocked outright. Anything interactive has to be static.
<script> - Charts are inline SVG or CSS bars, with real labels and a
<text>. Always print the numbers next to the chart too.viewBox - Aim under 80 KB. The hard cap is 500,000 bytes, and the error says "the limit is 500 KB". Inlined images are the usual way people blow it. A filled report is normally 10-30 KB.
- No backticks and no anywhere in the HTML. Codex passes the argument through a JavaScript template literal, where both are syntax. Use
${for inline code and plain text everywhere else.<code> - Finish the document. The server rejects HTML that does not end with as "stopped early". Write the whole page in one call rather than trailing off mid-section.
</html> - Keep the doctype, ,
<html>, and<head>. The app renders the whole document you save, not a fragment.<title>
这些约束由查看器强制执行,而非 merely 审美偏好。违反约束的报告会显示为空白或损坏。
- 不得使用任何外部资源。 不使用 Web 字体、CDN 脚本或样式表、不通过 URL 加载图片,也不使用 。保存后的报告发出的所有请求都会被阻止。将所有 CSS 内联到一个
fetch块中。<style> - 链接在新标签页中打开。 每个链接都写成 。普通链接会让报告框架自身导航,从而用目标页面的损坏副本替换报告。唯一例外是页内锚点(
<a href="..." target="_blank" rel="noopener">,例如目录导航栏中的锚点),它应留在当前文档中。href="#id" - 不得使用 。 脚本会被直接阻止。所有交互内容都必须是静态的。
<script> - 图表使用内联 SVG 或 CSS 条形图,并带真实的 标签和
<text>。同时还要在图表旁写出数字。viewBox - 目标控制在 80 KB 以内。 硬上限为 500,000 bytes,错误信息会显示“the limit is 500 KB”。内嵌图片通常最容易导致体积超限。内容完整的报告通常为 10–30 KB。
- HTML 中任何位置都不得出现反引号和 。 Codex 会通过 JavaScript 模板字面量传递参数,而这两者都会造成语法问题。行内代码使用
${,其他位置一律使用纯文本。<code> - 完整结束文档。 服务端会拒绝未以 结尾的 HTML,并提示“stopped early”。应一次性写入整个页面,不要在章节中途结束。
</html> - 保留 doctype、、
<html>和<head>。 应用会渲染保存的整个文档,而不是片段。<title>
After you save
保存之后
- returns
save_report. The whole reply is at most three short bullets, then the link last on its own line as{ reportId, url, htmlBytes }. The bullets: the verdict, the top action, and anything the user has to act on (a project you created, a question you need answered). Nothing else: no account of the run, no reviewer notes, no list of what worked, no restating the report. The report is how they learn; chat only points at it.Read the full report: <url> - The skill you are running appends its own research-log line; add one only if it does not: .
{ appendResearchLog: { summary: "Report: <title>. Verdict: <conclusion>" } } - If the save fails, the error names the limit and the value. Fix that one thing and save again. Never paste the report into chat instead.
- 返回
save_report。整个回复最多包含三个简短项目符号,然后最后单独一行提供链接,格式为{ reportId, url, htmlBytes }。三个要点分别是:结论、首要行动,以及用户必须处理的事项(你创建的项目、需要用户回答的问题)。不要添加其他内容:不要叙述运行过程、评审备注、成功项列表,也不要复述报告。用户通过报告了解详情;聊天只提供链接。Read the full report: <url> - 正在运行的 skill 会追加自己的研究日志行;仅当它没有追加时,才添加:。
{ appendResearchLog: { summary: "Report: <title>. Verdict: <conclusion>" } } - 如果保存失败,错误信息会指出限制和对应值。修复该问题后再次保存。绝不要改为把报告粘贴到聊天中。
Starter template
起始模板
Copy this, keep the CSS as it is, and replace the ALL-CAPS placeholders. Each primitive shows one example row; repeat the ones you need and delete the ones you do not.
html
<!doctype html>
<html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>DOMAIN — 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 the one action.</p>
<h2 id="section-heading">SECTION HEADING</h2>
<h3>FINDING TITLE</h3>
<ul class="finding">
<li><b>Status:</b> what is true, with the number or the quoted tag that proves it.</li>
<li><b>Fix:</b> the concrete step, doable this week by a non-technical person.</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 top priority, first.</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>复制以下内容,保持 CSS 不变,并替换所有全大写占位符。每个基础组件展示一行示例;按需重复需要的部分,并删除不需要的部分。
html
<!doctype html>
<html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>DOMAIN — 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 the one action.</p>
<h2 id="section-heading">SECTION HEADING</h2>
<h3>FINDING TITLE</h3>
<ul class="finding">
<li><b>Status:</b> what is true, with the number or the quoted tag that proves it.</li>
<li><b>Fix:</b> the concrete step, doable this week by a non-technical person.</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 top priority, first.</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>The primitives
基础组件
- Header — (the report title) and
h1(who it is for and the date): "Prepared for badseo.dev · September 3, 2026"..byline - contents — the table of contents, sticky to the right of the text on a wide screen, dropped on a phone and in print. Every
.railhas an id, and the contents list links to each one with a plainh2— in-page anchors are the one kind of link that must not usehref="#id". Ids are the kebab-case of the heading text.target="_blank" - /
h2—h3opens a section,h2names one finding. Do not skip levels.h3 - Finding — , then a
h3list:.finding,<li><b>Status:</b> …</li>, and<li><b>Fix:</b> …</li>only when the reason is not obvious. Each bullet is one or two sentences. This is the workhorse; most of a report is a run of these.<li><b>Why:</b> …</li> - — one left-ruled callout for a caveat, a confidence limit, or something you could not verify. Two or three in a report, never a row of them.
.note - table — every numeric column gets
.twon both theclass="n"and thethso the digits line up. Keep tables to five columns or fewer, put the long-text column last, and keep cell text short; a wide table scrolls on a phone and clips in print.td - +
figure— one small bar chart where a comparison reads faster than a sentence. One row per item:.bars, a.labelholding a.trackwhose inline width is the value as a percentage of the largest, and.bar. Inline SVG is fine for anything that is not a bar chart; give it a.valueand realviewBoxlabels.<text> - then a closing
hr— the "What to do next" list, ordered, shortest useful.h2 - How this report was made — the last : the skill link line, then Tools and Verified bullets. See the section above.
h2 - — one line: the sign-off and the data date. Method detail belongs in the closing section, not here.
footer
- Header — (报告标题)和
h1(报告面向谁以及日期):例如“为 badseo.dev 准备 · 2026 年 9 月 3 日”。.byline - 目录 — 目录在宽屏上固定于正文右侧,在手机和打印时隐藏。每个
.rail都有 id,目录通过普通的h2链接到各章节——页内锚点是唯一不得使用href="#id"的链接类型。Id 是标题文本的 kebab-case 形式。target="_blank" - /
h2—h3开启一个章节,h2命名一个发现项。不要跳过层级。h3 - 发现项(Finding) — ,然后是
h3列表:.finding、<li><b>Status:</b> …</li>,仅在原因不显而易见时添加<li><b>Fix:</b> …</li>。每条要点为一到两句。这是报告最常用的结构;报告的大部分内容都应由一系列这种结构组成。<li><b>Why:</b> …</li> - — 左侧带边线的提示框,用于注意事项、置信度限制或无法核实的内容。每份报告放两到三个,绝不要排成一长列。
.note - 表格 — 每个数值列都要在
.tw和th上添加td,使数字对齐。表格最多五列,把长文本列放在最后,并保持单元格文本简短;宽表格会在手机上横向滚动,在打印时被裁切。class="n" - +
figure— 当比较比一句话更容易理解时,使用一个小型条形图。每个项目一行:.bars、包含.label的.bar(.track的内联宽度为该值占最大值的百分比),以及.bar。非条形图可使用内联 SVG;为其提供.value和真实的viewBox标签。<text> - 后接收尾
hr— 编写“What to do next”列表,使用有序列表,并保持简短实用。h2 - How this report was made — 最后一个 :先放 skill 链接行,然后是 Tools 和 Verified 要点。参见上文对应章节。
h2 - — 一行内容:落款和数据日期。方法细节应放在收尾章节,而不是这里。
footer
Guardrails
防护规则
- Do not narrate the run in chat. Three bullets and the link is the ceiling, not the floor.
- Do not restyle the template per report. One look, kept good, is the point. A report template may set , the byline (for example
--accentor aPrepared for NAMEsign-off), and the footer; nothing else in the CSS changes.Prepared by - Do not paste the report body into chat, and do not offer to write it to a local file instead. The report lives in the project.
- Do not save a report into a project you were not asked about. takes the
save_reportthe skill is already working in.projectId - Do not invent a number to fill a table cell. Write and say why in a
unknown..note
- 不要在聊天中叙述运行过程。三个要点加链接是上限,而不是下限。
- 不要针对每份报告重新设置样式。统一且良好的视觉风格才是重点。报告模板可以设置 、byline(例如
--accent或Prepared for NAME落款)和 footer;CSS 中其他内容均不得更改。Prepared by - 不要把报告正文粘贴到聊天中,也不要提出改为写入本地文件。报告应保存在项目中。
- 不要把报告保存到用户未要求处理的项目中。使用该 skill 正在操作的
save_report。projectId - 不要编造数字来填表。写入 ,并在
unknown中说明原因。.note