---
name: cse-intake
description: Create or repair CSE Engagement Jira tickets from Slack threads and Gong transcripts. Use only for explicit create, repair, or source-to-ticket intent such as cse intake, create cse ticket, repair CSE-XX, slack to cse, or intake from slack. Route vague CSE engagement research or discovery requests to cse-engagement-finder.
argument-hint: "[slack permalink | search terms | customer]"
---

# CSE Engagement Intake

## Compact MCP routing

Follow the shared [compact MCP routing contract](../../shared/compact-mcp-routing.md). Interactive facade tools are `cse_capabilities`, `cse_read`, `cse_apply`, `context_assemble`, and `cse_session_info`; named operations are capability ids. Call reads through `cse_read` with the capability id. Every mutation goes through `cse_apply` twice: dry-run first, then the identical capability and arguments with `execute:true`, a justification of at least 16 trimmed characters, and the returned `preview_digest`. Call `context_assemble` and `cse_session_info` directly when needed. Check `cse_capabilities` when a capability id or schema is genuinely unknown. Step 2 uses `context_assemble` with `kind:"account"` as the primary account-context read.

Worked preview/apply example (the capability arguments must otherwise be identical). Preview omits underlying `arguments.execute`; apply repeats the mutation args with underlying `arguments.execute: true` and the returned `preview_digest`:

```js
cse_apply({
  capability: "jira_create_issue",
  arguments: {
    fields: { summary: "<Customer> [<Category>]" },
    semantic_fields: { "<field>": "<value>" }
  },
  execute: true,
  justification: "Preview the qualified CSE engagement intake create"
})
cse_apply({
  capability: "jira_create_issue",
  arguments: {
    fields: { summary: "<Customer> [<Category>]" },
    semantic_fields: { "<field>": "<value>" },
    execute: true,
    preview_digest: "<preview_digest returned by dry-run>"
  },
  execute: true,
  justification: "Create the qualified CSE engagement intake"
})
```


Create CSE Engagement Tracker Jira tickets from Slack messages about customer opportunities. Pull Gong call transcripts via Kepler tools inside local `cse-tools` MCP, fetch attached Google Docs when needed, resolve Salesforce Team IDs, and populate the required Jira fields.

## Domain Configuration

Use the `cse_domain_info` capability to discover engagement stage names, semantic field names, ADF fields, and the intake label; use `cse_resolve_field` for field semantics when needed. Use `jira_create_issue` with `semantic_fields` and `jira_transition_issue` with `stage` (for example, `stage: "Technical Discovery"`). Never pass Jira custom-field keys or raw transition ids.

Do not read `~/.cse-tools/config.yaml`; domain discovery stays behind `cse_domain_info` and `cse_resolve_field`.

## Comment & message voice

Every Jira comment this skill posts — the intake-confirm comment, the data-quality resolution / escalation comments written via the shared policy — follows [`.agents/shared/prose-voice.md`](../../shared/prose-voice.md). The intake-confirm specifically needs `originator_mention`, defined here as the plain Jira display name of the AE/SE/CSM who surfaced the engagement, with no `@` syntax or mention node; if no display name can be resolved, skip the comment. Evidence (source, dates, permalinks) lives on the `cse-dq` entity property per [`.agents/shared/audit-manifest.md`](../../shared/audit-manifest.md), never in the body.

Before drafting any intake-confirm or data-quality comment, follow `.agents/shared/prose-voice.md` (and the `writing` skill) for operator voice.

The daemon resolves Jira site, project, issue-type, field, and engagement-stage details. Use `jira_create_issue` with `semantic_fields` and `jira_transition_issue` with `stage`; use `cse_domain_info` to discover stage names and the intake label.

## Inputs

Accept any of the following:
- Slack permalink
- Slack search terms (`from:<author> keyword`, channel, customer name, or thread hints)
- Customer name
- Gong call reference (call ID, account name, or description)
- Engagement category such as `API Catalog > Spec-Driven Automation`

## Required dependencies

Before starting, source the bootstrap once per shell so `CSE_TOOLD_BIN` and `CSE_OPERATOR` resolve:

