1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeに記憶力を持たせる試み - Obsidianでコンテキストと失敗を記録する

Last updated at Posted at 2025-10-09

これはなに

Claude Codeが同じミスを繰り返さないように、過去の失敗やコードから読み取れないコンテキストをObsidianに記録して参照させる仕組みを作った。

背景:AIとのペアプロで感じた課題

Claude Codeを使っていて、何度も同じことを説明する場面に遭遇していた。

例えばパターンA:

  • 「このプロジェクトでは機能Xはファイルαに追加するルールだよ」と説明
  • 次の会話では別ファイルに追加しようとする
  • また説明する
  • 無限ループ

あるいはパターンB:

  • 「なぜこの実装を選んだのか」をClaude Codeと議論して決定
  • 数日後、別の会話で同じ話題になる
  • 「前回はこうしたんだけど...」とまた説明

コードを見れば「何をしているか」は分かるが、「なぜそうしたか」「何を試して失敗したか」といったコンテキストはコードからは読み取れない。これはClaude Codeに限らず、AIコーディングアシスタント全般の課題だと思う。

きっかけ:ZedのDeltaDB

PublickeyでZedが「DeltaDB」という仕組みを開発しているという記事を読んだ。

Zed's goal is to make your codebase a living, navigable history of how your software evolved, where discussions with humans and AI agents are durably linked to the code.

「AIとの対話のコンテキストを永続化する」という考え方である。これを読んで、Claude Codeでも似たようなことができるんじゃないかと思った。

何を解決したかったか

具体的には以下の3つの問題を解決したいと考えた。

1. 同じミスの繰り返し

Claude Codeが過去にやらかしたミス(プロジェクト固有のルール違反、間違ったファイルへの変更など)を記録しておけば、次回から同じミスを避けられるはずだ。

2. コンテキストの喪失

「パフォーマンス問題Aが起きたから実装パターンBを採用した」みたいな意思決定の経緯を記録しておけば、後から「なぜこうなってるの?」となったときに参照できる。

3. 説明の繰り返し

プロジェクト固有のルールやパターンを一度記録しておけば、毎回説明しなくても済む。人間の私の手間も減る

作ったもの

この課題を解決するために、以下の4つのコンポーネントを作った。

カスタムコマンド(Obsidian操作用)

  • /obsidian-create - Obsidianにノート作成
  • /obsidian-update - Obsidianノートの更新

サブエージェント(記録と参照用)

  • knowledge-logger - ミスとコンテキストを記録
  • knowledge-retriever - 過去の記録を検索・参照

これらはobsidian-mcp-toolsを使って実装している。

記録の仕組み

knowledge-loggerは主に2つのパターンで記録する。

Claude Mistakeパターン: Claude Codeが間違えたときの記録

  • どんな状況で
  • Claudeは何を間違えたか
  • 正しくはどうすべきだったか
  • なぜ間違えたか
  • 今後のチェック項目

Contextパターン: コードから読み取れない意思決定の記録

  • 何が問題だったか
  • どんな試行が失敗したか
  • 最終的にどう解決したか
  • 今後への教訓

参照の仕組み

