claude-skills/

Anthropic公式スキル・プラグインの日本語ディレクトリ

last sync 22h ago
スキルKnowledge Workproductivity

📊carta-fetch-actuals

プラグイン
carta-investors

説明

Carta MCPから既存のExcelの予算ワークブックに実績データを書き込む — Budget/Actual/Variance列の追加・インターリーブ、タグビュータブ、またはベンダービュータブを追加します。 **使用する場合:** - [企業/ManCo]の実績データをプル/取得/更新/同期/追加する - Budget/Actual/Varianceを相互配置する - 部門/コストセンター/タグ/ベンダー別の実績データを取得する - 次の月/期間の列を追加する - 予算を[月]まで延長する - ベンダー別に詳細化する - ベンダーサマリー/時系列支出/[期間]全体のベンダー比較を表示する **使用しない場合:** - ペーシング分析 - 「進捗はどうか」という質問 - 「[期間]の予算対実績」または分散分析クエリ(carta-budget-analysis) - 新規予算作成(carta-create-budget) - シナリオ分析 - P&L/バランスシートの統合 - CartaからManCo予算を取得する(carta-fetch-budget)— このskillは既存ワークブックに実績データを書き込むもので、予算自体ではありません

原文を表示

Write actuals into an existing Excel budget workbook from Carta MCP — add/interleave Budget/Actual/Variance columns, a tag-view tab, or a vendor-view tab. TRIGGER: pull/fetch/get/retrieve/refresh/sync/add actuals for [firm/ManCo], interleave Budget/Actual/Variance, actuals by department/cost center/tag/vendor, add next month/period column, extend budget through [month], broken down by vendor, vendor summary/spend over time/vendors across [period]. NOT: pacing, "how are we doing", "budget versus actual for [period]", or variance-analysis queries (carta-budget-analysis); new budgets (carta-create-budget); scenarios; consolidating P&L / balance sheet. NOT: pulling a stored ManCo budget from Carta (carta-fetch-budget) — this skill writes actuals into an existing workbook, not the budget itself.

ユースケース

  • 実績データをExcelに書き込む
  • Budget/Actual/Variance列を追加する
  • タグビュータブを追加する
  • ベンダービュータブを追加する
  • ベンダー別の実績詳細を表示する

本文

[PATTERN carta-writing-style v0.0.2] [PATTERN etiquette v0.0.6] [PATTERN text v0.0.8] [PATTERN tables v0.0.12] [PATTERN carta-watermark v0.0.10] [PATTERN menus-and-flows v0.0.7] [PATTERN base v0.1.0]

Budget actuals

Entry point for updating actuals in an existing budget. Seven references:

  • references/add-actuals-columns.mdLayout A: interleave Budget / Actual / Variance per month on the Budget tab (recommended for active tracking).
  • references/add-actuals-tab.mdLayout B: add a peer <year> Actuals tab alongside the Budget tab.
  • references/refresh-existing.mdLayout C: overwrite stale actuals cells in columns that already exist.
  • references/add-period.mdLayout D: append the single next month/quarter column.
  • references/tag-view.mdLayout E: new tab with actuals sliced by reporting dimension (department, project code, class, etc.) and a three-row period / category / tag header. Only offered when the entity has tagged journal data.
  • references/vendor-view.mdLayout F: new tab with actuals sliced by vendor, with per-vendor subtotals and a 'No vendor' section. Only offered when the entity has vendor-tagged journal data.
  • references/inline-vendor.mdLayout G: vendor sub-rows added inline to the current actuals tab; accounts become subtotals of their vendor children.
  • references/vendor-only-view.mdLayout H: new tab with one row per vendor across a timeline — no GL account sub-rows. The lightweight vendor summary view.
  • references/get-actuals.md — internal helper, the canonical actuals-query routine.

UX Rules

Audience is an accountant in Excel. Plain English only. Never surface MCP identifiers, DWH column names, UUIDs, raw JSON, SQL, or gate labels. Currency: $X,XXX positive, ($X,XXX) negative, totals bolded. Differences are absolute. Status: ✅ Match | ⚠ Mismatch ($X diff) | ❌ Missing in Carta | ❌ Missing in Client Doc.

Closing summary link is a workbook citation (<citation:Sheet!Range>) in Claude for Excel mode, and a file:// path in Claude Code / Cowork mode.

Every numbered choice in this skill — including the closing next-step menu — MUST be presented via AskUserQuestion. Never render options as a bare code-fenced markdown list. The AskUserQuestion tool is in allowed-tools; use it. Bare-text menus break the chooser UI in Claude for Excel and force the user to type the number.

When to use

  • "Refresh the actuals on my budget"
  • "Pull the latest actuals into the open budget"
  • "Update my budget with March numbers"
  • "The actuals are stale — sync them"
  • "Add next month's column to the budget"
  • "Extend the budget through April"

DO NOT use this skill for

  • Building a new budget from scratch — use carta-create-budget.
  • Pulling the Carta-stored ManCo budget — use carta-fetch-budget.
  • Pacing / YTD vs budget / variance / "are we on track" — use carta-budget-analysis.
  • What-if scenarios — use carta-budget-scenarios.
  • P&L / income statement requests — use carta-consolidating-pnl.
  • Balance sheet requests — use carta-consolidating-balance-sheet.

Execution discipline

Execute all gates silently. Do not narrate tool calls, intermediate results, or status updates. Only speak at explicit decision points: Gate 0.5 (if runtime is ambiguous), Gate 1 (destination chooser), Gate 2 (layout choice — always ask), Gate 3 (period/parameter gate), Gate 6 (approval), and Gate 8 (next-step menu).


Entry mode — fresh session vs. chained skill

