{"tools":[{"name":"approve_draft","description":"Mark a draft as approved (ready to send).","roles":[],"required_capabilities":["outreach:approve"]},{"name":"clear_last_outbound_override","description":"Clear the manual override for last outbound touch date.\n\nSets the manual field to null so the formula falls back to the\nautomated Vitally date.","roles":[],"required_capabilities":["outreach:override"]},{"name":"create_outreach_draft","description":"Create a new outreach draft for a sender to review and send.","roles":[],"required_capabilities":["outreach:create"]},{"name":"create_user","description":"Register a user with a role (ops, super_ops, csm, am, pm, manager, marketing).","roles":[],"required_capabilities":["users:create"]},{"name":"crm_create_campaign_member","description":"Add a Contact or Lead to a Salesforce Campaign as a CampaignMember.\n\nProvide exactly one of contact_id or lead_id. Response always includes\ncreated=true|false: true when a CampaignMember was created, false when\nthe target was already a member (reason='already_member', no write\nperformed). Callers must check `created` — not `success` — to know\nwhether a write happened.\n\nIf the campaign is inactive (IsActive=false) the call still proceeds\nand a `warning` field is included in the response.\n\nStatus, if provided, must match one of the campaign's CampaignMemberStatus\npicklist values. If omitted, SFDC applies the campaign's default status.\nStatus picklist values vary per campaign — on a picklist error the\nresponse includes a hint pointing to CampaignMemberStatus.","roles":[],"required_capabilities":["crm:campaign_member"]},{"name":"crm_create_contact","description":"Create a new Salesforce Contact on an existing Account.\n\nBlocks on duplicates: matching email (anywhere) OR same first+last on the\nsame Account. Writes to Linkedin_Profile_URL__c when linkedin_url is provided.","roles":[],"required_capabilities":["crm:create_contact"]},{"name":"crm_describe_sobject","description":"Return schema metadata for a Salesforce sObject.\n\nSuper-ops only. Use this before writing SOQL or crm_soql_update calls\nto confirm field API names, types, picklist values, and relationships.","roles":[],"required_capabilities":["crm:describe"]},{"name":"crm_soql_query","description":"Run a SOQL query against Salesforce and return all records.\n\nSuper-ops only. The SOQL string, record count, and target org are\nlogged to crm_audit_log on every call.","roles":[],"required_capabilities":["crm:query"]},{"name":"crm_soql_update","description":"Patch up to 200 Salesforce records in a single batch.\n\nSuper-ops only. Each record must include 'Id' plus the fields to change.\nThe field set must be uniform across the batch (same keys, different\nvalues). Different field patterns require separate calls.\n\nBefore-state is captured by selecting the touched fields for all record\nIDs immediately before the PATCH. Batch writes one row to crm_audit_log\nwith before/after snapshots, SF save results, and the reason.","roles":[],"required_capabilities":["crm:soql_update"]},{"name":"crm_update_contact","description":"Update a Salesforce Contact. Data-quality edits and outreach drafting.","roles":[],"required_capabilities":["crm:update_contact"]},{"name":"decks","description":"Publish and manage HTML decks in the HG Decks Library (as the calling user).\n\nHTML decks are the SECONDARY deck format; prefer google_slides unless an\nHTML deck is specifically wanted. Build the HTML with the html-slide-decks\nskill first (skeleton + HG brand + components), then publish it here.\n\nActions:\n- publish: create or update a deck (re-push same slug = new version, same\n  URL). Params: html (full deck HTML), title, slug (^[a-z0-9][a-z0-9-]{0,63}$),\n  optional visibility (\"private\"|\"everyone\"), description. An em dash blocks\n  the publish; unbalanced divs / a missing 1280x720 stage return non-blocking\n  \"warnings\" alongside the URL. Returns the URL.\n- list: your decks. Params: view (\"mine\"|\"everyone\"). Returns slug/title/url.\n- delete: delete one of your decks (permanent). Params: slug.\n- set_owner: reassign a deck to another user (privileged; needs the\n  decks:set_owner capability, super_ops only). Params: slug, new_owner (email).","roles":[],"required_capabilities":["decks:manage"]},{"name":"delete_user","description":"Remove a user's access.","roles":[],"required_capabilities":["users:delete"]},{"name":"get_account_detail","description":"Get raw (unsummarized) data for a specific section of an account brief.\n\nUse this to drill down into data that was summarized in the main research response.","roles":[],"required_capabilities":["accounts:read"]},{"name":"get_book_of_accounts","description":"Get a person's book of accounts with per-opportunity contract detail.\n\nWorks for both CSMs and AEs. Finds accounts where the person is the\nassigned CSM and/or where they own active opportunities. Each account\nshows its opportunities with individual renewal dates, ARR, and deal types.","roles":[],"required_capabilities":["accounts:read"]},{"name":"get_csm_book_stats","description":"Get Growth CSM book stats: account count, ARR, segment breakdown, and AM coverage per CSM.\n\nAlso shows growth-segment accounts with no CSM and accounts\nassigned to non-growth CSMs.","roles":[],"required_capabilities":["accounts:read"]},{"name":"get_draft_detail","description":"Get full draft details including body, cc, bcc, and account context.","roles":[],"required_capabilities":["outreach:read"]},{"name":"get_research_result","description":"Get the result of a research task started by start_research.\n\nWhen status is \"completed\", call show_account_brief with the sfdc_account_id to display the dashboard.","roles":[],"required_capabilities":["research:read"]},{"name":"get_user_access","description":"Show a user's role, default bundle, effective capabilities, and per-user grants/revokes.","roles":[],"required_capabilities":["users:read"]},{"name":"google_slides","description":"Create, read, update, and manage HG-branded Google Slides presentations.\n\nBuild actions:\n- create_deck: Create an empty deck. Params: customer_name, name, folder_type (customer|team|misc), folder_name\n- create_deck_from_spec: Create a deck AND all its slides in ONE call (much cheaper than N add_slide calls).\n  Params: name/customer_name, folder_type, folder_name, slides=[{type,title,body,body2,left_title,right_title,title_color,body_color, and per-type structured fields: items/rows/series/nodes/edges/chart_type}, ...]\n- add_slide: Add one branded slide. Params: deck_id, type, title, body, body2, left_title, right_title, position (1-indexed insert; default appends)\n  Slide types (prefer the richer visual ones over walls of bullet text):\n    title       - cover slide. title, body (subtitle)\n    content     - white slide with a branded header and body text. title, body\n    two_column  - two side-by-side cards. title, left_title, body (left), right_title, body2 (right)\n    section     - dark blue divider. title, body (subtitle)\n    stat_grid   - 2-4 shadowed KPI tiles. title, body with one tile per line \"VALUE|LABEL|CAPTION\"\n    callout     - large navy accent panel for one headline. title (eyebrow), body (statement)\n    quote       - large pull quote on a soft panel. body (quote), body2 (attribution), title (eyebrow)\n    drivers     - numbered driver cards. title, items=[{title, value}, ...] (or body lines \"title | value\")\n    ladder      - segment ladder of proportional bars. title, rows=[{label, value}, ...] (value 0..1 or any number; or body lines \"label | value\")\n    pills       - row of status chips. title, items=[{label, color?}, ...] (or body lines), body2 (optional caption)\n    count_boxes - row of equal colored boxes. title, items=[{label, color?}, ...] (or body lines)\n    links       - grid of clickable link buttons. title, items=[{label, url}, ...] (or body lines \"label | url\")\n    graph       - node/edge graph from native shapes. title, nodes=[{label}, ...], edges=[[parent_i, child_i], ...] (or body lines \"A -> B\")\n    chart       - native editable chart from shapes (real category labels, no image). title, series=[{name, labels:[...], values:[...]}, ...], chart_type=\"column\" (vertical, default) or \"bar\" (horizontal); one series colors per category, many series draw grouped bars with a legend\n- add_box: styled text box. Params: deck_id, slide_number, x, y, w, h (points, canvas 720x405), title, body, fill. Omit y to auto-stack (no overlaps).\n- add_table: styled table from markdown. Params: deck_id, slide_number, table_markdown, x, y, w, col_widths, font_size. Omit y to auto-stack.\n- add_image: place an image (logo, chart PNG) as content. Params: deck_id, slide_number, image_url, x, y, w, h.\n\nRead:\n- read_deck: deck structure. Params: deck_id, detail=summary|full. Returns EACH element's object_id + geometry (x/y/w/h points) +\n  text, and full table cell contents. Use this to get object_ids for the targeted edits below (no rebuild needed).\n- screenshot: inline viewable PNG of one slide. Params: deck_id, slide_number. Thumbnail is cached, so a just-edited slide may lag.\n- check_layout: CHEAP geometry-based defect scan (no image). Params: deck_id. Returns per-slide overflow/overlap defects with object_ids.\n  Review flow that avoids per-slide screenshots: check_layout -> fix all defects in ONE batch_edit -> screenshot only the changed slides to confirm.\n\nTargeted edits (fix in place instead of delete-and-rebuild; get object_id from read_deck):\n- edit_text: replace an element's or table cell's text in place. Params: deck_id, object_id, text, cell_location={row,col}, color, font_size, bold. Supports **bold**.\n- find_replace_text: replace text deck-wide. Params: deck_id, find, replace, match_case.\n- set_element_style: recolor/restyle an element. Params: deck_id, object_id, text_color, fill, bold, font_size, cell_location.\n- move_element / resize_element: reposition/resize by object_id. Params: deck_id, object_id, x, y, w, h (points), mode=absolute|relative.\n- delete_element: delete one element. Params: deck_id, object_id.\n- resize_table: Params: deck_id, table_id, col_widths (\"120,200\" pts or \"20%,50%\"), row_height, w, x, y.\n- edit_table: add/remove rows/cols. Params: deck_id, table_id, op=insert_row|delete_row|insert_col|delete_col, at_row, at_col, count.\n- duplicate_element: clone a slide or element. Params: deck_id, object_id.\n- batch_edit: apply MANY edits in one atomic call (cheapest way to fix several things, and avoids per-call rate limits). Params: deck_id, operations=[{op,object_id,...}, ...]\n  op accepts the short verb OR the full action name: edit_text | delete/delete_element | style/set_element_style |\n  move/move_element | resize/resize_element | resize_table | find_replace. Each op carries the same params as its standalone action\n  (e.g. {\"op\":\"move_element\",\"object_id\":\"box_..\",\"x\":40,\"y\":90} or {\"op\":\"edit_text\",\"object_id\":\"..\",\"text\":\"..\"}).\n- add_speaker_notes: set a slide's talk track. Params: deck_id, slide_number, text.\n\nSlide/deck lifecycle:\n- update_slide: text on a slide by heuristic. Params: deck_id, slide_number, title, body, body2. (edit_text by object_id is more precise.)\n- delete_slide / reorder: Params: deck_id, slide_number | from_pos, to_pos.\n- delete_deck: trash the whole deck (recoverable). Params: deck_id, permanent (default false = trash).\n\nDecks are created in the CS Shared Drive. folder_type: customer -> Customers/<folder_name>/, team -> CSMs/<folder_name>/,\nmisc (default) -> HG GTM Tool Decks/. All slides are auto-styled with HG brand colors, Nunito Sans, accent bars, and footer.","roles":[],"required_capabilities":["slides:create"]},{"name":"grant_capability","description":"Grant a capability to one user on top of their role bundle. Audited.","roles":[],"required_capabilities":["users:update"]},{"name":"hg_get_spend_categories","description":"Get HG Insights' full IT spend category taxonomy with guidance on how to use it.\n\nReturns the complete tree of 135 spend categories along with instructions\nfor mapping a customer's competitive landscape to the right categories.\nUse this when a customer wants to identify companies by technology spend\nfor displacement campaigns, ICP targeting, or account prioritization.","roles":[],"required_capabilities":["hg:read"]},{"name":"hg_lookup_industry_codes","description":"Look up industry classification codes from the HG data platform.\n\nUse this when a customer or rep needs to find precise industry codes\nfor filtering companies. Three classification systems are available:\n\n- **industries**: HG's own industry list (simple id + name)\n- **naics2012**: NAICS 2012 codes (hierarchical, with parent_id)\n- **sicus1987**: SIC US 1987 codes (hierarchical, with parent_id and code_standard)\n\nWhen someone can't find the right industry in HG's platform filters,\nNAICS or SIC codes provide more granular alternatives.","roles":[],"required_capabilities":["hg:read"]},{"name":"hg_lookup_intent","description":"Look up intent data catalogs from the HG data platform.\n\nTwo catalogs are available:\n\n- **intent_topics**: All intent topics tracked by HG (~21k topics). Each has a name and category.\n- **intent_buyers_journey**: Buyer journey stages (e.g. \"Evaluating\"). Each has a name and description.\n\nUse this when someone needs to find intent topics for targeting or\nunderstand what buyer journey stages are available.","roles":[],"required_capabilities":["hg:read"]},{"name":"hg_lookup_products","description":"Look up product and vendor catalogs from the HG data platform.\n\nThree catalogs are available:\n\n- **products**: All products tracked by HG (~27k). Each has a name, description, category, and vendor.\n- **product_categories**: Product category taxonomy (hierarchical, with name_tree showing full path).\n- **vendors**: All vendors tracked by HG (~11k). Each has a name and domain.\n\nUse this when someone needs to find a specific product, vendor, or\nproduct category in HG's data.","roles":[],"required_capabilities":["hg:read"]},{"name":"jira_create_provisioning_ticket","description":"Create an HG Platform Provisioning ticket in the HDH Jira project.\n\nFiles the standard provisioning request (issuetype \"HG Platform\nProvisioning\") that Platform Ops works from. Resolve the account and\nopportunity FIRST with `lookup_account` so the user confirms which opp the\nrequest is for — provisioning is billed against opps and a wrong ID causes\ncredit-allocation rework.\n\nReporter is auto-resolved from the calling user's email; the ticket is\nattributed to them, not to the MCP service account.\n\nParent epic: if `account_id` is provided and `parent_key` is not, the tool\nresolves the customer's HG project epic in this order — (1) SFDC\n`Account.HG_Jira_Epic_Key__c`, (2) Jira summary/cf search, (3) create new\nepic when `auto_create_parent=True`. Whenever the epic is found in Jira\nor freshly created, it's written back to the Account in SFDC so the two\nsystems stay in sync. Pass `parent_key` to override the resolution.\n\nFor internal HG requests, pass `opportunity_id=\"internal\"` and skip\n`account_id` (no parent epic resolution).","roles":[],"required_capabilities":["jira:create"]},{"name":"jira_get_ticket","description":"Get full details for a single Jira ticket including recent comments.\n\nReturns summary, status, assignee, description, Account Type, Impacted Area,\nSFDC Account ID, and the most recent comments (newest first).","roles":[],"required_capabilities":["jira:read"]},{"name":"jira_search_tickets","description":"Search CPF Jira tickets by text. Scoped to the Customer Product Feedback project.\n\nSearches summary, description, comments, and the Salesforce Account ID field.\nReturns a compact list: key, status, issue type, priority, assignee, updated date, summary.\nUse jira_get_ticket to fetch full details including comments for a specific ticket.\n\nTips for CSMs:\n- Try multiple name variations if the first search misses (e.g. \"Acme\", \"Acme Corp\")\n- Pass a Salesforce Account ID to find tickets tagged with it directly\n- Use status=\"all\" to include closed tickets (past 6 months of history)","roles":[],"required_capabilities":["jira:read"]},{"name":"kb_doc360_search","description":"Search the customer-facing HG Insights help center for an answer.\n\nThis is the REQUIRED next step after kb_search returns nothing for\nany product question (RGIP, MadKudu, Sales Copilot, Contact\nDiscovery, event mapping, scoring, the Chrome extension, anything\ncustomer-facing). Do NOT skip ahead to kb_flag_gap, and do NOT use\nWebFetch against help.madkudu.com — Doc360 blocks generic crawlers,\nso this tool is the supported path to the help center.\n\nSends the question to Ask Eddy AI (Document360's built-in\nassistant) and returns Eddy's draft answer alongside the full text\nof the top 3 cited articles.\n\nWrite the final answer using verbatim quotes from\narticles[i].content and cite each one with articles[i].url. Eddy's\neddy_answer is a starting point but always verify it against the\nsource — it sometimes compresses away conditional logic or\ncontradictions in the source article.\n\nWhen to use this tool:\n- kb_search returned no internal hits AND the question is\n  product-related → call this immediately, before kb_flag_gap.\n- The question is obviously about a customer-facing feature that\n  would be documented for customers (e.g. \"how does Sales Copilot\n  handle event mapping?\") → call this even if you would also call\n  kb_search.\n- You are about to call kb_flag_gap for a product question → call\n  this FIRST. Most gaps are actually answered in the help center.\n\nWhen NOT to use:\n- The question is about internal HG processes, tooling, or\n  workflows that customers wouldn't see. Use kb_search instead,\n  and if that misses, use kb_flag_gap.\n- kb_search returned a usable internal hit. Read that article\n  first; only call this tool if you also need the customer-facing\n  perspective.\n\nEach call consumes one Eddy credit. If the pool is exhausted the\nresponse will include limit_exceeded: true and an empty articles\nlist — fall back to kb_flag_gap in that case.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_flag_gap","description":"Flag a knowledge gap when no article answers the user's question.\n\nCreates a record in the gaps/ folder of HG-Product/hg-internal-knowledge\nwith a frontmatter source tag so KB owners can filter to gaps in their\nknowledge base.\n\nIMPORTANT, do NOT call this as the immediate fallback after kb_search\nreturns no results. The order matters:\n\n1. kb_search (internal KB), try first.\n2. The right external search, REQUIRED next step if the question\n   is product-related:\n     - RGIP / MadKudu / Sales Copilot / Contact Discovery / event\n       mapping / scoring → kb_doc360_search (help.madkudu.com).\n     - TrustRadius / TR / IDL / trScore / Top Rated / vendor portal /\n       reviews / awards → kb_freshdesk_search (2-3 keyword variants\n       in parallel; trustradius.freshdesk.com).\n     - HG Insights / Cloud Dynamics / HubSpot / matching / enrichment\n       connectors → kb_pylon_search + kb_pylon_read\n       (support.hginsights.com).\n   Most \"gaps\" are actually answered in one of those help centers.\n3. kb_flag_gap, only when internal AND the relevant external search\n   have come back empty, OR when the question is about an internal\n   HG process / workflow / tooling that no external help center would\n   cover.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_freshdesk_read","description":"Read the full body of a TrustRadius help-center article.\n\nCall this after `kb_freshdesk_search` has narrowed down which\narticles look most relevant. Pass the `id` from a preview.\n\nReturns the full plain-text body plus metadata (category, folder,\ntags, view count, last-modified). Quote from `body_text` and cite\nthe article using `url`.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_freshdesk_search","description":"Search the TrustRadius help center (Freshdesk) by keyword.\n\nReturns up to 5 article PREVIEWS — title, category, folder,\ncanonical URL, and a ~300-char snippet of the body. Bodies are\nNOT included. To read an article's full body, call\n`kb_freshdesk_read(article_id)` with the `id` from a preview.\n\nFreshdesk keyword search does not expand acronyms or paraphrase.\nFor best results, call this tool 2-4 times in parallel with\ndifferent keyword variants of the user's question, dedupe results\nby `id`, then call `kb_freshdesk_read` on the 1-3 articles that\nlook most relevant by title/category/snippet.\n\nVariant examples:\n- User: \"How do I become Top Rated?\"\n  → call with: \"Top Rated eligibility\", \"Top Rated criteria\",\n    \"Top Rated award requirements\"\n- User: \"How does the IDL program work?\"\n  → call with: \"Intent Driven Leads\", \"IDL setup\",\n    \"lead delivery integration\"\n\nAlways expand acronyms (IDL → Intent Driven Leads, TR →\nTrustRadius) — Freshdesk doesn't.\n\nWhen to use this tool:\n- The question is about TrustRadius, TR reviews, IDL, trScore,\n  Top Rated, vendor portal, awards, incentive budgets, the TR\n  Community, or anything else at trustradius.freshdesk.com.\n- kb_search returned no internal results AND the question fits\n  the TR scope above.\n\nWhen NOT to use:\n- RGIP / MadKudu / Sales Copilot — use kb_doc360_search.\n- Internal HG processes — kb_search, then kb_flag_gap if nothing.\n\nDo NOT WebFetch trustradius.freshdesk.com — use this tool. It's\nfaster and the response is structured.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_internal_create_article","description":"Author a new article in the internal HG knowledge base.\n\nOpens a PR against HG-Product/hg-internal-knowledge with Max as\nreviewer, it does NOT publish directly. The article goes live in\nkb_search only after the PR is merged and the MCP redeploys.\n\nUse this after kb_search confirms no article exists and you have a\ndurable, reusable answer worth saving (a process, a data-methodology\nexplanation, an internal FAQ). Do NOT use it for customer-facing\nproduct docs, those belong in Doc360 / Freshdesk / Pylon.\n\nIf the answer resolves an open gap, pass its filename as\n`resolves_gap`, the same PR moves the gap to gaps/resolved/ with\nresolution metadata, closing the loop in one step.\n\nThe server auto-fills author (from your identity), the date, and a\nURL slug. You only supply the content fields.","roles":[],"required_capabilities":["kb:create"]},{"name":"kb_list_drafts","description":"List staged KB drafts and their review status.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_list_placements","description":"List the folders/collections an article can be placed in.\n\nCall before kb_stage_article to choose a folder_id. Returns\n{placements: [{id, name}]}.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_pylon_read","description":"Read the full body of one HG Insights Pylon help-center article.\n\nCall this after `kb_pylon_search` has narrowed down which\narticles look most relevant. Pass the `id` from a preview.\n\nReturns the full plain-text body plus metadata. Quote from\n`body_text` and cite the article using `url`.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_pylon_search","description":"Search the HG Insights Pylon help center by keyword.\n\nReturns up to 5 article PREVIEWS — title, slug, url, collection,\nand a ~300-char snippet of the body. Bodies are NOT included.\nTo read an article's full body, call `kb_pylon_read(article_id)`\nwith the `id` from a preview.\n\nPylon has no server-side text search, so this tool fetches the\nfull article list on every call (paginated; one round trip at\nHG's article count) and runs deterministic token-based scoring\nin memory: title hits weigh 3x body hits. Cheap on tokens, slow\non first call (~1s).\n\nLike Freshdesk, call this 2-4 times in parallel with different\nkeyword variants of the user's question, dedupe by id, then\nread the top 1-3.\n\nWhen to use this tool:\n- The question is about HG Insights / Cloud Dynamics features\n  that may live in HG's Pylon help center, public at\n  support.hginsights.com (also reachable at\n  hg-insights-knowledge-base.help.usepylon.com — same content,\n  custom domain mapped to Pylon).\n- Common topics: HG for Salesforce Connector, HG for HubSpot,\n  enrichment configuration, technographic data structure,\n  firmographic fields, validation rules, install-base data.\n- kb_search returned no internal hits AND the question doesn't\n  fit MadKudu/RGIP (kb_doc360_search) or TrustRadius\n  (kb_freshdesk_search) scope.\n\nDo NOT WebFetch support.hginsights.com or\nhg-insights-knowledge-base.help.usepylon.com — use this tool.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_read","description":"Read the full content of a knowledge base article.\n\nIf the article links to help.madkudu.com or trustradius.freshdesk.com,\nthe response is prefixed with a routing hint telling you to use\nkb_doc360_search or kb_freshdesk_search (not WebFetch) for those\nlinks. Both help centers block generic crawlers; the search tools\nare the supported path to their content.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_search","description":"Search the internal knowledge base by keywords.\n\nReturns a list of matching articles with title, description, and path.\nUse kb_read to get the full content of a specific article.\n\nTips for better results:\n- Try multiple keyword variations (e.g. \"confidence scoring\" and \"install quality\")\n- Use short, specific terms rather than full questions\n- Pass an empty query to list all available articles","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_stage_article","description":"Stage a NEW article as a draft in an external KB.\n\nThe article is created as an unpublished draft, never live. A\nreviewer publishes it later from the drafts dashboard. Use this when\nkb_search and the external search found nothing and you have a\ndurable answer worth adding.\n\nWrite the body in Markdown. It is converted to clean HTML server\nside. Images are not supported yet and will be rejected.\n\nCall kb_list_placements first to pick a folder/collection for the\narticle, or omit folder_id to place it at the top level (Pylon).","roles":[],"required_capabilities":["kb:create"]},{"name":"kb_stage_edit","description":"Stage an EDIT to an existing external KB article as a draft.\n\nEdits are applied as exact find/replace pairs against the article's\ncurrent HTML, so only the text you target changes and the rest of\nthe article's formatting is preserved exactly. Each `find` must\nmatch the live HTML verbatim and exactly once; make it long enough\nto be unambiguous.\n\nFirst read the article (kb_pylon_read / kb_freshdesk_read) to see\nits current HTML, then supply edits like:\n    [{\"find\": \"<p>Old sentence.</p>\", \"replace\": \"<p>New sentence.</p>\"}]\n\nThe live article is not changed until a reviewer pushes the draft.","roles":[],"required_capabilities":["kb:create"]},{"name":"kb_studio_read","description":"Read the full content of a Data Studio second-brain article.\n\nArticles due for re-review are prefixed with a staleness note; treat\nthose claims with slightly more care. Routing hints are prepended when\nthe article links to external help centers.","roles":[],"required_capabilities":["kb:read"]},{"name":"kb_studio_search","description":"Search the Data Studio second brain (scoring & Data Studio expertise).\n\nThis knowledge base covers HOW to do scoring well: building customer-fit\nmodels, datasets, conversion definitions, thresholds, signals, event\nweights, aggregations, connectors (MK vs HG), pushing scores, MQL\nrollout, qualification, onboarding sequence, known quirks and\nlimitations. Use it for any scoring / Data Studio / RGIP-configuration\nmethodology question. It does NOT cover ops/provisioning/credits\n(kb_search) or customer-facing product docs (kb_doc360_search).\n\nReturns matching articles with title, description, type (concept,\nhow-to, use-case, qualification, limitation, workaround, integration,\nplaybook), and a stale flag for articles due re-review. Use\nkb_studio_read for full content.\n\nTips:\n- Try multiple keyword variations; short specific terms beat questions.\n- Filter mentally by type: `concept` for \"what IS this / how does it\n  work\" (definitions and mechanics, the layer a CSM needs in a customer\n  conversation), `how-to` for \"how do I do it\" (the operator layer),\n  `limitation`/`workaround` for \"why is this broken\",\n  `use-case`/`qualification` for business questions.\n- Empty query lists all articles.","roles":[],"required_capabilities":["kb:read"]},{"name":"list_capabilities","description":"List every defined capability (the full catalog), grouped by resource.","roles":[],"required_capabilities":["users:read"]},{"name":"list_customer_projects","description":"List all open customer projects.\n\nReturns all Vitally tasks tagged 'Customer Project' that have not been\ncompleted. Each project includes the customer name, use case, CSM email,\nproject notes, and linked organization.","roles":[],"required_capabilities":["accounts:read"]},{"name":"list_drafts","description":"List all drafts with optional filters.","roles":[],"required_capabilities":["outreach:list"]},{"name":"list_role_bundles","description":"Show the default capability bundle for every role, or just one role if given.\n\nA role's bundle is the set of capabilities every user in that role gets by\ndefault (before per-user grants/revokes).","roles":[],"required_capabilities":["users:read"]},{"name":"list_users","description":"List all registered users and their roles.","roles":[],"required_capabilities":["users:read"]},{"name":"lookup_account","description":"Look up an account by name. Returns account details from Salesforce\nand recent meetings/conversations from Vitally.","roles":[],"required_capabilities":["accounts:read"]},{"name":"lookup_contact","description":"Look up a contact by email address. Checks Salesforce (Contact, then Lead),\nvalidates against LinkedIn via web search, and writes the LinkedIn URL back\nto Salesforce if missing.\n\nIf the person is not in Salesforce at all but a LinkedIn profile is found,\nposts a request to #sales-operations to create the contact.\n\nArgs:\nemail: The contact's email address (e.g. nav@cockroachlabs.com).","roles":[],"required_capabilities":["crm:lookup"]},{"name":"my_drafts","description":"List outreach drafts assigned to the current user.","roles":[],"required_capabilities":["outreach:read"]},{"name":"pylon_create_ticket","description":"Create a new Pylon support ticket on behalf of a customer.\n\nUse this when a user needs help and wants to open a ticket with the support team.\nAutomatically resolves the account by name before creating the issue.\n\nIMPORTANT — before calling this tool:\n- If the account is not clear from context, ask the user: \"Which account is this for?\"\n  Do not guess or infer the account name. Only proceed once the user confirms.\n- Generate a clear, specific title from the conversation context\n- Write body_html as a concise HTML summary of the issue (use <p> tags)\n- Present all ticket details to the user for review before calling this tool:\n    Account, Requester name, Requester email, Title, Body (rendered from body_html)\n  Ask: \"Does everything look correct? I'll create the ticket once you confirm.\"\n  Only call this tool after the user explicitly approves.\n- If multiple accounts match account_name, show them to the user and ask which one they mean\n\nNote: The ticket body always includes an opener attribution line (\"This ticket is opened by\n<name> at HG Insights.\") regardless of whether a custom requester is provided. This is\nintentional — it traces which HG team member triggered the ticket.","roles":[],"required_capabilities":["pylon:create"]},{"name":"pylon_get_issue","description":"Get full details for a single Pylon issue including the message thread.\n\nReturns metadata (title, state, assignee, team, tags, account, timestamps)\nand the most recent messages (newest first) with author, timestamp, body,\nand whether each message was internal.","roles":[],"required_capabilities":["pylon:read"]},{"name":"pylon_search_accounts","description":"Find a Pylon account by customer name (substring match).\n\nReturns a compact list of matching accounts with id, name, domain, and owner.\nUse the account id with pylon_search_issues to fetch support issues for that account.\n\nTips:\n- If multiple accounts match, show them to the user and ask which one they mean\n- If no match, try a shorter or alternate name\n- Pylon accounts are separate from Salesforce accounts; search by customer name, not SFDC ID","roles":[],"required_capabilities":["pylon:read"]},{"name":"pylon_search_issues","description":"List Pylon support issues for a specific account.\n\nUse pylon_search_accounts first to find the account_id. Returns a compact list:\nid, number, title, state, assignee, created/updated dates, and link.\nUse pylon_get_issue to fetch full details and the message thread for a specific issue.","roles":[],"required_capabilities":["pylon:read"]},{"name":"reset_capability","description":"Remove a per-user grant/revoke, resetting that capability to the role default. Audited.","roles":[],"required_capabilities":["users:update"]},{"name":"revoke_capability","description":"Revoke a capability for one user, subtracting it from their role bundle. Audited.","roles":[],"required_capabilities":["users:update"]},{"name":"rgip_get_usage","description":"Show how a customer is using the RGIP / MadKudu product (the standard usage report).\n\nReturns active-user trend, adoption, value realization, operator activity\n(who builds playbooks, who maintains the model), and service dependency\n(how much config is run by the customer vs HG vs an agency), across 30d /\n90d / all-time windows. Renders an interactive dashboard artifact.\n\nUse this for general \"how is <account> doing in the product?\" questions,\nreview prep, and renewal-risk triage. For a specific ad-hoc question that\nthe report does not answer, use rgip_query_usage instead.","roles":["am","csm","manager","ops","super_ops"],"required_capabilities":[]},{"name":"rgip_list_mappings","description":"List event, audience, and conversion mapping definitions for a Data Studio (RGIP) tenant.\n\nUse this to answer CSM questions like \"what is my model trained on?\",\n\"what events are we capturing?\", and \"what conversions are defined?\".\n\nReads tenant configuration from the mk-tenant-config GitHub repo. Filters\non conversion definitions are translated to clean Studio expressions\n(`probability EQUALS 100`, `a_arr__c AT LEAST 20000`).","roles":[],"required_capabilities":["rgip:read"]},{"name":"rgip_query_usage","description":"Run a read-only DuckDB SQL query against a tenant's RGIP usage events (advanced).\n\nSuper-ops only. Use for ad-hoc questions the standard rgip_get_usage\nreport does not answer, e.g. \"who were the top playbook builders in the\nlast 30 days\" or \"which intent-signal cards did they click most\".\n\nThe query runs against a single table `ev` scoped to the resolved tenant.\nOnly a single read-only SELECT / WITH statement is allowed; results are\ncapped at 200 rows. See the `rgip-usage` skill for the `ev` schema, the\nevent taxonomy, and example queries.\n\n`ev` columns: event_type, email, domain, tenant, app\n(extension/embed=SCP, studio/addax=Data Studio), dt (date),\nuid (per-user id). Sendgrid noise is already excluded.","roles":["super_ops"],"required_capabilities":[]},{"name":"rgip_show_model_diagnostics","description":"Show the deployed Customer Fit model diagnostics for a Data Studio (RGIP) tenant.\n\nReturns the top and bottom ICP profiles from the active decision tree,\nthe score overrides applied after the tree (with Studio's is / at most /\nat least semantics), and the state of the deployed vs latest-trained\nmodel.\n\nUse this when a CSM is preparing for a reactivation or model-review call\nand needs to walk a customer through what their model is doing.","roles":[],"required_capabilities":["rgip:read"]},{"name":"search_crm_contacts","description":"Search for contacts across CRM accounts by location, title, and account type.\nIncludes Vitally engagement data (last inbound/outbound message).\n\nResults are sorted by most recently engaged contacts first.","roles":[],"required_capabilities":["crm:read"]},{"name":"set_bundle_capability","description":"Add (present=true) or remove (present=false) a capability from a ROLE's default bundle. Audited.\n\nThis changes the default access for EVERY current and future user in that\nrole, so it is higher-leverage than a per-user grant. Use a clear reason.\nTo change one person instead, use grant_capability / revoke_capability.","roles":[],"required_capabilities":["bundles:update"]},{"name":"show_account_brief","description":"Display the account brief dashboard for a researched account.\n\nCall this after start_research or get_research_result returns a completed brief.","roles":[],"required_capabilities":["accounts:read"]},{"name":"skip_draft","description":"Skip a draft with a reason.","roles":[],"required_capabilities":["outreach:skip"]},{"name":"start_research","description":"Start researching an account across all internal systems (Vitally, Salesforce, Slack, Jira, Brave).\n\nReturns immediately. If a cached brief exists, returns the full brief JSON.\nOtherwise starts background research and returns a task_id.\nPoll with get_research_result every 60 seconds. Research typically takes 3-10 minutes for a full refresh. Do not give up early.\nWhen research is complete, call show_account_brief with the sfdc_account_id to display the dashboard.","roles":[],"required_capabilities":["research:start"]},{"name":"tr_get_answer_signals","description":"Whether AI answer engines mention/cite a company (GEO outcome signal).\n\nTrustRadius Conductor data: how often AI answer engines (ChatGPT, Claude,\nGoogle AI, Perplexity, and others) mention the brand in answers, across how\nmany distinct engines and distinct buyer prompts.\n\nThere is deliberately NO sentiment score. TrustRadius exposes no brand-scoped\nsentiment; the figure this tool returned before 2026-07-27 was a table-wide\naverage identical for every brand. Do not describe a company's AI-answer\nsentiment from this tool.\n\nSelf-resolves by brand name (works for prospects). Pass brand when the display\nname differs from how the brand appears in AI answers. If brand_mentions is 0\nthe brand isn't surfacing in the monitored answer set under that name.\n\nCompanion to tr_get_crawler_signals: crawler = the input (bots reading TR),\nanswer = the outcome (the brand actually showing up in AI answers).","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_get_campaign_report","description":"Get the history of review campaigns for a vendor's products.\n\nReproduces the TrustRadius Review Campaigns dashboard: one row per\ncampaign with published review count, rating count, and publish date\nrange. Filtered to HG-relevant campaigns (RaaS and VendorSourced\nfirst-touch source) — excludes TR internal research/community invites.\n\nCampaigns are grouped by product and split into:\n  - owned: campaigns targeting this vendor's product directly\n  - cross_vendor: RaaS campaigns from other vendors that surfaced\n    ratings for this product via multi-product surveys\n\nPer-campaign estimated spend is parsed from the campaign code\n(gc25 → $25, gc50 → $50, amzn25 → $25). TR does not expose per-review\npayouts, so these are directional estimates.\n\nUse tr_search_vendors first to resolve a vendor name to a vendor_trid.\nOptionally pass product_trid to scope to a single product.","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_get_crawler_pages","description":"Page-level AI-crawler volume + head-to-head comparison pairs (GEO account brief).\n\nThe page grain behind tr_get_crawler_signals. Returns which individual\nTrustRadius URLs the AI crawlers pull with request volume per page, per-product\nportfolio totals, and — for compare-products pages — which two products each\npage matches up, so a brief can carry both a portfolio rollup and a\nhead-to-head comparison table.\n\nPass product_names to scope to a defined product list rather than the whole\nvendor catalog. On this crawler tool, values are slugified and matched to exact\nTrustRadius URL slugs; this is different from tr_get_product_reviews, which\nexact-matches catalog product names. Resolve the appropriate input for each\ntool when building one brief. Page URLs and head-to-head rows are returned\nbiggest-first and each capped at top_pages; page_count and head_to_head_count\nreport their full counts before the cap.\n\nProducts are matched against the TrustRadius URL slug, so a name that is not\nthe TR product name matches nothing: \"Redwood Software\" (a vendor name) returns\n0 while \"Redwood\" returns thousands. Any requested slug absent from every\nreturned page is listed in unmatched_products. It may be a naming mismatch or a\nreal no-row result; resolve it before trusting the portfolio total. A returned\npage with zero volume is treated as a resolved genuine zero.\n\npages_truncated means the Looker row cap was reached, so totals and counts are\nlower bounds and must not be quoted as complete.\n\nScoped by TrustRadius URL slug, so it works for prospects, not just customers.\nWindow floors at 30 days (TrustRadius Looker sync lag).","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_get_crawler_signals","description":"How often AI crawlers pull a company's TrustRadius pages (GEO input signal).\n\nTrustRadius-proprietary telemetry: the crawlers behind LLM answers\n(GPTBot/OpenAI, ClaudeBot/Anthropic, Google, PerplexityBot) hitting a\ncompany's TR pages. Returns total successful requests over the window plus\nsplits by operator (which AI), by individual crawler bot name\n(ChatGPT-User, OAI-SearchBot, GPTBot, ClaudeBot, Claude-User, GoogleBot —\neach with its own count and purpose), by purpose (Grounding = feeding a live\nanswer vs Training), and by page type, plus an up/down/flat trend.\n\nScoped by the company's TrustRadius URL slug (works for prospects, not just\ncustomers). Pass product_slug when the company name doesn't match its TR URL\n(rebrands, multi-word names); otherwise the company name is slugified. Pass\nproduct_names to scope to a defined product subset instead of every page\ncarrying the company slug. If total is 0 the company likely has no TR\nlisting under that slug.\n\nWindow floors at 30 days (TrustRadius syncs into Looker with lag; shorter\nreads artificially low).\n\nFor individual page URLs and head-to-head comparison pairs, use\ntr_get_crawler_pages.","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_get_incentive_budget","description":"Look up TrustRadius incentive budgets for an HG customer.\n\nReturns CVP product details including incentive budget, spend,\nremaining balance, package purchased, and contract dates.\n\nResolution path matches the other TR tools: an HG SFDC Account name\nresolves to a `vendor_trid` via `TR_Vendor_TrustRadius_ID__c`, which\nis then used to look up the TR SFDC Account. HG SFDC is the single\nsource of truth for \"is this an HG customer with a TR mapping\" — we\ndo NOT search TR's CRM by name (it contains duplicates and unrelated\naccounts that produce wrong results).\n\nProvide one of:\n  - `account_name`: HG customer name (resolved via HG SFDC, same as\n    `tr_search_vendors`).\n  - `vendor_trid`: TrustRadius vendor ID (Mongo-style). Skip the HG\n    resolution step if you already have it.\n\nIf no HG account matches, or the matched HG account has no\n`TR_Vendor_TrustRadius_ID__c` populated, the tool surfaces that as\nfeedback to backfill the mapping — same behavior as\n`tr_search_vendors`.\n\nHeadline totals (`active_*`) count only products that are subscribed\nAND whose contract has not lapsed — that's what's actually accessible\nto the customer. Lapsed-but-subscribed budget is reported separately\nas `lapsed_remaining` so CSMs can see it without mistaking it for\navailable funds. Full roll-up (`total_*`) is also returned for\ntransparency.","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_get_product_reviews","description":"Per-product review count, latest publish date and rating over a trailing window.\n\nFor each product: how many reviews published in the window and the most recent\npublish date, plus a vendor-wide rollup across the full published catalog —\nalways the full catalog, even when product_names narrows the per-product list.\n\nThree separate \"rating\" numbers, which mean different things and do not agree:\naverage_review_rating is the mean score of reviews inside the window;\ntrscore_current is the product's live TrustRadius score (TR's own weighted\nalgorithm over all history, and the figure shown publicly, so it will not equal\nthe window mean); rating_submission_count is how many star-only rating\nsubmissions landed in the window, which is volume rather than a score and is a\ndifferent submission type from a review. Say which one you are quoting.\n\nUse tr_search_vendors first to resolve a vendor name to a vendor_trid.\nPass product_names to limit the per-product breakdown to a defined product\nlist; any name that does not match the catalog comes back in\nunmatched_products rather than failing silently. This tool exact-matches\ncatalog names case-insensitively; the crawler tool instead slugifies its input.\nreview_product_conflicts lists any review joined to multiple product IDs; those\nper-product counts require investigation before being quoted.\n\nDifferent question from tr_get_review_report, which is hard-scoped to the\nTop Rated award cycle and only walks subscribed products. This one takes an\narbitrary window over the full published catalog, for account briefs.","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_get_rejected_leads","description":"IDL rejected leads breakdown for a vendor.\n\nSources from the IDL Rejected Lead Report Looker dashboard. Aggregates\nrejected leads by reason, email_domain, campaign, and product, plus\nthe 20 most recent individual rejections.\n\nPII handling: raw email and full payload are NOT returned. Only\nemail_domain, reason text, and TR-side IDs (campaign, product,\nsource) are surfaced.\n\nUse to answer: Why are leads bouncing for this customer/campaign?\nAre rejections concentrated on a specific form field, product, or\ndomain?\n\nUse tr_search_vendors first to resolve a vendor name to a vendor_trid.","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_get_review_report","description":"Get TrustRadius review counts and Top Rated eligibility for a vendor's products.\n\nReturns one entry per published product with: reviews in the current award\ncycle (May 1 – today), reviews needed to reach Top Rated (threshold: 10),\ncurrent trScore (rounded to 1 decimal), and 90-day score trend.\n\nAwards are granted per product, not per vendor. Most vendors have one\nproduct; multi-product vendors return a list.\n\nUse tr_search_vendors first to resolve a vendor name to a vendor_trid.","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_get_webhook_health","description":"IDL webhook delivery health for a customer's webhooks.\n\nSources from the IDL Webhook Activity Looker dashboard.\n\n**Primary scoping: `webhook_name_contains`.** Webhooks are named for\nthe customer/campaign (e.g. \"PingIdentity NA CISO (integrate)\",\n\"SAP Concur (May 2026)\"). Pass a substring of the customer name —\ncamel-cased, no spaces, since that's how TR names them. If \"Ping\nIdentity\" returns nothing, retry with \"PingIdentity\" or \"Ping\".\n\n**Recommended workflow:** call `tr_search_vendors` first to resolve\nthe customer name to a canonical TR vendor record. Use the returned\n`vendor_name` (already in TR's preferred form) as the substring\nhere. The data model does NOT expose a vendor_id → webhook join in\nLooker, so a name substring is the only reliable scope.\n\n`salesforce_oid` is rarely useful — the column stores the TR-side\nSalesforce *Org* identifier (one value across all webhooks), not a\nper-customer Account ID, and only ~27% of webhooks have it set.\n**Do NOT pass an HG SFDC Account Id here** — that's a different\nSalesforce org and will never match. Use `webhook_name_contains`\ninstead.\n\nReturns per-webhook: success/failure counts, success rate, last\nsuccess and last failure timestamps (ISO 8601 UTC), and the most\nrecent 5 errors. Email addresses are scrubbed from error messages;\nraw payload and response bodies are NOT returned.\n\nUse to answer: Is this customer's webhook firing? Did the test lead\ndeliver? When was the last successful delivery?","roles":[],"required_capabilities":["tr:read"]},{"name":"tr_search_vendors","description":"Resolve an HG customer vendor name to a TrustRadius vendor_trid.\n\nSource of truth is the HG Salesforce Account: SOSL-searches Accounts\nby name and returns those with TR_Vendor_TrustRadius_ID__c populated.\nSame pattern as lookup_account / get_book — case-insensitive, partial\nmatch.\n\nIf no match is returned, ask the user to share feedback so the\nTR_Vendor_TrustRadius_ID__c field can be backfilled on the Account.","roles":[],"required_capabilities":["tr:read"]},{"name":"update_last_outbound","description":"Override the last outbound touch date for an account.\n\nWrites to the manual override field in Salesforce. The formula field\nrecalculates as MAX(automated, manual).","roles":[],"required_capabilities":["outreach:override"]},{"name":"update_outreach_draft","description":"Update a pending outreach draft.","roles":[],"required_capabilities":["outreach:update"]},{"name":"update_user","description":"Update a user's name or role.","roles":[],"required_capabilities":["users:update"]},{"name":"vitally_create_success_plan","description":"Create an IDL Success Plan against a Vitally organization.\n\n`fields` uses short keys matching Vitally's custom-field slugs (no\n`vitally.custom.` prefix). Dropdown fields must use configured option\nvalues — unknown values are passed through with a warning.\n\nSupported keys: idlLead, idlCampaignType (list), partner (list),\nleadDeliveryDay, ioTotal, ioDate, leadGoal, leadsDelivered,\nleadsRemaining, expectedLaunchDate, actualLaunchDate, intentPullDate,\nlandingPages, outcomes, feedback, accountsGoogleFolder,\ncustomerCsBoxFolder, kickOffDeck, linkToIdlJira.","roles":[],"required_capabilities":["plans:create"]},{"name":"vitally_show_success_plans","description":"Show IDL Success Plans (Vitally custom object) grouped by customer\norganization in an interactive UI.\n\nBoth arguments are optional. Call with no arguments to see every plan\nin the system. Provide a filter to narrow down:","roles":[],"required_capabilities":["plans:read"]},{"name":"vitally_update_success_plan","description":"Update an IDL Success Plan. Only provided fields change.\n\nPass a field as `null` to clear it. Dropdown fields validate against\nknown options (unknown values pass through with a warning).","roles":[],"required_capabilities":["plans:update"]},{"name":"weflow_get_transcript","description":"Get the full transcript and metadata for a single Weflow recording.\n\nReturns metadata (name, start/end times, duration, platform, summary,\nWeflow URL) plus the full transcript text.","roles":[],"required_capabilities":["weflow:read"]},{"name":"weflow_search_recordings","description":"List recent Weflow call recordings that have already happened for a Salesforce account.\n\nReturns a compact list per recording: id, name, start date, duration, platform,\nand a short summary preview. Sorted by most recent first. Only includes calls\nwhose start time is in the past (skips scheduled future calls).\nUse weflow_get_transcript to fetch the full transcript for a specific recording.\n\nUsage:\n- Resolve the account first with lookup_account if you only have a name\n- Pass the Salesforce Account ID (starts with 001)\n- A call that ended minutes ago may show has_transcript=false while Weflow is\n  still processing; transcripts typically land ~30 minutes after the call ends","roles":[],"required_capabilities":["weflow:read"]}],"count":83}