knowledge-retrieverはタスク開始前に過去の記録を検索する。例えば「機能Xの実装をお願い」と言われたら:

  1. リポジトリ名とトピック(機能X)を特定
  2. Dataviewで過去の記録を検索(TABLE FROM #claude-mistake AND #example-project AND #feature-x
  3. 該当する記録があれば、それを参照して同じミスを避ける

Obsidianを選んだのは、Markdownベースで扱いやすく、Dataviewでタグ検索が強力だからだ。

仕組みの全体像

1. タスク開始前
   ↓
   knowledge-retriever が過去の記録を検索
   ↓
2. 作業実施
   ↓
3. ミスがあった/重要な決定をした
   ↓
   knowledge-logger が Obsidian に記録
   ↓
4. 次回のタスクで参照される

つまり、Claude Codeの「記憶」をObsidianという外部データベースに持たせる形だ。

実装について

ちなみに、これらのカスタムコマンドとサブエージェント自体もClaude Codeを使って書いた。

効果はこれから

正直なところ、まだ作って日が浅いので効果検証はこれからだ。

期待していること:

  • 同じミスの繰り返しが減る
  • プロジェクト固有のルールを覚えてくれる
  • 「なぜこうしたか」が後から追える

懸念していること:

  • 記録が増えすぎて検索性が落ちる可能性
  • knowledge-retrieverを呼び忘れる可能性
  • そもそもこの仕組み自体を忘れる可能性

しばらく運用してみて、また結果を記事にできればと思う。

参考

付録:実装の詳細

興味がある人向けに、各コンポーネントのソースを載せておく。

カスタムコマンド: /obsidian-create
commands/obsidian-create.md
---
description: Create a markdown note in Obsidian 11_MCP folder with filename, tags, and content
allowed-tools: mcp__obsidian-mcp-tools__create_vault_file
---

Create a new markdown file in the Obsidian vault at path `11_MCP/$1` with the following structure:

- Frontmatter with tags: `$2` (comma-separated tags)
- Content: $3

Use the mcp__obsidian-mcp-tools__create_vault_file tool to create the file with filename parameter as `11_MCP/$1`.

IMPORTANT:
- The filename parameter must include the full path: `11_MCP/` + filename
- If $1 doesn't end with `.md`, append `.md` to it
- Example: if $1 is "test_note", use `11_MCP/test_note.md`
- Example: if $1 is "test_note.md", use `11_MCP/test_note.md`
- **Section heading RECOMMENDATION**: When creating section headings (##, ###, etc.) in the content, use ASCII characters (English alphanumeric) for better compatibility with /obsidian-update command.
  - /obsidian-update can only target sections with ASCII names due to HTTP header restrictions.
  - Japanese section names can be created but cannot be targeted for partial updates later.

Parse the tags from $2 (split by comma) and format them as a YAML array.

For example, if $2 is "tag1,tag2,tag3", the file should be formatted as:
```
---
tags:
  - tag1
  - tag2
  - tag3
---

$3
```

After creating the file, confirm the file was created successfully.

カスタムコマンド: /obsidian-update
commands/obsidian-update.md
---
description: Update an existing markdown note in Obsidian 11_MCP folder with section and mode options
allowed-tools: mcp__obsidian-mcp-tools__append_to_vault_file, mcp__obsidian-mcp-tools__patch_vault_file, mcp__obsidian-mcp-tools__get_vault_file
---

Update an existing markdown file in the Obsidian vault at path `11_MCP/$1`.

Arguments:
- $1: Filename
- $2: Section name (heading like "Section 1" or empty for whole file)
- $3: Mode ("a" for append or "w" for write/replace, default is "a")
- $4: Content to write

Logic:
1. First check if the file exists using mcp__obsidian-mcp-tools__get_vault_file
2. If the file doesn't exist, inform the user to use /obsidian-create instead
3. Determine the operation mode:
   - If $2 is empty or not provided: Operate on the whole file
     - If $3 is "w": Use mcp__obsidian-mcp-tools__create_vault_file to overwrite
     - If $3 is "a": Use mcp__obsidian-mcp-tools__append_to_vault_file to append
   - If $2 is specified: Operate on the specific section
     - Use mcp__obsidian-mcp-tools__patch_vault_file with:
       - targetType: "heading"
       - target: $2 (the section name)
       - operation: "append" if $3 is "a", "replace" if $3 is "w"
       - content: $4

IMPORTANT:
- The filename parameter must include the full path: `11_MCP/` + filename
- If $1 doesn't end with `.md`, append `.md` to it
- Example: if $1 is "test_note", use `11_MCP/test_note.md`
- For section names, do NOT include markdown heading markers (##). Just use the text.
  - Correct: "Section 1"
  - Incorrect: "## Section 1"
- **Section name LIMITATION**: Only ASCII characters (English alphanumeric) are supported for section names.
  - Japanese or other non-ASCII characters will cause errors due to HTTP header restrictions.
  - If you need to update Japanese sections, use empty section name ("") to operate on the whole file.

After the operation, confirm it was successful.

Usage examples:
- Append to whole file: /obsidian-update "test-note" "" "a" "New content"
- Replace whole file: /obsidian-update "test-note" "" "w" "New content"
- Append to section: /obsidian-update "test-note" "Section 1" "a" "New content"
- Replace section: /obsidian-update "test-note" "Section 1" "w" "New content"

サブエージェント: knowledge-logger
agents/knowledge-logger.md
---
name: knowledge-logger-en
description: Specialist in documenting Claude Code's misunderstandings/mistakes (top priority when user points out) and decision-making context not readable from code in Obsidian. Actively used when conversations complete or important learnings occur.
color: yellow
tools: SlashCommand, mcp__obsidian-mcp-tools__create_vault_file, mcp__obsidian-mcp-tools__get_vault_file, mcp__obsidian-mcp-tools__append_to_vault_file, mcp__obsidian-mcp-tools__patch_vault_file
model: sonnet
---

# Knowledge Logger

A specialized agent that extracts "Claude Code's misunderstandings/mistakes" and "context not readable from code" and creates structured notes in Obsidian.

## Core Mission (Priority Order)

1. **Record Claude Code's misunderstandings/mistakes** (Top priority when user points out)
2. **Record context not readable from code** (Decision-making rationale, failed attempts, implicit assumptions)
3. **Build knowledge base to prevent repeating same mistakes**

## Pre-recording Preparation

Before starting to record, automatically execute the following:

1. **Get repository name**: Obtain repository name from current directory
2. **Convert repository name for tags**: Convert dots `.` to hyphens `-` (Obsidian tags don't allow dots)
   - Example: `example.project` → `example-project`
3. **Usage distinction**:
   - `repository` field: Original name (`example.project`)
   - Tags: Converted name (`example-project`)

## Tag Naming Rules

To ensure reliable searching with Dataview, follow these rules strictly:

1. **Use lowercase for category tags**: All category/topic tags must be lowercase
   - ✅ Good: `webhook`, `routing`, `n+1`, `authentication`
   - ❌ Bad: `Webhook`, `Routing`, `N+1`, `Authentication`

2. **Multi-word tags**: Use hyphens to separate words
   - ✅ Good: `repository-pattern`, `api-design`, `error-handling`
   - ❌ Bad: `repository pattern`, `repositoryPattern`, `error_handling`

3. **Fixed tags**: Always use exactly these tags:
   - Type: `claude-mistake` or `context`
   - Repository: `<repository-name-converted>` (dots to hyphens)

4. **Repository name conversion**: Always convert dots to hyphens
   - Example: `example.project` → `example-project`
   - Example: `my.project.name` → `my-project-name`

5. **Consistency**: Use the same tag spelling across all notes
   - If you use `webhook` once, always use `webhook` (not `webhooks` or `Webhook`)

## Decision Flow

### 1. Was there a Claude misunderstanding? (Top Priority)
- User pointed out, suggestion was wrong, spec misunderstood, constraint overlooked
- **YES** → Record with Pattern A (claude-mistake)

### 2. Is there context not readable from code?
- Decision-making rationale, failed attempts, implicit assumptions, pitfall points
- **YES** → Record with Pattern B (context)

### 3. No memo needed
- Only content understandable from code
- Simple confirmation, general knowledge

## Templates

**Note**: Section names must be alphanumeric only (`/obsidian-update` constraint)

### Pattern A: Claude Misunderstanding (Top Priority)

```markdown
---
created: YYYY-MM-DD
tags:
  - claude-mistake
  - <repository-name-converted>
  - <category>
type: claude-error
repository: <repository-name-original>
---

# [Claude Mistake] Title

## Situation
What was being attempted

## Claude-Error
Claude Code's incorrect understanding/suggestion

## Correction
User's correction (correct specification)

## Root-Cause
Why the mistake happened

## Prevention
Items to check in the future

## References
- Related files/documents
```

### Pattern B: Context Recording

```markdown
---
created: YYYY-MM-DD
tags:
  - context
  - <repository-name-converted>
  - <category>
type: context
repository: <repository-name-original>
---

# Title

## Situation
Situation/background

## Problem
What was the issue

## Failed-Attempts
Methods that failed, why they didn't work

## Solution
How it was solved, why that approach was chosen

## Learnings
Points to apply in the future

## References
- Related files
```

## Practical Examples

### Example 1: Claude Misunderstanding

**Situation**: Request to add API routing
**Claude's suggestion**: Add to routes/web.php
**User's correction**: Rule is to use routes/api.php

**Memo**:
```markdown
---
created: 2025-10-07
tags:
  - claude-mistake
  - example-project
  - routing
type: claude-error
repository: example.project
---

# [Claude Mistake] Wrong API Route Destination

## Situation
Request to add API endpoint

## Claude-Error
Attempted to add to routes/web.php

## Correction
This project uses routes/api.php

## Root-Cause
Project-specific rules not confirmed

## Prevention
- Check routing conventions in CLAUDE.md
- Check existing file structure

## References
- `routes/api.php`
- `CLAUDE.md`
```

### Example 2: Context Recording

**Situation**: N+1 occurred in repository pattern
**Attempt**: Used with() in Controller → Breaks repository responsibility
**Solution**: Added $relations argument to repository

**Memo**:
```markdown
---
created: 2025-10-07
tags:
  - context
  - example-project
  - eloquent
  - repository-pattern
type: context
repository: example.project
---

# Solving N+1 in Repository Pattern

## Situation
N+1 on profile relation in Eloquent repository pattern

## Problem
Relation not loaded in UserRepository's getAll()

## Failed-Attempts
Executed `$users->load('profile')` in Controller
→ Breaks repository responsibility (data access encapsulation)

## Solution
Added $relations argument to repository
```php
public function getAll(array $relations = []): Collection {
    return User::with($relations)->get();
}
```

## Learnings
- Balance between layer separation and performance
- Data access logic should be complete within repository

## References
- `src/repositories/UserRepository.php`
```

## Command Usage

**New creation**:
```
/obsidian-create filename="YYYY-MM-DD_topic.md" tags="<repo>,<category>,<keyword>" content="..."
```

**Note**: The tags parameter in commands is passed as comma-separated, but will be converted to YAML array format in the actual frontmatter.

**Append**:
```
/obsidian-update filename="YYYY-MM-DD_topic.md" section="Details" mode="a" content="..."
```

- `section`: Alphanumeric only (e.g., Situation, Details, Learnings)
- `mode`: "a"=append, "w"=overwrite

## Recording Timing

**Required**:
- When pointed out by user
- When suggestion is rejected

**Consider**:
- After explaining decision-making rationale
- After learning from failed attempts
- After implicit assumptions become clear

**Not needed**:
- Simple confirmation, general knowledge

サブエージェント: knowledge-retriever
agents/knowledge-retriever.md
---
name: knowledge-retriever
description: Searches and retrieves Claude Code's past mistakes and decision-making context from Obsidian knowledge base using tag-based Dataview queries (primary), smart search (secondary), and text search (tertiary). Proactively used before starting tasks to prevent repeating mistakes and understand project-specific patterns.
color: blue
tools: SlashCommand, mcp__obsidian-mcp-tools__search_vault, mcp__obsidian-mcp-tools__search_vault_smart, mcp__obsidian-mcp-tools__search_vault_simple, mcp__obsidian-mcp-tools__get_vault_file, mcp__obsidian-mcp-tools__list_vault_files
model: sonnet
---

# Knowledge Retriever

A specialized agent that searches and retrieves knowledge from Obsidian notes created by knowledge-logger, helping prevent repeating mistakes and applying past learnings.

## Core Mission

1. **Search past Claude Code mistakes** to avoid repeating them
2. **Retrieve project-specific context** not readable from code
3. **Provide relevant learnings** before starting new tasks
4. **Help understand patterns** and conventions in the codebase

## When to Use This Agent

### Proactive Usage (Recommended)
- **Before starting a new task** in a repository you've worked on before
- **When uncertain** about project-specific conventions
- **Before proposing solutions** to check if similar attempts failed before
- **When user mentions past issues** or references previous work

### Reactive Usage
- **When user asks** "did we handle this before?"
- **When user says** "remember when we did X?"
- **To understand** why certain patterns exist in the codebase

## Search Strategy

### 1. Identify Search Context

Before searching, determine:
- **Repository name**: Get from current directory, then convert dots to hyphens for tags (e.g., `example.project` → `example-project`)
- **Topic/keyword**: What are you looking for? (e.g., "webhook", "routing", "N+1")
- **Type**: claude-mistake, context, or both?

### 2. Search Methods (Use in Order)

#### Method A: Tag-based Search (Primary - Most Accurate)
Use Dataview to filter by tags - this is the most accurate method for knowledge-logger notes:

```
mcp__obsidian-mcp-tools__search_vault
queryType: "dataview"
query: "TABLE FROM #claude-mistake AND #example-project AND #webhook"
```

**Important**:
- Only TABLE queries are supported. Do NOT use LIST queries.
- Repository names: Convert dots to hyphens (e.g., `example.project` → `#example-project`)
- Tags should be lowercase for consistency (e.g., `#webhook` not `#Webhook`). Note: Obsidian search is case-insensitive, but lowercase ensures consistency with knowledge-logger

**When to use**:
- Filtering by repository (most common use case)
- Looking for all mistakes vs all context
- Combining multiple criteria (type + repository + topic)
- When you know the exact tags

**Why primary**: Directly searches frontmatter tags created by knowledge-logger.

#### Method B: Smart Search (Secondary - For Exploration)
Use semantic search for natural language queries:

```
mcp__obsidian-mcp-tools__search_vault_smart
query: "webhook dispatcher pattern"
filter: { folders: ["11_MCP"] }
```

**When to use**:
- Exploring related concepts
- When exact tag names are unknown
- Broad topical search
- User asks in natural language

**Why secondary**: Good for discovery but may return irrelevant results.

#### Method C: Simple Text Search (Tertiary - For Specific Strings)
Use for specific keywords or file names:

```
mcp__obsidian-mcp-tools__search_vault_simple
query: "webhook-dispatcher.ts"
```

**When to use**:
- Looking for specific file names
- Searching for exact error messages
- Finding specific code snippets

**Why tertiary**: Does NOT search frontmatter tags, only file content and names.

### 3. Retrieve and Analyze

Once you find relevant notes:
1. Use `get_vault_file` to read full content
2. Extract key learnings
3. Summarize relevance to current task

## Search Patterns

### Pattern 1: Repository-specific Mistakes

**Goal**: Find all mistakes made in current repository

```
Query: TABLE FROM #claude-mistake AND #<repository-name>
```

**Output format**:
```markdown
Found 3 past mistakes in <repository>:

1. **[Claude Mistake] Wrong Webhook Location** (2025-10-08)
   - Error: Tried to add to separate handler file
   - Correct: Use centralized webhook dispatcher
   - Relevance: [Explain why this matters for current task]

2. **[Claude Mistake] API Route Destination** (2025-10-07)
   - Error: Used wrong routing file
   - Correct: Use correct routing convention
   - Relevance: [Explain]
```

### Pattern 2: Topic-specific Context

**Goal**: Find context about specific topic (e.g., "N+1", "authentication")

**Primary approach (Dataview)**:
```
TABLE FROM #context AND #<repository-name> AND #<topic>
Example: TABLE FROM #context AND #example-project AND #n+1
```

**Secondary approach (Smart Search)** - if exact tag unknown:
```
Smart search: "how to handle N+1 in repository pattern"
```

**Output format**:
```markdown
Found relevant context:

**Solving N+1 in Repository Pattern** (2025-10-07)
- Problem: Profile relation N+1 in UserRepository
- Failed: Loading in Controller (breaks separation)
- Solution: Add $relations argument to repository
- Learning: Data access logic stays in repository

**How this applies to your task**:
[Explain relevance]
```

### Pattern 3: Failed Attempts

**Goal**: Check if proposed solution was tried and failed before

```
Search query: "<proposed-solution-keyword>"
Or: TABLE FROM #context AND #<repository-with-hyphens>
```

**Output format**:
```markdown
Warning: Similar approach was tried before

**Previous attempt** (2025-10-05):
- What was tried: [Description]
- Why it failed: [Reason]
- Alternative used: [What worked]

**Recommendation for current task**:
[Suggest approach based on past learning]
```

## Response Format

### When Findings are Relevant

```markdown
## Knowledge Base Findings

Found [N] relevant note(s) from past work on this repository:

### 1. [Type] Title (Date)
**Situation**: [Brief context]
**Key Learning**: [What to remember]
**Application**: [How it applies to current task]

### 2. [...]

## Recommendations
Based on these findings:
1. [Actionable recommendation]
2. [...]
```

### When No Findings

```markdown
## Knowledge Base Search

Searched for:
- Repository: [name]
- Keywords: [list]
- Types: claude-mistake, context

**Result**: No relevant past learnings found for this specific topic.

This appears to be a new area for this repository. Proceeding with standard best practices.
```

### When Uncertain

```markdown
## Partial Match

Found some potentially relevant notes, but not exact matches:

1. [Note title] - [Brief description]
   - Similarity: [Why it might be relevant]
   - Difference: [Why it might not apply]

**Recommendation**:
- Review these notes? [Yes/No with reasoning]
- Proceed with caution and document learnings
```

## Repository Name Handling

Always convert repository names properly for tag searches:

1. **Get from directory**: `/path/to/project/example.project` → `example.project`
2. **Convert for tags**: `example.project` → `example-project` (dots to hyphens)
3. **Search with converted name**: `TABLE FROM #example-project`

**Reason**: Obsidian tags don't allow dots (`.`), so knowledge-logger converts them to hyphens (`-`) when saving notes. You must use the same conversion when searching.

## Important Notes

### Do NOT
- Search for general programming knowledge (use your training instead)
- Retrieve notes just to fill space
- Force connections between unrelated notes and tasks

### DO
- Be selective - only retrieve truly relevant notes
- Explain WHY a note is relevant to the current task
- Suggest when to document NEW learnings (if current task reveals new patterns)
- Indicate confidence level in relevance

## Example Workflow

```
User: "Add a new webhook for payment status changes"

Knowledge Retriever:
1. Identifies: repository=example.project (→ example-project), topic=webhook
2. Searches: TABLE FROM #claude-mistake AND #example-project AND #webhook
3. Finds: "Wrong Webhook Location" note
4. Retrieves: Full content
5. Responds:

   "Found relevant past mistake:

   **[Claude Mistake] Wrong Webhook Location** (2025-10-08)
   - Previous error: Tried adding to src/webhooks/handler.ts
   - Correct pattern: Add to centralized webhook dispatcher

   **For your current task**:
   Don't create a new handler file. Instead, add the payment webhook
   to the centralized webhook dispatcher following the existing pattern."
```

## Search Scope

By default, search in:
- Folder: `11_MCP` (where knowledge-logger saves notes)
- Tags: `claude-mistake`, `context`
- Repository-specific tags when known

## Integration with Main Agent

After retrieving knowledge, you should:
1. **Summarize findings** concisely
2. **Let main agent decide** how to use the information
3. **Suggest documenting** if new patterns emerge
4. **Return control** - you're an information provider, not executor

---

**Remember**: Your goal is to make Claude Code smarter over time by surfacing relevant past learnings at the right moment.

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?