```bash
source "${PLUGIN_ROOT:-${DROID_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-$PWD/plugins/cse-tools}}}/.agents/shared/skill-bootstrap.sh"
```

The daemon keeps daemon keychain auth fresh on its own; no mint step is needed. On a 401, call `cse_session_info({"force_refresh": true})` once, retry once, then stop and report the exact failing surface. A 403 means blocked or revoked access: surface the returned operator action without retry. If `127.0.0.1:9901/mcp` refuses the connection, follow `cse-mcp-setup` daemon recovery, re-probe once, and stop if that single retry still refuses the connection. Prefer MCP tools for normal work; shared scripts are fallback/diagnostic helpers.

Required surfaces:
- **Read strategy:** Follow [`.agents/shared/read-strategy.md`](../../shared/read-strategy.md). Account discovery context is a single `context_assemble(kind:account)` call (Step 2); the Slack thread read, Team-ID resolution, and Jira create/transition stay direct.
- **Direct-tool guardrails for this skill:** Follow [`.agents/shared/tool-frugality.md`](../../shared/tool-frugality.md). Owned tools (`jira_search`, `google_calendar_events`, `confluence_*`) return compact by default; pass `verbosity:"full"` only when you need the raw payload. Hydrate Kepler/Granola only for what you'll actually cite.
- **Jira (reads + writes)** — local `cse-tools` MCP capabilities (`jira_get_issue`, `jira_search`, `jira_create_issue`, `jira_edit_issue`, `jira_transition_issue`, `jira_add_comment`, properties).
- **Slack reads** — local `cse-tools` MCP (`slack_search`, `slack_channels`, `slack_users`, `slack_read_channel`, `slack_read_thread`). `slack_read_thread` can return "No thread messages" on group DMs (mpIMs) even when the thread has replies — the search index sees them, the threading endpoint does not. If the permalink points to a group DM and `slack_read_thread` returns empty, use `slack_search` with `from:<@<user_id>>` plus a distinctive phrase from the parent message: the search response inlines thread replies as `context_after` entries.
- **Slack writes** — local `cse-tools` MCP write tools (`slack_post_message`, `slack_add_reaction`, `slack_open_dm`). Zero app attribution.
- **Granola (recommended, optional)** — use `granola_list_meetings` for active-workspace attendee discovery and `granola_get_meetings` for selected details (internal sponsor-alignment meetings, scoping sessions, and recent customer calls that haven't landed in Kepler yet). Use `granola_get_meeting_transcript` only for exact wording and REST only for an explicit cross-workspace gap. Skip silently when Granola is not enrolled; Gong transcripts via Kepler remain the primary narrative source for the intake's pain-points + next-steps fields.
- **Account context** — `context_assemble({entity:{kind:"account", ref:"<customer>"}})` is the discovery entry point (Step 2): one call resolves the account and returns its recent calls/emails + Salesforce card, replacing the manual `list_customers` -> `semantic_context_search` -> `list_communications` ladder. Then hydrate the specific transcript you'll cite with `get_communications(ids=[...], include_content="full")`. The underlying Kepler tools (`list_customers`, `get_salesforce_account`, `semantic_context_search`, `list_communications`, `get_communications`) remain available for the targeted hydration and as a fallback if `context_assemble` is unavailable.

Do not block ticket creation on Kepler if both MCPs are unreachable — record what you have from Slack and mark Kepler-enrichment as skipped. Full MCP installation docs are in `README.md`.

## Scope gate (check before creating)

A CSE Engagement is hands-on integration, automation, or devops co-execution, where the CSE builds something alongside a named customer engineer. Before creating an engagement ticket, confirm the ask is a build, not an advisory question.

If the request is a best-practices or governance-policy question (for example, how to stop free users sharing collections publicly), a security or admin config task (SSO, SCIM, Domain Capture, BYOK), break/fix, a version unlock, onboarding, training, or commercial/renewal work, it is not a CSE engagement. Route it (SE or Solutions, Support, AE/CSM/TAM) and either log a lightweight CSE consult or skip the ticket. See the "Not CSE-shaped" list in the cse-engagement-finder skill. Create the engagement only once there is an implementation to build with a named technical counterpart.

## Workflow

Follow this sequence exactly.

### 1. Find the Slack message

Use local `cse-tools` MCP Slack reads to locate the relevant message and thread.

- If the user provided a permalink, extract channel and timestamp from it and use `slack_read_thread` to read the full thread.
- Otherwise, use `slack_search` with the supplied customer name, author, keywords, or channel hints. The default visible scope includes private channels and DMs the operator can read.
- Read the thread and collect:
  - message body
  - replies
  - attachments
  - linked documents
  - names of customer and Postman participants

### 2. Pull the account's recent calls + backend context

One `context_assemble` call discovers the customer's recent Gong calls, emails, and Salesforce record in one shot — it replaces the manual `list_customers` -> `semantic_context_search` -> `list_communications` -> `get_salesforce_account` discovery ladder (the daemon owns canonicalization, the comms/semantic/salesforce fan-out, rerank, and the coverage manifest).

```jsonc
context_assemble({
  entity: { kind: "account", ref: "<CustomerName as it appears in Jira>" },
  facets: ["recent_activity", "blockers", "open_loops", "ownership"],
  window: { since: "<a few weeks back, to span the surfacing thread>" }
})
```

From the returned `working_set`: the `salesforce` card carries the account/team context; `kepler_comms` and `kepler_semantic` cards are the recent calls/emails ranked by relevance. Pick the call(s) the intake is about (the one named in the Slack thread, or the most recent scoping/discovery call) and hydrate the transcript in full:

- Call `get_communications` with arguments `ids=["<gong_call_id from the card citation>"]`, `include_content="full"`, `content_max_chars=10000`, and `content_page=1`. If the response reports more pages, increment `content_page` until all pages required for the full text are read. `body` and `transcript` are identical strings; read one, never both.

Read `coverage`: `kepler_comms=error` means mark Kepler enrichment unavailable and proceed from Slack, Jira, Google Docs, and Granola evidence; `salesforce=hit` confirms the Team ID lookup in Step 4 will resolve.

Extract:
- customer pain points
- technical requirements
- what Postman demonstrated or should demonstrate
- executive sponsor and technical counterpart candidates
- concrete next steps
- architecture or platform details

If the transcript is too large to use comfortably, save it to a temp file and run:

```bash
python3 "${SKILL_DIR}/scripts/transcript_filter.py" /tmp/transcript.txt catalog MCP governance drift agent test contract health
```

Use the filtered output, not a lossy paraphrase.

### 3. Pull attached Google Docs from the Slack thread

Inspect thread attachments from the `slack_read_thread` result for Google Docs links (files appear in the `files[]` array on each message, with `url_private` / `permalink`). For broader searches, use `slack_search` with distinctive document or customer terms; there is no separate `slack_search_files`.

- Only fetch docs that are relevant to the engagement.
- If the document is public or directly readable, use the simplest successful approach.
- If the document is org-protected, use local `cse-tools` MCP `google_file_text(file_id=<doc-id>, format=docs_markdown)` first.
- If the MCP surface is unavailable, record Google Docs as unavailable and follow `cse-mcp-setup` rather than invoking an untracked helper.

Fold the useful Markdown content into the Jira issue.

### 4. Resolve the Salesforce Team ID

Team ID comes from `get_salesforce_account` — the Kepler DB caches the `Postman_Team__c` mirror so this is one MCP call with no live SFDC round-trip.

1. Read the canonical Salesforce account id from the Step 2 `context_assemble` identity or Salesforce card. If it is absent, use `list_customers` once to resolve it.
2. Use `get_salesforce_account` and that account id. It returns `team_id`, `team_arr`, and `teams[]` (every linked team record, with plan / license / renewal detail).

If the account has multiple `Postman_Team__c` records, `team_id` is promoted from the first record with a non-empty `Postman_Team_ID__c`. Inspect `teams[]` if a different team is in scope for the engagement (e.g. the requester's Jira thread names a specific team that is not the primary). If `team_id` is `null`, the account has no `Postman_Team__c` with an ID — stop, report the blocker (customer name + the teams the tool returned), and ask the user to confirm the correct team or whether Salesforce needs a new `Postman_Team__c` record.

### 5. Inspect current CSE board conventions in Jira

Before creating or repairing a ticket, inspect recent CSE issues when you are unsure about field conventions or current workflow expectations.

Reference points:
- Project key, gold-standard example, and field conventions: use `cse_domain_info` for stage/field discovery and a recent issue search to confirm current conventions before writing fields.

### 6. Create the CSE Engagement issue

Use `jira_create_issue` with `semantic_fields` (the daemon injects project key + issue type id, maps field ids, and wraps ADF fields automatically).

Before any create, perform these duplicate checks directly and `jira_search`:

Escape every dynamic value before interpolating it into a quoted JQL literal: first replace `\` with `\\`, then `"` with `\"`. Never splice raw customer names, Gong call IDs, or Slack timestamps into quotes unescaped.

1. Search open CSE issues by canonical customer with `jql: "project = CSE AND statusCategory != Done AND summary ~ \"\\\"<escaped canonical customer>\\\"\""`, `maxResults: 50`, and bounded fields `summary,status,description,customer_name,customer_assets`.
2. Search open CSE issues by the exact source identifier with `jql: "project = CSE AND statusCategory != Done AND text ~ \"\\\"<escaped Gong call ID or distinctive Slack timestamp>\\\"\""` and the same bounds. For a Slack permalink, use its stable message timestamp as the search token, then compare the full permalink in returned `customer_assets` or `description`.
3. Normalize the returned `customer_name` against the canonical identity from Step 2. If one open issue matches both the canonical customer and exact source, do not create; load that key with `jira_get_issue`, route it through Repair mode, and preserve the source evidence there. Customer-only or source-only matches are collision warnings: inspect them before deciding, but do not treat a different customer or different initiative as a duplicate.

Required semantic fields:
- Customer Name
- Team ID (from Salesforce)
- Primary Timezone
- Account ARR Tier
- Problem Statement (ADF -- wrapped automatically via `semantic_fields`)
- Executive Sponsor (customer-side)
- Technical Counterpart
- Impact Metrics (ADF -- wrapped automatically via `semantic_fields`)
- Postman Demonstration (ADF -- wrapped automatically via `semantic_fields`)
- Customer Assets (ADF -- wrapped automatically via `semantic_fields`)

**Team ID is a hard Jira schema constraint, not just a "required field".** Jira rejects issue creation when Team ID is absent. This means the resolve-or-escalate policy in step 6b (which applies post-create) cannot cover Team ID — it must be resolved before the create call. If step 4 returned `team_id: null`, do NOT create a partial ticket: stop and report the blocker with the customer name and returned `teams[]`. Never placeholder-string this field.

Also set:
- `labels`: use the intake label from `cse_domain_info`
- `description`: markdown summary with key context, account team roster, sourced links, and next steps
- `summary`: `<Customer Name> [<Engagement Category>]`

```js
cse_apply({
  capability: "jira_create_issue",
  arguments: {
    fields: {
      summary: "<Customer Name> [<Engagement Category>]",
      labels: ["<intake label from cse_domain_info>"]
    },
    semantic_fields: {
      customer_name: "<Customer Name>",
      team_id: "<Salesforce Team ID>",
      primary_timezone: "<Primary Timezone>",
      account_arr_tier: "<Account ARR Tier>",
      problem_statement: "<sourced problem statement>",
      executive_sponsor: "<customer-side sponsor>",
      technical_counterpart: "<named customer engineer>",
      impact_metrics: "<sourced impact metrics>",
      postman_demonstration: "<demonstration plan>",
      customer_assets: "<source permalink or Gong call ID>"
    }
  },
  execute: true,
  justification: "Preview a qualified CSE engagement from validated intake evidence"
})
cse_apply({
  capability: "jira_create_issue",
  arguments: {
    fields: {
      summary: "<Customer Name> [<Engagement Category>]",
      labels: ["<intake label from cse_domain_info>"]
    },
    semantic_fields: {
      customer_name: "<Customer Name>",
      team_id: "<Salesforce Team ID>",
      primary_timezone: "<Primary Timezone>",
      account_arr_tier: "<Account ARR Tier>",
      problem_statement: "<sourced problem statement>",
      executive_sponsor: "<customer-side sponsor>",
      technical_counterpart: "<named customer engineer>",
      impact_metrics: "<sourced impact metrics>",
      postman_demonstration: "<demonstration plan>",
      customer_assets: "<source permalink or Gong call ID>"
    },
    execute: true,
    preview_digest: "<preview_digest returned by dry-run>"
  },
  execute: true,
  justification: "Create a qualified CSE engagement from validated intake evidence"
})
```

After creation, post the intake-confirm comment. `originator_mention` means the originator's plain Jira display name in this comment, never `@` syntax or a mention node. If the display name cannot be resolved, skip the comment. Author the prose in `/tmp` before previewing and applying it:

```bash
cat > /tmp/cse-intake-confirm.md <<'EOF'
<Originator Display Name>, I opened this for the qualified implementation work. The next step is to connect the named customer engineer for the first working session.
EOF
```

```js
cse_apply({
  capability: "jira_add_comment",
  arguments: {
    key: "CSE-XX",
    body_path: "/tmp/cse-intake-confirm.md"
  },
  execute: true,
  justification: "Preview the intake-confirm comment for the originator"
})
cse_apply({
  capability: "jira_add_comment",
  arguments: {
    key: "CSE-XX",
    body_path: "/tmp/cse-intake-confirm.md",
    execute: true,
    preview_digest: "<preview_digest returned by dry-run>"
  },
  execute: true,
  justification: "Confirm qualified intake with the originating teammate"
})
```

### 6b. Fill data-quality fields via shared policy

After the issue exists, invoke the shared policy at `.agents/shared/resolve-or-escalate.md` for fields `executive_sponsor`, `technical_counterpart`, and `problem_statement`. The policy will:

- resolve values that the Slack thread or Gong transcript did not already populate (Gong 90d -> Salesforce -> brief -> Slack);
- post prose-voice comments only when the rubric warrants it; evidence, dates, and permalinks live on the `cse-dq` entity property, not in the visible comment body;
- if a field cannot be resolved, escalate once by naming the account team with display names (Jira plain ADF cannot render clickable mentions).

Do not write placeholder strings (`TBD`, `[Needs requester input]`) into the Jira field. If the policy cannot resolve it, the escalation comment replaces manual placeholder text.

The policy's stage gate suppresses escalation at `Submitted` and `Qualification Review`, which is where the ticket sits at this point -- resolution is still attempted, escalation is held until step 7 transitions the ticket into Technical Discovery. Remember which of `executive_sponsor`, `technical_counterpart`, and `problem_statement` remain unresolved after this pass; step 7b re-invokes the policy for those fields once status is Technical Discovery.

### 7. Advance through Qualification Review

To move the issue into **Technical Discovery**, execute two reachable single-hop transitions (discover stage and field semantics via `cse_domain_info`):
1. From **Submitted**, set `stage_complete` through `semantic_fields` and transition to **Qualification Review**.
2. From **Qualification Review**, transition to **Technical Discovery**.

Preview each hop separately and apply only with that hop's returned digest. Never request Technical Discovery directly from Submitted; the daemon rejects that target as unreachable.

```js
cse_apply({
  capability: "jira_transition_issue",
  arguments: {
    key: "CSE-XX",
    stage: "Qualification Review",
    semantic_fields: { stage_complete: "<configured complete value>" }
  },
  execute: true,
  justification: "Preview hop 1 into Qualification Review"
})
cse_apply({
  capability: "jira_transition_issue",
  arguments: {
    key: "CSE-XX",
    stage: "Qualification Review",
    semantic_fields: { stage_complete: "<configured complete value>" },
    execute: true,
    preview_digest: "<hop 1 preview_digest>"
  },
  execute: true,
  justification: "Advance the schema-complete intake into Qualification Review"
})
cse_apply({
  capability: "jira_transition_issue",
  arguments: {
    key: "CSE-XX",
    stage: "Technical Discovery"
  },
  execute: true,
  justification: "Preview hop 2 into Technical Discovery"
})
cse_apply({
  capability: "jira_transition_issue",
  arguments: {
    key: "CSE-XX",
    stage: "Technical Discovery",
    execute: true,
    preview_digest: "<hop 2 preview_digest>"
  },
  execute: true,
  justification: "Advance the qualified intake into Technical Discovery"
})
```

### 7b. Re-run resolve-or-escalate after Technical Discovery

Once hop 2 has landed the issue in **Technical Discovery**, re-invoke `.agents/shared/resolve-or-escalate.md` for any of `executive_sponsor`, `technical_counterpart`, and `problem_statement` that step 6b left unresolved. Pass the current status name (`Technical Discovery`) so `skip_escalation` is false. The policy posts at most one batched escalation under its existing `cse-dq` property cooldown and idempotency rules — do not invent a second escalation path, and do not re-escalate fields that 6b already resolved. Keep the two required direct hops and the step-6 duplicate JQL escaping unchanged.

### 8. Verify and correct

After creation or repair, verify:
- summary was not truncated
- Executive Sponsor is customer-side
- Team ID is populated and not `TBD`
- required fields are filled
- intake label is present
- status is **Technical Discovery**

Return the Jira issue key and URL plus a short note about any manual follow-up that remains.

## Batch & Repair Modes

The workflow above covers the single-ticket case. Handle these variants autonomously without asking the user per ticket.

### Batch mode

Triggered when the user pastes multiple Slack permalinks, names multiple customers, or says "intake all of these". For each input, run steps 1-8 as an independent ticket. Run Gong transcript fetches and Salesforce Team ID lookups in parallel across the batch where possible. Produce a summary table at the end: `Customer | CSE Key | Stage | Gaps`. If any ticket fails a required-field check, list the ticket in HELD with the specific gap rather than creating a partial ticket.

### Repair mode

Triggered when the user names an existing CSE-XX ticket ("repair CSE-53", "fix the VyStar ticket", "this ticket is missing fields"). Do not create a new ticket. Instead:

1. Load the existing ticket with `jira_get_issue`.
2. Diff current field values against the 10 required semantic fields.
3. For `executive_sponsor`, `technical_counterpart`, and `problem_statement`, invoke the shared policy at `.agents/shared/resolve-or-escalate.md`. The policy handles resolution (Gong 90d -> Salesforce -> Slack), field writes with evidence comments, and escalation that names account-team members by display name when a value cannot be auto-resolved.
4. For remaining fields not covered by the policy, reuse the account `context_assemble` result and exact Salesforce values from `get_salesforce_account`; write with `jira_edit_issue` (dry-run, then execute with the digest).
5. If the ticket is stuck in Qualification Review with all fields now filled, set `stage_complete` and transition to Technical Discovery.

Report the outcome with a RESULT block: transitions executed, fields updated with source citations, comments posted with the display-name reference target, and any HELD items with reason.

## Pitfalls

- Executive Sponsor is always customer-side.
- Jira textarea custom fields must use ADF; when using `semantic_fields` with `jira_create_issue` / `jira_edit_issue`, the daemon wraps ADF fields automatically.
- Jira automations may truncate the summary on transition (observed: "Accept and start qualification" rewrites summary to the customer name only). Re-check after every transition, and bundle the summary fix into the same `jira_edit_issue` capability call that sets `stage_complete` before the next transition.
- Direct Jira REST calls can silently omit requested semantic fields because of request-shaping differences. For field reads, always use `jira_search` (named query + bounded `fields`) or `jira_get_issue`. Do not hand-roll curl.
- Google Docs behind org auth should use local `cse-tools` MCP `google_file_text(file_id=<doc-id>, format=docs_markdown)`; follow `cse-mcp-setup` if that surface is unavailable.
- Gong transcripts can be large; filter them instead of skimming blindly.
- If the full Kepler upstream fails (5xx or timeout), continue from Slack, Jira, Google Docs, and Granola evidence. Do not add Kepler API-key env headers; normal Kepler auth comes from daemon keychain entries.

## Success criteria

The workflow is successful only when all of the following are true:
- the issue exists in Jira
- all 10 required semantic fields are populated
- Team ID came from Salesforce, not guesswork
- the issue is in **Technical Discovery**
- the summary follows `<Customer> [<Category>]`
- Slack, Gong, Google Docs, and Salesforce context have been incorporated when available
- the user receives the issue key and URL
