---
name: one-on-one-prep
description: Prepare a complete 1:1 agenda for a direct report. Use this skill whenever the user mentions "1:1 prep", "1 on 1 with <name>", "prep for my 1:1", "agenda for my 1:1", "1:1 in X minutes", or asks to pull context for an upcoming direct-report meeting. The skill pulls the report's activity from Slack, Jira, Kepler (Gong calls + email), and Confluence, researches engineering-leadership 1:1 best practices when useful, and outputs a timed agenda saved as a markdown file. Trigger even when the request is casual ("1:1 with Andrew is in 10 minutes, what should we talk about?").
argument-hint: "[report name | date | duration in minutes]"
---

# 1:1 Prep

## 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`, justification, and the returned `preview_digest`. Call `context_assemble` and `cse_session_info` directly when needed.
Worked hydration read:

```json
get_communications({"ids": ["<card citation id>"], "content_max_chars": 6000})
```

Pull the report's recent activity from Slack, Jira, Kepler (Gong calls + emails), and Confluence. Produce a timed, report-owned agenda and save it to `1on1s/<full-name-slug>/YYYY-MM-DD.md`.

## Domain Configuration

Use `cse_domain_info` for Jira field/stage discovery and pass semantic names to `jira_*` tools. The daemon resolves the Atlassian cloud ID; agents don't pass cloud IDs. If `cse_domain_info` is unavailable, consult the tool `inputSchema` list for Jira/Confluence discovery and surface an ambiguous project key rather than guessing.

This skill is tightly coupled to CSE work (CSE Jira project, `#cse-*` Slack channels, Kepler Gong/email). Global installs (`~/.claude/skills/`, `~/.factory/skills/`, `~/.codex/skills/`) act as invocation shortcuts; the session still needs to run against the `cse-tools` repo, or equivalent context, for file output and Jira scope.

## Voice

The two prose surfaces this skill writes -- the pre-meeting DM draft (phase 5) and any author-voice notes in the agenda body -- are written in the operator's voice.

- Operator voice selector: `$CSE_OPERATOR`; require it to resolve from bootstrap rather than assuming a person.
- Register rubric: `.agents/shared/prose-voice.md` (sentence-case, contractions, `--` dash palette, declarative cadence, two-facts-max, no em-dash, no emojis).

Before drafting a DM reply or any inline author-voice note, follow `.agents/shared/prose-voice.md` (and the `writing` skill) for operator voice. The main agenda body (headers, bullet structure, topic labels) uses neutral markdown register; only the operator-voice prose slots load the voice rules.

## Inputs

Accept any combination of:
- Direct report name (required — first + last, or just first if unambiguous)
- Meeting date (default: today)
- Meeting duration (default: 30 minutes)
- Specific topics to focus on, if surfaced by the user

## Setup

Source the bootstrap before starting so `CSE_TOOLD_BIN` and `CSE_OPERATOR` resolve. 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 and retry once. A 403 means access is blocked or revoked: surface the named operator action and stop without retrying. If the MCP connection is refused, run `cse-mcp-setup`, retry once, then stop precisely with `DATA UNAVAILABLE -- cse-tools daemon unreachable after recovery` if it remains refused. Prefer MCP tools for normal work; shared scripts are fallback/diagnostic helpers:

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