Mandatory telemetry beacon — run this before any skip-gate check: If <SERVER> and <ENTITY_UUID> are already in context, call mcp__<SERVER>__set_context(firm_id=<ENTITY_UUID>, _instrumentation={"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}) as your very first action. Do not skip this even when all data is already available — it records this skill invocation. If either is unknown, it fires in Gate 0 below.

Before Gate 0, check whether these context variables are already set from an earlier budgeting skill call in the same session:

  • <SERVER> — connected Carta MCP server prefix
  • <ENTITY_NAME> and <ENTITY_UUID> — the resolved entity
  • <RUNTIME>excel-addin or local-file

If all four are in context: skip Gates 0 and 0.5 entirely. Call mcp__<SERVER>__set_context(firm_id=<ENTITY_UUID>, _instrumentation={"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}) to re-anchor the session scope and record this skill invocation. In Gate 3, pre-fill <ENTITY_NAME> and skip asking for it — ask only for the period. Proceed from Gate 1 (destination), then Gate 2 (layout choice), then Gate 3 (period).

If any is missing (fresh session or cold invocation): run Gates 0 and 0.5 in order, then continue from Gate 1.

Do not ask "which firm?" or "which runtime?" when those are already established from the skill the user just ran.


Gate 0 — Carta MCP environment + resolve firm

  1. Call refresh_mcp_connectors. Filter servers[] to name matching Carta / Carta (…) / carta with status: "connected". Drop failed.
  2. For each connected, probe all three prefix forms in parallel: mcp__claude_ai_Carta__welcome(_instrumentation={"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}) , mcp__carta_production__welcome(_instrumentation={"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}), and mcp__carta__welcome(_instrumentation={"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}). First success = <SERVER>.
  3. Don't call any other mcp__<SERVER>__* tool before welcome — every command is gated.

If none connected, list failed connectors and stop. If multiple, default to Carta (production).

Resolve firm: if user named one → mcp__<SERVER>__list_contexts(firm_name="<entity>", _instrumentation={"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}) → disambiguate via AskUserQuestion if multiple → mcp__<SERVER>__set_context(firm_id=<FIRM_UUID>, _instrumentation={"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}). Do not use call_tool for list_contexts or set_context — call the granular tools directly with _instrumentation as shown.

DWH param-name traps: dwh:execute:query takes sql: not query:. dwh:get:table_schema takes table_name: not table:. format accepts "ndjson" / "markdown", not "csv".

If no firm was named, defer to Gate 3.


Gate 0.5 — Detect runtime

Detect whether this is Claude for Excel (workbook is open in the add-in) or Claude Code / Cowork (working with a .xlsx file on disk). See carta-create-budget/SKILL.md Gate 0.5 for the heuristic — same rule applies here.

If unclear, ask the user via AskUserQuestion:

"How are you working with the budget — inside Excel via Claude for Excel, or as a local .xlsx file (Claude Code / Cowork)?"

Store <RUNTIME> (excel-addin or local-file) for Gates 1, 4, 7, 8.


Gate 1 — Where to write

Branches by <RUNTIME>.

If <RUNTIME> is excel-addin:

Empty-workbook shortcut: if the active workbook has one sheet, maxRows == 0, no other tabs (typically a fresh Book1.xlsx/Sheet1), skip the chooser. Announce the rename in one sentence — "I'll use the empty workbook you have open and rename Sheet1 to <TARGET_TAB>." — then proceed. The chooser only exists to protect non-empty state; an empty workbook has none. The chooser still applies whenever there is data or more than one tab.

Where should I write the updates?

  • "Update the open workbook directly — recommended" (modify in place).
  • "Update the open workbook in a new tab" (preserves the original).
  • "Create a brand new workbook with the updated data".

If user picks "update directly", confirm which tab explicitly. If multiple tabs look like budgets, ask which one.

If <RUNTIME> is local-file:

Where is the budget file, and where should the updated version land?

  • "Modify the file in place — recommended" — ask for the path.
  • "Write a new file alongside the original" — ask for the path; new file gets a -updated suffix by default.

If the user gave a path in the original prompt, skip the choice. Store <DESTINATION> (open workbook + tab in add-in mode, or .xlsx path + sheet name in local-file mode).


Gate 2 — Choose the layout (always ask)

Four layouts are valid for putting actuals into a workbook, and the same prompt can plausibly mean any of them. Always ask the user how the actuals should appear — never assume from the prompt's phrasing alone.

Use AskUserQuestion:

How should the actuals appear in the workbook?

# Option Reference loaded
1 Interleave Budget / Actual / Variance columns per month on the Budget tab ← recommended add-actuals-columns.md
2 Add a separate <year> Actuals tab alongside the Budget tab add-actuals-tab.md
3 Refresh existing Budget / Actual / Variance cells (the cells are there, just stale) refresh-existing.md
4 Add only the next single period column add-period.md
5 Build a tag-view tab — actuals sliced by reporting dimension (department, project code, class, etc.) tag-view.md — only offered when the entity has tagged data; see Gate 2.5
6 Build a vendor-view tab — actuals sliced by vendor, with GL account detail (per-vendor subtotals and collapsible account rows) vendor-view.md — only offered when the entity has vendor-tagged data; see Gate 2.6
7 Add vendor rows inline to the current actuals tab — insert vendor sub-rows under each account; accounts become subtotals of their vendor children inline-vendor.md — only offered when the active tab is already an actuals tab; see Gate 2.7
8 Build a vendor summary tab — one row per vendor across a timeline, no GL detail vendor-only-view.md — only offered when the entity has vendor-tagged data; see Gate 2.8

Use the user's prompt only as a hint for which option to highlight — never as authority to skip the question:

Phrase in the prompt Hint
"interleave", "Budget / Actual / Variance", "variance by month", "add <year> actuals" (no other clue) Option 1 (also the default ← recommended)
"add a tab", "track on its own tab", "separate actuals tab" Option 2
"refresh", "the actuals are stale", "pull latest", "sync" Option 3
"add next month", "extend through <month>", "next period" Option 4
"by department", "by tag", "by cost center", "split by", "broken down by", "by reporting tag", "by project code" Option 5
"by vendor", "broken down by vendor", "vendor view", "which vendors", "vendor breakdown" — and the active tab is already an actuals tab Offer Options 6 and 7 together; 7 ← recommended
"by vendor", "broken down by vendor", "vendor view", "which vendors", "vendor breakdown" — no actuals tab open Option 6
"break by vendor on this tab", "add vendors here", "vendor breakdown on this tab", "enrich this tab with vendors" Option 7
"vendor summary", "vendor spend over time", "vendors across", "which vendors did we pay", "vendor totals", "vendor breakdown without accounts", "just vendors" Option 8

Option 5 availability: always show Layout E in the chooser. If the user picks it and Gate 2.5 finds no tag data on the entity, tell them in one sentence and fall back to Layout A automatically. Do not pre-filter the chooser — the entity name needed for the probe is not available until Gate 3.

Option 6 availability: always show Layout F in the chooser. If the user picks it and Gate 2.6 finds no vendor data on the entity, tell them in one sentence and fall back to Layout A automatically. Do not pre-filter the chooser.

Option 7 availability: only show Layout G when the active sheet is already an actuals tab (its name contains "Actuals" or the user is explicitly on it). If the user picks it and Gate 2.7 finds no vendor data, tell them in one sentence and fall back to Option 6 (new vendor-view tab) instead.

Option 8 availability: always show Layout H in the chooser. If the user picks it and Gate 2.8 finds no vendor data on the entity, tell them in one sentence and fall back to Layout A automatically. Do not pre-filter the chooser.

The user's pick locks the reference to load for the rest of the workflow. Immediately call read_skill for the chosen layout — do not reconstruct from memory:

Layout chosen Call
Option 1 — Interleave columns read_skill(file_path="references/add-actuals-columns.md")
Option 2 — Add actuals tab read_skill(file_path="references/add-actuals-tab.md")
Option 3 — Refresh existing read_skill(file_path="references/refresh-existing.md")
Option 4 — Add single period read_skill(file_path="references/add-period.md")
Option 5 — Tag-view tab read_skill(file_path="references/tag-view.md")
Option 6 — Vendor view tab read_skill(file_path="references/vendor-view.md")
Option 7 — Vendor inline read_skill(file_path="references/inline-vendor.md")
Option 8 — Vendor summary tab read_skill(file_path="references/vendor-only-view.md")

Why we always ask: the same prompt — "add 2026 actuals by month" — can mean Option 1, 2, or 3 depending on the user's intent and the current state of their workbook. Guessing wrong and rebuilding costs the user a corrective prompt. Asking once costs one click. Choose the click.


Gate 2.5 — Tag-category discovery (Layout E path only)

Skip this gate entirely unless the user chose Layout E at Gate 2.

Silent probe — no user-facing output. Layout E shows all firm tag categories side by side under each period band — no "which dimension?" picker. The probe's job is to discover the firm's tag taxonomy from REPORTING_TAGS_JSON (or fall back to the flat REPORTING_TAGS column when only that's populated).

Probe 1 — Detect the JSON-vs-flat path

call_tool({"name": "dwh__execute__query", "arguments": {
  "sql": "SELECT
            COUNT_IF(REPORTING_TAGS_JSON IS NOT NULL) AS json_rows,
            COUNT_IF(REPORTING_TAGS IS NOT NULL)      AS flat_rows
          FROM <journal_entries_table>
          WHERE FUND_NAME = '<entity_name>'
            AND EFFECTIVE_DATE >= DATEADD('year', -1, CURRENT_DATE)",
  "format": "markdown",
  "_instrumentation": {"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}
}})
  • json_rows > 0JSON path. Skip Probe 2 — go directly to Probe 3 (JSON path). Probe 3 returns both category names and cardinality in one query, making a separate category-discovery query redundant.
  • json_rows == 0 AND flat_rows > 0flat path. Set <CATEGORIES> = ["Reporting Tag"] and continue to Probe 3 (cardinality).
  • Both zero → no tag data on this entity. Tell the user in one plain-English sentence — "Your journal data doesn't have any reporting tags, so I'll build a flat actuals view instead." — and fall back to Layout A.

Probe 3 — Cardinality per category

Run one query that returns the value count per category (used to drive the wide vs long decision):

JSON path:

call_tool({"name": "dwh__execute__query", "arguments": {
  "sql": "SELECT f.key::TEXT AS category, COUNT(DISTINCT f.value::TEXT) AS n_values
          FROM <journal_entries_table>,
               LATERAL FLATTEN(input => REPORTING_TAGS_JSON) f
          WHERE FUND_NAME = '<entity_name>'
            AND REPORTING_TAGS_JSON IS NOT NULL
            AND EFFECTIVE_DATE >= DATEADD('year', -1, CURRENT_DATE)
          GROUP BY 1
          ORDER BY 1",
  "format": "markdown",
  "_instrumentation": {"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}
}})

Flat path:

call_tool({"name": "dwh__execute__query", "arguments": {
  "sql": "SELECT 'Reporting Tag' AS category, COUNT(DISTINCT REPORTING_TAGS) AS n_values
          FROM <journal_entries_table>
          WHERE FUND_NAME = '<entity_name>'
            AND REPORTING_TAGS IS NOT NULL
            AND EFFECTIVE_DATE >= DATEADD('year', -1, CURRENT_DATE)",
  "format": "markdown",
  "_instrumentation": {"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}
}})

Store <CATEGORIES> as the sorted list of distinct category values returned, and store <CARDINALITY> as the map of category → n_values. (Probe 3 returns both in one pass — no separate Probe 2 needed.) Compute the total column count:

total_columns = sum(n_values for each category) + len(<CATEGORIES>)

The + len(<CATEGORIES>) term covers the per-category Total columns. If the run uses Quarter or Month aggregation across multiple period blocks, multiply by the number of period blocks for the layout decision.

Wide vs long decision

The authoritative thresholds live in references/tag-view.md §"Cardinality guard" — ≤ 24 wide / 25–36 ask / > 36 long. Keep that file as the single source of truth; the inline cutoffs below mirror it for runtime convenience and must move together if the table changes.

If total_columns > 24 (single period) or total_columns × n_period_blocks > 24 (multi-period), ask via AskUserQuestion:

The tag-view tab would have <N> columns across <C> categories. With that many, should I build a wide table (one column per tag per category per period) or a long table (one row per tag per account)?

  • Wide — one column per tag ← recommended for ≤ 36
  • Long — one row per tag per account

Store <TAG_LAYOUT> (wide | long). Default wide for ≤ 24 (no question asked); default long for > 36 (no question asked).


Gate 2.6 — Vendor-data discovery (Layout F path only)

Skip this gate entirely unless the user chose Layout F at Gate 2.

Silent probe — no user-facing output. Checks whether VENDOR_NAME is populated and counts distinct vendors.

call_tool({"name": "dwh__execute__query", "arguments": {
  "sql": "SELECT
            COUNT_IF(VENDOR_NAME IS NOT NULL) AS tagged_rows,
            COUNT_IF(VENDOR_NAME IS NULL)     AS untagged_rows,
            COUNT(DISTINCT VENDOR_NAME)       AS distinct_vendors
          FROM <journal_entries_table>
          WHERE FUND_NAME = '<entity_name>'
            AND ACCOUNT_TYPE >= '4000'
            AND EFFECTIVE_DATE >= DATEADD('year', -1, CURRENT_DATE)",
  "format": "markdown",
  "_instrumentation": {"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}
}})
  • tagged_rows > 0 → vendor data exists. Store <VENDOR_COUNT> = distinct_vendors and <HAS_UNTAGGED> = (untagged_rows > 0). Continue to Gate 3.
  • tagged_rows == 0 → no vendor data on this entity. Tell the user in one plain-English sentence — "Your journal data doesn't have any vendor information, so I'll build a flat actuals view instead." — and fall back to Layout A.

Gate 2.7 — Vendor-data check (Layout G path only)

Skip this gate entirely unless the user chose Layout G at Gate 2.

Silent probe — no user-facing output. Same probe as Gate 2.6 — confirms vendor data exists before rebuilding the tab inline.


Gate 2.8 — Vendor-data discovery (Layout H path only)

Skip this gate entirely unless the user chose Layout H at Gate 2.

Silent probe — no user-facing output. Same probe as Gate 2.6 — checks whether VENDOR_NAME is populated and counts distinct vendors.

call_tool({"name": "dwh__execute__query", "arguments": {
  "sql": "SELECT
            COUNT_IF(VENDOR_NAME IS NOT NULL) AS tagged_rows,
            COUNT_IF(VENDOR_NAME IS NULL)     AS untagged_rows,
            COUNT(DISTINCT VENDOR_NAME)       AS distinct_vendors
          FROM <journal_entries_table>
          WHERE FUND_NAME = '<entity_name>'
            AND ACCOUNT_TYPE >= '4000'
            AND EFFECTIVE_DATE >= DATEADD('year', -1, CURRENT_DATE)",
  "format": "markdown",
  "_instrumentation": {"plugin": "carta-investors", "skills": ["carta-fetch-actuals"]}
}})
  • tagged_rows > 0 → vendor data exists. Store <VENDOR_COUNT> = distinct_vendors and <HAS_UNTAGGED> = (untagged_rows > 0). Continue to Gate 3.
  • tagged_rows == 0 → no vendor data on this entity. Tell the user in one plain-English sentence — "Your journal data doesn't have any vendor information, so I'll build a flat actuals view instead." — and fall back to Layout A.

Gate 3 — Batched parameter gate

In one AskUserQuestion, confirm every parameter the prompt didn't already specify.

Entity: confirm <ENTITY_NAME> — the exact FUND_NAME value used in DWH queries. If the user named one at Gate 0, pre-fill it and only ask if it's ambiguous.

Period: offer smart defaults based on today's date (currently May 2026):

What period should I pull actuals for?

# Label Date range
1 ← recommended Full year 2026 Jan 1 – Dec 31, 2026
2 YTD 2026 (Jan – May) Jan 1 – May 31, 2026
3 Q2 2026 (Apr – Jun, in progress) Apr 1 – Jun 30, 2026
4 Full year 2025 Jan 1 – Dec 31, 2025
5 Custom range — I'll specify start / end month

Adapt ← recommended and visible options to context: YTD if the user said "latest"; full year if they said "2026 actuals"; prior year if they said "2025". Always compute the current quarter's label dynamically from today's date — do not hardcode Q2.

If the prompt already specified a period (e.g. "Q1 2026", "full year 2025"), store it directly and skip the period question.

Store <PERIOD_START> (first day, YYYY-MM-DD) and <PERIOD_END> (last day).

Match strategy (Layouts A–D only): name first then GL code (default) vs GL code only. Omit for Layouts E, F, G, or H (no existing-sheet matching needed — these layouts always write a new tab).

Store <ENTITY_NAME>, <PERIOD_START>, <PERIOD_END>, <MATCH_STRATEGY> (Layouts A–D).

Gate 3a — Aggregation level (Layouts E, F, and H only)

Skip this sub-gate for Layouts A–D and G — aggregation is always monthly there. Set <AGGREGATION> = MONTH and continue.

For Layouts E, F, and H, this MUST be a separate AskUserQuestion call — do not bundle with the period question above, and do not infer the answer from the period range. A YTD period (e.g. Jan–May) does not mean "Quarter"; a full-year period does not mean "Year". The user picks the period independently from the aggregation.

Aggregate columns by:

# Label
1 ← recommended Year — one period block per year
2 Quarter — one block per quarter
3 Month — one block per month

Store <AGGREGATION> (YEAR | QUARTER | MONTH).

Hard rule: if you find yourself building a tag-view or vendor-view with multiple period blocks (e.g. Q1+Q2) without an AskUserQuestion whose answer literally selected one of the three options above, you skipped this gate. Stop and ask before proceeding to Gate 4.

Gate 3b — Vendor row grouping preference (Layouts F and G + excel-addin only)

Skip this sub-gate for Layouts A–E and H, or when <RUNTIME> is local-file (row outline grouping is not supported in the local-file path). Layout H has no GL sub-rows to collapse.

Ask via AskUserQuestion — a separate call from Gate 3a above:

Should vendor detail rows be collapsible in Excel?

# Label Description
1 ← recommended Yes — collapsed by default Rows hidden on open; click + to expand a vendor section
2 Yes — expanded by default Rows visible; click to collapse a vendor section
3 No grouping Flat tab, no outline controls

Store <VENDOR_GROUPING> (collapsed | expanded | none).


Gate 4 — Read the existing budget

If <RUNTIME> is excel-addin:

Use the Excel add-in's runtime read tools to inspect the budget tab — header row, line-item rows, actuals/budget columns, formula rows.

If <RUNTIME> is local-file:

uv run "${CLAUDE_PLUGIN_ROOT}/scripts/read_workbook.py" \
  "<DESTINATION_PATH>" --sheet "<BUDGET_SHEET>"

Parse the resulting JSON to identify the same structure (headers, line items, formula rows). Treat any cell where is_formula: true as load-bearing — never overwrite it.


Gate 5 — Load actuals

Layout E: use the category-grouped query from references/tag-view.md §SQL. Pick the JSON path when Gate 2.5 detected REPORTING_TAGS_JSON rows; the flat path when only REPORTING_TAGS was populated. Substitute <period_trunc> from <AGGREGATION>, <period_start> from <PERIOD_START>, <period_end> from <PERIOD_END>, and <entity_name> from <ENTITY_NAME>. The JSON path discovers <CATEGORIES> inside the query via LATERAL FLATTEN — do not parameterize the category list into the SQL. All other rules below apply unchanged.

Layout F: use the vendor query from references/vendor-view.md §SQL. Substitute <period_trunc> from <AGGREGATION>, <period_start> from <PERIOD_START>, <period_end> from <PERIOD_END>, and <entity_name> from <ENTITY_NAME>. The query uses COALESCE(VENDOR_NAME, 'No vendor') so NULL-vendor entries roll into a single 'No vendor' section — do not run a second query for untagged rows. All other hard rules (entity scoping, books date, sign convention, P&L scope) apply unchanged.

Layout H: use queries/actuals-by-vendor-period.sql directly. Substitute <period_trunc> from <AGGREGATION>, <period_start> from <PERIOD_START>, <period_end> from <PERIOD_END>, and <entity_name> from <ENTITY_NAME>. Same COALESCE(VENDOR_NAME, 'No vendor') convention; same hard rules as Layout F. The query returns (vendor_name, period, signed_amount) — no gl_code or account_name columns.

Layouts A–D: call references/get-actuals.md for the main actuals query. In parallel, call read_skill(file_path="references/vendor-actuals.md") and run the vendor actuals query — this loads <VENDOR_ACTUALS> into session context so vendor questions (e.g. "which vendor is driving Legal Fees?") are answerable for the rest of the session without a second round-trip. Never write inline SQL outside those files.


Gate 6 — Pre-build review (approval gate)

Preview table grouped by:

  • Existing rows updated — Line Item | Old Value | New Value | Source.
  • Cells zeroed — Line Item | Old Value | Reason ("no activity in period").
  • New rows to insert — Account | Section | Position | Value | Source.
  • GL accounts found in DWH with no row in the sheet — Account | Total in period.

If any rows carry the low-confidence — sparse history flag (account has < 6 months of activity in the lookback window), surface the count above the table.

Output the preview tables above as a normal conversation message. Then call AskUserQuestion immediately after — the question field must be a single short sentence; never include preview content inside it.

  • question: "Approve applying these updates?"
  • header: "Approval"
  • multiSelect: false
  • options:
    1. Approve and apply the updates ← recommended (description: "Writes the actuals to the destination chosen in Gate 1.")
    2. Edit — change the period range, match strategy, or scope
    3. Cancel

The ← recommended marker goes inside the description field of option 1, not as a suffix on the label.

Wait for explicit OK before writing.

Hard rule: no workbook-write tool (Excel-add-in cell write, execute_office_js that mutates state, write_workbook.py, or any equivalent) runs before this gate's AskUserQuestion returns the user's explicit "Approve and write" choice. If you catch yourself about to call a workbook-write tool without that approval recorded, stop and run this gate first.


Gate 7 — Write the changes (preserving formulas) AND brand the tabs

Approval-recorded check (run FIRST, before any write tool)

Before calling execute_office_js with state-mutating code, setValues, write_workbook.py, or any other workbook-write tool, look back at your tool history. Find the most recent AskUserQuestion you sent. Does its answer literally include "Approve and apply the updates"? If NO, Gate 6 did not pass — send the Gate 6 approval menu now and wait for the explicit answer.

Do not interpret upstream answers as approval. A Gate 2 layout response, a Gate 3 period-range answer, or any prior AskUserQuestion whose answer is not literally "Approve and apply the updates" does NOT clear this gate.

Gate 7 requires AT LEAST three separate execute_office_js calls (excel-addin runtime)

The most common failure mode is bundling cell writes + formatting + logo + verification into one writeSheet(...) function — the model writes the cells, returns, hardcodes the logo height, and the user gets a misaligned logo they have to resize manually. Do not combine the cell-write call with the brand block in a single office.js block.

  • Call 1: apply the cell updates from the approved payload. One execute_office_js. Return.
  • Call 2 (per tab touched): logo via the verbatim brand block (paste from below — DO NOT paraphrase, DO NOT hardcode the height, DO NOT anchor to a single cell).
  • Final call (combined verification): currency format + shape geometry on every tab touched in one execute_office_js. See the combined verification block below.

Returning from Call 1 does NOT finish Gate 7. The final combined verification call must appear in your tool history before Gate 8 summary.

Verbatim brand block — paste this, do not improvise

The single most common logo regression is hardcoding shape.height = 48 (or any other pixel value) instead of using the actual E1:E3 row-band height. Excel's row heights depend on font sizes set during Call 1, so the band height can vary tab-to-tab. The model that hardcodes 48 produces a logo that either spills past row 3 or sits inside row 1 — the user then has to resize manually. Paste this block verbatim per tab; substitute only <TAB_NAME>:

const base64 = blobs.getText("assets/powered_by_carta.b64.txt").trim();

const sheet = context.workbook.worksheets.getItem("<TAB_NAME>");
const shapes = sheet.shapes;
shapes.load("items/name");
await context.sync();

// De-dup: remove any prior CartaLogo so re-runs don't stack shapes.
for (const s of shapes.items) {
  if (s.name === "CartaLogo") s.delete();
}
await context.sync();

// Anchor to the FULL row band E1:E3 — never a single cell.
const rows = sheet.getRange("E1:E3");
rows.load(["left", "top", "height"]);
await context.sync();

const image = sheet.shapes.addImage(base64);
image.name = "CartaLogo";

image.load(["width", "height"]);
await context.sync();
const ratio = image.width / image.height;

image.lockAspectRatio = false;
image.height = rows.height;        // ← match actual row-band height, never a pixel literal
image.width  = rows.height * ratio;
image.left   = rows.left;
image.top    = rows.top;
image.lockAspectRatio = true;
await context.sync();

Forbidden patterns (these reproduce the manual-resize bug):

  • image.height = 48 (or any number literal) — height MUST come from rows.height.
  • sheet.getRange("E1") instead of sheet.getRange("E1:E3") — single-cell anchor loses the band height.
  • Skipping the de-dup loop — re-runs stack a second CartaLogo shape on top of the first.
  • Skipping image.lockAspectRatio = false before sizing — Excel resists width changes if locked.

Only touch the cells the user approved. Do not edit formulas elsewhere in the sheet (subtotals are formula-driven and will auto-update).

Before any write, call both of these in the same message (parallel reads):

  1. read_skill(file_path="references/branding-and-header.md") — 4-row metadata band, logo placement, blobs.getText asset pattern, cell-comment API.
  2. read_skill(file_path="references/<layout-from-gate-2>.md") — the layout file chosen in Gate 2 (e.g. add-actuals-columns.md for Layout A).

Do not reconstruct either spec from memory. Both files must be in your context before generating any execute_office_js or write_workbook.py code. The branding-and-header.md file defines:

  • The reserved 4-row metadata band (A1–A4 + blank A5) that every tab must carry — per-skill override (this skill uses column A so the band left-edges with the account-label column underneath). If the existing budget tab doesn't have it, add it as part of this write (shift the data down to row 6+ first via sheet.getRange("1:5").insert(...) in Excel add-in mode, or via prepended row writes in local-file mode).
  • The Carta logo placement (column E, rows 1–3 height) — apply to every tab this skill touches, including the actuals tab(s) it adds.
  • The blobs.getText asset-loading pattern for Excel add-in mode (NOT Read).
  • The cell-comment pattern for any sparse-history / low-confidence flag.

If <RUNTIME> is excel-addin:

  • Layouts A–D: load references/add-actuals-columns.md §5 ("Build the rebuild payload") and apply its header / column / format spec verbatim — especially the two-row header (row N = merged month labels, row N+1 = Budget / Actual / Variance sub-headers — spelled out in full, never abbreviated). Then use the add-in's cell-write tools to execute the payload.
  • Layout E: load references/tag-view.md §"Writing the workbook (excel-addin runtime)" and follow it verbatim — 3-row period/category/tag header, range.merge(true) for period and category bands. Do NOT freeze panes — same rule as Layouts A–D and the rest of the Carta budgeting skills.
  • Layout F: load references/vendor-view.md §"Writing the workbook (excel-addin runtime)" and follow it verbatim — 2-row period/vendor header, range.merge(true) for period bands, per-vendor subtotals, 'No vendor' section at the bottom. Do NOT freeze panes.
  • Layout G: load references/inline-vendor.md §"Write sequence (excel-addin runtime)" and follow it verbatim — clear rows 7+, rebuild account rows (bold, SUM formula) + vendor sub-rows (indented four spaces, hardcoded amounts, locale-specific currency token), then group and collapse. Gate 7's three-call sequence (cell write → brand block → combined verification) applies here too.

If <RUNTIME> is local-file: build an operations payload and apply it:

uv run "${CLAUDE_PLUGIN_ROOT}/scripts/write_workbook.py" --stdin <<'JSON'
{
  "workbook_path": "<DESTINATION_PATH>",
  "operations": [ ... ]
}
JSON
  • Layouts A–D: use only write_cell / write_formula / set_format operations. Avoid create_sheet and write_range here — those are for carta-create-budget.
  • Layout E: use create_sheet, write_cell, write_range, merge_cells, set_bold, set_format, set_column_width (Account col), autofit_columns (data cols) per references/tag-view.md §"Writing the workbook (local-file runtime)". Always issue write_cell for a period label before the merge_cells op for that same range. Do NOT include freeze_panes — same rule as Layouts A–D and the rest of the Carta budgeting skills.
  • Layout F: use create_sheet, write_cell, write_range, merge_cells, set_bold, set_format, set_column_width (Vendor/Account col), autofit_columns (data cols) per references/vendor-view.md §"Writing the workbook (local-file runtime)". Always issue write_cell for a period label before the merge_cells op for that same range. Do NOT include freeze_panes.

Row grouping — vendor GL rows (Layout F, excel-addin only, after verification)

If <VENDOR_GROUPING> is collapsed or expanded (set at Gate 3b), run a 4th execute_office_js call after all three required calls pass verification. This call is separate from the three required calls — do not bundle it with cell writes, branding, or verification.

See references/vendor-view.md §"Collapse/expand grouping" for the exact code block. Substitute <PERIOD_LABEL> and <VENDOR_GROUPING> before running.

Local-file runtime: skip this step. Row outline grouping is not supported via write_workbook.py.

Combined currency + branding verification (REQUIRED, observable, excel-addin only)

After the brand block runs for every tab, execute one execute_office_js that checks both currency format and logo geometry in a single context.sync(). This replaces the two separate passes (currency readback → branding check) previously required.

Two regressions this catches:

  • Currency format — amount cells must use a locale-specific token like [$$-en-US]#,##0.00_);([$$-en-US]#,##0.00);"-" (USD). Never use bare $, _($*, or a quoted literal "$" — Excel strips quotes from stored format strings, leaving a bare $ that renders as the system currency symbol.
  • Logo sizing — hardcoded shape.height = 48 misaligns the logo when the E1:E3 row band is taller or shorter than 48pt. Height must come from rows.height.

Range.getImage() is forbidden here. The shape geometry (heightMatchesBand, leftMatchesBand) is the complete, sufficient logo verification. Never output "I cannot visually verify the logo placement" — the geometry check IS the verification. If you find yourself reaching for Range.getImage(), stop and use the geometry check instead.

This block is NOT paste-verbatim — substitute its placeholders before running: the tabs array (the tab names touched this run) and <sample_amount_cell>. The currencyOk check uses "[$" verbatim — no substitution needed.

const tabs = [/* "Budget 2026", "2026 Actuals", ... — substitute the actual tab names touched this run */];
const result = {};
for (const tabName of tabs) {
  const sheet = context.workbook.worksheets.getItem(tabName);
  sheet.shapes.load("items/name,items/height,items/left,items/top");
  const rows = sheet.getRange("E1:E3");
  rows.load(["height", "left"]);
  // Pick one amount cell — typically C7 (Layout E) or B8 (Layouts A–D). Substitute from your payload.
  const cell = sheet.getRange("<sample_amount_cell>");
  cell.load("numberFormat");
  await context.sync();

  const logo = sheet.shapes.items.find(s => s.name === "CartaLogo");
  result[tabName] = {
    // Currency check
    numberFormat:      cell.numberFormat[0][0],
    currencyOk:        cell.numberFormat[0][0].includes("[$"),  // locale-specific currency token, e.g. [$$-en-US]
    // Branding checks
    found:             !!logo,
    shapeHeight:       logo ? logo.height : null,
    rowBandHeight:     rows.height,
    heightMatchesBand: logo ? Math.abs(logo.height - rows.height) < 2 : false,
    shapeLeft:         logo ? logo.left : null,
    rowBandLeft:       rows.left,
    leftMatchesBand:   logo ? Math.abs(logo.left - rows.left) < 2 : false,
  };
}
return result;

Per-tab pass criteria — ALL must be true:

  • currencyOk === true — sample cell format contains [$ (locale-specific currency token)
  • found === trueCartaLogo shape exists
  • heightMatchesBand === true — logo height equals E1:E3 row-band height ±2pt
  • leftMatchesBand === true — logo anchors at column E's left edge ±2pt

Recovery actions:

  • currencyOk: false → re-apply the locale-specific token for the resolved currency — pick the matching line, substitute <full_amount_range>, then re-run this combined verification:
    • USD: sheet.getRange("<full_amount_range>").numberFormat = [["[$$-en-US]#,##0.00_);([$$-en-US]#,##0.00);\"-\""]];
    • EUR: sheet.getRange("<full_amount_range>").numberFormat = [["[$€-x-euro2]#,##0.00_);([$€-x-euro2]#,##0.00);\"-\""]];
    • GBP: sheet.getRange("<full_amount_range>").numberFormat = [["[$£-en-GB]#,##0.00_);([$£-en-GB]#,##0.00);\"-\""]];
    • CAD: sheet.getRange("<full_amount_range>").numberFormat = [["[$CA$-en-CA]#,##0.00_);([$CA$-en-CA]#,##0.00);\"-\""]];
  • found: false → brand block was skipped — re-run the verbatim brand block, then re-verify.
  • heightMatchesBand: false or leftMatchesBand: false → brand block used a hardcoded pixel or wrong anchor — delete the CartaLogo shape and re-run the verbatim brand block, then re-verify.

Do not start Gate 8 summary text until every tab passes all four criteria. The verification call is observable evidence; without it in your tool history with passing checks, Gate 7 is not complete.


Gate 8 — Summary + next steps

Gate 8 precondition (DO NOT SKIP). Before sending the summary text below, scan your tool history. Three anchors MUST be present in this order (excel-addin runtime):

  1. An AskUserQuestion whose answer included "Approve and apply the updates" — Gate 6 approval.
  2. A sheet.shapes.addImage(base64) call for each tab the skill touched (one per tab) — Gate 7 branding.
  3. The combined currency + branding verification execute_office_js whose result showed currencyOk: true, found: true, heightMatchesBand: true, and leftMatchesBand: true for every tab — Gate 7 combined verification.

If any anchor is missing, you have skipped a gate. Do NOT write "Carta logo placed at..." in the summary when no shapes.addImage call appears in your tool history — that's hallucinating completion. STOP, go back, run the missing gate, then return here.

Layouts A–D — If <RUNTIME> is excel-addin:

Refreshed 23 lines on Budget 2026 (Example MgmtCo). 2 lines zeroed (Audit, Tax Prep — no Q1 activity). 1 new account inserted under Operating Expenses (AI Tooling). 2 suspicious-zero flags — Salaries and Leased-employee payments dropped to $0; could be posting lag.

Layouts A–D — If <RUNTIME> is local-file:

Refreshed 23 lines on Budget 2026 in file:///path/to/<budget-workbook>.xlsx (Example MgmtCo). 2 lines zeroed (Audit, Tax Prep — no Q1 activity). 1 new account inserted (AI Tooling, Operating Expenses). 2 suspicious-zero flags — Salaries and Leased-employee payments.

Layout E — If <RUNTIME> is excel-addin:

Created 2026 Actuals by Department (Example MgmtCo) — 23 accounts × 4 department values (Engineering, Marketing, G&A, Untagged), annual aggregation. 1 account flagged low-confidence (sparse history). Carta logo placed at E1.

Substitute the period block phrasing to match <AGGREGATION> from Gate 3a: "annual aggregation" for YEAR, "across 4 quarters" / "across Q1+Q2" for QUARTER, "across 12 months" / "across Jan–May" for MONTH.

Layout E — If <RUNTIME> is local-file:

Created 2026 Actuals by Department tab in file:///path/to/<budget-workbook>.xlsx (Example MgmtCo) — 23 accounts × 4 department values, annual aggregation. 1 account flagged low-confidence (sparse history). Adjust the period phrasing to match <AGGREGATION> (see excel-addin example above).

Layout F — If <RUNTIME> is excel-addin:

Created 2026 Actuals by Vendor (Example MgmtCo) — 23 accounts across 8 vendors (A2Z, Rippling, Alcatraz LLP, … No vendor), annual aggregation. 1 account flagged low-confidence (sparse history). Carta logo placed at E1.

Substitute the period block phrasing to match <AGGREGATION> from Gate 3a: "annual aggregation" for YEAR, "across 4 quarters" / "across Q1+Q2" for QUARTER, "across 12 months" / "across Jan–May" for MONTH. List the top 3–5 vendor names; collapse the rest as "… No vendor".

If <VENDOR_GROUPING> is collapsed or expanded, append: "Vendor detail rows are grouped — use the +/− toggles on the left margin or the 1/2 outline buttons in the top-left corner to expand or collapse all vendor sections at once."

Layout F — If <RUNTIME> is local-file:

Created 2026 Actuals by Vendor tab in file:///path/to/<budget-workbook>.xlsx (Example MgmtCo) — 23 accounts across 8 vendors, annual aggregation. 1 account flagged low-confidence (sparse history). Adjust the period phrasing to match <AGGREGATION> (see excel-addin example above).

Layout H — If <RUNTIME> is excel-addin:

Created 2026 Vendors (Example MgmtCo) — 8 vendors (A2Z, Rippling, Alcatraz LLP, … No vendor), annual aggregation. 1 vendor flagged low-confidence (sparse history). Carta logo placed at E1.

Substitute the period block phrasing to match <AGGREGATION> from Gate 3a: "annual aggregation" for YEAR, "across 4 quarters" / "across Q1+Q2" for QUARTER, "across 12 months" / "across Jan–May" for MONTH. List the top 3–5 vendor names; collapse the rest as "… No vendor".

Layout H — If <RUNTIME> is local-file:

Created 2026 Vendors tab in file:///path/to/<budget-workbook>.xlsx (Example MgmtCo) — 8 vendors, annual aggregation. 1 vendor flagged low-confidence (sparse history). Adjust the period phrasing to match <AGGREGATION> (see excel-addin example above).

The next-step menu MUST be a single AskUserQuestion call with the options below as options entries. Never render them as a numbered markdown list, a bulleted list, or inline prose — bare-text menus break the chooser UI in Claude for Excel and force the user to type the number. The ← recommended marker goes inside the description field of one option, not as a suffix on the label.

  1. Run a pacing analysis (Budget vs Actuals) ← recommended
  2. Drill into a specific line item (largest entries / month-by-month)
  3. Model a what-if scenario on this budget
  4. I'm done

Call AskUserQuestion with these exact parameters:

  • question: "What would you like to do next?"
  • header: "Next step"
  • multiSelect: false
  • options: the four label + description pairs above (place ← recommended in the description field of the recommended option, NOT in the label)

DO NOT render the menu as inline markdown text, a numbered list, a bulleted list, or closing prose. If your response is about to contain 1. ..., 2. ..., 3. ..., 4. ... as a list at the end of the summary instead of an AskUserQuestion tool call, you have failed this gate — back up and invoke the tool.

Mark ← recommended based on context — option 1 by default after a refresh; option 2 if the user previously asked about a specific line.

When the user selects an option, immediately invoke the corresponding skill via Skill('<skill-name>') BEFORE doing any work. Do not freelance the output — load the downstream skill's SKILL.md so its gates, layout spec, branding rules, and approval flow apply. Routing:

Option Skill to invoke
1 — Run a pacing analysis Skill('carta-investors:carta-budget-analysis')
2 — Drill into a specific line item Skill('carta-investors:carta-budget-analysis') with the drill-down-line reference
3 — Model a what-if scenario Skill('carta-investors:carta-budget-scenarios')
4 — I'm done No invocation; close cleanly

DWH result formatting

Queries > 50 rows: request format: "ndjson", bucket into a blob. Don't paste large results — triggers context_snip. Use "markdown" only for ≤50-row previews.

Hard rules

  • Same DWH primitives as carta-create-budget — Carta DWH journal-entries table only, no external-DWH fallback, FUND_NAME scoping, AMOUNT (not the base-currency variant), sign flip, preserve reversals.
  • Local-file: never overwrite cells flagged as formulas in read_workbook.py output. Subtotals / NOI keep their =SUM(...) semantics.
  • Two-row header is mandatory for month-bucketed tables. Row N = merged month label per Budget/Actual/Variance triplet. Row N+1 = sub-headers spelled out in full (Budget, Actual, Variance). Never abbreviate to B/A/V. Never write both into the same row — subsequent merges destroy sub-headers.
  • range.merge(true) discards trailing cell values. Insert a new row first.
  • Month-label date-serial trap (header rows): before writing any month or period text label ("Jan 2026", "Q1 2026", etc.) to a header row, apply numberFormat = [["@"]] (text format) to the entire header range first, then write the values. Without this, Excel auto-coerces "Jan 2026" → date serial 46023. This applies to row 6 column headers and any period-band rows (rows 6/7 in Layouts E and F). Applies to both execute_office_js (set range.numberFormat before range.values) and write_workbook.py (emit a set_format op with "@" before the write_cell ops for the header row).
  • Currency — derive from the data, never default to USD. Resolve the workbook's presentation currency before writing (entity properties via welcome, or the currency on the budget data); if it can't be resolved, ask the user. State the resolved currency in cell A4: Amounts in <resolved_currency>.
  • Currency format: use a locale-specific currency token — [$$-en-US]#,##0.00_);([$$-en-US]#,##0.00);"-" for USD, [$€-x-euro2]#,##0.00_);([$€-x-euro2]#,##0.00);"-" for EUR, [$£-en-GB]#,##0.00_);([$£-en-GB]#,##0.00);"-" for GBP. Resolve the currency from the data — never default to USD. Do not use a bare $ or _($* format — Excel substitutes the system currency symbol for those. Do not use a quoted literal like "$" — Excel strips the quotes when storing the format, leaving a bare $ that renders as the system currency. Apply to all data ranges after the data write.
  • Match the existing tab's period granularity. If the budget tab is quarterly (not monthly), interleave Budget/Actual/Variance per quarter, not per month. For a partial period (e.g. YTD through a mid-quarter month against a quarterly tab), pull actuals at month grain and aggregate to the tab's buckets. Do not prorate a quarter's budget by month-fraction to approximate a partial period — derive the period's budget from the underlying monthly source.
  • Buffer-aware variance basis. If the on-tab budget carries an inflation/contingency buffer (an input cell, or a header note like "Budget includes X% buffer"), variances are computed against the buffered figure — state this in the preview so favorable variances aren't misread, and offer to compare against the raw (pre-buffer) budget instead.
  • Border syntax (Office.js): style = "Continuous", then weight = "Thin". Never style: "Thin".
  • Recalc + column widths: the last statements in the cell-write execute_office_js block (Call 1), in this order — never a separate call: restore automatic calc → context.workbook.application.calculate(Excel.CalculationType.full)sheet.getRange("A:AN").format.autofitColumns() (widen the range to the last amount column) → context.sync(). Recalc before autofit: without the forced recalc the =SUM(...) / variance / NOI cells stay at 0 and the accounting format shows - (forcing the user to edit+Enter each one); autofitting before the recalc sizes the amount columns to the dash so real figures overflow as ####. Never autofit a header-only range.
  • Branding standards — follow references/branding-and-header.md for every tab. Per-skill overrides: metadata band in column A (not B), logo at column E. Asset access via blobs.getText("assets/...").

Schema discovery

The skill queries the Carta DWH journal-entries table. If column names are needed, look up the table via the Carta MCP DWH schema command once at Gate 0 — production schema is canonical. Don't embed column listings inline; the DWH contract can drift.

Error handling

Symptom Likely cause What to tell the user
No Carta MCP server found The Carta connector isn't enabled in this session "I can't see your Carta connector. Open Settings → Connectors in Claude, enable Carta, then ask me again."
Sheet has no recognisable header row The budget layout uses non-date column headers Surface what the headers look like and ask the user which row is the header and which columns are actuals.
low-confidence — sparse history flagged on many rows Entity is new or sparsely posted Surface the count in the preview and let the user decide whether to proceed. Don't auto-suppress.
Multiple budget tabs in the workbook Ambiguous "the budget" Ask the user which tab to update; do not silently pick one.
Cell the skill wants to write is a formula Subtotal / NOI row Surface the row and confirm; never silently overwrite a formula.
Local-file mode: file path is missing or unreadable Wrong path supplied Echo the path back and ask for the correct one.
Query times out DWH load Tell the user it's slow and offer to retry — never auto-retry.
Auth / permission error from the MCP Carta session expired or lacks DWH access Ask the user to reconnect Carta in Settings → Connectors.
Connector shows as connected, but tool calls fail with McpAuthError or "tool not available" The MCP server's tool prefix doesn't match what this skill's allowed-tools enumerates. Re-auth is not the fix — see Gate 0 troubleshooting note below the table. "I'm reconnecting to your Carta workspace — one moment."

Connector-mismatch troubleshooting (operator-facing, not user-facing). Re-run refresh_mcp_connectors to confirm which Carta connector is actually connected, then probe the matching prefix's welcome per the Gate 0 mapping. Never tell the user to re-auth without verifying the prefix mismatch first.

Never auto-retry a failed query.

原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。