Initial release: Claude Code × Obsidian Wiki framework
This commit is contained in:
commit
f8d084eae4
23 changed files with 833 additions and 0 deletions
332
README.md
Normal file
332
README.md
Normal file
|
|
@ -0,0 +1,332 @@
|
||||||
|
# Claude Code × Obsidian Wiki — Your AI Remembers, Reflects, and Evolves
|
||||||
|
|
||||||
|
> AIが勝手に記憶し、整理し、毎朝振り返ってくれるナレッジシステム
|
||||||
|
>
|
||||||
|
> Inspired by [Karpathy's LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) + OpenClaw's Dreaming pattern
|
||||||
|
|
||||||
|
Claude Codeの中に眠っている記憶(Memory)、設定ファイル(CLAUDE.md)、スキル(Skills)を
|
||||||
|
Obsidianで可視化し、毎朝・毎夕のDreamingで自動振り返りを行う仕組み。
|
||||||
|
|
||||||
|
PC閉じてても動く。iPhoneからも見える。人間はObsidianを開いて読むだけ。
|
||||||
|
|
||||||
|
## コンセプト
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─ Claude Code の世界(普段は .claude/ に隠れている)───────────┐
|
||||||
|
│ │
|
||||||
|
│ CLAUDE.md ×N ←──┐ │
|
||||||
|
│ CC Memory ×N ←──┤── 自動同期 ──→ ~/vault/ │
|
||||||
|
│ Skills ×N ←──┤ (Obsidian) │
|
||||||
|
│ Cron jobs ←──┘ 人間が見る窓 │
|
||||||
|
│ │
|
||||||
|
│ + 日記(daily/)は Obsidian にだけ存在 │
|
||||||
|
│ + Dreaming(朝夕の自動振り返り)で知見が複利で増える │
|
||||||
|
│ │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3つの性格を持つハイブリッド設計
|
||||||
|
|
||||||
|
```
|
||||||
|
vault/
|
||||||
|
├── system/, skills/, memory/
|
||||||
|
│ → 静的ミラー(ダッシュボード)
|
||||||
|
│ → Claude Codeの中身を自動同期、人間は読むだけ
|
||||||
|
│ → <!-- SYNCED: DO NOT EDIT --> ヘッダー付き
|
||||||
|
│
|
||||||
|
├── daily/
|
||||||
|
│ → 自動ログ + 手書き日記
|
||||||
|
│ → Calendar + Slack + Gmail + AI Analysis
|
||||||
|
│ → 朝夕2回のDreaming(パターン検出・振り返り)
|
||||||
|
│
|
||||||
|
└── meetings/, clients/, insights/
|
||||||
|
→ Karpathyパターン(知識が複利で増える)
|
||||||
|
→ 議事録を処理するたびに顧客ページに自動蓄積
|
||||||
|
→ 12回の議事録を読み返す必要がない
|
||||||
|
```
|
||||||
|
|
||||||
|
## アーキテクチャ
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─ Layer 1: Cloud Scheduled Tasks(PC不要)──────────────────┐
|
||||||
|
│ │
|
||||||
|
│ 毎朝 07:00 vault-daily-morning │
|
||||||
|
│ ├── Google Calendar → 今日の予定 │
|
||||||
|
│ ├── Slack → 昨夜〜今朝のハイライト │
|
||||||
|
│ ├── Gmail → 未読・重要メール │
|
||||||
|
│ ├── Morning Dreaming(昨日の振り返り→今日の注目) │
|
||||||
|
│ └── GitHub push │
|
||||||
|
│ │
|
||||||
|
│ 毎夕 18:30 vault-daily-evening │
|
||||||
|
│ ├── Evening Dreaming(今日+7日分→パターン検出) │
|
||||||
|
│ ├── 日曜は週次Dreaming + Lint + Slack通知 │
|
||||||
|
│ └── GitHub push │
|
||||||
|
│ │
|
||||||
|
└──────────────────────┬──────────────────────────────────────┘
|
||||||
|
│ push
|
||||||
|
▼
|
||||||
|
┌─ GitHub (private repo) ─────────────────────────────────────┐
|
||||||
|
│ vault/ の全ファイル │
|
||||||
|
└──────────────────────┬──────────────────────────────────────┘
|
||||||
|
│ pull (launchd 毎時)
|
||||||
|
▼
|
||||||
|
┌─ Layer 2: ローカル自動化 ───────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
│ Claude Code Hooks (async: true) │
|
||||||
|
│ ├── PostToolUse → ファイル変更をログ記録 │
|
||||||
|
│ └── Stop → セッション終了をdaily noteに自動追記 │
|
||||||
|
│ │
|
||||||
|
│ OpenClaw Cron(PCオン時の追加データ) │
|
||||||
|
│ ├── SF/Stripe/HERP/YouTube等の専門データ追記 │
|
||||||
|
│ └── PCオフなら単にスキップ(Layer 1だけで完成) │
|
||||||
|
│ │
|
||||||
|
└──────────────────────┬──────────────────────────────────────┘
|
||||||
|
│ iCloud
|
||||||
|
▼
|
||||||
|
Obsidian (Mac + iPhone)
|
||||||
|
```
|
||||||
|
|
||||||
|
## AIの記憶システム(Memory)
|
||||||
|
|
||||||
|
Claude Codeは `.claude/projects/*/memory/` に記憶を保存する。
|
||||||
|
この記憶がObsidianに自動ミラーされ、人間が読める形になる。
|
||||||
|
|
||||||
|
```
|
||||||
|
memory/
|
||||||
|
├── feedback/ (21件) ← AIへの行動指針
|
||||||
|
│ ├── never-send-email.md 「メール送信は絶対禁止。下書きのみ」
|
||||||
|
│ ├── gas-version-control.md 「GAS編集後は毎回git commit」
|
||||||
|
│ └── minutes-include-sf.md 「議事録にはSF+Slack報告も含める」
|
||||||
|
│
|
||||||
|
├── reference/ (7件) ← 外部システムへのポインタ
|
||||||
|
│ ├── wordpress-api.md 「APIの認証情報はここ」
|
||||||
|
│ └── typefully-api.md 「X投稿はTypefully経由」
|
||||||
|
│
|
||||||
|
├── project/ (4件) ← プロジェクト状況
|
||||||
|
│ └── personal-budget.md 「月間支出目標¥3,000,000」
|
||||||
|
│
|
||||||
|
└── user/ (1件) ← ユーザープロファイル
|
||||||
|
└── user-profile.md 「シェル環境にまだ詳しくない」
|
||||||
|
```
|
||||||
|
|
||||||
|
AIが過去の失敗や指示を覚えていて、次から同じミスをしない。
|
||||||
|
その記憶が全部Obsidianで見える。「何を覚えてるの?」が一目瞭然。
|
||||||
|
|
||||||
|
## Dreaming(朝夕の自動振り返り)
|
||||||
|
|
||||||
|
OpenClawのSOUL/MEMORY/DREAMSパターンを参考に設計。
|
||||||
|
|
||||||
|
```
|
||||||
|
毎朝 07:00 — Morning Dreaming
|
||||||
|
├── 昨日のdaily noteを読み返す
|
||||||
|
├── 決定事項・未解決タスクを抽出
|
||||||
|
└── 「今日の注目ポイント」を3行で生成
|
||||||
|
|
||||||
|
毎夕 18:30 — Evening Dreaming
|
||||||
|
├── 今日のSlack/Gmail/Calendarを振り返り
|
||||||
|
├── 直近7日とのパターン比較
|
||||||
|
│ 例: 「火曜は会議密度が高い(3週連続)」
|
||||||
|
│ 例: 「メール返信が午後に集中」
|
||||||
|
├── 未解決の問いを抽出
|
||||||
|
└── パターンが見つかったら insights/ にページ作成
|
||||||
|
|
||||||
|
毎週日曜 — Weekly Dreaming
|
||||||
|
├── 1週間分のdailyから洞察を抽出
|
||||||
|
├── DREAMS.md に成長軌跡を記録
|
||||||
|
├── Lint(壊れたリンク・orphanページ検出)
|
||||||
|
└── Slackでサマリー通知
|
||||||
|
```
|
||||||
|
|
||||||
|
DREAMS.mdに蓄積される内容:
|
||||||
|
- Current Insights(最新の内省結果)
|
||||||
|
- Emerging Patterns(浮かび上がるパターン)
|
||||||
|
- Growth Trajectory(成長の軌跡)
|
||||||
|
- Open Questions(未解決の問い)
|
||||||
|
|
||||||
|
## Vault構造
|
||||||
|
|
||||||
|
```
|
||||||
|
~/vault/
|
||||||
|
├── CLAUDE.md ← Schema(LLM向けルール定義)
|
||||||
|
├── DREAMS.md ← Dreaming蓄積ファイル
|
||||||
|
│
|
||||||
|
├── daily/ ← デイリーノート
|
||||||
|
│ └── 2026-04-07.md Schedule / Gmail / Slack / AI Analysis /
|
||||||
|
│ Morning Reflection / Evening Reflection /
|
||||||
|
│ Claude Code Session / Thoughts
|
||||||
|
│
|
||||||
|
├── system/ ← Claude Codeシステムのミラー(SYNCED)
|
||||||
|
│ ├── claude-md-tree.md 全CLAUDE.mdの階層ツリー
|
||||||
|
│ ├── global-rules.md ルール・禁止事項の要約
|
||||||
|
│ ├── api-inventory.md 保有API一覧(キーは除外)
|
||||||
|
│ ├── tech-stack.md 技術スタック
|
||||||
|
│ └── cron-jobs.md 稼働中ジョブ一覧
|
||||||
|
│
|
||||||
|
├── skills/ ← 全スキル一覧 + 個別ページ(SYNCED)
|
||||||
|
│ ├── _index.md カテゴリ別テーブル
|
||||||
|
│ └── auto-minutes.md 各スキルの説明・コマンド
|
||||||
|
│
|
||||||
|
├── memory/ ← CC Memory完全ミラー(SYNCED)
|
||||||
|
│ ├── _index.md 全メモリ一覧(タイプ別)
|
||||||
|
│ ├── feedback/ 行動指針
|
||||||
|
│ ├── reference/ 外部参照
|
||||||
|
│ ├── project/ プロジェクト状況
|
||||||
|
│ └── user/ ユーザープロファイル
|
||||||
|
│
|
||||||
|
├── clients/ ← 顧客ナレッジ蓄積(Karpathyパターン)
|
||||||
|
│ ├── _index.md 全顧客一覧
|
||||||
|
│ └── naoru.md 議事録のたびに自動蓄積
|
||||||
|
│
|
||||||
|
├── meetings/ ← 議事録要点(/auto-minutes連携)
|
||||||
|
├── decisions/ ← 経営判断ログ
|
||||||
|
├── insights/ ← 学び・パターン + 週次Dreaming
|
||||||
|
├── templates/ ← daily-note, meeting, decision
|
||||||
|
└── scripts/ ← hookスクリプト + 同期スクリプト
|
||||||
|
```
|
||||||
|
|
||||||
|
## セットアップ手順
|
||||||
|
|
||||||
|
### 前提条件
|
||||||
|
- Claude Code(Pro or Max)
|
||||||
|
- Obsidian(無料)
|
||||||
|
- GitHub アカウント
|
||||||
|
- (オプション)Slack / Google Calendar / Gmail の Connector
|
||||||
|
|
||||||
|
### Step 1: Vault作成
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# フォルダ作成
|
||||||
|
mkdir -p ~/vault/{daily,system,skills,memory/{feedback,reference,project,user},clients,meetings,decisions,insights,templates,scripts}
|
||||||
|
|
||||||
|
# iCloud同期(iPhone対応する場合)
|
||||||
|
mv ~/vault ~/Library/Mobile\ Documents/iCloud~md~obsidian/Documents/claude-code
|
||||||
|
ln -s ~/Library/Mobile\ Documents/iCloud~md~obsidian/Documents/claude-code ~/vault
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: テンプレートファイルをコピー
|
||||||
|
|
||||||
|
このリポジトリの `vault-template/` をコピー:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -r vault-template/* ~/vault/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Claude Code Hooks 設定
|
||||||
|
|
||||||
|
`~/.claude/settings.json` に追加:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"PostToolUse": [{
|
||||||
|
"matcher": "Write|Edit",
|
||||||
|
"hooks": [{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash ~/vault/scripts/on-file-change.sh",
|
||||||
|
"async": true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"Stop": [{
|
||||||
|
"hooks": [{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash ~/vault/scripts/on-session-end.sh",
|
||||||
|
"async": true
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: 初回同期
|
||||||
|
|
||||||
|
Claude Codeで実行:
|
||||||
|
|
||||||
|
```
|
||||||
|
/wiki-sync-init
|
||||||
|
```
|
||||||
|
|
||||||
|
または手動:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Skills同期
|
||||||
|
for d in ~/.claude/skills/*/; do
|
||||||
|
name=$(basename "$d")
|
||||||
|
# SKILL.md を読んで vault/skills/ にページ作成
|
||||||
|
done
|
||||||
|
|
||||||
|
# Memory同期
|
||||||
|
find ~/.claude/projects -name "*.md" -path "*/memory/*" ! -name "MEMORY.md" | while read src; do
|
||||||
|
# vault/memory/ にミラー作成
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: GitHub + 自動pull
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/vault
|
||||||
|
git init && git add -A && git commit -m "Initial vault"
|
||||||
|
gh repo create my-vault --private --source=. --push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: Cloud Scheduled Tasks(オプション、PC不要にする場合)
|
||||||
|
|
||||||
|
claude.ai/code/scheduled で:
|
||||||
|
- **vault-daily-morning**: 毎朝07:00、Calendar+Slack+Gmail→daily note生成
|
||||||
|
- **vault-daily-evening**: 毎夕18:30、Evening Dreaming+パターン検出
|
||||||
|
|
||||||
|
## デイリーノートの完成形
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
date: 2026-04-07
|
||||||
|
weekday: Monday
|
||||||
|
type: daily
|
||||||
|
score: 74
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schedule
|
||||||
|
| 時間 | 予定 | 備考 |
|
||||||
|
|------|------|------|
|
||||||
|
| 09:00 | 経営管理部 定例 | |
|
||||||
|
| 10:00 | 開発営業 定例 | |
|
||||||
|
| 14:00 | デジライズ定例 | |
|
||||||
|
|
||||||
|
## Gmail
|
||||||
|
| From | Subject | Action |
|
||||||
|
|------|---------|--------|
|
||||||
|
| freee 上野 | セミナー開催打合せ | 要返信 |
|
||||||
|
|
||||||
|
## Slack Highlights
|
||||||
|
- **#経営**: 人事部長アサイン議論
|
||||||
|
- **#開発営業**: チャットbot進捗、SF議事録デモ依頼
|
||||||
|
- **#日報_柴田**: エイジス様研修225万円受注ほぼ確定
|
||||||
|
|
||||||
|
## AI Analysis
|
||||||
|
- 生産性: B — 会議完了率100%
|
||||||
|
- 対応力: B — 未読メール6件
|
||||||
|
- 営業: B- — 商談0件
|
||||||
|
|
||||||
|
## Morning Reflection
|
||||||
|
- 昨日の決定: スクール料金改定を決定
|
||||||
|
- 今日の注目: freeeセミナー返信、金成さんMTG
|
||||||
|
|
||||||
|
## Evening Reflection
|
||||||
|
- 今日のハイライト: エイジス225万円ほぼ確定
|
||||||
|
- パターン: 月曜は会議が10件超で最多(3週連続)
|
||||||
|
- 未解決: freeeセミナー返信
|
||||||
|
|
||||||
|
## Thoughts
|
||||||
|
<!-- 自分で一言 -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## 参考
|
||||||
|
|
||||||
|
- [Karpathy's LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) — 設計思想の原点
|
||||||
|
- [obsidian-wiki (Ar9av)](https://github.com/Ar9av/obsidian-wiki) — Karpathyパターンのフレームワーク
|
||||||
|
- [QMD](https://github.com/tobi/qmd) — Markdownセマンティック検索(100ページ超で導入検討)
|
||||||
|
- [Claude Code Hooks](https://code.claude.com/docs/en/hooks-guide) — async hookの公式ドキュメント
|
||||||
|
- [Cloud Scheduled Tasks](https://code.claude.com/docs/en/web-scheduled-tasks) — PC不要の自動化
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
7
vault-template/.gitignore
vendored
Normal file
7
vault-template/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
.obsidian/workspace.json
|
||||||
|
.obsidian/workspace-mobile.json
|
||||||
|
.obsidian/graph.json
|
||||||
|
.sync.log
|
||||||
|
.DS_Store
|
||||||
|
.trash/
|
||||||
|
.git-sync.lock
|
||||||
32
vault-template/CLAUDE.md
Normal file
32
vault-template/CLAUDE.md
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Obsidian Vault Schema
|
||||||
|
|
||||||
|
> このファイルはLLMがvaultを読み書きする際のルール定義。
|
||||||
|
|
||||||
|
## ファイル区分
|
||||||
|
|
||||||
|
| 区分 | 場所 | 編集権限 | ヘッダー |
|
||||||
|
|------|------|---------|---------|
|
||||||
|
| SYNCED | system/, skills/, memory/ | 自動同期のみ。手動編集禁止 | `<!-- SYNCED: DO NOT EDIT -->` |
|
||||||
|
| editable | daily/, meetings/, clients/, decisions/, insights/ | Claude + 人間が自由に編集 | なし |
|
||||||
|
|
||||||
|
## 書き込みルール
|
||||||
|
|
||||||
|
1. **frontmatter必須** — 全ページに YAML frontmatter を付ける
|
||||||
|
2. **日本語** — 本文は日本語。タグ・フォルダ名は英語kebab-case
|
||||||
|
3. **日付フォーマット** — YYYY-MM-DD(ISO 8601)
|
||||||
|
4. **SYNCEDファイルの冒頭** — `<!-- SYNCED: DO NOT EDIT -->` を1行目に
|
||||||
|
|
||||||
|
## リンク規約
|
||||||
|
|
||||||
|
- 内部リンク: `[[フォルダ/ファイル名]]` 形式
|
||||||
|
- 外部ソース: frontmatterの `source:` フィールドにパス記載
|
||||||
|
- 双方向リンク推奨
|
||||||
|
|
||||||
|
## 命名規則
|
||||||
|
|
||||||
|
| コンテンツ | パターン | 例 |
|
||||||
|
|-----------|---------|-----|
|
||||||
|
| デイリーノート | `YYYY-MM-DD.md` | `2026-04-07.md` |
|
||||||
|
| 議事録 | `YYYY-MM-DD_<顧客>_<種別>.md` | `2026-04-07_naoru_定例.md` |
|
||||||
|
| 判断ログ | `YYYY-MM_<テーマ>.md` | `2026-04_料金改定.md` |
|
||||||
|
| 顧客 | `<kebab-case>.md` | `naoru.md` |
|
||||||
22
vault-template/DREAMS.md
Normal file
22
vault-template/DREAMS.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
type: dreams
|
||||||
|
updated:
|
||||||
|
last_dreaming:
|
||||||
|
---
|
||||||
|
|
||||||
|
# Dreams
|
||||||
|
|
||||||
|
## Current Insights
|
||||||
|
<!-- weekly-dreaming が毎週自動更新 -->
|
||||||
|
|
||||||
|
## Emerging Patterns
|
||||||
|
|
||||||
|
| パターン | 観測回数 | 傾向 |
|
||||||
|
|---------|---------|------|
|
||||||
|
<!-- Dreamingが蓄積 -->
|
||||||
|
|
||||||
|
## Growth Trajectory
|
||||||
|
<!-- 月次サマリーが追記される -->
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
<!-- Dreamingが検出した未解決課題 -->
|
||||||
0
vault-template/clients/.gitkeep
Normal file
0
vault-template/clients/.gitkeep
Normal file
0
vault-template/daily/.gitkeep
Normal file
0
vault-template/daily/.gitkeep
Normal file
0
vault-template/decisions/.gitkeep
Normal file
0
vault-template/decisions/.gitkeep
Normal file
0
vault-template/insights/.gitkeep
Normal file
0
vault-template/insights/.gitkeep
Normal file
0
vault-template/meetings/.gitkeep
Normal file
0
vault-template/meetings/.gitkeep
Normal file
0
vault-template/memory/feedback/.gitkeep
Normal file
0
vault-template/memory/feedback/.gitkeep
Normal file
0
vault-template/memory/project/.gitkeep
Normal file
0
vault-template/memory/project/.gitkeep
Normal file
0
vault-template/memory/reference/.gitkeep
Normal file
0
vault-template/memory/reference/.gitkeep
Normal file
0
vault-template/memory/user/.gitkeep
Normal file
0
vault-template/memory/user/.gitkeep
Normal file
40
vault-template/scripts/git-pull-sync.sh
Executable file
40
vault-template/scripts/git-pull-sync.sh
Executable file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# git-pull-sync.sh — GitHub から最新を取得して iCloud に反映
|
||||||
|
# launchd で毎時実行。Cloud Taskがpushした変更をローカルに取り込む。
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
|
VAULT_DIR="$HOME/vault"
|
||||||
|
LOG_FILE="$VAULT_DIR/.sync.log"
|
||||||
|
LOCKFILE="$VAULT_DIR/.git-sync.lock"
|
||||||
|
|
||||||
|
cd "$VAULT_DIR" || exit 0
|
||||||
|
|
||||||
|
# ロックファイルで同時実行を防止
|
||||||
|
if [ -f "$LOCKFILE" ] && kill -0 "$(cat "$LOCKFILE" 2>/dev/null)" 2>/dev/null; then
|
||||||
|
echo "[$(date '+%F %T')] git-pull: locked, skipping" >> "$LOG_FILE"; exit 0
|
||||||
|
fi
|
||||||
|
echo $$ > "$LOCKFILE"
|
||||||
|
trap 'rm -f "$LOCKFILE"' EXIT
|
||||||
|
|
||||||
|
DIRTY=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
if [ "$DIRTY" -gt "0" ]; then
|
||||||
|
git stash 2>/dev/null
|
||||||
|
if ! git pull --rebase origin main 2>/dev/null; then
|
||||||
|
git rebase --abort 2>/dev/null
|
||||||
|
echo "[$(date '+%F %T')] git-pull: rebase failed, aborted" >> "$LOG_FILE"
|
||||||
|
fi
|
||||||
|
if ! git stash pop 2>/dev/null; then
|
||||||
|
echo "[$(date '+%F %T')] git-pull: stash pop FAILED — manual resolution needed" >> "$LOG_FILE"
|
||||||
|
git checkout -- . 2>/dev/null
|
||||||
|
git stash drop 2>/dev/null
|
||||||
|
fi
|
||||||
|
echo "[$(date '+%F %T')] git-pull: pulled with stash (dirty=$DIRTY)" >> "$LOG_FILE"
|
||||||
|
else
|
||||||
|
RESULT=$(git pull --rebase origin main 2>&1)
|
||||||
|
if ! echo "$RESULT" | grep -q "Already up to date"; then
|
||||||
|
echo "[$(date '+%F %T')] git-pull: $RESULT" >> "$LOG_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
48
vault-template/scripts/on-file-change.sh
Executable file
48
vault-template/scripts/on-file-change.sh
Executable file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# on-file-change.sh — Claude Code PostToolUse hook (Write|Edit)
|
||||||
|
# ファイル変更時にvaultの関連ページを更新する
|
||||||
|
# 呼び出し元: ~/.claude/settings.json → hooks.PostToolUse (async: true)
|
||||||
|
set +e
|
||||||
|
|
||||||
|
LOG="$HOME/vault/.sync.log"
|
||||||
|
|
||||||
|
# stdinからJSON(tool_input)を読み取る
|
||||||
|
INPUT=$(cat 2>/dev/null || true)
|
||||||
|
[ -z "$INPUT" ] && exit 0
|
||||||
|
|
||||||
|
# 変更されたファイルパスを抽出
|
||||||
|
FP=$(echo "$INPUT" | python3 -c "
|
||||||
|
import sys, json
|
||||||
|
try:
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
ti = d.get('tool_input', d)
|
||||||
|
print(ti.get('file_path', ti.get('path', '')))
|
||||||
|
except:
|
||||||
|
print('')
|
||||||
|
" 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
[ -z "$FP" ] && exit 0
|
||||||
|
|
||||||
|
# パスに基づいて同期対象を判定(case文でgrepを避ける)
|
||||||
|
case "$FP" in
|
||||||
|
*/vault/*)
|
||||||
|
# vault内のファイル変更は無視(再帰防止)
|
||||||
|
;;
|
||||||
|
*/CLAUDE.md)
|
||||||
|
echo "[$(date '+%F %T')] CLAUDE.md changed: $FP" >> "$LOG"
|
||||||
|
;;
|
||||||
|
*/.claude/projects/*/memory/*|*/memory/*)
|
||||||
|
echo "[$(date '+%F %T')] Memory changed: $FP" >> "$LOG"
|
||||||
|
;;
|
||||||
|
*/.claude/skills/*|*/skills/*)
|
||||||
|
echo "[$(date '+%F %T')] Skill changed: $FP" >> "$LOG"
|
||||||
|
;;
|
||||||
|
*/clients/*/minutes/*)
|
||||||
|
echo "[$(date '+%F %T')] Minutes changed: $FP" >> "$LOG"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# 同期対象外
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
63
vault-template/scripts/on-session-end.sh
Executable file
63
vault-template/scripts/on-session-end.sh
Executable file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# on-session-end.sh — Claude Code Stop hook
|
||||||
|
# セッション終了時にdaily noteにサマリーを追記する
|
||||||
|
# 呼び出し元: ~/.claude/settings.json → hooks.Stop (async: true)
|
||||||
|
set +e
|
||||||
|
|
||||||
|
VAULT_DIR="$HOME/vault"
|
||||||
|
DAILY_DIR="$VAULT_DIR/daily"
|
||||||
|
LOG="$VAULT_DIR/.sync.log"
|
||||||
|
TODAY=$(date +%Y-%m-%d)
|
||||||
|
DAILY_FILE="$DAILY_DIR/$TODAY.md"
|
||||||
|
NOW=$(date +%H:%M)
|
||||||
|
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] on-session-end" >> "$LOG"
|
||||||
|
|
||||||
|
# daily noteが存在しない場合は作成
|
||||||
|
if [ ! -f "$DAILY_FILE" ]; then
|
||||||
|
WEEKDAY=$(TODAY="$TODAY" python3 -c "
|
||||||
|
import os, datetime
|
||||||
|
d = datetime.date.fromisoformat(os.environ['TODAY'])
|
||||||
|
print(d.strftime('%A'))
|
||||||
|
")
|
||||||
|
printf -- "---\ndate: %s\nweekday: %s\n---\n\n## Schedule\n\n## Log\n\n## Thoughts\n\n## Links\n" "$TODAY" "$WEEKDAY" > "$DAILY_FILE"
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Created daily note: $DAILY_FILE" >> "$LOG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# stdinからJSONを読み取る(hookから渡される)
|
||||||
|
INPUT=$(cat 2>/dev/null || true)
|
||||||
|
CWD=$(echo "${INPUT:-{}}" | python3 -c "import sys,json;print(json.load(sys.stdin).get('cwd',''))" 2>/dev/null || echo "")
|
||||||
|
LABEL=$([ -n "$CWD" ] && basename "$CWD" || echo "unknown")
|
||||||
|
|
||||||
|
ENTRY="- $NOW セッション終了 (cwd: $LABEL)"
|
||||||
|
|
||||||
|
# ## Log セクションに追記(環境変数経由でPythonに渡す — シェル補間を避ける)
|
||||||
|
export DAILY_FILE ENTRY
|
||||||
|
python3 -c '
|
||||||
|
import os
|
||||||
|
|
||||||
|
f = os.environ["DAILY_FILE"]
|
||||||
|
e = os.environ["ENTRY"]
|
||||||
|
|
||||||
|
lines = open(f).readlines()
|
||||||
|
out = []
|
||||||
|
in_log = False
|
||||||
|
done = False
|
||||||
|
|
||||||
|
for l in lines:
|
||||||
|
if l.strip() == "## Log":
|
||||||
|
in_log = True
|
||||||
|
out.append(l)
|
||||||
|
continue
|
||||||
|
if in_log and not done and l.startswith("## "):
|
||||||
|
out.append(e + "\n\n")
|
||||||
|
done = True
|
||||||
|
out.append(l)
|
||||||
|
|
||||||
|
if in_log and not done:
|
||||||
|
out.append(e + "\n\n")
|
||||||
|
|
||||||
|
open(f, "w").writelines(out)
|
||||||
|
' 2>/dev/null || echo "$ENTRY" >> "$DAILY_FILE"
|
||||||
|
|
||||||
|
exit 0
|
||||||
167
vault-template/scripts/sync-openclaw-to-vault.sh
Executable file
167
vault-template/scripts/sync-openclaw-to-vault.sh
Executable file
|
|
@ -0,0 +1,167 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# sync-openclaw-to-vault.sh — OpenClawのJSON → vault/daily/ に追記
|
||||||
|
# Usage: bash sync-openclaw-to-vault.sh [morning|evening]
|
||||||
|
# OpenClaw cron: 07:30 (morning), 18:30 (evening)
|
||||||
|
# Cloud TaskがLayer 1でdaily noteを作成済み。このスクリプトはLayer 2でデータ追記。
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
|
MODE="${1:-morning}"
|
||||||
|
TODAY=$(date +%Y-%m-%d)
|
||||||
|
WEEKDAY=$(date +%A)
|
||||||
|
VAULT_DIR="$HOME/vault"
|
||||||
|
DAILY_FILE="$VAULT_DIR/daily/$TODAY.md"
|
||||||
|
JSON_FILE="$HOME/clawd/reports/data/daily/$TODAY.json"
|
||||||
|
LOG_FILE="$VAULT_DIR/.sync.log"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] sync-vault($MODE): $1" >> "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ロックファイルで同時実行を防止
|
||||||
|
LOCKFILE="$VAULT_DIR/.git-sync.lock"
|
||||||
|
if [ -f "$LOCKFILE" ] && kill -0 "$(cat "$LOCKFILE" 2>/dev/null)" 2>/dev/null; then
|
||||||
|
log "locked, skipping"; exit 0
|
||||||
|
fi
|
||||||
|
echo $$ > "$LOCKFILE"
|
||||||
|
trap 'rm -f "$LOCKFILE"' EXIT
|
||||||
|
|
||||||
|
# まずGitHub最新を取得(Cloud Taskがpush済みの可能性)
|
||||||
|
cd "$VAULT_DIR" && git pull --rebase origin main 2>/dev/null
|
||||||
|
|
||||||
|
if [ ! -f "$JSON_FILE" ]; then
|
||||||
|
log "JSON not found: $JSON_FILE (OpenClaw may not have generated yet)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Starting $MODE sync"
|
||||||
|
|
||||||
|
export DAILY_FILE JSON_FILE MODE TODAY WEEKDAY
|
||||||
|
python3 << 'PYEOF'
|
||||||
|
import os, json
|
||||||
|
|
||||||
|
mode = os.environ['MODE']
|
||||||
|
today = os.environ['TODAY']
|
||||||
|
weekday = os.environ['WEEKDAY']
|
||||||
|
daily_file = os.environ['DAILY_FILE']
|
||||||
|
json_file = os.environ['JSON_FILE']
|
||||||
|
|
||||||
|
with open(json_file) as f:
|
||||||
|
d = json.load(f)
|
||||||
|
|
||||||
|
score = d.get('score', 0)
|
||||||
|
meetings = d.get('meetings', {})
|
||||||
|
emails = d.get('emails', {})
|
||||||
|
slack = d.get('slack', {})
|
||||||
|
deals = d.get('deals', {})
|
||||||
|
ai = d.get('aiAnalysis', {})
|
||||||
|
tomorrow = d.get('tomorrow', {})
|
||||||
|
highlights = d.get('highlights', [])
|
||||||
|
|
||||||
|
# daily noteが存在しない場合(Cloud Taskが未実行)→ 作成
|
||||||
|
if not os.path.exists(daily_file):
|
||||||
|
lines = [
|
||||||
|
'---', f'date: {today}', f'weekday: {weekday}', 'type: daily',
|
||||||
|
f'score: {score}', '---', '',
|
||||||
|
]
|
||||||
|
# 最低限のセクション
|
||||||
|
for section in ['Schedule', 'Gmail', 'Slack Highlights', 'Salesforce',
|
||||||
|
'AI Analysis', 'Morning Reflection', 'Claude Code Session',
|
||||||
|
'Evening Update', 'Evening Reflection', 'Tomorrow',
|
||||||
|
'Thoughts', 'Links']:
|
||||||
|
lines.append(f'## {section}')
|
||||||
|
lines.append('')
|
||||||
|
with open(daily_file, 'w') as f:
|
||||||
|
f.write('\n'.join(lines))
|
||||||
|
|
||||||
|
content = open(daily_file).read()
|
||||||
|
|
||||||
|
# OpenClaw専用データを追記セクションとして構築
|
||||||
|
enrich_lines = []
|
||||||
|
|
||||||
|
# Salesforce
|
||||||
|
deal_items = deals.get('items', [])
|
||||||
|
if isinstance(deal_items, list) and deal_items:
|
||||||
|
sf_lines = []
|
||||||
|
for dl in deal_items:
|
||||||
|
if isinstance(dl, dict):
|
||||||
|
name = dl.get('name', dl.get('title', ''))
|
||||||
|
stage = dl.get('stage', dl.get('status', ''))
|
||||||
|
sf_lines.append(f'- {name}: {stage}')
|
||||||
|
active = deals.get('active', 0)
|
||||||
|
sf_lines.append(f'- アクティブ案件: {active}件')
|
||||||
|
sf_text = '\n'.join(sf_lines)
|
||||||
|
if '## Salesforce' in content and content.split('## Salesforce')[1].split('##')[0].strip() == '':
|
||||||
|
content = content.replace('## Salesforce\n', f'## Salesforce\n{sf_text}\n', 1)
|
||||||
|
|
||||||
|
# AI Analysis
|
||||||
|
if isinstance(ai, dict) and ai:
|
||||||
|
ai_lines = []
|
||||||
|
for key, label in [('productivity','生産性'), ('responsiveness','対応力'), ('salesProgress','営業')]:
|
||||||
|
info = ai.get(key, {})
|
||||||
|
if isinstance(info, dict) and info:
|
||||||
|
ai_lines.append(f'- {label}: {info.get("grade","")} — {info.get("comment","")}')
|
||||||
|
recs = ai.get('recommendations', [])
|
||||||
|
if recs:
|
||||||
|
ai_lines.append('')
|
||||||
|
for r in recs:
|
||||||
|
ai_lines.append(f'- {r}')
|
||||||
|
ai_text = '\n'.join(ai_lines)
|
||||||
|
if '## AI Analysis' in content and content.split('## AI Analysis')[1].split('##')[0].strip() == '':
|
||||||
|
content = content.replace('## AI Analysis\n', f'## AI Analysis\n{ai_text}\n', 1)
|
||||||
|
|
||||||
|
if mode == 'evening':
|
||||||
|
# Evening Update
|
||||||
|
completed = meetings.get('completed', 0)
|
||||||
|
total = meetings.get('total', 0)
|
||||||
|
sent = emails.get('sent', 0)
|
||||||
|
pending = emails.get('pending', 0)
|
||||||
|
ev_lines = [
|
||||||
|
f'- 会議: {completed}/{total} 完了',
|
||||||
|
f'- スコア: {score}',
|
||||||
|
f'- メール送信: {sent}件 / 未対応: {pending}件',
|
||||||
|
]
|
||||||
|
if highlights:
|
||||||
|
for h in highlights:
|
||||||
|
if isinstance(h, dict):
|
||||||
|
ev_lines.append(f'- {h.get("emoji","")} {h.get("text","")}')
|
||||||
|
ev_text = '\n'.join(ev_lines)
|
||||||
|
content = content.replace(
|
||||||
|
'<!-- sync-openclaw-to-vault.sh evening が自動追記 -->',
|
||||||
|
ev_text
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tomorrow
|
||||||
|
t_lines = []
|
||||||
|
t_items = tomorrow.get('items', [])
|
||||||
|
if isinstance(t_items, list):
|
||||||
|
for t in t_items:
|
||||||
|
if isinstance(t, dict):
|
||||||
|
time = t.get('time', '')
|
||||||
|
title = t.get('title', '')
|
||||||
|
warn = ' !!!' if t.get('warning') else ''
|
||||||
|
t_lines.append(f'- {time} {title}{warn}')
|
||||||
|
t_count = tomorrow.get('meetings', 0)
|
||||||
|
t_lines.append(f'')
|
||||||
|
t_lines.append(f'明日の会議: {t_count}件')
|
||||||
|
advice = ai.get('tomorrowAdvice', '') if isinstance(ai, dict) else ''
|
||||||
|
if advice:
|
||||||
|
t_lines.append(f'')
|
||||||
|
t_lines.append(advice)
|
||||||
|
t_text = '\n'.join(t_lines)
|
||||||
|
content = content.replace(
|
||||||
|
'<!-- sync-openclaw-to-vault.sh evening が自動生成 -->',
|
||||||
|
t_text
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(daily_file, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
print(f'{mode} enrichment done: {daily_file}')
|
||||||
|
PYEOF
|
||||||
|
|
||||||
|
# git commit & push
|
||||||
|
cd "$VAULT_DIR" && git add "daily/$TODAY.md" && git commit -m "enrich: $TODAY $MODE (OpenClaw data)" 2>/dev/null && git push 2>/dev/null
|
||||||
|
|
||||||
|
log "Completed $MODE sync"
|
||||||
|
exit 0
|
||||||
72
vault-template/scripts/weekly-sync.sh
Executable file
72
vault-template/scripts/weekly-sync.sh
Executable file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# weekly-sync.sh — 週次Lintスクリプト
|
||||||
|
# 毎週日曜 03:00 に実行(cron or manual)
|
||||||
|
# vault内の整合性チェック・壊れたリンク検出・orphanページ検出
|
||||||
|
set +e
|
||||||
|
|
||||||
|
VAULT="$HOME/vault"
|
||||||
|
LOG="$VAULT/.sync.log"
|
||||||
|
ISSUES=""
|
||||||
|
IC=0
|
||||||
|
|
||||||
|
add() {
|
||||||
|
ISSUES="${ISSUES}"$'\n'"- $1"
|
||||||
|
IC=$((IC + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "[$(date '+%F %T')] weekly-sync start" >> "$LOG"
|
||||||
|
|
||||||
|
# 1. 壊れたwikilinksを検出(grep -oE はmacOS互換)
|
||||||
|
echo "--- Checking broken wikilinks ---"
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
# grep -oE で [[...]] リンクを抽出(-oP は macOS 非対応なので使わない)
|
||||||
|
while IFS= read -r link; do
|
||||||
|
[ -z "$link" ] && continue
|
||||||
|
[ ! -f "$VAULT/${link}.md" ] && add "Broken: [[${link}]] in $(basename "$f")"
|
||||||
|
done < <(grep -oE '\[\[[^]|]+' "$f" 2>/dev/null | sed 's/\[\[//')
|
||||||
|
done < <(find "$VAULT" -name "*.md" -not -path "*/.obsidian/*" -not -path "*/templates/*" -print0)
|
||||||
|
|
||||||
|
# 2. 過去7日のdaily noteが存在するかチェック
|
||||||
|
echo "--- Checking daily notes ---"
|
||||||
|
for i in $(seq 1 7); do
|
||||||
|
d=$(date -v-"${i}d" +%Y-%m-%d 2>/dev/null || continue)
|
||||||
|
[ ! -f "$VAULT/daily/${d}.md" ] && add "Missing daily: ${d}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 3. SYNCEDファイルのヘッダーチェック
|
||||||
|
echo "--- Checking SYNCED headers ---"
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
FIRST_LINE=$(head -1 "$f")
|
||||||
|
case "$FIRST_LINE" in
|
||||||
|
"<!-- SYNCED: DO NOT EDIT -->") ;;
|
||||||
|
*) add "Missing SYNCED header: $(basename "$f")" ;;
|
||||||
|
esac
|
||||||
|
done < <(find "$VAULT/system" -name "*.md" -print0 2>/dev/null)
|
||||||
|
|
||||||
|
# 4. frontmatterのないファイルを検出
|
||||||
|
echo "--- Checking frontmatter ---"
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
FIRST_LINE=$(head -1 "$f")
|
||||||
|
case "$FIRST_LINE" in
|
||||||
|
"---"|"<!-- SYNCED: DO NOT EDIT -->") ;;
|
||||||
|
*) add "Missing frontmatter: $(basename "$f")" ;;
|
||||||
|
esac
|
||||||
|
done < <(find "$VAULT" -name "*.md" -not -path "*/templates/*" -not -path "*/.obsidian/*" -print0 2>/dev/null)
|
||||||
|
|
||||||
|
# 5. CLAUDE.mdの総数をカウント
|
||||||
|
echo "--- Counting CLAUDE.md files ---"
|
||||||
|
CLAUDE_COUNT=0
|
||||||
|
while IFS= read -r -d '' _f; do
|
||||||
|
CLAUDE_COUNT=$((CLAUDE_COUNT + 1))
|
||||||
|
done < <(find "$HOME/work" "$HOME/dev" "$HOME/content" -name "CLAUDE.md" -print0 2>/dev/null)
|
||||||
|
|
||||||
|
echo "[$(date '+%F %T')] weekly-sync done: $IC issues, $CLAUDE_COUNT CLAUDE.md files" >> "$LOG"
|
||||||
|
|
||||||
|
# サマリー出力
|
||||||
|
if [ "$IC" -gt 0 ]; then
|
||||||
|
printf "Lint: %s issues%s\n" "$IC" "$ISSUES"
|
||||||
|
else
|
||||||
|
echo "Lint: All clear! ($CLAUDE_COUNT CLAUDE.md files)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
0
vault-template/skills/.gitkeep
Normal file
0
vault-template/skills/.gitkeep
Normal file
0
vault-template/system/.gitkeep
Normal file
0
vault-template/system/.gitkeep
Normal file
17
vault-template/templates/daily-note.md
Normal file
17
vault-template/templates/daily-note.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
date: {{date}}
|
||||||
|
weekday: {{weekday}}
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schedule
|
||||||
|
<!-- morning-briefing が自動記入 -->
|
||||||
|
|
||||||
|
## Log
|
||||||
|
<!-- Claude Code hooks が自動追記 -->
|
||||||
|
<!-- 手動で書き足してもOK -->
|
||||||
|
|
||||||
|
## Thoughts
|
||||||
|
<!-- 自分の考え・感想を自由に書く場所 -->
|
||||||
|
|
||||||
|
## Links
|
||||||
|
<!-- 今日作成/更新されたvaultページへの自動リンク -->
|
||||||
17
vault-template/templates/decision.md
Normal file
17
vault-template/templates/decision.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
date: {{date}}
|
||||||
|
category: {{category}}
|
||||||
|
impact: {{impact}}
|
||||||
|
---
|
||||||
|
|
||||||
|
## 判断
|
||||||
|
-
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
-
|
||||||
|
|
||||||
|
## 代替案と却下理由
|
||||||
|
-
|
||||||
|
|
||||||
|
## 結果
|
||||||
|
<!-- 判断後の結果を追記 -->
|
||||||
16
vault-template/templates/meeting.md
Normal file
16
vault-template/templates/meeting.md
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
date: {{date}}
|
||||||
|
client: {{client}}
|
||||||
|
source: {{source}}
|
||||||
|
---
|
||||||
|
|
||||||
|
## 決定事項
|
||||||
|
-
|
||||||
|
|
||||||
|
## 宿題
|
||||||
|
-
|
||||||
|
|
||||||
|
## 気づき
|
||||||
|
-
|
||||||
|
|
||||||
|
## 関連
|
||||||
Loading…
Add table
Add a link
Reference in a new issue