Analyze the current conversation, extract valuable insights, and save them as structured notes in the Obsidian vault. Supports both interactive multi-insight selection and targeted single-topic extraction.
Follow these steps exactly. Do not skip steps or reorder them.
Stop here if config is missing.
Stop here if FAIL.
Run a single Python call to search the vault index for existing notes matching the topic:
Parse the JSON output. If the script exits non-zero or the output cannot be parsed as JSON, treat it as {"match": false} and proceed silently (log a note: "Could not search vault index; creating new note.").
Wait for the user's response:
- "update" โ Go to Step 4A-update.
- "create new" โ Go to Step 4A (create new note as before).
Step 4A โ Single-topic extraction
Analyze the current conversation for content related to the user's specified topic. Draft a note that includes:
- Summary: 2-4 sentence overview of the topic as discussed in this session
- Details: Key points, code snippets, configurations, or commands relevant to the topic
- Context: Why this came up, what problem it solved, any trade-offs discussed
Skip to Step 5.
Step 4A-update โ Append to existing note
This step is reached when the user chose "update" in Step 3.5. The matched note path is $MATCH_PATH.
4A-update.1 โ Read the existing note
Use the Read tool to read the full contents of $MATCH_PATH. Note the existing frontmatter tags and whether a last_updated field is already present.
4A-update.2 โ Draft the update section
Analyze the current conversation for content related to the topic. Draft a dated update section:
## Update (YYYY-MM-DD)
<New content about this topic from today's session. Include:
- New findings, corrections, or extensions to the original insight
- Code snippets or commands if relevant
- Context on why this update was triggered>
Where YYYY-MM-DD is today's date.
Important: Do NOT rewrite or duplicate existing content. The update section captures only what is NEW from this session.
4A-update.3 โ Show preview and ask for edits
Present ONLY the new update section (not the full existing note):
Update section to append to "< existing note title>":
(show the drafted ## Update (YYYY-MM-DD) section)
Preview above. Would you like to:
- save โ append this update
- edit content โ tell me what to change
- cancel โ discard this update
Wait for the user's response. Apply edits and re-show if requested. Repeat until the user says save or cancel.
If cancel, stop here.
4A-update.4 โ Append the update section
Use the Edit tool to append the update section to the note body.
Insertion point: Scan the note from the bottom for these trailing metadata patterns: _(Summary source: ...)_, ## Tool Usage, ## Conversation (raw), ## Session Metadata, ## Files Touched. If any are found, insert the update section on a new line immediately BEFORE the first trailing section. If none are found, append at the very end of the file.
Use the Edit tool with the first line of the trailing section (or the last line of the file) as old_string, and prepend the update section + a blank line before it.
Verify: After the Edit, use the Read tool to confirm the ## Update (YYYY-MM-DD) heading is present in the note. If it is not, tell the user: "Failed to append update section โ file may have unexpected structure. Please edit manually at $MATCH_PATH." Do NOT proceed to 4A-update.5 if the append failed.
4A-update.5 โ Update frontmatter
Use the Edit tool to update the frontmatter of the existing note:
-
last_updated field: If last_updated: already exists in the frontmatter, replace its value with today's date. If it does not exist, add last_updated: YYYY-MM-DD after the date: line.
-
New topic tags: Generate 1-3 topic tags from the update content (same logic as Step 5). For each new tag, check if it already exists in the tags: list. Only append tags that are NOT already present. Add new tags at the end of the tags list, before the closing ---.
Do NOT change: date, source_session, source_session_note, or type fields. These record the original creation context.
4A-update.6 โ Re-sync vault index
Run:
cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
python3 -c '
import sys, os
import glob; sys.path.insert(0, max(glob.glob(os.path.expanduser("~/.claude/plugins/cache/*/obsidian-brain/*/hooks")), default="hooks"))
from vault_index import ensure_index
from obsidian_utils import load_config
c = load_config()
vp = c["vault_path"]
folders = [c.get("sessions_folder", "claude-sessions"), c.get("insights_folder", "claude-insights")]
try:
ensure_index(vp, folders)
print("OK")
except Exception as e:
print(f"WARN: re-sync failed (non-fatal): {e}")
'
4A-update.7 โ Confirm
Print:
Note updated!
- File:
$MATCH_PATH
- Added section: "Update (YYYY-MM-DD)"
- New tags:
<list of newly added tags> (or "none")
Skip to Step 10 (offer follow-up). Do NOT proceed through Steps 5-9 (those are the create-new flow).
Step 4B โ Multi-insight suggestion
First, check for claudeception output using layered detection:
Layer 1 โ High-confidence structured markers (check first):
Scan the current conversation for these patterns. If found, extract the skill/knowledge name and a one-line summary:
- The
MANDATORY SKILL EVALUATION REQUIRED banner (from the claudeception activator hook)
Result: PASS or Result: FAIL (from the claudeception skill validator)
- Skill file paths matching
~/.claude/skills/*/SKILL.md or .claude/skills/*/SKILL.md
If any Layer 1 markers are found, create a candidate for each and label it [from claudeception].
Layer 2 โ Broad phrase scanning (fallback, only if Layer 1 found nothing):
Scan the conversation for these phrases:
- "created skill", "new skill at", "skill file written"
- "extracted knowledge", "pattern identified", "reusable insight"
- Output from a
/claudeception invocation
If any Layer 2 phrases are found, create a candidate for each and label it [possibly from claudeception].
Then, perform standard insight discovery:
Analyze the full conversation and identify 3-5 additional candidate insights (beyond any claudeception candidates). Each candidate should be one of these types:
- Decision โ an architectural or design choice made during the session
- Pattern โ a reusable approach, technique, or workflow discovered
- Solution โ a specific problem solved with a clear fix
- Error Fix โ a bug or error diagnosed and resolved
- Discovery โ a new finding about a tool, API, library, or system behavior
Present all candidates as a numbered list, with claudeception candidates first:
Insights found in this session:
- [from claudeception] [Discovery] Rate limiter pattern โ extracted as reusable skill
- [possibly from claudeception] [Pattern] Retry with exponential backoff โ identified across 3 sessions
- [Decision] Chose Redis for session store โ trade-off analysis
- [Solution] Fixed CORS issue with Safari โ root cause in preflight handling
Which would you like to save? (e.g. 1,3 or all)
If no claudeception output was detected, present only the standard candidates (same as before โ no labels).
When the user says all, all candidates (including claudeception ones) are saved. When the user picks specific numbers, only those are saved โ standard selection behavior.
Wait for the user to pick. For each selected insight, draft the note content and continue to Step 5. Process selected insights one at a time.
Step 5 โ Auto-generate topic tags
Based on the note content, generate 1-3 topic tags. Tags should be lowercase, hyphenated, and specific. Examples:
claude/topic/rate-limiting
claude/topic/react-hooks
claude/topic/git-workflow
claude/topic/api-design
Step 6 โ Show preview and ask for edits
Present the full note to the user including frontmatter:
---
type: claude-insight
date: YYYY-MM-DD
created_at: <ISO-8601-UTC>
source_session: <current-session-id>
source_session_note: "[[<session-note-filename>]]"
project: <project-name>
tags:
- claude/insight
- claude/project/<project-name>
- claude/topic/<auto-generated-topic-1>
- claude/topic/<auto-generated-topic-2>
---
# <Title>
<Note body>
Where:
-
YYYY-MM-DD is today's date
-
<ISO-8601-UTC> is the current UTC timestamp at second precision. Get it via:
python3 -c 'from datetime import datetime, timezone; print(datetime.now(timezone.utc).isoformat(timespec="seconds"))'
Example: 2026-04-24T18:42:11+00:00
-
<current-session-id> and <session-note-filename> are derived together. Get session context via the shared helper:
cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
python3 -c '
import sys, os
import glob; sys.path.insert(0, max(glob.glob(os.path.expanduser("~/.claude/plugins/cache/*/obsidian-brain/*/hooks")), default="hooks"))
from obsidian_utils import load_config, get_session_context
c = load_config()
ctx = get_session_context(c["vault_path"], c.get("sessions_folder", "claude-sessions"))
print("SID=" + ctx["session_id"] + " HASH=" + ctx["hash"] + " PROJECT=" + ctx["project"] + " SESSION_NOTE=" + ctx["session_note_name"])
'
Parse the output to get SESSION_ID, HASH, PROJECT, and SESSION_NOTE. Use these for the frontmatter fields.
Important: If SESSION_ID is unknown, use unknown for source_session and omit source_session_note entirely.
-
<project-name> is the PROJECT value from get_session_context() (lowercased, hyphenated basename of cwd)
-
The source_session_note field creates an Obsidian backlink from the insight to its source session, enabling bidirectional navigation in the graph view
Ask the user:
Preview above. Would you like to:
- save as-is
- edit tags โ add or remove tags
- edit content โ tell me what to change
- cancel โ discard this note
Wait for the user's response. Apply any requested edits and show the updated preview. Repeat until the user says save or cancel.
If cancel, stop here (or move to the next selected insight if processing multiple from Step 4B).
Step 7 โ Generate filename
Construct the filename from these parts:
- Date:
YYYY-MM-DD (today)
- Slug: The note title, lowercased, spaces replaced with hyphens, non-alphanumeric characters (except hyphens) removed, truncated to 50 characters
- Hash: 4-character hex hash derived from the current timestamp:
date +%s | md5 | cut -c29-32 (macOS) or date +%s | md5sum | cut -c1-4 (Linux). Do NOT use tail -c 4 โ it counts the trailing newline as a byte and returns only 3 visible characters.
Final filename: YYYY-MM-DD-<slug>-<hash>.md
Example: 2026-04-04-rate-limiting-with-redis-a3f2.md
Step 8 โ Write the note
Run:
mkdir -p "$VAULT_PATH/$INSIGHTS_FOLDER"
Then use the Write tool to write the full note (frontmatter + body) to:
$VAULT_PATH/$INSIGHTS_FOLDER/YYYY-MM-DD-<slug>-<hash>.md
Then set permissions:
chmod 644 "$VAULT_PATH/$INSIGHTS_FOLDER/YYYY-MM-DD-<slug>-<hash>.md"
Step 9 โ Confirm
Print:
Insight saved!
- File:
$VAULT_PATH/$INSIGHTS_FOLDER/<filename>
- Tags:
claude/insight, claude/project/<name>, claude/topic/<topic1>, ...
- Open in Obsidian to view and link to other notes.
If processing multiple insights from Step 4B, repeat Steps 5-9 for each remaining selected insight.
Step 10 โ Offer follow-up
After all insights are saved, ask:
Anything else to capture from this session? You can run /compress again or /compress <topic> to extract a specific topic (will offer to update if an existing note matches).