carta-reporting の内部向け補助スキル。Claude Code(AIが直接コードを操作できる機能)とのやり取り全般を制御します。具体的には、データ構造の確認、ユーザーが設定を変更する段階、データ変換の設定(絞り込み、並べ替え、計算式、集計など)、結果の確認、carta-reporting-excel への処理引き継ぎまでを担当します。 プレビューファイルが読み込まれた後に、carta-reporting(Claude Code 経由)から呼び出されます。ユーザーが直接実行するスキルではありません。
Internal subskill for carta-reporting. Drives the full Claude Code interaction: schema preview, customization checkpoint, transform config (filtering, sorting, formulas, aggregations), output preview, and hand-off to carta-reporting-excel. Invoked by carta-reporting (Claude Code path) after the preview file lands. Not for direct user invocation.
<!-- carta:instrumentation-fallback -->
<重要事項>
_instrumentation_v2 は、Cartaスキルの利用状況を匿名で記録するテレメトリ(使用データの収集)です。Carta MCPツール呼び出しの引数に常に含めてください。プラグインのフックが実行時に上書きするため、常に送信することは安全です。形式は以下の通り:
_instrumentation_v2: {"skills": ["<plugin>:<skill>", ...], "model": "<model-id>", "surface": "<value>"}
skills はセッション累積: これまでロードされたCartaスキルをすべてリストアップします(このコール自体を実行するものだけでなく)。各エントリを "plugin:skill" の形式で名前空間を指定し、古い順に保持して、最も最近使用したスキルを最後に置きます。Cartaスキル(carta-cap-table:*、carta-crm:*、carta-investors:*)のみをリストアップ。非Cartaプラグインのスキルは含めません。
surface はClaudeが実行されているサーフェス(実行環境): "chat"(claude.aiまたはClaudeアプリ、通常のチャット。Coworkではない)、"cowork"(Coworkモード)、"code-terminal"、"code-desktop"、"excel"のいずれか。これらのいずれにも当てはまらない、または判断できない場合は完全に省略。推測したり、別の値を作り出したりしないでください。
</重要事項>
carta-reporting のステップ 4d(Claude Code / MARKDOWNパス)から呼び出されます。このセッション内で以前に解決された値を使用: データファイルパス、corporation_id、user_report_pk、および _report_processor_path(親スキルが一度解決したスクリプトパス。find を再実行する代わりに再利用します)。
変換なしでデータファイルに対して report_processor.py を実行し、列名と型を抽出します。キャッシュされた _report_processor_path を再利用。空の場合のみ find にフォールバック:
UV_PYTHON_DOWNLOADS=never uv run "${_report_processor_path:-$(find ~ -name "report_processor.py" -path "*/carta-reporting/scripts/*" 2>/dev/null | head -1)}" <<'EOF'
{
"local_file": "<プレビューまたはフルレポートファイルパス>"
}
EOF
簡潔な結果サマリーで始めます(例:「ここはあなたの有価証券台帳レポートです。バックグラウンドで全データを読み込み中です」)。その後、列リストを提示します。
列リストの形式 — カテゴリーごとにグループ化した番号付きリスト。28列のレポートの例:
**全28列:**
識別情報
1 — 権利者名(テキスト) 2 — グラントID(テキスト) 3 — 株式プラン(テキスト)
グラント詳細
4 — グラント日(日付) 5 — グラントタイプ(テキスト) 6 — 行使価格(金額)
7 — 失効日(日付)
株式数
8 — 発行済み株式(整数) 9 — 帰属済み株式(整数)
10 — 未帰属株式(整数) 11 — キャンセル済み株式(整数)
...
グループ化のヒューリスティクス(順番に適用。マッチなし → 「その他」):
dateinteger、列名に Share(株式)、Quantity(数量)、Count(件数)、Units(単位)を含むmoneypercentage列、フィルター、ソート、形式をカバーする AskUserQuestion を1つ実施。内容は元のプロンプトで既に指定されているかに応じて調整します。
プロンプトで詳細が指定されている場合:
あなたのリクエストに基づいて、以下を適用します:
- 列: 権利者名、グラント日、発行済み株式、帰属%
- フィルター: 帰属% > 50%
- ソート: グラント日(降順)
これらの設定で続行 と返信して進めるか、何か調整してください。計算列(全体の%、累計、比率、差分)または集計(小計行、グループごとの集計)も追加できます。
プロンプトが曖昧な場合:
カスタマイズは何をしたいですか? 全列、フィルターなし と返信するとそのままのデータセットが得られます。または以下の任意を指定できます:
- 列 — どの列を含めるか
- フィルター — 例:「帰属% > 50」、「グラント日が2024年1月1日以降」、「名前に Smith を含む」
- ソート — 例:「グラント日(最新順)」、「発行済み株式(降順)」
- 計算列 — 全体の%、累計、比率(A ÷ B)、差分(行ごとの変動)
- 集計 — 小計行またはグループごとの集計
設定を構築する前に、ユーザーが言及したすべての列名とフィルターターゲットをスキーマプレビューの実際の列名に対してチェック。ユーザーの用語は往々にしてレポートの列名と異なります(例:「Department(部門)」→「Cost Center(コストセンター)」、「Employee(従業員)」→「Stakeholder Name(権利者名)」、「Vest %(帰属%)」→「Vested %(帰属済み%)」)。
マッチングルール(順番に適用):
用語がマッチできない場合、チェックポイントに候補を表示:
⚠ 「Department(部門)」 はこのレポートに見つかりません。最も近いテキスト列: Cost Center(コストセンター)、Equity Plan(株式プラン)、Grant Type(グラントタイプ)。どれを意味しましたか、またはこのフィルターをスキップしましょうか?
最大3候補を編集距離/単語重複でランク付けして表示。マッチしなかった用語がフィルターターゲットの場合、ユーザーが解決するまで設定に追加しません。
このチェックを以下に適用: 明示的な列選択、フィルター列名、ソート列名、計算列のソース列。
常に主要な識別子列(権利者名、グラントID、またはそれに相当するもの)と、プロンプトで明示的に名前が挙げられた列を事前選択。チェックポイントで何が事前選択されたかを述べます:
事前選択済みの列: 1 — 権利者名、2 — グラントID、6 — 行使価格 すべて と返信するとすべての28列、番号で追加(例:+8, 12, 13)、キーワードで検索(例:vesting(帰属))、または事前選択を yes で確認。
ユーザーがキーワードで返信する場合、一致する列のみを表示する追加の AskUserQuestion を一度だけ実施し、確認または追加で番号の入力を求めます。これが2番目のチェックポイント質問が許可される唯一のケースです。
すべてのフィルタリングは report_processor.py で処理。Claudeのメモリーで適用しません。
ユーザーリクエストをフィルターオブジェクトに変換:
| ユーザーリクエスト | フィルターオブジェクト |
|---|---|
| 「帰属% > 50」 | {"column": "Vested %", "op": ">", "value": 0.5} |
| 「グラント日が2024年1月1日以降」 | {"column": "Grant Date", "op": ">", "value": "2024-01-01"} |
| 「名前に Smith を含む」 | {"column": "Stakeholder Name", "op": "contains", "value": "Smith"} |
| 「フルディリューション%が5%以上」 | {"column": "Fully Diluted %", "op": ">", "value": 0.05} |
サポートされる演算子: > < >= <= = != contains
列型が percentage の場合、パーセンテージ値を小数で渡します(例:50% → 0.5)。
フィルターがシートのすべての行を削除する場合、スクリプトは0行を返す。そのシートをスキップしサマリーに記載します。
すべての列選択は report_processor.py で処理。列名を目的の表示順で渡します。スクリプトはその順序を保持します。
ユーザーが明示的にリクエストしなかった場合でも、常に主要な識別子列(権利者名、グラントID、またはそれに相当するもの)を含めます。
ユーザーリクエストをソートオブジェクトに変換:
| ユーザーリクエスト | ソートオブジェクト |
|---|---|
| 「最新順」 | {"column": "Grant Date", "direction": "desc"} |
| 「数が多い順」 | {"column": "Shares Issued", "direction": "desc"} |
| 「アルファベット順」 | {"column": "Stakeholder Name", "direction": "asc"} |
複数キー: 優先順位順に複数オブジェクトを渡す(最初 = 主ソートキー)。
計算列の処理は report_processor.py で実施。計算列は列選択後に適用。出力に含まれる列のみ参照できます。
計算列はレポートデータに既に存在する値に対する機械的な変換 のため。株式所有ルールを知らなくても任意のスプレッドシートが実行できる算術。サポートされる4つの演算:
| 演算 | 説明 | 必須フィールド |
|---|---|---|
pct_of_total |
各行を列の合計のパーセンテージで表示 | column |
running_sum |
累計合計(現在のソート順) | column |
ratio |
分子 ÷ 分母 | numerator、denominator |
delta |
行ごとの差分(現在のソート順) | column |
ユーザーが資本構成(キャップストラクチャー)、株式の権利、または所有権の計算についての理解が必要な値をリクエストした場合、その値が既に含まれるCartaレポートに誘導:
「その計算には生データから安全に計算できない株式ルールが関わります。Cartaの [レポート名] レポートには既に含まれています。その代わりにそれを取得しましょうか?」
例:
[
{"name": "全体の%", "op": "pct_of_total", "column": "Shares Issued"},
{"name": "累計株式", "op": "running_sum", "column": "Shares Issued"}
]
集計は report_processor.py で処理。
小計行 — 最下部に1つの合計行を追加。最初の列に「Total(合計)」と表示:
{"type": "summary", "columns": {"Shares Issued": "sum", "Vested %": "avg"}}
グループ化 — キー列で行を折りたたみ、一意の値ごとに1行:
{"type": "group_by", "group_by": "Stakeholder Name",
"columns": {"Shares Issued": "sum", "Grant Count": "count"}}
サポートされる演算: sum avg min max count
carta-reporting の スクリプトリファレンス を参照(全フィールド、複数シート、マージ、出力形式)。
幻の株式(ファントムエクイティ)ラベル: このセッションで _phantom_label_<corporation_id> が解決された場合(`carta-
<!-- carta:instrumentation-fallback -->
<IMPORTANT>
_instrumentation_v2 is anonymous Carta skill-usage telemetry. ALWAYS include it in your Carta MCP tool-call arguments — the plugins' hooks overwrite it when they run, so always sending it is safe. Shape:
_instrumentation_v2: {"skills": ["<plugin>:<skill>", ...], "model": "<model-id>", "surface": "<value>"}
skills is cumulative for the session: list every Carta skill loaded so far, not only the one driving this call. Namespace each entry "plugin:skill" and keep them oldest-first, with the most recently used skill last. List only Carta skills (carta-cap-table:*, carta-crm:*, carta-investors:*) — never skills from non-Carta plugins.
surface is the Claude surface you are running in: "chat" (claude.ai or the Claude app, i.e. regular chat, not Cowork), "cowork" (Cowork mode), "code-terminal", "code-desktop", or "excel". Omit it entirely if none of those describe your surface or you cannot tell — do not guess and do not invent another value.
</IMPORTANT>
Called from carta-reporting step 4d (Claude Code / MARKDOWN path). Use values resolved earlier in this session: data file path, corporation_id, user_report_pk, and _report_processor_path (the script path the parent skill resolved once — reuse it instead of re-running find).
Run report_processor.py on the data file with no transforms to extract column names and types. Reuse the cached _report_processor_path; only fall back to find if it is empty:
UV_PYTHON_DOWNLOADS=never uv run "${_report_processor_path:-$(find ~ -name "report_processor.py" -path "*/carta-reporting/scripts/*" 2>/dev/null | head -1)}" <<'EOF'
{
"local_file": "<preview or full report file path>"
}
EOF
Lead with a brief result summary (e.g. "Here's your Securities Ledger report — loading full data in the background."), then present the column inventory.
Column inventory format — numbered list, grouped by category. Example for a 28-column report:
**All 28 columns:**
Identity
1 — Stakeholder Name (text) 2 — Grant ID (text) 3 — Equity Plan (text)
Grant details
4 — Grant Date (date) 5 — Grant Type (text) 6 — Exercise Price (money)
7 — Expiration Date (date)
Share counts
8 — Shares Issued (integer) 9 — Shares Vested (integer)
10 — Shares Unvested (integer) 11 — Shares Cancelled (integer)
...
Grouping heuristics (apply in order; unmatched → "Other"):
dateinteger, name contains Share, Quantity, Count, UnitsmoneypercentageOne AskUserQuestion covering columns, filters, sort, and format. Content adapts based on what the original prompt already specified.
When the prompt specified details:
Here's what I'll apply based on your request:
- Columns: Stakeholder Name, Grant Date, Shares Issued, Vested %
- Filter: Vested % > 50%
- Sort: Grant Date descending
Reply Continue with these settings to proceed, or adjust anything. You can also add: formula columns (% of total, running sum, ratio, delta), or aggregations (totals row, group-by).
When the prompt was vague:
What would you like to customize? Reply all columns, no filters to get the full dataset as-is, or specify any of:
- Columns — which to include
- Filters — e.g. "Vested % > 50", "Grant Date after 2024-01-01", "Name contains Smith"
- Sort — e.g. "Grant Date newest first", "Shares Issued descending"
- Formulas — % of total, running sum, ratio (A ÷ B), delta (row-over-row change)
- Aggregations — totals row or group-by rollup
Before building the config, check every column name and filter target the user mentioned against the actual column names from the schema preview. The user's terminology often differs from the report's column names (e.g. "Department" → "Cost Center", "Employee" → "Stakeholder Name", "Vest %" → "Vested %").
Matching rules (apply in order):
When a term can't be matched, surface it in the checkpoint with candidates:
⚠ "Department" wasn't found in this report. Closest text columns: Cost Center, Equity Plan, Grant Type. Which did you mean, or should I skip this filter?
Show at most 3 candidates, ranked by edit distance / word overlap. If the unmatched term was a filter target, do not add it to the config until the user resolves it.
Apply this check to: explicit column selections, filter column names, sort column names, and formula source columns.
Always pre-select key identifier columns (Stakeholder Name, Grant ID, or equivalent) plus any columns explicitly named in the prompt. State what's pre-selected in the checkpoint:
Columns pre-selected: 1 — Stakeholder Name, 2 — Grant ID, 6 — Exercise Price Reply all for all 28 columns, add by number (e.g. +8, 12, 13), enter a keyword to filter (e.g. vesting), or confirm the pre-selection with yes.
If the user replies with a keyword, call AskUserQuestion once more showing only matching columns and ask them to confirm or add more by number. This is the only case where a second checkpoint question is allowed.
All filtering is handled by report_processor.py — do not apply filters in Claude's memory.
Translate user requests to filter objects:
| User request | Filter object |
|---|---|
| "vested % > 50" | {"column": "Vested %", "op": ">", "value": 0.5} |
| "grant date after 2024-01-01" | {"column": "Grant Date", "op": ">", "value": "2024-01-01"} |
| "name contains Smith" | {"column": "Stakeholder Name", "op": "contains", "value": "Smith"} |
| "ownership above 5%" | {"column": "Fully Diluted %", "op": ">", "value": 0.05} |
Supported ops: > < >= <= = != contains
Pass percentage values as decimals when the column type is percentage (e.g. 50% → 0.5).
When a filter removes all rows from a sheet, the script returns 0 rows — skip that sheet and note it in the summary.
All column selection is handled by report_processor.py. Pass column names in the desired display order; the script preserves that order.
Always include key identifier columns (Stakeholder Name, Grant ID, or equivalent) even if the user didn't explicitly request them.
Translate user requests to sort objects:
| User request | Sort object |
|---|---|
| "newest first" | {"column": "Grant Date", "direction": "desc"} |
| "largest first" | {"column": "Shares Issued", "direction": "desc"} |
| "alphabetical" | {"column": "Stakeholder Name", "direction": "asc"} |
Multi-key: pass multiple objects in priority order (first = primary sort key).
Formula computation is handled by report_processor.py. Formulas are applied after column selection — they can only reference columns that are included in the output.
Formulas are for mechanical transforms on values already present in the report data — arithmetic that any spreadsheet could do without knowing anything about equity rules. The four supported ops:
| Op | Description | Required fields |
|---|---|---|
pct_of_total |
Each row as % of the column's grand total | column |
running_sum |
Cumulative total down the column (current sort order) | column |
ratio |
numerator ÷ denominator | numerator, denominator |
delta |
Row-over-row difference (current sort order) | column |
If a user asks for a value that requires understanding cap structure, equity rights, or ownership math, direct them to the Carta report that already contains it:
"That calculation involves equity rules that I can't safely compute from the raw data. Carta's [Report Name] report already has it — want me to pull that one instead?"
Example:
[
{"name": "% of Total Shares", "op": "pct_of_total", "column": "Shares Issued"},
{"name": "Cumulative Shares", "op": "running_sum", "column": "Shares Issued"}
]
Aggregation is handled by report_processor.py.
Summary row — appends one totals row at the bottom; first column reads "Total":
{"type": "summary", "columns": {"Shares Issued": "sum", "Vested %": "avg"}}
Group-by — collapses rows by a key column, one row per unique value:
{"type": "group_by", "group_by": "Stakeholder Name",
"columns": {"Shares Issued": "sum", "Grant Count": "count"}}
Supported ops: sum avg min max count
See Script Reference in carta-reporting for the full API (all fields, multi-sheet, merge, output format).
Phantom equity label: If _phantom_label_<corporation_id> was resolved in this session (Step 1a of carta-reporting), include "label_overrides": {"CBU": "<label>"} in every report_processor.py invocation for this corporation — both the schema preview call and the output preview/full-report call. Use the corporation-keyed variable (e.g. _phantom_label_12345) to correctly handle multi-corporation flows.
Always check stats after running:
missing_columns non-empty → list available column names from data[sheet].columns and ask the user which they meant, then re-run with the corrected nameskipped_formulas non-empty → tell the user which formulas couldn't run (usually the source column wasn't included in the selection)filtered_row_count = 0 → no rows matched; offer to relax the filter or change as_of_datedisplayed_row_count < filtered_row_count → preview is active; re-run without preview for full resultsAfter the Customization Checkpoint, check if /tmp/carta_report_<user_report_pk>.json exists. If ready, use it as local_file. If not, poll every 5 s up to 5 more attempts.
Run the script with "preview": 5:
UV_PYTHON_DOWNLOADS=never uv run "${_report_processor_path:-$(find ~ -name "report_processor.py" -path "*/carta-reporting/scripts/*" 2>/dev/null | head -1)}" <<'EOF'
{
"local_file": "<path>",
"columns": [...],
"filters": [...],
"sort": [...],
"preview": 5
}
EOF
Show first 5 rows of each processed sheet as a markdown table. Above each table write: N of M rows matched · K columns.
Ask:
Does this look right?
- Generate full report — all rows as a markdown table
- Excel — download as .xlsx
- Describe any change to filters, columns, or sorting — I'll update just that field and re-run the preview without restarting the whole checkpoint.
If the user requests a change, update only the affected config field and re-run the preview — do not restart the customization checkpoint.
If the user chooses Excel, invoke Skill(carta-cap-table:carta-reporting-excel).
$1,234.56.12.34% (script stores as decimal; multiply × 100 for display).MMM D, YYYY (e.g. May 3, 2026) — the Carta brand standard.原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。