carta-reporting用の内部処理専用スキルです。Claude Codeによる全体的なやり取りを制御しており、スキーマ(データ構造の定義)のプレビュー、カスタマイズの確認段階、変換設定(絞り込み・並べ替え・計算式・集計処理)、出力のプレビュー、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-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": "<preview or full report file path>"
}
EOF
結果の概要を短く述べてから(例:「証券台帳レポートです。バックグラウンドでフルデータを読み込み中です」)、カラムの一覧を表示します。
カラム一覧の形式 — カテゴリごとに分類した番号付きリスト。28カラムレポートの例:
**全28カラム:**
識別情報
1 — 利害関係者名(テキスト) 2 — 付与ID(テキスト) 3 — 株式プラン(テキスト)
付与の詳細
4 — 付与日(日付) 5 — 付与種別(テキスト) 6 — 行使価格(金額)
7 — 失効日(日付)
株数
8 — 発行済株数(整数) 9 — ベスティング済株数(整数)
10 — ベスティング未了株数(整数) 11 — キャンセル済株数(整数)
...
分類ルール(順に適用。該当なし → 「その他」):
dateintegerで、Share、Quantity、Count、Unitsを含むmoneypercentageカラム、フィルター、ソート、形式をカバーする1つの質問。元のプロンプトで既に指定された内容に基づいて適応します。
プロンプトで詳細が指定された場合:
ご指定の内容に基づいて以下を適用します:
- カラム: 利害関係者名、付与日、発行済株数、ベスティング率
- フィルター: ベスティング率 > 50%
- ソート: 付与日(降順)
これらの設定で続行を返信して進めるか、何か調整してください。その他、計算式カラム(全体の%、累積合計、比率、差分)や集計(合計行、グループ集計)も追加できます。
プロンプトが曖昧な場合:
どのようなカスタマイズをしたいですか?全カラム、フィルターなしを返信してデータセット全体を取得するか、以下の内容を指定してください:
- カラム — 含めるカラム
- フィルター — 例:「ベスティング率 > 50」「付与日が2024年1月1日以降」「名前に Smith を含む」
- ソート — 例:「付与日が最新順」「発行済株数が多い順」
- 計算式 — 全体の%、累積合計、比率(A ÷ B)、差分(行間変化)
- 集計 — 合計行またはグループ別集計
設定を構築する前に、ユーザーが指定したカラム名とフィルター対象をスキーマプレビューの実際のカラム名と照合してください。ユーザーの用語がレポートのカラム名と異なることがよくあります(例:「部門」→「コストセンター」、「従業員」→「利害関係者名」、「ベスト%」→「ベスティング率」)。
マッチングルール(順に適用):
用語がマッチしない場合、確認質問で候補を表示します:
⚠ **「部門」**はこのレポートに見つかりません。最も近いテキストカラム:コストセンター、株式プラン、付与種別。どれをお考えですか、それともこのフィルターをスキップしますか?
最大3つの候補を、編集距離/単語の重複度でランク付けして表示してください。マッチしない用語がフィルター対象の場合、ユーザーが解決するまで設定に追加しないでください。
この確認を適用対象:明示的なカラム選択、フィルターカラム名、ソートカラム名、計算式のソースカラム。
常に主要識別カラム(利害関係者名、付与IDまたは同等のもの)およびプロンプトで明示的に指定されたカラムを事前選択します。確認質問で事前選択内容を述べてください:
事前選択済みカラム: 1 — 利害関係者名、2 — 付与ID、6 — 行使価格 すべてを返信して全28カラムを取得するか、番号で追加(例:+8, 12, 13)するか、キーワードで検索(例:vesting)、またはyesで事前選択を確認してください。
ユーザーがキーワードで返信した場合、マッチするカラムのみを表示する確認質問を再度呼び出し、確認するか番号で追加するよう求めてください。これはチェックポイント質問が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 |
pct_of_totalは現在のレポートの行の合計で除算します。これは、レポートが全社の場合のみが会社全体です。ステップ1bのcarta-reportingで_scope_<corporation_id>がis_limited_admin: trueを報告する場合、カラムを「{種類}合計の%」という名前にしてください — または複数のクラスの場合は「範囲内合計の%」 — 会社の所有権として表示しないでください。
ユーザーが資本構造、株式ライプロセス、または所有権計算の理解が必要な値を求める場合、それを既に含むCartaレポートに誘導してください:
「この計算は生データから安全に計算できない株式ルールに関するものです。Cartaの**[レポート名]**レポートに既に含まれています。そちらの方がいいですか?」
例:
[
{"name": "全体に占める%", "op": "pct_of_total", "column": "Shares Issued"},
{"name": "累積株数", "op": "running_sum", "column": "Shares Issued"}
]
集計はreport_processor.pyで処理されます。
集計行 — 下部に1つの合計行を追加します。最初のカラムは「合計」と表示されます:
{"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-reportingのステップ1a)、この企業に対するreport_processor.pyのすべての呼び出し(スキーマプレビュー呼び出しと出力プレビュー/フルレポート呼び出しの両方)に"label_overrides": {"CBU": "<label>"}を含めてください。企業をキーにした変数を使用して(例:_phantom_label_12345)、複数企業フロー処理を正しく処理してください。
実行後、常にstatsを確認してください:
missing_columnsが空でない → data[sheet].columnsから利用可能なカラム名を一覧表示し、ユーザーにどの列を意図したのか尋ねて、正しい名前で再実行skipped_formulasが空でない → 実行できなかった計算式をユーザーに伝えます(通常、ソースカラムが選択に含まれていない)filtered_row_count = 0 → 一致する行がない。フィルターを緩和するかas_of_dateを変更することを提案displayed_row_count < filtered_row_count → プレビューが有効です。previewなしで再実行してフルレポートを取得カスタマイズ確認後、`/tmp/carta_report_<user_report_
<!-- carta:plugin-version --> <carta-plugin>carta-cap-table:6.96.0</carta-plugin>
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 total in this report | 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 |
pct_of_total divides by the sum of the rows present, which is the whole company only when the
report is. If _scope_<corporation_id> reports is_limited_admin: true (step 1b of
carta-reporting), name the column "% of {Share Class} Total" — or "% of In-Scope Total" for more
than one class — and never present it as ownership of the company.
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 による自動翻訳です。