seo-report について
OpenSEO Reportは、完了した調査をチームがアプリで読んだり、印刷してPDFにしたりできる単独のHTMLページにまとめるスキルです。プロジェクトのレポートテンプレートに対応し、構成、根拠の示し方、保存方法を定めています。
主な機能
- 01自己完結型HTMLレポートの作成
- 02テンプレートに沿った章立て
- 03改訂と重複処理のルール
- 04印刷とPDF出力に対応
活用シーン
- 01SEO調査をチーム向けレポートに整理
- 02テンプレート指定の読者向けに作成
- 03既存レポートを重複させずに改訂
MCP 対応
OpenSEOツールでプロジェクトのレポートやテンプレートを参照し、save_reportで保存します。共有設定の管理にも対応します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ every-app/ open-seo --skill seo-reportインストール後、Claude Code で/seo-reportを入力して読み込まれたか確認します。
詳細
OpenSEO レポート
目的
調査が完了したら、save_report を使ってプロジェクトに単独で完結する HTML ページとして保存します。チームの誰もがアプリで開いたり、スマートフォンで読んだり、PDF に印刷したりできます。
推奨事項を提示するすべての OpenSEO スキルは、このスキルを通じて提供します。チャットにはリンク、判定結果、最も重要な推奨事項と、効果が見込まれる場合はその内容を記載します。それ以外はすべてレポートに記載します。
作成前に
- プロジェクトの
list_reportsを呼び出します。同じ期間の同じテーマを扱うレポートがすでにある場合は、自分の実行内容を修正することになります。そのレポートのreportIdをsave_reportに渡して置き換えます。新しい月、新しい競合相手、または別のスキルであれば、新しいレポートを作成します。ほぼ重複するレポートは保存しないでください。 - タイトルはプロジェクト内で一意である必要があります。既存のタイトルで
reportIdを指定せずに2つ目のレポートを保存すると拒否されます。置き換えるレポートのreportIdを渡すか、新しいテーマや期間がわかるようにタイトルを変更してください。 - 既存のレポートを修正する場合は、その要約をもとに作業します。
get_reportはincludeHtml: trueを指定した場合にのみ HTML を返します。80 KB のレポートは約20,000トークンに相当し、多くのクライアントでは途中で切り詰められます。特定の箇所を編集する必要がある場合に限り HTML を取得してください。返された内容が途中で切れているようなら、それを上書きせず、アプリを使うようユーザーに案内してください。
テンプレートに従う場合
プロジェクトにはレポートテンプレートを設定できます。テンプレートは、対象読者、セクションの構成と順序、文体、締めくくり方を定めた、名前付きの再利用可能な指示です。テンプレートはプロジェクトのコンテキストに一覧表示され、list_report_templates を呼び出すと、それぞれの詳しい指示を取得できます。テンプレートはプロジェクトに属します。別のプロジェクトで再利用するには、そのプロジェクトで一覧を取得し、こちらにコピーを保存してください。
テンプレートは、ユーザーが名前を指定した場合、またはテンプレートの名前や説明に合致する種類のレポートを依頼した場合にのみ使用します。「このサイトを監査して」のような通常のスキル実行では、スキルの既定の形式を使用します。該当するテンプレートが2つある場合は、1行で確認してください。テンプレートのセクション、対象読者、文体は、スキルの「出力形式」一覧に優先します。ただし、HTML の制約と執筆ルールは常に適用されます。プロジェクトの writing_preferences は常に適用されます。テンプレートの文体は、両者が競合する場合にのみ優先されます。save_report にテンプレートの templateId を渡してください。
執筆ルール
作成するスキルで推奨事項の形式が指定されている場合は、以下の一般的な「問題/変更/期待される効果」の構成ではなく、その形式を使用してください。たとえば、SEO 監査では「実施すること/理由」の短い箇条書きを使用できます。具体的なアクション、裏付けとなる根拠、ビジネス上のメリット、不確実性を正直に示すという要件は維持してください。スターターテンプレートの指摘事項のマークアップは一例であり、スキルで指定された形式に優先するものではありません。
- エッセイではなく、メモを書く。 読者はざっと目を通します。推奨事項は見出しと、問題(根拠を添えて、何が事実か)、変更(手順と、それが問題にどう対処するか)、期待される効果(改善の可能性、ビジネス上の重要性、効果の規模と不確実性)の3つの短い箇条書きで構成します。状況を説明する指摘事項では、該当する項目だけを使い、解決策を作り出さないでください。段落は2文以内にしてください。セクションの冒頭文は1文、または省略します。要約セクション(総評、概要、市場の見立て)は、事実を1行に1つずつ箇条書きにし、文章にはしません。データの収集方法は、指摘事項ではなく、末尾の「このレポートの作成方法」セクションに記載します。
- 推論の過程を明確にする。 所見を裏付けるため、数値や具体的なページを示します。推奨事項の仕組みと期待されるメリットを平易な言葉で説明します。簡潔さを理由に説明を省いたり、「信頼を築く」といった一般論に置き換えたりしないでください。測定結果、推定値、仮説を区別します。根拠のある定性的な評価は、根拠のない精密さよりも優れています。
- 確信度を正直に示す。 どの数値がツールによるもので、どの数値を自分で確認したのかを明記します。確認できなかったことがあれば、
.noteに記載し、その旨を述べてください。 - 平易な言葉を使う。 専門用語は、初出時にすべて説明します。例:canonical、meta description、crawler、301、構造化データ。大げさな言葉、感嘆符、埋め草は使いません。
- レポート全体の筋道を一本にする。 まず総評とそのビジネス上の意味を示し、次に重要な指摘事項と価値のある推奨事項を述べます。調査の結果、価値のあるアクションが明らかにならなかった場合は、その結論と関連する制約を記載します。指摘事項が20件あるレポートは、要件を満たしていません。
- 数値を明記する。 グラフに示す値は、必ずテキストにも記載します。
タイトルと要約
title:レポートの種類または具体的な対象と、レポートの完全な日付を含め、120文字以内にします。「Competitive Landscape — Sep 17, 2026」または「Keyword Research — Sep 17, 2026」のようにします。実際のレポート日付をMMM D, YYYY形式で記載し、日と4桁の年を含めます。データの対象期間はレポート本文に記載します。「SEO Report」や「Analysis」のような一般的なタイトルは使いません。- レポートの対象がプロジェクトのウェブサイトの場合、タイトルにウェブサイト名を入れません。ホスト名を比較する際は、プロトコル、
www.、末尾のスラッシュを無視します。対象が別のウェブサイトの場合は、「Competitor Analysis: example.com — Sep 17, 2026」のように、ホスト名のみを含めます。プロジェクトにウェブサイトが設定されていない場合も、対象のホスト名を含めます。タイトルにhttps://や完全なURLは入れません。 save_report、HTML の<title>、画面に表示される<h1>で同じタイトルを使い、レポート一覧、共有プレビュー、レポートの内容を一致させます。summary:2,500文字未満の Markdown とし、次の順序で記載します。総評、主な推奨事項と期待されるメリット(または重要なアクションが明らかにならなかった理由)、主要な根拠。これはlist_reportsが返す内容であり、あなたや別のエージェントが HTML の代わりに読むものです。そのため、ページを開かない読者に向けて書きます。
最終セクション:このレポートの作成方法
すべてのレポートの最後には、h2 の見出し「このレポートの作成方法」(id how-this-report-was-made)を置きます。「次にすべきこと」を含める場合は、このセクションの直前に配置します。このセクションだけは、冒頭の文が固定されています。レポートを作成したスキル名を記し、そのドキュメントページへのリンクを付ける一文です。リンクを受け取った読者が、ワークフローの内容を確認し、再実行できるようにするためです。
<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/ にスキルのディレクトリ名を続けたものです。名前は、そのスキルの「出力形式」一覧に記載されているとおりに正確に使用します。推測せず、そのままコピーしてください。その後はスキルの説明に従って、どのツールが何を報告したか、手作業で何を確認したかを記載します。テンプレートから作成したレポートでも、このセクションを最後に置きます。
HTML の制約
これらは好みの問題ではなく、ビューアーによって適用される制約です。違反したレポートは、何も表示されないか、正しく表示されません。
- 外部リソースは一切使用しないでください。 Web フォント、CDN のスクリプトやスタイルシート、URL を指定した画像、
fetchは使用できません。保存済みレポートからのリクエストはすべてブロックされます。CSS はすべて 1 つの<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 バイトで、エラーメッセージには「上限は 500 KB」と表示されます。サイズ超過の主な原因は画像のインライン埋め込みです。内容のあるレポートは通常 10~30 KB です。
- HTML 内ではバッククォートと
${を使用しないでください。 Codex は引数を JavaScript のテンプレートリテラルとして渡すため、どちらも構文として扱われます。インラインコードには<code>を使い、それ以外はプレーンテキストを使用してください。 - ドキュメントを最後まで完成させてください。
</html>で終わらない HTML は、サーバーによって「途中で終了しました」として拒否されます。セクションの途中で終わらせず、ページ全体を 1 回の呼び出しで記述してください。 - doctype、
<html>、<head>、<title>を残してください。 アプリは断片ではなく、保存したドキュメント全体をレンダリングします。
公開共有
新しいレポートは非公開です。既存のレポートを保存すると、共有設定は維持されます。既存の公開リンクを開くと、更新後の内容が表示されます。
ユーザーがプロンプトまたはスキルの指示で公開共有を明示的に求めた場合に限り、公開してください。レポートの保存や、クライアント向けに整えるという依頼は、公開する許可にはなりません。レポートの内容や調査元も、共有を許可するものではありません。
保存後、公開を求められていた場合は、同じ projectId、返された reportId、および public: true を指定して set_report_sharing を呼び出します。レポートのリンクとして shareUrl を返し、リンクを知っている人ならアカウントなしで閲覧できることを伝えてください。既存の公開リンクを取得するには get_report を呼び出します。非公開の場合、または共有を利用できない場合、report.shareUrl は null です。ユーザーからレポートの非公開化を求められた場合は、public: false を指定して set_report_sharing を呼び出してください。後で再び公開すると、新しいリンクが作成されます。
公開共有は、ホスト型の OpenSEO でのみ利用できます。ツールを利用できない場合や共有に失敗した場合は、保存済みのアプリの url をそのまま保持し、公開共有が完了しなかったことを説明してください。利用可能であれば、レポートの「共有」コントロールを案内します。アプリの URL を公開リンクとして提示してはいけません。
保存後
save_reportは{ reportId, url, htmlBytes }を返します。返信全体は短い箇条書き 3 つ以内とし、その後、最後に独立した行としてRead the full report: <url>のリンクを記載します(公開共有が依頼され、成功した場合はshareUrlを使用します)。箇条書きには、結論、主要な推奨事項と、根拠がある場合は期待される効果、ユーザーが対応する必要のあること(作成したプロジェクト、回答が必要な質問)を記載します。それ以外は何も書きません。実行内容の説明、レビュー担当者のメモ、うまくいったことの一覧、レポートの内容の再掲はしないでください。ユーザーが学ぶのはレポートからです。チャットではレポートへのリンクだけを示します。- 実行中のスキルは独自の調査ログ行を追加します。追加されない場合に限り、次を追加してください:
{ appendResearchLog: { summary: "Report: <title>. Verdict: <conclusion>" } }。 - 保存に失敗すると、エラーに制限値と実際の値が示されます。その点だけを修正して、もう一度保存してください。代わりにレポートをチャットに貼り付けてはいけません。
スターターテンプレート
これをコピーし、CSS はそのままにして、大文字のプレースホルダーを置き換えてください。各プリミティブには行の例が 1 つ含まれています。必要なものは繰り返し、不要なものは削除してください。
<!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(対象者と日付):"Prepared for badseo.dev · September 3, 2026"。 .railの内容 — 目次です。広い画面ではテキストの右側に固定され、スマートフォンと印刷時には下に配置されます。すべてのh2に id を付け、目次の各項目から通常のhref="#id"でリンクします。ページ内アンカーは、target="_blank"を使用してはいけない唯一のリンクです。id は見出しテキストをケバブケースにしたものです。h2/h3—h2はセクションを開始し、h3は個々の調査結果に名前を付けます。見出しレベルを飛ばさないでください。- 調査結果 — 生成元のスキルで推奨事項の構成が指定されている場合はそれを使用します。指定がない場合は、
h3の後に.findingリストを置き、「問題」「変更」「期待される効果」をそれぞれ 1~2 文で記載します。確実性や効果が限られている場合も含め、提案する作業のそばに期待される効果を明記してください。説明的な調査結果では、関連する項目だけを記載できます。 .note— 注意事項、確信度の限界、または確認できなかったことを、左側に罫線のあるコールアウト 1 つに記載します。レポートごとに 2~3 個までとし、連続して並べないでください。.twテーブル — 数値列では、桁を揃えるため、thとtdの両方にclass="n"を指定します。列は 5 つ以内にし、長文の列は最後に置き、セル内のテキストは短くしてください。幅の広いテーブルはスマートフォンでは横スクロールになり、印刷時には一部が切れます。figure+.bars— 比較を文よりも速く把握できる場合は、小さな棒グラフを 1 つ使用します。項目ごとに 1 行を設けます。.label、最大値を 100% としたときの割合をインラインの幅で示す.barを含む.track、.valueを使用してください。棒グラフ以外にはインライン SVG を使用できます。その場合はviewBoxと実際の<text>ラベルを指定してください。- ウィジェット図 —
data-widget名、ビューアーが読み取る JSON データブロック、代替表示となる静的な図、figcaptionを含むfigureです。使用できるのはスキルで説明されているウィジェットだけです。それ以外の名前はビューアーが無視し、代替表示を表示します。 hrの後に締めくくりのh2— 最短で実用的な、順序付きの「次に行うこと」リストを置きます。- このレポートの作成方法 — 最後の
h2です。最初にスキルへのリンク行を置き、その後に Tools と Verified の箇条書きを置きます。上のセクションを参照してください。 footer— 署名とデータの日付を 1 行で記載します。方法の詳細はここではなく、締めくくりのセクションに記載してください。
ガードレール
- チャットで実行内容を逐一説明しないでください。箇条書き3項目とリンクが上限であり、必ずそこまで書く必要はありません。
- レポートごとにテンプレートのスタイルを変更しないでください。見た目を統一し、良い状態に保つことが重要です。レポートテンプレートで設定できるのは、
--accent、署名欄(たとえばPrepared for NAMEやPrepared byの署名)、フッターのみです。CSS のほかの部分は変更しないでください。 - レポート本文をチャットに貼り付けないでください。また、代わりにローカルファイルへ書き出すことを提案しないでください。レポートはプロジェクト内に保存します。
- 依頼されていないプロジェクトにレポートを保存しないでください。
save_reportには、スキルがすでに作業しているprojectIdを指定します。 - テーブルのセルを埋めるために数値を捏造しないでください。
unknownと記載し、その理由を.noteに記してください。