Initial commit
This commit is contained in:
386
commands/recall.md
Normal file
386
commands/recall.md
Normal file
@@ -0,0 +1,386 @@
|
||||
# Recall - Search Existing Memories
|
||||
|
||||
Search for existing memory notes in the Obsidian vault and present the top results.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/recall [query]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
- `query` - Search terms to find relevant memories (required)
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/recall git worktrees
|
||||
/recall debugging race condition
|
||||
/recall react hooks patterns
|
||||
/recall authentication flow
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
When this command is invoked:
|
||||
|
||||
### 1. Parse and Validate Query
|
||||
|
||||
1. Parse the query by trimming whitespace from the command input
|
||||
2. Validate that the query is not empty
|
||||
- If query is empty, return error message: "Query is required. Usage: /recall [query]"
|
||||
|
||||
### 2. Detect Project Context
|
||||
|
||||
1. Attempt to detect the current project from the git repository:
|
||||
- Run `git rev-parse --show-toplevel` to find the git repository root
|
||||
- Extract the project name from the repository directory name
|
||||
2. If not in a git repository:
|
||||
- Fall back to using the current working directory name
|
||||
- If that fails, use 'default' as the project name
|
||||
3. Store the detected project name for scoped search
|
||||
|
||||
### 3. Attempt Semantic Search (Smart Connections)
|
||||
|
||||
**Note:** Semantic search via Smart Connections plugin is an optional enhancement. If available, it provides better relevance ranking and conceptual matching.
|
||||
|
||||
1. Set initial search method to 'semantic' and initialize empty results array
|
||||
2. Attempt to use semantic search (if Smart Connections plugin is installed):
|
||||
- Try to perform semantic search across both project notes and global entities
|
||||
- Search path: `claude/projects/{currentProject}/**` and `claude/global/**`
|
||||
- Retrieve top 10 results for ranking
|
||||
3. If Smart Connections is not available or fails:
|
||||
- Set search method to 'text' for fallback
|
||||
- Continue to text search in next step
|
||||
|
||||
**Implementation Note:** Since obsidian-mcp-plugin does not provide native Smart Connections integration, this step may require custom MCP extensions or can be skipped in favor of text search only.
|
||||
|
||||
### 4. Perform Text Search
|
||||
|
||||
If semantic search was unavailable or returned no results, use text search:
|
||||
|
||||
1. Invoke MCP `search_notes` operation for project notes:
|
||||
- vault: `~/.claude-memory`
|
||||
- query: The user's search query
|
||||
- path_filter: `claude/projects/{currentProject}/**`
|
||||
|
||||
2. Invoke MCP `search_notes` operation for global entities:
|
||||
- vault: `~/.claude-memory`
|
||||
- query: The user's search query
|
||||
- path_filter: `claude/global/entities/**`
|
||||
|
||||
3. Combine the project results and global results, removing any duplicates
|
||||
4. Set search method to 'text'
|
||||
|
||||
5. Handle errors:
|
||||
|
||||
**If MCPUnavailableError:**
|
||||
- Return graceful degradation message explaining:
|
||||
- MCP server is unavailable
|
||||
- Steps to restore: ensure Obsidian is running, check plugin installation, verify config
|
||||
- Reference to docs/setup-guide.md
|
||||
|
||||
**If other error:**
|
||||
- Return error message with details
|
||||
|
||||
### 5. Rank and Filter Results
|
||||
|
||||
1. Rank results by relevance:
|
||||
- If semantic search was used: Results are already ranked by vector similarity
|
||||
- If text search was used: Rank by match frequency and recency
|
||||
- Calculate match count: How many times the query appears in the result
|
||||
- Calculate recency boost: More recent notes ranked higher
|
||||
- Combine into relevance score: match count + (recency boost × 10)
|
||||
- Sort results by score in descending order
|
||||
|
||||
2. Limit to top 5 results for presentation
|
||||
|
||||
3. Check if no results were found:
|
||||
- If results are empty, return info message with:
|
||||
- "No memories found for query: '{query}'"
|
||||
- Suggestions: Try different terms, use /remember to create memories, search more broadly
|
||||
- Current project and search scope information
|
||||
|
||||
### 6. Track Cross-Project Recalls
|
||||
|
||||
Use the cross-project tracking patterns defined in the managing-working-memory skill:
|
||||
|
||||
1. Identify cross-project recalls by filtering results:
|
||||
- A recall is cross-project if the note's project differs from the current project
|
||||
- Exclude global entities (project = 'global') as they're expected to be cross-project
|
||||
|
||||
2. For each cross-project entity recall:
|
||||
- Load the current note using MCP `read_note`
|
||||
- Append a new entry to the `cross_project_recalls` frontmatter array:
|
||||
- project: Current project name
|
||||
- date: Current date (YYYY-MM-DD)
|
||||
- context: "Recalled via search: '{query}'"
|
||||
- Update the note using MCP `update_note` with:
|
||||
- Updated cross_project_recalls array
|
||||
- Updated claude_last_accessed timestamp
|
||||
|
||||
3. Check if promotion threshold is met:
|
||||
- If cross_project_recalls length >= 3, trigger promotion prompt (see below)
|
||||
- Promotion prompt is handled by the managing-working-memory skill
|
||||
|
||||
**Promotion Prompt Format (I4):**
|
||||
|
||||
When an entity reaches 3 cross-project recalls, display:
|
||||
|
||||
```
|
||||
I've referenced [[{Entity Name}]] from {source-project} while working on other projects 3 times now:
|
||||
|
||||
1. {project-name} ({date}): {context}
|
||||
2. {project-name} ({date}): {context}
|
||||
3. {project-name} ({date}): {context}
|
||||
|
||||
This pattern seems reusable across projects. Should I promote it to global knowledge?
|
||||
|
||||
Options:
|
||||
1. Yes, promote to global (move to ~/.claude-memory/claude/global/entities/)
|
||||
2. Remind me later (ask again after 5 cross-project recalls)
|
||||
3. No, it's project-specific (stop tracking)
|
||||
|
||||
What should I do?
|
||||
```
|
||||
|
||||
User responses:
|
||||
- If option 1: Execute promotion process (move entity, update frontmatter, create redirect)
|
||||
- If option 2: Continue tracking, increase threshold to 5
|
||||
- If option 3: Clear cross_project_recalls array and stop tracking
|
||||
|
||||
4. Handle errors silently:
|
||||
- Cross-project tracking is best-effort
|
||||
- Log warnings for failed tracking but don't interrupt the search flow
|
||||
|
||||
### 7. Present Results
|
||||
|
||||
1. Format the output message with:
|
||||
- Header: "Found {count} {memory/memories} for: '{query}'"
|
||||
- Search method used: Semantic or Text search
|
||||
- Current project name
|
||||
- Blank line
|
||||
|
||||
2. For each result (numbered 1-5):
|
||||
- Extract title from path (filename without extension)
|
||||
- Get type, project, and updated date from frontmatter
|
||||
- Get snippet preview from search result
|
||||
- Format as:
|
||||
```
|
||||
{number}. [[{title}]] ({type})
|
||||
Project: {project}
|
||||
Updated: {updated}
|
||||
Preview: {first 150 chars of snippet}...
|
||||
```
|
||||
|
||||
3. Add footer with options:
|
||||
- "Type a number (1-{count}) to load full note content"
|
||||
- "Continue conversation to work with these memories"
|
||||
- "Use /remember to create a new memory if nothing matches"
|
||||
|
||||
4. Return the formatted output as a success message
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Missing Query
|
||||
|
||||
**Input:** `/recall`
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Error: Query is required.
|
||||
|
||||
Usage: /recall [query]
|
||||
|
||||
Examples:
|
||||
/recall git worktrees
|
||||
/recall debugging race condition
|
||||
/recall react hooks patterns
|
||||
```
|
||||
|
||||
### No Results Found
|
||||
|
||||
**Input:** `/recall nonexistent topic`
|
||||
|
||||
**Output:**
|
||||
```
|
||||
No memories found for query: "nonexistent topic"
|
||||
|
||||
Suggestions:
|
||||
- Try different search terms
|
||||
- Check if you've created memories for this topic (use /remember)
|
||||
- Search more broadly (fewer specific terms)
|
||||
|
||||
Current project: tabula-scripta
|
||||
Searched: Project notes + global entities
|
||||
```
|
||||
|
||||
### MCP Unavailable
|
||||
|
||||
**Input:** `/recall authentication` (when MCP server is down)
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Obsidian MCP server is unavailable. Cannot search memories.
|
||||
|
||||
To restore memory features:
|
||||
1. Ensure Obsidian is running
|
||||
2. Check obsidian-mcp-plugin is installed in ~/.claude-memory/
|
||||
3. Verify Claude Code config includes MCP server
|
||||
|
||||
See docs/setup-guide.md for troubleshooting.
|
||||
```
|
||||
|
||||
## Success Output
|
||||
|
||||
**Input:** `/recall git worktrees`
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Found 3 memories for: "git worktrees"
|
||||
Search method: Semantic (Smart Connections)
|
||||
Project: tabula-scripta
|
||||
|
||||
1. [[Git Worktrees]] (entity)
|
||||
Project: tabula-scripta
|
||||
Updated: 2025-11-18
|
||||
Preview: Git worktrees enable isolated directory trees for parallel development. Each worktree has its own working directory but shares the .git repository...
|
||||
|
||||
2. [[Parallel Execution Patterns]] (topic)
|
||||
Project: global
|
||||
Updated: 2025-11-17
|
||||
Preview: Techniques for concurrent task execution including git worktrees, background processes, and isolation strategies...
|
||||
|
||||
3. [[2025-11-18 - Spectacular Implementation]] (session)
|
||||
Project: tabula-scripta
|
||||
Updated: 2025-11-18
|
||||
Preview: Implementing parallel phase execution using git worktrees for task isolation. Decision: Use trap handlers for cleanup...
|
||||
|
||||
|
||||
Options:
|
||||
- Type a number (1-3) to load full note content
|
||||
- Continue conversation to work with these memories
|
||||
- Use /remember to create a new memory if nothing matches
|
||||
```
|
||||
|
||||
## Search Scope
|
||||
|
||||
The `/recall` command searches:
|
||||
|
||||
1. **Current project notes:**
|
||||
- `claude/projects/{current-project}/sessions/**`
|
||||
- `claude/projects/{current-project}/entities/**`
|
||||
|
||||
2. **Global entities:**
|
||||
- `claude/global/entities/**`
|
||||
- `claude/global/topics/**`
|
||||
|
||||
3. **Excludes:**
|
||||
- Archived sessions (`claude/projects/{project}/archive/**`)
|
||||
- Other project's sessions (unless global)
|
||||
|
||||
## Semantic Search vs Text Search
|
||||
|
||||
### Semantic Search (Preferred)
|
||||
|
||||
**Requirements:**
|
||||
- Smart Connections plugin installed in Obsidian
|
||||
- Plugin configured for `~/.claude-memory/` vault
|
||||
|
||||
**Advantages:**
|
||||
- Better relevance ranking
|
||||
- Finds conceptually similar notes
|
||||
- Handles synonyms and related concepts
|
||||
|
||||
**Example:**
|
||||
- Query: "concurrency issues"
|
||||
- Finds: "Race Condition Debugging", "Parallel Execution Gotchas"
|
||||
|
||||
### Text Search (Fallback)
|
||||
|
||||
**When used:**
|
||||
- Smart Connections not installed
|
||||
- Smart Connections unavailable
|
||||
- Semantic search fails
|
||||
|
||||
**Behavior:**
|
||||
- Exact/fuzzy text matching
|
||||
- Ranked by match frequency and recency
|
||||
- Still effective for keyword search
|
||||
|
||||
**Example:**
|
||||
- Query: "race condition"
|
||||
- Finds: Notes containing exact phrase "race condition"
|
||||
|
||||
## Cross-Project Recall Tracking
|
||||
|
||||
When a memory from Project A is recalled while working in Project B:
|
||||
|
||||
1. **Silent logging:**
|
||||
- Update `cross_project_recalls` frontmatter array
|
||||
- No user-visible output (non-intrusive)
|
||||
|
||||
2. **Threshold detection:**
|
||||
- After 3 cross-project recalls
|
||||
- Trigger promotion prompt (via `managing-working-memory` skill)
|
||||
|
||||
3. **Context capture:**
|
||||
```yaml
|
||||
cross_project_recalls:
|
||||
- project: tabula-scripta
|
||||
date: 2025-11-18
|
||||
context: "Recalled via search: \"git worktrees\""
|
||||
- project: another-project
|
||||
date: 2025-11-19
|
||||
context: "Recalled via search: \"isolation patterns\""
|
||||
```
|
||||
|
||||
## Interactive Follow-Up
|
||||
|
||||
After presenting results, user can:
|
||||
|
||||
1. **Load full note content:**
|
||||
- User types: `1`
|
||||
- Claude loads: Full content of result #1
|
||||
|
||||
2. **Continue conversation:**
|
||||
- User asks: "What did we decide about worktree cleanup?"
|
||||
- Claude references loaded memories in response
|
||||
|
||||
3. **Create new memory:**
|
||||
- User types: `/remember entity Worktree Cleanup`
|
||||
- New entity created based on discussion
|
||||
|
||||
## Relevance Filtering
|
||||
|
||||
Results are filtered for relevance:
|
||||
|
||||
- **Minimum score threshold:** Only include results with score > 0.3
|
||||
- **Recency boost:** Recently updated notes ranked higher
|
||||
- **Type priority:** Entities ranked above sessions (more persistent knowledge)
|
||||
- **Project scoping:** Current project results ranked above cross-project results
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Finds notes via semantic search (Smart Connections) when available
|
||||
- [ ] Falls back to text search when semantic search unavailable
|
||||
- [ ] Presents top 5 results with relevance ranking
|
||||
- [ ] Handles MCP unavailable gracefully
|
||||
- [ ] Detects project context correctly from git repo
|
||||
- [ ] Tracks cross-project recalls silently
|
||||
- [ ] Searches both project notes and global entities
|
||||
- [ ] Shows clear message when no results found
|
||||
- [ ] Includes note type, project, updated date, and preview in results
|
||||
- [ ] Offers interactive follow-up options
|
||||
|
||||
## Integration with managing-working-memory Skill
|
||||
|
||||
This command provides the manual interface for memory search. The `managing-working-memory` skill uses the same search logic for:
|
||||
- Proactive recall at session start
|
||||
- Finding related entities during updates
|
||||
- Cross-project pattern detection
|
||||
|
||||
**Relationship:**
|
||||
- `/recall` - Manual, user-initiated search
|
||||
- `managing-working-memory` - Automatic, skill-driven search
|
||||
- Both use same search methods (semantic → text fallback)
|
||||
- Both track cross-project recalls
|
||||
265
commands/remember.md
Normal file
265
commands/remember.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# Remember - Create New Memory Note
|
||||
|
||||
Create a new memory note in the Obsidian vault at `~/.claude-memory/`.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/remember [type] [title]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
- `type`: The type of memory note (required)
|
||||
- `session` - Temporal note for current work session
|
||||
- `entity` - Persistent note for a concept/component/pattern
|
||||
- `topic` - Organizational note (Map of Content)
|
||||
- `title` - The title for the memory note (required)
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/remember entity Git Worktrees
|
||||
/remember session 2025-11-18 - Working Memory Implementation
|
||||
/remember topic React Patterns
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
When this command is invoked:
|
||||
|
||||
### 1. Parse and Validate Arguments
|
||||
|
||||
1. Parse the command input by splitting on spaces
|
||||
2. Extract the first argument as the type
|
||||
3. Extract remaining arguments and join with spaces as the title
|
||||
4. Validate that type is one of the allowed values: session, entity, or topic
|
||||
- If type is invalid, return error message: "Invalid type '{type}'. Must be one of: session, entity, topic"
|
||||
5. Validate that title is provided and not empty
|
||||
- If title is missing or empty, return error message: "Title is required. Usage: /remember [type] [title]"
|
||||
|
||||
### 2. Detect Project Context
|
||||
|
||||
1. Attempt to detect the current project from the git repository:
|
||||
- Run `git rev-parse --show-toplevel` to find the git repository root
|
||||
- Extract the project name from the repository directory name
|
||||
2. If not in a git repository (command fails):
|
||||
- Fall back to using the current working directory name as the project
|
||||
- If that also fails, use 'default' as the project name
|
||||
3. Store the detected project name for use in vault path generation
|
||||
|
||||
### 3. Generate Vault Path
|
||||
|
||||
1. Sanitize the title to create a valid filename:
|
||||
- Replace any characters that are invalid in filenames with hyphens
|
||||
- Invalid characters include: / \ : * ? " < > |
|
||||
2. Generate the vault path based on the note type:
|
||||
- For session notes: `claude/projects/{project}/sessions/{sanitized-title}.md`
|
||||
- For entity notes: `claude/projects/{project}/entities/{sanitized-title}.md`
|
||||
- For topic notes: `claude/global/topics/{sanitized-title}.md`
|
||||
|
||||
Note that topic notes are always global (not project-specific)
|
||||
|
||||
### 4. Generate Frontmatter
|
||||
|
||||
1. Get the current date in YYYY-MM-DD format
|
||||
2. Create frontmatter with the following fields:
|
||||
- type: The note type (session, entity, or topic)
|
||||
- project: The project name, or 'global' for topic notes
|
||||
- tags: Type-specific tags
|
||||
- Session notes: [session, work-in-progress]
|
||||
- Entity notes: [entity]
|
||||
- Topic notes: [topic, moc]
|
||||
- created: Current date (YYYY-MM-DD)
|
||||
- updated: Current date (YYYY-MM-DD)
|
||||
- status: 'active'
|
||||
- claude_last_accessed: Current date (YYYY-MM-DD)
|
||||
- cross_project_recalls: Empty array (for tracking cross-project usage)
|
||||
|
||||
### 5. Generate Note Content from Template
|
||||
|
||||
Use the note templates defined in the managing-working-memory skill to generate the initial content. The templates vary by note type:
|
||||
|
||||
**For session notes:**
|
||||
- Include frontmatter with all required fields
|
||||
- Add a main heading with the session title
|
||||
- Include sections for:
|
||||
- Context (why we're working on this)
|
||||
- Work Log (timestamped entries of what happened)
|
||||
- Decisions Made (with rationale)
|
||||
- Open Questions (blockers or uncertainties)
|
||||
- Next Steps (action items as checkboxes)
|
||||
- Related Entities (wikilinks to relevant entities)
|
||||
|
||||
**For entity notes:**
|
||||
- Include frontmatter with all required fields
|
||||
- Add a main heading with the entity name
|
||||
- Include sections for:
|
||||
- Overview (purpose and role)
|
||||
- Architecture (structure and how it works)
|
||||
- Key Decisions (with date, rationale, alternatives, impact)
|
||||
- Gotchas & Troubleshooting (symptom, root cause, solution, tags)
|
||||
- Recent Changes (timestamped log)
|
||||
- Related Entities (wikilinks with relationship descriptions)
|
||||
- References (external docs, code paths, commits)
|
||||
|
||||
**For topic notes:**
|
||||
- Include frontmatter with project set to 'global'
|
||||
- Add a main heading with the topic name
|
||||
- Include sections for:
|
||||
- Overview (what the topic covers)
|
||||
- Key Concepts (wikilinks to core entities)
|
||||
- Patterns & Best Practices (descriptions and related entities)
|
||||
- Common Pitfalls (antipatterns to avoid)
|
||||
- Learning Path (ordered sequence of entities)
|
||||
- References (external resources and documentation)
|
||||
|
||||
All templates use placeholder text in curly braces {like this} to indicate where content should be filled in.
|
||||
|
||||
### 6. Invoke MCP create_note
|
||||
|
||||
1. Invoke the MCP `create_note` operation with:
|
||||
- vault: `~/.claude-memory`
|
||||
- path: The generated vault path
|
||||
- content: The generated note content with frontmatter
|
||||
|
||||
2. Handle the response:
|
||||
|
||||
**If successful:**
|
||||
- Return success message including:
|
||||
- Confirmation with wikilink to the created note
|
||||
- Type and project information
|
||||
- Vault path
|
||||
- Note that the note is ready for editing
|
||||
|
||||
**If FileExistsError:**
|
||||
- Return error message indicating the note already exists
|
||||
- Suggest using /update-memory to update it, or choosing a different title
|
||||
|
||||
**If MCPUnavailableError:**
|
||||
- Return graceful degradation message explaining:
|
||||
- MCP server is unavailable
|
||||
- Steps to restore: ensure Obsidian is running, check plugin installation, verify config
|
||||
- Reference to docs/setup-guide.md
|
||||
- Offer to create a draft in a local markdown file instead
|
||||
|
||||
**If unknown error:**
|
||||
- Return error message with the error details
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Invalid Type
|
||||
|
||||
**Input:** `/remember invalid-type My Note`
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Error: Invalid type "invalid-type". Must be one of: session, entity, topic
|
||||
|
||||
Usage: /remember [type] [title]
|
||||
|
||||
Examples:
|
||||
/remember entity Git Worktrees
|
||||
/remember session 2025-11-18 - Working Memory Implementation
|
||||
/remember topic React Patterns
|
||||
```
|
||||
|
||||
### Missing Title
|
||||
|
||||
**Input:** `/remember entity`
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Error: Title is required.
|
||||
|
||||
Usage: /remember [type] [title]
|
||||
|
||||
Examples:
|
||||
/remember entity Git Worktrees
|
||||
/remember session 2025-11-18 - Working Memory Implementation
|
||||
/remember topic React Patterns
|
||||
```
|
||||
|
||||
### Note Already Exists
|
||||
|
||||
**Input:** `/remember entity Git Worktrees` (when it already exists)
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Error: Memory note [[Git Worktrees]] already exists at claude/projects/tabula-scripta/entities/Git Worktrees.md
|
||||
|
||||
Use /update-memory to update an existing note, or choose a different title.
|
||||
```
|
||||
|
||||
### MCP Unavailable
|
||||
|
||||
**Input:** `/remember entity My Component` (when MCP server is down)
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Obsidian MCP server is unavailable. Cannot create memory note.
|
||||
|
||||
To restore memory features:
|
||||
1. Ensure Obsidian is running
|
||||
2. Check obsidian-mcp-plugin is installed in ~/.claude-memory/
|
||||
3. Verify Claude Code config includes MCP server
|
||||
|
||||
See docs/setup-guide.md for troubleshooting.
|
||||
|
||||
Would you like me to create a draft in a local markdown file instead?
|
||||
```
|
||||
|
||||
## Success Output
|
||||
|
||||
**Input:** `/remember entity Git Worktrees`
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Created memory note: [[Git Worktrees]]
|
||||
|
||||
Type: entity
|
||||
Project: tabula-scripta
|
||||
Path: claude/projects/tabula-scripta/entities/Git Worktrees.md
|
||||
|
||||
The note is ready for editing in Obsidian or via /update-memory.
|
||||
```
|
||||
|
||||
## Integration with managing-working-memory Skill
|
||||
|
||||
This command provides the manual interface for memory creation. The `managing-working-memory` skill uses the same underlying logic but triggers automatically based on workflow events (code review, debugging, etc.).
|
||||
|
||||
**Relationship:**
|
||||
- `/remember` - Manual, user-initiated memory creation
|
||||
- `managing-working-memory` - Automatic, skill-driven memory creation
|
||||
- Both use identical frontmatter schema and note templates
|
||||
- Both invoke same MCP operations
|
||||
|
||||
## Wikilink Generation
|
||||
|
||||
All created notes support Obsidian wikilinks:
|
||||
- Entity reference: `[[Git Worktrees]]`
|
||||
- Session reference: `[[2025-11-18 - Working Memory Implementation]]`
|
||||
- Topic reference: `[[React Patterns]]`
|
||||
|
||||
Links work bidirectionally in Obsidian's graph view.
|
||||
|
||||
## Project Context Detection
|
||||
|
||||
The command detects project context in priority order:
|
||||
|
||||
1. **Git repository name** - `git rev-parse --show-toplevel`
|
||||
2. **Working directory name** - `path.basename(process.cwd())`
|
||||
3. **Fallback** - `'default'`
|
||||
|
||||
This ensures session and entity notes are scoped to the correct project.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Creates notes at correct vault path with valid frontmatter
|
||||
- [ ] Validates type argument (session/entity/topic)
|
||||
- [ ] Requires title argument
|
||||
- [ ] Detects project context from git repo
|
||||
- [ ] Generates wikilinks correctly
|
||||
- [ ] Handles MCP unavailable gracefully
|
||||
- [ ] Shows clear error for note already exists
|
||||
- [ ] Uses templates from managing-working-memory skill
|
||||
- [ ] Frontmatter includes all required fields
|
||||
- [ ] Timestamp format is YYYY-MM-DD
|
||||
459
commands/update-memory.md
Normal file
459
commands/update-memory.md
Normal file
@@ -0,0 +1,459 @@
|
||||
# Update Memory - Update Existing Note
|
||||
|
||||
Update an existing memory note with new information, using patch operations and conflict detection.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/update-memory [title]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
- `title` - The title of the existing memory note to update (required)
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
/update-memory Git Worktrees
|
||||
/update-memory 2025-11-18 - Working Memory Implementation
|
||||
/update-memory React Patterns
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
When this command is invoked:
|
||||
|
||||
### 1. Parse and Validate Title
|
||||
|
||||
1. Parse the title by trimming whitespace from the command input
|
||||
2. Validate that the title is not empty
|
||||
- If title is empty, return error message: "Title is required. Usage: /update-memory [title]"
|
||||
|
||||
### 2. Detect Project Context
|
||||
|
||||
1. Attempt to detect the current project from the git repository:
|
||||
- Run `git rev-parse --show-toplevel` to find the git repository root
|
||||
- Extract the project name from the repository directory name
|
||||
2. If not in a git repository:
|
||||
- Fall back to using the current working directory name
|
||||
- If that fails, use 'default' as the project name
|
||||
3. Store the detected project name for locating the note
|
||||
|
||||
### 3. Search for Note
|
||||
|
||||
1. Try to find the note by checking multiple possible locations in order:
|
||||
- Current project entities: `claude/projects/{currentProject}/entities/{title}.md`
|
||||
- Current project sessions: `claude/projects/{currentProject}/sessions/{title}.md`
|
||||
- Global entities: `claude/global/entities/{title}.md`
|
||||
- Global topics: `claude/global/topics/{title}.md`
|
||||
|
||||
2. For each possible path:
|
||||
- Attempt to read the note using MCP `read_note`
|
||||
- If successful, store the path and note content, then stop searching
|
||||
- If FileNotFoundError, continue to next path
|
||||
- If other error, propagate it
|
||||
|
||||
3. If not found in standard locations, use search as fallback:
|
||||
- Invoke MCP `search_notes` with query=title and path_filter='claude/**'
|
||||
- Find exact title match in results (case-insensitive comparison)
|
||||
- If exact match found, load the note using MCP `read_note`
|
||||
|
||||
4. If still not found after all attempts:
|
||||
- Return error message listing all searched locations
|
||||
- Suggest using /remember to create the note
|
||||
- Provide example command
|
||||
|
||||
### 4. Load Note and Check Timestamps
|
||||
|
||||
1. Store the loaded timestamp from frontmatter for conflict detection later
|
||||
- Save note.frontmatter.updated as the loaded timestamp
|
||||
|
||||
2. Update claude_last_accessed in frontmatter to current date (YYYY-MM-DD)
|
||||
|
||||
3. Display the current note content to the user:
|
||||
- Show wikilink title, type, project, last updated date, and path
|
||||
- Display full current content
|
||||
- Add separator line
|
||||
- Prompt: "What would you like to update? I'll apply patch operations to preserve existing content."
|
||||
|
||||
### 5. Collect User Updates
|
||||
|
||||
This is a conversational step where the user describes what they want to update.
|
||||
|
||||
1. User provides their update request in natural language
|
||||
- Example: "Add a new decision about using trap handlers for cleanup"
|
||||
|
||||
2. Parse the user's intent to identify the appropriate patch operation type:
|
||||
- Append to section: Add new entry to an existing section (e.g., "## Recent Changes")
|
||||
- Add new section: Create a completely new section (e.g., "## Troubleshooting")
|
||||
- Update frontmatter: Modify frontmatter fields (e.g., add a tag)
|
||||
- Insert in list: Add item to an existing list (e.g., "## Related Entities")
|
||||
|
||||
3. Confirm with the user what will be done
|
||||
- Example: "I'll add this to the Key Decisions section."
|
||||
|
||||
### 6. Check for Conflicts (Before Writing)
|
||||
|
||||
Use the conflict detection logic defined in the managing-working-memory skill:
|
||||
|
||||
1. Before applying the patch, reload the note using MCP `read_note` to get the current state
|
||||
|
||||
2. Compare timestamps to detect conflicts:
|
||||
- Get the current timestamp from the reloaded note's frontmatter.updated
|
||||
- Compare with the loaded timestamp saved in step 4
|
||||
- If current timestamp > loaded timestamp: CONFLICT DETECTED (human edited since Claude loaded)
|
||||
- If timestamps match: No conflict, safe to update
|
||||
|
||||
3. If conflict detected:
|
||||
- Trigger conflict resolution flow (see managing-working-memory skill for detailed flow)
|
||||
- Present both changes to user and offer resolution options
|
||||
|
||||
4. If no conflict:
|
||||
- Proceed to apply patch operation in next step
|
||||
|
||||
### 7. Apply Patch Operation
|
||||
|
||||
Use the patch operation patterns defined in the managing-working-memory skill. Apply the identified patch operation type:
|
||||
|
||||
**For append_to_section:**
|
||||
- Locate the specified section in the note content
|
||||
- Append the new content to the end of that section
|
||||
- Preserve all existing content in the section
|
||||
|
||||
**For add_new_section:**
|
||||
- Create a new markdown section with the specified title
|
||||
- Add the section content
|
||||
- Insert at appropriate location in the note structure
|
||||
|
||||
**For update_frontmatter:**
|
||||
- Modify the specified frontmatter field(s)
|
||||
- Common operations: adding tags, updating status, etc.
|
||||
|
||||
**For insert_in_list:**
|
||||
- Locate the specified list within a section
|
||||
- Add the new list item
|
||||
- Maintain proper markdown list formatting
|
||||
|
||||
After applying content changes:
|
||||
|
||||
1. Update frontmatter timestamps:
|
||||
- Set updated to current date (YYYY-MM-DD)
|
||||
- Set claude_last_accessed to current date (YYYY-MM-DD)
|
||||
|
||||
2. If adding tags, merge new tags with existing tags (remove duplicates)
|
||||
|
||||
### 8. Write Updated Note
|
||||
|
||||
1. Invoke MCP `update_note` with:
|
||||
- vault: `~/.claude-memory`
|
||||
- path: The note path
|
||||
- content: The updated content
|
||||
- frontmatter: The updated frontmatter
|
||||
|
||||
2. Handle the response:
|
||||
|
||||
**If successful:**
|
||||
- Return success message including:
|
||||
- Confirmation with wikilink
|
||||
- Description of applied changes
|
||||
- Updated timestamp
|
||||
- Path
|
||||
- Note that Obsidian has been updated
|
||||
|
||||
**If MCPUnavailableError:**
|
||||
- Return graceful degradation message explaining:
|
||||
- MCP server is unavailable
|
||||
- Steps to restore: ensure Obsidian is running, check plugin installation, verify config
|
||||
- Reference to docs/setup-guide.md
|
||||
- Offer to save pending update to a local file
|
||||
|
||||
**If other error:**
|
||||
- Return error message with details
|
||||
|
||||
## Conflict Detection and Resolution
|
||||
|
||||
All conflict detection and resolution flows are defined in the managing-working-memory skill. The /update-memory command uses these patterns:
|
||||
|
||||
### Case 1: Clean Update (No Conflict)
|
||||
|
||||
Timeline:
|
||||
- T1: Claude loads note (updated = "2025-11-17")
|
||||
- T2: User discusses updates with Claude
|
||||
- T3: Claude applies patch (updated still "2025-11-17")
|
||||
- Result: No conflict, proceed with update
|
||||
|
||||
See managing-working-memory skill for timestamp comparison logic.
|
||||
|
||||
**Example Output:**
|
||||
```
|
||||
Updated: [[Git Worktrees]]
|
||||
|
||||
Applied changes:
|
||||
- Added new entry to "Recent Changes"
|
||||
- Appended decision about trap handlers to "Key Decisions"
|
||||
- Updated tags: [entity, git, worktrees, error-handling]
|
||||
|
||||
Updated: 2025-11-18
|
||||
Path: claude/projects/tabula-scripta/entities/Git Worktrees.md
|
||||
|
||||
The note has been updated in Obsidian.
|
||||
```
|
||||
|
||||
### Case 2: Human Edit Conflict
|
||||
|
||||
Timeline:
|
||||
- T1: Claude loads note (updated = "2025-11-17")
|
||||
- T2: Human edits note in Obsidian (updated = "2025-11-18")
|
||||
- T3: Claude attempts patch (detects conflict)
|
||||
- Result: Conflict detected, show diff and offer resolution options
|
||||
|
||||
See managing-working-memory skill for conflict resolution flow and user options.
|
||||
|
||||
**Example Output:**
|
||||
```
|
||||
I want to update [[Git Worktrees]] but you've edited it since I loaded it.
|
||||
|
||||
Your changes (at 2025-11-18):
|
||||
+ Added new section "## Performance Considerations"
|
||||
+ Updated "Overview" with additional context
|
||||
~ Modified frontmatter tags: added #optimization
|
||||
|
||||
My pending changes:
|
||||
- Add new entry to "Recent Changes"
|
||||
- Append decision about trap handlers to "Key Decisions"
|
||||
|
||||
Options:
|
||||
1. Show me both diffs and I'll merge manually
|
||||
2. Abort your update (keep my changes only)
|
||||
3. Create new section "## Claude's Updates (conflicted)" with your changes
|
||||
4. Let's discuss and resolve together
|
||||
|
||||
What should I do?
|
||||
```
|
||||
|
||||
### Case 3: Major Rewrite Needed
|
||||
|
||||
When Claude's understanding contradicts existing note fundamentally, use the major rewrite pattern from managing-working-memory skill to present options without overwriting user knowledge.
|
||||
|
||||
**Example Output:**
|
||||
```
|
||||
My understanding of [[Git Worktrees]] changed significantly.
|
||||
|
||||
Current note says:
|
||||
"Git worktrees are primarily for parallel feature development and should be short-lived."
|
||||
|
||||
But I now think:
|
||||
"Git worktrees can be long-lived for maintaining multiple release branches simultaneously."
|
||||
|
||||
Options:
|
||||
1. Create new entity note with alternative understanding
|
||||
2. Update existing note (I'll show you the full diff first)
|
||||
3. Let's discuss the contradiction - maybe both are valid
|
||||
|
||||
What should I do?
|
||||
```
|
||||
|
||||
## Patch Operation Types
|
||||
|
||||
All patch operations are defined in the managing-working-memory skill. The /update-memory command uses these standard patterns:
|
||||
|
||||
### 1. Append to Section
|
||||
|
||||
Add new content at the end of an existing section. Example: Adding to "## Recent Changes" section.
|
||||
|
||||
See managing-working-memory skill for appendToSection pattern.
|
||||
|
||||
### 2. Add New Section
|
||||
|
||||
Create a new section in the note. Example: Adding "## Performance Considerations" section.
|
||||
|
||||
See managing-working-memory skill for addSection pattern.
|
||||
|
||||
### 3. Update Frontmatter
|
||||
|
||||
Modify frontmatter fields such as tags or status.
|
||||
|
||||
Examples:
|
||||
- Adding a tag: Append to tags array
|
||||
- Changing status: Set status field to new value
|
||||
|
||||
See managing-working-memory skill for frontmatter update pattern.
|
||||
|
||||
### 4. Insert in List
|
||||
|
||||
Add item to an existing list like "## Related Entities" or "## References".
|
||||
|
||||
See managing-working-memory skill for insertInList pattern.
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Note Not Found
|
||||
|
||||
**Input:** `/update-memory Nonexistent Entity`
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Error: Memory note [[Nonexistent Entity]] not found.
|
||||
|
||||
Searched:
|
||||
- Project entities: claude/projects/tabula-scripta/entities/
|
||||
- Project sessions: claude/projects/tabula-scripta/sessions/
|
||||
- Global entities: claude/global/entities/
|
||||
- Global topics: claude/global/topics/
|
||||
|
||||
Would you like to create it with /remember?
|
||||
|
||||
Example: /remember entity Nonexistent Entity
|
||||
```
|
||||
|
||||
### MCP Unavailable
|
||||
|
||||
**Input:** `/update-memory Git Worktrees` (when MCP server is down)
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Obsidian MCP server is unavailable. Cannot update memory note.
|
||||
|
||||
To restore memory features:
|
||||
1. Ensure Obsidian is running
|
||||
2. Check obsidian-mcp-plugin is installed in ~/.claude-memory/
|
||||
3. Verify Claude Code config includes MCP server
|
||||
|
||||
See docs/setup-guide.md for troubleshooting.
|
||||
|
||||
Would you like me to save the pending update to a local file?
|
||||
```
|
||||
|
||||
### Missing Title
|
||||
|
||||
**Input:** `/update-memory`
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Error: Title is required.
|
||||
|
||||
Usage: /update-memory [title]
|
||||
|
||||
Examples:
|
||||
/update-memory Git Worktrees
|
||||
/update-memory 2025-11-18 - Working Memory Implementation
|
||||
/update-memory React Patterns
|
||||
```
|
||||
|
||||
## Success Output (Clean Update)
|
||||
|
||||
**Input:** `/update-memory Git Worktrees`
|
||||
|
||||
**Conversation:**
|
||||
```
|
||||
User: /update-memory Git Worktrees
|
||||
|
||||
Claude: Loaded: [[Git Worktrees]]
|
||||
Type: entity
|
||||
Project: tabula-scripta
|
||||
Last updated: 2025-11-17
|
||||
Path: claude/projects/tabula-scripta/entities/Git Worktrees.md
|
||||
|
||||
Current content:
|
||||
[... full note content ...]
|
||||
|
||||
---
|
||||
|
||||
What would you like to update? I'll apply patch operations to preserve existing content.
|
||||
|
||||
User: Add a decision about using trap handlers for cleanup
|
||||
|
||||
Claude: I'll add this to the Key Decisions section.
|
||||
|
||||
[Claude applies patch]
|
||||
|
||||
Updated: [[Git Worktrees]]
|
||||
|
||||
Applied changes:
|
||||
- Added new entry to "Key Decisions"
|
||||
### Trap Handlers for Cleanup
|
||||
Date: 2025-11-18
|
||||
Rationale: Ensures worktree cleanup even if subagent crashes
|
||||
Alternatives Considered: Manual cleanup (error-prone), atexit hooks (unreliable)
|
||||
Impact: Improves reliability of parallel execution
|
||||
|
||||
Updated: 2025-11-18
|
||||
Path: claude/projects/tabula-scripta/entities/Git Worktrees.md
|
||||
|
||||
The note has been updated in Obsidian.
|
||||
```
|
||||
|
||||
## Timestamp Tracking
|
||||
|
||||
### Frontmatter Fields
|
||||
|
||||
```yaml
|
||||
---
|
||||
created: 2025-11-17 # Never changes, original creation
|
||||
updated: 2025-11-18 # Modified every save (human or Claude)
|
||||
claude_last_accessed: 2025-11-18 # When Claude loaded into context
|
||||
---
|
||||
```
|
||||
|
||||
### Conflict Detection Logic
|
||||
|
||||
See the managing-working-memory skill for the complete timestamp comparison logic. The basic flow is:
|
||||
|
||||
1. **When loading:** Store the updated timestamp and set claude_last_accessed
|
||||
2. **When updating:** Reload the note and compare timestamps
|
||||
3. **If current timestamp > loaded timestamp:** Conflict detected
|
||||
4. **If timestamps match:** Safe to update
|
||||
|
||||
## Graceful Degradation (MCP Unavailable)
|
||||
|
||||
When MCP server is unavailable:
|
||||
|
||||
1. **Detect failure** - Catch `MCPUnavailableError`
|
||||
2. **Offer alternatives:**
|
||||
- Save pending update to local markdown file
|
||||
- Export as diff patch for manual application
|
||||
- Continue conversation without update
|
||||
3. **Guide troubleshooting:**
|
||||
- Link to `docs/setup-guide.md`
|
||||
- Check Obsidian is running
|
||||
- Verify plugin installation
|
||||
|
||||
## Interactive Update Flow
|
||||
|
||||
The `/update-memory` command is conversational:
|
||||
|
||||
1. **Load note** - Show current content to user
|
||||
2. **Collect intent** - User describes what to update
|
||||
3. **Confirm operation** - Claude describes patch operation
|
||||
4. **Check conflict** - Reload note to detect edits
|
||||
5. **Apply or resolve** - Update cleanly or trigger conflict resolution
|
||||
6. **Confirm success** - Show what changed
|
||||
|
||||
This ensures transparency and prevents data loss.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Loads existing note via MCP read_note
|
||||
- [ ] Checks timestamps for conflict detection (updated vs loaded)
|
||||
- [ ] Detects conflicts when human edited since load
|
||||
- [ ] Shows diff when conflict detected
|
||||
- [ ] Applies patch operations (append, add section, update frontmatter)
|
||||
- [ ] Preserves existing content (no full rewrites)
|
||||
- [ ] Updates frontmatter timestamps (updated, claude_last_accessed)
|
||||
- [ ] Handles MCP unavailable gracefully
|
||||
- [ ] Offers to create note if not found
|
||||
- [ ] Searches multiple locations (project entities, sessions, global)
|
||||
- [ ] Shows clear success message with changes applied
|
||||
|
||||
## Integration with managing-working-memory Skill
|
||||
|
||||
This command provides the manual interface for memory updates. The `managing-working-memory` skill uses the same update logic for:
|
||||
- Automatic updates after code review
|
||||
- Updates after debugging sessions
|
||||
- Periodic checkpoint updates
|
||||
- Session end compaction
|
||||
|
||||
**Relationship:**
|
||||
- `/update-memory` - Manual, user-initiated updates
|
||||
- `managing-working-memory` - Automatic, skill-driven updates
|
||||
- Both use identical conflict detection and patch operations
|
||||
- Both track timestamps for data integrity
|
||||
Reference in New Issue
Block a user