Claude
Skills
Sign in
Back

carta-soi

Included with Lifetime
$97 forever

Display a fund's Schedule of Investments (SOI) as a Live Artifact in Cowork. The artifact is firm-scoped — it loads every fund the user has access to in the firm and presents them in a header dropdown for one-click switching. Use when asked for the SOI, fund holdings, what a fund is invested in, or a portfolio breakdown. Do NOT use for general fund metrics (NAV, IRR, TVPI, DPI) or ad-hoc warehouse queries — use carta-explore-data instead.

Ads & Marketingscripts

What this skill does


<!-- Part of the official Carta AI Agent Plugin -->

# Schedule of Investments (SOI) Live Artifact

Render a firm's Schedule of Investments as a persistent, refreshable Live Artifact in the Cowork sidebar. There is one artifact per firm; the dropdown in the header lets users switch between every fund they have access to in that firm. The artifact queries the Carta data warehouse on load and on each fund switch, so the data is always current. Re-invoking the skill for the same firm rebuilds the artifact with the freshly-enumerated fund list — newly-added funds appear automatically.

## When to Use

- "Show me the SOI for [Fund Name]"
- "What is [Fund Name] invested in?"
- "Give me [Fund Name]'s schedule of investments"
- "Show me [Fund Name]'s portfolio breakdown"
- "What are [Fund Name]'s holdings?"
- "Show me the SOIs for [Firm Name]" (no specific fund named)

## Prerequisites

- The user must have the Carta MCP server connected
- The user must be in Cowork — Live Artifacts only render there
- The user must have access to the firm and at least one fund within it

## User-facing output

Customer-facing narration should sound like a person, not an implementer. The customer asked to see a fund's Schedule of Investments — they don't care about step numbers, UUIDs, MCP discovery, "templates", or "render scripts". Quiet implementation; loud delivery.

**Phase-by-phase guidance:**

- **On invocation** — One short sentence by fund name or firm name, e.g. *"Pulling the Schedule of Investments for Acme Ventures Fund III…"* or *"Pulling Acme Capital's funds…"*
- **During Steps 1–5 (the mechanical middle)** — Say *"Building your view…"* once after the opening acknowledgment. Nothing else.
- **On disambiguation** — Use `AskUserQuestion` with a clean prompt naming the candidate funds. Don't explain *why* you're asking.
- **On the final delivery (Step 6)** — One friendly delivery sentence (see Step 6) plus a 3–5 bullet summary of what the artifact shows.

**Do NOT:**

- Number the steps in user-visible text ("Step 1 — checking firm context", "Step 2 & 3 — finding funds and MCP tool").
- Surface internals: fund UUIDs, MCP tool prefixes, "the render script", "the artifact template", "inject placeholders", "set firm context", "discover the Carta MCP", "writing the fund list file".
- Print "Perfect!" / "Excellent!" / "Great!" / "Done!" between every tool call. One natural confirmation at the end is enough.

## Workflow

### Step 1 — Set firm context if needed

If the user's accessible firms are already in your conversation context (e.g. from a prior `welcome` Carta MCP tool call), use that list. Otherwise, call `list_contexts` to enumerate them.

With the firm list in hand:
- If only one firm is accessible, call `set_context` with it.
- If multiple are accessible, try to infer which firm the user means from their request (firm name, fund name, or any other hint). If you can't pick confidently, ask via `AskUserQuestion`. Then call `set_context`.

**Capture both the firm name and firm UUID** — you'll pass the name to the render script in Step 4 (eyebrow display) and the UUID twice: once to the render script and again as the `firm_id` the artifact uses to pin context on every load.

### Step 2 — Enumerate the firm's funds

> **Run in parallel with Step 3.** Fund enumeration (this step) and MCP UUID discovery (Step 3) are fully independent — issue both tool batches concurrently in the same response, not sequentially. 

Call `fetch("fa:list:entities", { entity_types: "fund,spv" })`. The filter excludes entity types that can't hold investments so it is critical. Capture the full `[{uuid, name}, ...]` list from the response.

**Pick the initial fund** for the dropdown and capture two variables — `initial_fund_uuid` and `name_status` — that Step 6 will read by name.

