| name | employee-profile-extraction |
|---|---|
| description | Extracts a generalized employee profile from the user's full Copilot CLI session history. Invoke to understand who someone is, what they do, and how they work — not what they did last week. |
Build a generalized employee profile from Copilot CLI local session data. Produces a structural description of role, work inboxes, competencies, and work patterns — like an employee description, not a sprint report.
Wave 1: Collect Wave 1.5: Engagement Wave 2: Classify Wave 3: Synthesize
──────────────── ────────────────── ──────────────── ─────────────────
Session store SQL → Turn-gap analysis → Parallel sub-agents → Single Opus agent
sessions per-session: ~15 sessions each reads classified
turns (turn 0) - steering turns classify each by: + engagement data
checkpoints - reviewing turns - category produces profile
files touched - autonomous turns - domain JSON
refs (PRs/issues) → engagement_mode - complexity
FTS5 search per session - role signal Wave 4: Present
- derived pattern ─────────────────
- engagement_mode Format tables
Anti-overfitting: Publish gist
1 branch = 1 vote
normalize by category
drop sprint-specific
Data source: session_store database (read-only, database: "session_store").
-- Schema you need:
-- sessions: id, cwd, repository, branch, summary, created_at
-- turns: session_id, turn_index, user_message, assistant_response
-- checkpoints: session_id, checkpoint_number, title, overview, work_done, next_steps
-- session_files: session_id, file_path, tool_name
-- session_refs: session_id, ref_type (commit/pr/issue), ref_value
-- search_index: FTS5 (content, session_id, source_type) — use MATCH for full-text
-- Start here: all sessions, no time filter
SELECT id, repository, branch, summary, created_at FROM sessions ORDER BY created_at DESC;For each real session (filter out automated/verifier noise — short summaries, repetitive bot patterns), collect:
- First user message (
turnswhereturn_index = 0) — this is the intent signal - Checkpoint overviews — these are work summaries
- Files touched — these reveal technical domains
- Refs — these reveal collaboration surface (PRs, issues)
- Repository + branch — these reveal project scope
Export to JSON backup files under /tmp/profile-extraction/. SQLite is the working copy; JSON is the safety net.
Scale: Expect hundreds to thousands of sessions. Batch into sub-agents of ~15 sessions each. Do not try to fit all session content into one context window.
Compute turn-to-turn time gaps per session. The gap between a user's message and their next message reveals whether the human was present, reviewing, or gone.
-- Per-session: compute gap between consecutive user turns
SELECT t1.session_id, t1.turn_index,
ROUND((julianday(t2.timestamp) - julianday(t1.timestamp)) * 24 * 60, 1) as gap_minutes,
substr(t1.user_message, 1, 100) as msg
FROM turns t1
JOIN turns t2 ON t2.session_id = t1.session_id AND t2.turn_index = t1.turn_index + 1
ORDER BY t1.session_id, t1.turn_index| Mode | Gap | Keyword signals | Human posture |
|---|---|---|---|
| Hands-on | <5 min | Corrections, follow-ups, frustration markers ("srsly?", "wtf") | Sitting at the problem. Active co-pilot usage. Rapid steering, real-time course correction. |
| Reviewing | 5–60 min | Questions, "what about...", "is this right?" | Reading AI output, thinking, then giving next direction. Side-by-side but not real-time. |
| Orchestrating | >60 min | "autopilot", "GO", "trust you", "fire and forget", TODO lists | Human left. Agent runs autonomously. Human returns later to inspect results and steer next phase. |
Classify each session by its dominant mode (plurality of turns):
-- Aggregate per session
SELECT session_id,
COUNT(*) as total_turns,
SUM(CASE WHEN gap_minutes < 5 THEN 1 ELSE 0 END) as hands_on,
SUM(CASE WHEN gap_minutes BETWEEN 5 AND 60 THEN 1 ELSE 0 END) as reviewing,
SUM(CASE WHEN gap_minutes > 60 THEN 1 ELSE 0 END) as orchestrating
FROM turn_gaps
GROUP BY session_idAssign engagement_mode per session: hands-on, reviewing, orchestrating, or mixed (no mode >50%).
Also compute per-session:
session_span_hours: time from first to last turn — reveals multi-day vs single-sitting workovernight_gaps: count of gaps >8h — reveals fire-and-forget patterns
Pass engagement_mode, session_span_hours, and mode distribution to Wave 2 classifiers as metadata alongside the session content. This lets classifiers answer: "Does this person orchestrate perf work but hands-on steer public-facing artifacts?"
The synthesis agent (Wave 3) receives aggregated engagement data:
- Distribution of engagement modes across all sessions
- Engagement mode × task category cross-tabulation (e.g., "orchestrates CI triage, hands-on for review feedback")
- This populates the
ai_integration_profileandcollaboration_profile.delegation_stylesections
Launch parallel sub-agents (~15 sessions per agent). Each agent receives full context for its batch (summary, first user message, checkpoints, files, refs) and classifies each session:
{
"session_id": "...",
"task_category": "...", // derive from data, don't hardcode list
"domain": "...", // technical domain
"complexity": "low|medium|high|extreme",
"role_signal": "...", // what this says about who the person IS
"derived_pattern": "..." // generalizable work pattern (1 sentence)
}Bootstrap the taxonomy. Do NOT use a hardcoded category list. First agent gets a stratified sample and proposes categories. Remaining agents use that taxonomy. Refine after: merge categories with <5 sessions, split categories with >30% of total.
Store all classifications in the session SQLite database. Aggregate:
- Category distribution (count + percentage)
- Complexity distribution
- Role signal frequency
- Derived patterns grouped by category
- Normalize by category, not volume. One branch = one vote. 150 sessions on one branch ≠ 150× weight. It's one instance of one category.
- Distinguish sprint work from role pattern. If it wouldn't appear in a different 3-week window 6 months from now, it's sprint work — collapse it into its category, don't feature it.
- Automated sessions are metadata, not content. If the user ran 200 automated verification loops, that's evidence of one pattern ("uses autonomous verification fleets"), not 200 data points.
- Generalize, don't transcribe. "Root-cause debugging across compiler subsystems" is a pattern. "Fixed NRE in layoutTyparRef on line 732" is a sprint artifact.
Single Opus agent. Receives ONLY:
- Aggregated category/complexity distributions (SQL output)
- Deduplicated role signals
- Derived patterns grouped by category
- Repository distribution
- Communication style signals (from user messages — tone, instruction patterns, quality standards)
Does NOT receive: raw turns, full checkpoint text, file paths, PR numbers.
Produces profile JSON with these sections:
| Section | Content | Rules |
|---|---|---|
profile_title |
Role title | 5 words max |
one_liner |
Who they are | 1 sentence |
work_inboxes |
Structural input channels | Name the channel + source + shape + processing pattern. NO specific items. |
work_dimensions |
What they do, with time % | Must sum to 100%. Cross-reference with any self-reported allocation if found in session data. |
core_competencies |
What they're good at | evidence_strength: strong (3+ sessions) / moderate (2) / signal (1) |
engineering_philosophy |
How they think | Universal principles, not project-specific rules |
ai_integration_profile |
How they use AI | Structural patterns, not specific tool invocations |
collaboration_profile |
How they work with others | Mentoring, review style, delegation, communication |
tools_and_systems |
Repos, platforms, frameworks | Structural names only |
distinguishing_traits |
What makes them stand out | Would survive a job change |
growth_vectors |
Where they're investing | Forward-looking |
- Name inboxes structurally: "GitHub review-requested PRs in {repo}" — not "PR #19505"
- Name repos, labels, queue mechanisms, flow shapes. Not current contents.
- NO PR numbers, branch names, issue numbers, commit SHAs in the profile body.
- NO function names or file paths unless they represent stable subsystems.
- Evidence appendix (max 10 entries): short grounding statements to prove claims. Only place where specifics are allowed.
Render two markdown tables:
- Work Inboxes — channel / source / shape / processing
- Work Dimensions — dimension / % / description
Publish to a GitHub gist via gh gist create.
- No single feature/branch dominates >1 table row
- Every work dimension would appear in a different 3-week sample
- Inboxes describe channels, not current items
- Profile reads as employee description, not data analysis output
- Zero PR numbers, branch names, or commit SHAs outside evidence appendix
- Time percentages sum to 100% and cross-check against self-reported allocation if available
- Automated/bot sessions collapsed into pattern evidence, not inflated as volume