with one click
xx-introspect
use to learn from existing coding sessions, or record hints
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
use to learn from existing coding sessions, or record hints
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | xx-introspect |
| description | use to learn from existing coding sessions, or record hints |
Three subcommands:
/xx-introspect extract — run the extraction pipeline against accumulated transcripts./xx-introspect hint — author, list, or retire human-authored hints that act as strong, single-shot seeds in the next cluster pass./xx-introspect load — detect the current session's activity and load the matching introspect-<activity> skill.The orchestrating Claude (you, in the user's session) executes every command on the user's behalf and surfaces every model judgment to the user for approval before writing. This skill is about extracting the user's taste — not Claude's. Don't run silent disambiguation, silent clustering, or silent file writes. Don't ask the user to copy-paste shell invocations either; you have the Bash tool, run them yourself.
The only steps that don't need user approval are deterministic, no-op-on-failure reads (normalize, classify, detect, view). Everything that involves judgment (3a disambiguation, 5 clustering, 6 drafting) or that writes user-facing artifacts (7 write-back) is a checkpoint where the user decides.
~/.claude/skills/introspect-<activity>/SKILL.md # produced output, loaded on demand
~/.claude/introspect-state.json # run history + processed-session pointers
~/.claude/introspect/cache/<run-id>/ # intermediate stages of one run
~/.claude/introspect/hints/<activity>/<slug>.md # human-authored hints (issue#19)
~/.claude/introspect/versions/vN/ # post-run snapshots for diffing
~/.claude/settings.json # permission entries written here
/xx-introspect extractAsk the user which transcripts to read. Three options:
[1] current repo → ~/.claude/projects/<repo-slug-of-cwd>/*.jsonl
[2] all projects → ~/.claude/projects/*/*.jsonl
[3] select → list project dirs, user picks subset
If cwd doesn't have a corresponding ~/.claude/projects/<slug>/ (slug = cwd path with / → -), current repo is unavailable and the user must pick from all or select.
For dogfood/testing, the user may pass an explicit slug: /xx-introspect extract --project charon (resolves to -Users-xianxu-workspace-charon).
python3 $REPO_ROOT/construct/local/introspect/scripts/normalize.py \
--scope <choice> \
[--project <slug>] \
[--cwd "$PWD"] # only when --scope current; defaults to os.getcwd()
[--since <last_run_at-from-state>] \
--out ~/.claude/introspect/cache/<run-id>/
Outputs:
sessions.json — one record per session: id, start, end, cwd, gitBranch, message counts, tool counts, slash commands invoked, files touchedrun.json — meta-record of the run (scope, projects, file/event counts, since filter)A flat events.jsonl stream will be added in M2/M3 once detectors need to walk events outside of session aggregates. Until then the raw JSONL files remain the source of truth for downstream stages.
Run-id format: YYYYMMDDTHHMMSS.
Postmortem runs are infrequent (weekly/biweekly), so we classify with model judgment rather than rules. The previous rule-based pass added precision overhead without enough recall to justify the maintenance — the rules under-classified by ~60% on the dogfood corpus and missed systematic categories like "user laying out a product vision is brainstorming" and "first-message-is-an-error-trace is debugging."
The orchestrating Claude classifies every session in sessions.json directly:
Procedure:
sessions.json. For each session record, gather: first_user_message, slash_commands, tool_calls_by_name, file write/edit/read counts, user/assistant message counts.assistant_message_count == 0 — emit activity: "skip", skip_reason: "no assistant messages". These are degenerate sessions.code-review, brainstorming, planning, debugging, implementation, exploration, out-of-scope (personal/non-code), ambiguous (genuinely uncertain)./security-review, /review, /ultrareview are strong code-review markers when they're the originating intent (not a sub-task within a longer session).ambiguous. Precision over recall — ambiguous rows are filtered out of clustering downstream, which is the right outcome when we don't trust the bucket.<run-dir>/classified.json:
confidence: "llm" for rows accepted as-proposedconfidence: "user" for rows the user overrodeconfidence: null for skip rowsskip, out-of-scope, and ambiguous rows. They don't contribute moments to any introspect-<activity> skill.scripts/classify.py (legacy): the rule-based scorer is retained in the repo as a baseline reference but is no longer part of the canonical flow. It's fine to consult it for a quick sanity check, but don't rely on it for the classified.json that drives downstream stages.
python3 $REPO_ROOT/construct/local/introspect/scripts/detect.py \
--cache-dir ~/.claude/introspect/cache/<run-id>/
Walks the raw JSONL for each non-skip session in classified.json, runs four detectors, emits moments.jsonl (one record per line) plus moments-summary.json.
Detector types:
redirect — user negates/redirects after assistant actionendorsement — user reacts positively to assistant actionedit-after-edit — assistant re-edits same file ≥3 times within 5-turn window with no user message between (one moment per file with count, not per pair)friction — same tool gets ≥3 explicit errors (is_error: true or Exit code N + friction-keyword)Two more detectors (taste-fingerprint requires git-diff correlation; process-shape requires cross-session aggregation) are deferred.
Each moment carries {session_id, project_slug, activity, type, ts, weight, evidence}. The evidence shape is type-specific.
This stage is a guided conversation. Do not write code that auto-clusters. The point of v1 is to build user-confirmed clusters by hand so we know what should group together before automating.
Preconditions:
out-of-scope, unknown, ambiguous, or skip. ambiguous is allowed to persist — for any row where the user (or you reasoning on their behalf) couldn't confidently pick a bucket, leaving it ambiguous is correct. Precision over recall: clustering operates on signal we trust, not signal we hope.out-of-scope, unknown, ambiguous, and skip rows are all filtered out before the cluster loop begins. Their moments are excluded from any introspect-<activity> skill draft.Iteration order: outer loop is activity, inner loop is type.
Process each in-taxonomy activity in descending session-count order (most data first). Within each activity, walk type buckets in this order — highest taste signal first:
redirect — explicit user correctionfriction — actionable tool/permission failuresendorsement with weight=2 — tool-backed acceptance (skip weight=1 text-only rows in v1)edit-after-edit — only cluster if a recurring file/area pattern is visibleSkip (activity, type) buckets that have fewer than 3 moments OR fewer than 2 distinct sessions — see "Skip thresholds" below.
Pagination loop:
For each (activity, type) bucket with ≥3 moments:
python3 $REPO_ROOT/construct/local/introspect/scripts/view_moments.py \
--cache-dir <run-dir> \
--activity <activity> \
--type <type> \
--limit 12
Read the page. For each page, propose 1-3 candidate cluster names that group similar moments, citing moment IDs. Format:
Cluster proposal 1: "user pushes back when assistant assumes file structure without checking"
evidence: [m_4c6e82bd4b, m_1bfd21350a, m_4b20568e3c]
rule sketch: Before writing to a path, verify the file exists and the
enclosing directory layout matches what the user expects.
Ask the user to: (a) accept, (b) merge with another proposal, (c) split off a moment, (d) discard. After each page, page forward (--offset) until the bucket is exhausted.
Cross-bucket merging: at the end of an activity (after walking all four types), ask the user whether any cross-type clusters within this activity should merge (e.g., a redirect cluster about "verify before writing" and a friction cluster about Bash permission failures might both signal "check before acting"). Merged clusters keep one combined moment_ids list and stay assigned to the current activity — there is no cross-activity merging in v1, since each activity will produce its own introspect-<activity> skill anyway.
Persist clusters: at end of each activity, write the accepted cluster set to <run-dir>/clusters/<activity>.json:
{
"activity": "implementation",
"clusters": [
{
"id": "c_impl_1",
"name": "...",
"rule_sketch": "...",
"moment_ids": ["m_4c6e82bd4b", "m_1bfd21350a", ...],
"moment_count": 3,
"session_count": 2
}
]
}
Skip thresholds:
Hint-aware ordering (issue#19). When reviewing the v1.1 clusters.json produced by introspect-extract.sh, hint-sourced clusters (source: "hint") bypass the threshold check — each is its own pre-formed cluster the user already endorsed by authoring. Surface them to the user first, in this order:
retirement_candidate: true). Show the hint's rule alongside the contradicting_evidence excerpts. Three actions:
~/.claude/introspect/hints/<activity>/<slug>.md, let user revise, save.rm ~/.claude/introspect/hints/<activity>/<slug>.md).
The retirement decision affects the hints/ directory directly, not just this run's clusters.json.source field) — proceed with the normal threshold/walk flow.Hints are never treated as ambiguous. The user authored them explicitly; precision-over-recall doesn't apply.
For each activity that has ≥1 accepted cluster, draft:
~/.claude/skills/introspect-<activity>/SKILL.md (only the draft — write-back is Stage 7):
---
name: introspect-<activity>
description: Use when the current session is doing <activity> work — extracted from past sessions where the user redirected, endorsed, or struggled. Loaded by /xx-introspect load when activity is detected.
version: <N>
generated_from_run: <run-id>
generated_at: <iso-ts>
---
# Notes from past <activity> sessions
## Rule: <rule name from cluster>
<the rule, written as a directive to a future Claude. Include the *why*
when the cluster's evidence makes it clear.>
**Evidence:** `<moment-id>`, `<moment-id>`, ... (3 moments, 2 sessions)
## Rule: <next>
...
Hint-sourced rules (issue#19). For clusters with source: "hint", render with Source: human hint in place of **Evidence:**. Optionally include the hint_created date. The full block:
## Rule: <hint name>
<hint rule body>
**Source:** human hint (authored <hint_created>)
This makes hint-sourced rules distinguishable from extracted ones at a glance, and means a future pipeline run reading the deployed SKILL.md can tell which rules came from hints without consulting the cache. (See "Round-trip safety" below.)
Permission additions (one entry per friction cluster targeting the same tool/command):
{
"permissions": {
"allow": [
"Bash(gh pr view:*)",
...
]
}
}
Each permission entry carries an inline comment-style note in the draft showing the friction count and example error, so the user can audit.
Provenance file: <run-dir>/drafts/<activity>.evidence.json (sibling, NOT inside the SKILL.md draft — two YAML frontmatters in one file is malformed). Schema:
{
"activity": "implementation",
"rules": [
{
"rule_name": "...",
"moment_ids": ["m_4c6e82bd4b", "m_1bfd21350a", ...],
"moment_excerpts": [
{"id": "m_4c6e82bd4b", "type": "redirect", "session": "74cf212a", "excerpt": "..."}
]
}
]
}
The user can audit any rule back to its source moments before accepting in Stage 7.
Not yet implemented. After drafts are generated, present diff-style and let the user accept/reject per cluster. Accepted drafts get atomic-write to ~/.claude/skills/introspect-<activity>/SKILL.md and ~/.claude/settings.json.
/xx-introspect hintAuthor, list, or retire human hints — strong, single-shot signals that the next cluster pass treats as their own pre-formed cluster (bypassing the ≥2-segment threshold that gates extracted patterns). Hints are stored as small markdown files under ~/.claude/introspect/hints/<activity>/<slug>.md. They are eligible for retirement, not frozen: if a future run finds transcript evidence contradicting a hint, the user is prompted at review time to keep / edit / retire it. (See issue#19 for full semantics.)
/xx-introspect hint <activity> "<rule>" # authoring mode
/xx-introspect hint # authoring mode, infer activity
/xx-introspect hint --list [<activity>] # list existing hints
/xx-introspect hint --retire <slug> # delete a hint file
When the user invokes /xx-introspect hint, with or without args:
<activity> was passed, validate it against the five-bucket taxonomy:
debugging, exploration, planning, implementation, brainstorming.
(Note: code-review is a classification bucket but does not have a deployed introspect-code-review skill yet, so hints there have no destination — reject for now.)-2, -3, … until unique.~/.claude/introspect/hints/<activity>/<slug>.md. Don't prompt again after confirmation — one round-trip.Hint file format:
---
activity: <one of the five buckets>
created: <YYYY-MM-DD>
---
## Rule: <imperative title>
<rule body — one or two short paragraphs, directive voice, same shape as a
rendered cluster rule.>
**Why:** <optional rationale — past incident, strong preference, etc.>
/xx-introspect hint --list walks ~/.claude/introspect/hints/ and prints, per activity:
## Rule: line)--list <activity> filters to one activity bucket.
This is a deterministic read; no LLM call, no user approval needed. Just tabulate and print.
/xx-introspect hint --retire <slug> deletes the matching hint file. Behaviors:
Retirement is hard delete — no tombstone. Re-authoring with the same slug creates a new hint with a fresh created date.
The same retirement effect can be achieved during cluster review (Stage 5+) when a hint surfaces as a retirement_candidate; this CLI form is for proactive cleanup outside a pipeline run.
Hint authoring is the only xx-introspect flow where the orchestrating Claude writes user-global state without a multi-step user-in-the-loop — because the user has already supplied the rule explicitly, and a one-round-trip confirm-and-write is the right friction level for "I have a hint to capture, capture it."
/xx-introspect loadNot yet implemented (M6). Placeholder: report "load subcommand pending — once introspect- skills exist at ~/.claude/skills/, this will detect activity and Skill-invoke the right one."
~/.claude/introspect-state.json:
{
"schema_version": 1,
"last_run_at": "2026-04-30T18:00:00Z",
"processed_session_ids": ["uuid1", "uuid2"],
"runs": [
{
"id": "20260430T180000",
"ts": "2026-04-30T18:00:00Z",
"scope": "charon",
"session_count": 6,
"version_pointer": null
}
]
}
Initialize as {"schema_version": 1, "last_run_at": null, "processed_session_ids": [], "runs": []} if the file doesn't exist.
~/.claude/. Never write to repo-local .claude/skills/ from this skill.introspect-<activity> skill without an explicit user accept.introspect/cache/<run-id>/ directory is keep-forever for now (small JSON). M7 versioning will introduce pruning.Use when 🤖{} or 🤖[] or 🤖~~ markers appear in markdown documents
Use when the user is requesting an artifact (capture, save, record, create) AND the substance to preserve is conversational context they've already produced. Skip when the user is stating facts, asking questions, or asking the agent to generate substance from scratch. Also trigger when editing markdown with known frontmatter type:
Use when editing issues in workshop/issues/.
Use to process interview feedback
apply a voice style
Generate a writing style guide