| Situation | `initial_fund_uuid` | `name_status` | Also capture |
|---|---|---|---|
| User named a fund, **one** match | the matched fund's uuid | `named_and_found` | — |
| User named a fund, **multiple** matches | the user-chosen uuid (via `AskUserQuestion`) | `named_and_found` | — |
| User named a fund, **no** match | alphabetically-first fund's uuid | `named_but_missing` | `named_term` = the term the user used |
| User did not name a fund | alphabetically-first fund's uuid | `unnamed` | — |

`named_but_missing` is **not** a blocker — render the artifact with the full firm fund list anyway. The user can pick their intended fund from the dropdown; Step 6 surfaces the miss in the confirmation message.

### Step 3 — Discover the Carta MCP UUID-form tool prefix

> **Run in parallel with Step 2** — see note in Step 2.

The artifact must call the Carta `fetch` tool by its **UUID-form prefix** (e.g., `mcp__33b9b857-8443-4b2d-b191-2d9b6c50eb86__fetch`) — name-form prefixes like `mcp__carta-test__fetch` fail with a 400 at runtime. The UUID is assigned per-installation by Cowork, so it must be discovered, not hardcoded.

Procedure:

1. **Find the UUID-form Carta `fetch` tool.** Look for a tool matching `mcp__<UUID>__fetch` where `<UUID>` is the 8-4-4-4-12 hex format. `ToolSearch` with query `"fetch"` can help if the deferred-tools list is hard to scan. In most sessions there is exactly one such candidate — capture it.

2. **If multiple UUID-form candidates exist** (e.g., both production and test Carta connectors are connected, or another MCP also uses a UUID prefix), disambiguate by calling `discover` on each candidate with `search: "dwh"` and picking the one that exposes `dwh:execute:query`. If two still pass (production + test Carta), ask the user via `AskUserQuestion`.

3. **Capture the chosen `mcp__<UUID>__fetch` string in a single local variable.** Reuse it as the fourth argument to the render script in Step 4 AND in `mcp_tools` at Step 5 (artifact allowlist). Step 5 also needs `mcp__<UUID>__set_context` — derive it from the fetch string by swapping the suffix, since both tools live on the same connector UUID. If any of these strings drift, the artifact loads but the corresponding MCP call fails with `"Tool ... is not in this artifact's mcp_tools allowlist."`.

### Step 4 — Write the funds file, then render the template

> **You must NEVER write the artifact HTML manually.** Every render goes through `render-artifact.py`. Manual edits — `Read` + `Edit` / `Write` against the rendered HTML or the template — bypass the placeholder substitution and validation logic. If the script fails, surface the error and stop. Do not fall back to manual edits.

Two sub-steps:

**4a.** Use the `Write` tool to drop the firm's fund list to a JSON file inside the session's current working directory. Filename should be `<firm-slug>-funds.json`. Contents must be a JSON array of `{"uuid", "name"}` objects:

```json
[
  {"uuid": "<fund_uuid_1>", "name": "<fund_name_1>"},
  {"uuid": "<fund_uuid_2>", "name": "<fund_name_2>"}
]
```

The fund list comes straight from Step 2's `fa:list:entities` response. Preserve the entity name verbatim — including apostrophes, ampersands, commas, and any punctuation. The script JSON-escapes hostile characters at substitution time.

**4b.** Run the bundled Python script:

```bash
uv run "${CLAUDE_PLUGIN_ROOT}/skills/carta-soi/scripts/render-artifact.py" \
    "${CLAUDE_PLUGIN_ROOT}/skills/carta-soi/references/artifact.html" \
    "<CWD>/<firm-slug>-fund-soi-collection.html" \
    "<firm-slug>-fund-soi-collection" \
    "<MCP_TOOL_NAME>" \
    "<FIRM_UUID>" \
    "<FIRM_NAME>" \
    "<CWD>/<firm-slug>-funds.json" \
    "<INITIAL_FUND_UUID>"
```

Positional arguments:

1. **Template path** — `${CLAUDE_PLUGIN_ROOT}/skills/carta-soi/references/artifact.html` (verbatim).
2. **Output path** — must be **absolute**, under the session's current working directory (`<CWD>`), and **not under `/tmp`** (`mcp__cowork__create_artifact` rejects `/tmp` paths). Use `pwd` to resolve `<CWD>` if needed. Filename is `<firm-slug>-fund-soi-collection.html`.
3. **Artifact ID** — the kebab-case Cowork artifact id, same string you'll

Related in Ads & Marketing