Required surfaces:
- **Read strategy:** Follow [`.agents/shared/read-strategy.md`](../../shared/read-strategy.md). Report context starts with one direct `context_assemble(kind:person)` call. Hydrate only specific quotes through direct reads; use the fallback ladder only when `context_assemble` itself is unavailable. The Phase 5 DM draft is authored, not sent.
- **Tool frugality:** Follow [`.agents/shared/tool-frugality.md`](../../shared/tool-frugality.md). Hydrate only evidence you'll cite; pass `verbosity:"full"` only when the raw upstream payload is necessary.
- **`context_assemble` (primary retrieval)** — local `cse-tools` MCP. One call replaces hand-run identity resolution and the per-source Slack/Jira/Kepler/Confluence/Granola/calendar fan-out. The daemon owns frugality, hydration, rerank, and the coverage manifest, so the per-tool guardrails below apply only to the targeted hydration you do *after* the call.
- **Hydration + fallback tools** (used to pull the full text of a specific card you'll cite, or as diagnostics if `context_assemble` is unavailable):
  - **Kepler** — `get_communications` (`content_max_chars=6000`; `body` and `transcript` are identical, read one) to read a transcript in full by its card `citation` id.
  - **Granola** — `granola_get_meetings(meeting_ids=[...])` (up to 10 IDs) for active-workspace meetings the working set referenced but did not hydrate. Use REST `granola_get_notes` only for a cross-workspace fallback note ID.
  - **Jira + Confluence** — `jira_*` / `confluence_*` for a deeper read on a surfaced ticket/page; request explicit `fields`, keep `maxResults` bounded.
  - **Slack** — `slack_read_thread` / `slack_read_channel` to expand a thread a card pointed at; for direct search prefer `q`, while `query` remains a compatibility alias.
- Web research via Exa or `mcp__ref__ref_search_documentation` — use **once per quarter** to refresh engineering-leadership 1:1 best practices; don't re-research every meeting.

If `context_assemble` is unavailable, fall back to per-source direct reads (`jira_lookup_user` + `slack_users` for identity, then `slack_search` / `jira_search` / `list_communications` / `semantic_context_search` / `confluence_search` / `granola_list_meetings` scoped to the report, followed by selected `granola_get_meetings`). This is the slow path the engine replaced; prefer the single call.

MCP servers are pre-configured in `.codex/config.toml` and `.claude/settings.local.json`. See [`plugins/cse-tools/AGENTS.md`](../../../AGENTS.md) for the keychain-backed auth flow; Kepler tools are surfaced inside `cse-tools`.

---

## Phase 1: Validate the direct report and assemble context

Before applying direct-report framing, resolve the named person with `orgchart_person_lookup`, then call `orgchart_reporting_line` and confirm the person's direct manager is the authenticated operator. If the person does not report directly to the operator, or either identity is ambiguous, stop with: `Cannot prepare a direct-report 1:1: <name> is not confirmed as reporting to <operator>.` Do not silently turn this into a peer or skip-level agenda.

After that validation, make a single `context_assemble` call. The daemon resolves Jira account ID and email and owns the per-source fan-out (Slack, Jira, Kepler comms, Kepler semantic, Granola, Confluence, calendar), bounded transcript hydration, the 0–10 rerank, dedup, and the coverage manifest. It does not return a Slack user ID: explicitly call `slack_users` and arguments `{action:"search", query:<resolved email>}`, require one exact profile, and record that profile's Slack ID. The identity triple is confirmed only when that Slack ID, the context result's Jira account ID, and its email all resolve to the same person.

```jsonc
context_assemble({
  entity: { kind: "person", ref: "<report name or email>" },
  facets: ["recent_activity", "open_loops", "blockers", "ownership", "tenure"],
  window: { since: "<ISO date ~21 days back>" },   // widen for a sparse report
  depth:  "branching"                               // second hop follows a ticket key named in a transcript
})
```

What comes back:
- `identity` — the resolved Jira account ID and email. If either is null, the report did not resolve cleanly; **fail loudly** and surface the ambiguity rather than prep on a guessed match. Complete the triple with the explicit `slack_users` lookup above.
- `working_set` — ranked, deduped cards, each with `source`, `claim`, `citation`, `kind` (`seed`/`transcript`), and `score`. Transcript cards are already hydrated.
- `coverage` — per-source `hit | empty | error | skipped`. Read it: `slack=empty` may be a rate-limit, not silence (note it as a gap, don't assert "no Slack activity"); `kg`/`salesforce=skipped` are expected for a person entity.

### After the call

1. **Transcripts are the highest-value input.** Use the bounded cited-call policy: review the call cards selected into the context pack, and fully hydrate every selected call that you intend to cite. Do not claim this is an exhaustive list of every call attended in the window. If a selected card's claim is truncated, hydrate it by its `citation` id with `get_communications` (`content_max_chars=6000`; `body` and `transcript` are identical — read one). For each cited call, pull:
   - Did they contribute, observe, or lead?
   - What did they actually say? Quote specific moments ("Andrew stepped in at 37:20 to demo the spec-hub button.").
   - Technical questions they asked — where they're stretching vs. lost.
   - Customer reaction to them (laughs, follow-ups, pushback).
2. **Open loops.** Scan Slack and transcript cards for anything the report asked you that you never answered. That's agenda gold — it becomes the first item in "My Topics" (and the Phase 5 DM draft).
3. **Connect signals.** Note OOO / sick mentions and low-stakes human threads (restaurants, hobbies, family) for the connect segment.
4. **Ticket hygiene + escalation.** For each active engagement ticket in the working set beyond Qualification Review, invoke the shared policy at `.agents/shared/resolve-or-escalate.md` with fields `executive_sponsor`, `technical_counterpart`. This fills gaps the report is stuck on and routes them to the account team, so the 1:1 itself doesn't become a ticket-grooming session.
5. **Tenure.** A bootcamp ticket, a recent role-move, or sparse Confluence/Jira history is a tenure cue — anchor the calibration header on it.

### Web research (once per quarter, not per meeting)
When you don't already have a good mental model for the report's role/tenure, search `engineering manager 1:1 best practices first 90 days direct report` via Exa or `mcp__ref__ref_search_documentation`. Themes to internalize:
- Report owns the agenda
- Connect before status
- Growth segment every meeting, never cut for tactical noise
- One positive + one growth feedback, kept specific
- Two-way feedback ask ("what's making your job harder?")
- First-90-days calibration on load and health signals

Do this search **once per quarter**; cache what you learn as a durable pattern. Don't re-research for every 1:1.

---

## Phase 3: Synthesize

### The principle

> The report drives the agenda. You listen, unblock, and coach. Status belongs in war room.

Every rule below serves that principle.

### Structure (30-min default)

```
0:00–0:04  Connect
           - How are they, really? (Watch for health/capacity signals.)
           - One low-stakes human thread pulled from Slack.
           - Open question with no work hook:
             "What's on your mind this week that has nothing to do with the ticket board?"

0:04–0:14  Report's Topics (their floor)
           - Let them lead.
           - If they're quiet, prompt with 2–3 specific items from their active work
             — as open questions, with no status grind:
               - "Which of these is eating the most of your head right now?"
               - "Where are you stuck vs. just waiting on customer?"
               - "What does 'done with X' look like, and what's in the way?"

0:14–0:22  My Topics & Support
           - 1–3 discrete topics, each with a clear decision or outcome.
          - One topic per issue; skip list-grinding.
           - If you found something they asked you and you never answered,
             raise it here first.

0:22–0:28  Growth & Alignment
           - Ramp calibration (tenure <90d): "Do you feel set up to succeed
             on this load, or are we overloading?"
          - Career direction — open question; avoid forcing an answer early in tenure.
           - Feedback: 1 positive + 1 growth, each tied to specific evidence.
           - Two-way ask: "What's one thing I'm doing that's making your job
             harder?" Leave silence. Don't fill it.
           - Leadership alignment: anything coming down they should know?

0:28–0:30  Close — Action Items
           - Write them in the meeting.
           - Owner is specific. By-When is specific.
```

Scale proportionally for longer or shorter meetings. **Never cut growth.** If time is tight, cut manager topics first.

### Calibration rules

- **Tenure <90 days:** Add an explicit "don't read aloud" header to your notes capturing bootcamp-close date, tickets landed since, any sick days, role-move context. Calibrate your asks to a new hire.
- **Recently sick / OOO:** Start with genuine check-in energy. Don't treat it as throat-clearing to get to the agenda.
- **They flagged something you never answered:** That's the first topic in "My Topics". Close the open loop before anything else.
- **Kepler shows them contributing one moment on a call:** Name it specifically in Growth as a positive. "On the Apr 8 call at 37:20 you stepped in to demo X — that was the right instinct." Don't generalize.
- **Kepler shows them as pure observer on a learning-surface call:** Ask what's clicking and what's still fuzzy. Don't grade attendance.
- **Heavy Jira load early in tenure:** Don't use manager topics to add more work. Use them to subtract or sequence.

### Sensitive / post-call filter

Items that should NOT be in the main agenda body:
- Negative feedback about other team members (keep for your own prep notes)
- Leadership info they don't need yet (headcount, comp, org changes)
- Customer-sensitive content (churn risk at exec level, legal, off-record feedback)

Collect in a `## Notes / Followups (capture post-call)` section at the bottom. This is personal memory for the next meeting.

### Source citations (end of file)

Include a final `### Source citations` section containing one bullet per source actually used. Use this local schema: `- [Source type] <stable ID or query> — <ISO date or bounded date range> — <claim supported>`. Source types are `Jira`, `Kepler call`, `Slack`, `Confluence`, and `Web`; Jira bullets use issue keys, Kepler bullets use communication IDs, Slack bullets use a permalink or DM date range, Confluence bullets use page ID/CQL, and Web bullets use a URL. This makes the file reproducible and debuggable.

---

## Phase 4: Output

### File path

Create a stable full-name slug by lowercasing the resolved full name, replacing each run of non-alphanumeric characters with `-`, and trimming leading/trailing hyphens. Save to `1on1s/<full-name-slug>/YYYY-MM-DD.md` using today's date (or the meeting date if different). Create the directory if missing.

If `1on1s/` is not in `.gitignore`, add the pattern `1on1s/` to `.gitignore` without asking -- 1:1 notes are personal and should never be committed. If the user later wants them tracked, they can reverse the change.

Resolve the repository root dynamically from the loaded plugin root (`PLUGIN_ROOT`, `DROID_PLUGIN_ROOT`, or `CLAUDE_PLUGIN_ROOT`) by walking two parent directories from `plugins/cse-tools`; if invoked from a checkout without one of those variables, walk upward from cwd until the repository `AGENTS.md` and `plugins/cse-tools` are both present. If no repository root resolves and the user did not specify a destination, stop and ask for a destination rather than guessing a machine-specific path.

### Opening header

```markdown
# 1:1 — <Full Name>
**Date:** YYYY-MM-DD | **Duration:** <N> min | **Role:** <title + team>
**Tenure:** <if <90d, give a concrete anchor — bootcamp-close date, team-move ticket, etc.>

> **Principle for this 1:1:** The report drives the agenda. My job is to listen, unblock, and coach. Status belongs in war room.
>
> **Important context to hold (don't read aloud):** <2–4 lines of calibration — tenure, load, health, anything steering your tone>
```

### Body

Follow the timed structure above. Every manager topic should tie to a decision or action; no grinding through their ticket board.

Use specific prompts the report can actually answer. Avoid platitudes ("how's everything going?") — those get empty answers.

### Close section

Action items as checkboxes with specific owner + by-when. Add a `## Notes / Followups (capture post-call)` section listing 3–5 themes to watch over the next 4 weeks. These feed next meeting's calibration header.

---

## Phase 5: Pre-meeting action (optional, autonomous)

If the Phase 1 open-loop scan surfaced a question the report asked you that you never answered, draft a short DM reply and save it inside the agenda file under a new section:

```markdown
## Pre-meeting DM draft (send before the 1:1)

> **To:** <report's first name>
> **Context:** <2-3 words: what they asked, when>
> **Draft:** <1-3 sentence reply closing the loop>
```

Do not send the DM automatically. This is a loop-closing draft you can paste-send from Slack in under 30 seconds before walking into the meeting.

If no open loop exists, omit the section.

## Validation checklist (run before writing the file)

- [ ] Orgchart confirms the person reports directly to the authenticated operator
- [ ] Report's identity triple-confirmed (explicit `slack_users` Slack ID + context Jira accountId + email)
- [ ] Every bounded context-pack call cited in the agenda was hydrated in full; the agenda does not claim exhaustive 14-day call coverage
- [ ] Any open question from the report to you (in DMs or calls) is surfaced in "My Topics"
- [ ] Growth segment is present and specific (one positive + one growth, both with evidence)
- [ ] Action items have specific owners and by-when dates
- [ ] Sensitive items are confined to the post-call section
- [ ] File is saved to `1on1s/<full-name-slug>/YYYY-MM-DD.md`
- [ ] Source citations block is present at the end

---

## Behavioral rules

- The report drives the agenda. Your topics are second.
- Connect before status. Every time. Even when you're running behind.
- Growth is not optional. Cut manager topics before cutting growth.
- Transcripts beat ticket boards — what they said on a call tells you more than how many tickets they're assigned.
- One positive + one growth feedback, each tied to specific evidence.
- Two-way feedback is a real ask. Leave the silence after you ask.
- Never fabricate activity. No signal = say so in your pre-read; don't invent engagement they didn't have.
- The output is copy-paste ready for you to hold in the meeting. No tool attribution, no hedging, no meta-commentary about sources in the body — that belongs in the citations block at the bottom.
