Initial release: Claude Code × Obsidian Wiki framework

This commit is contained in:
Masahiro Chaen 2026-04-08 00:39:33 +09:00
commit f8d084eae4
23 changed files with 833 additions and 0 deletions

332
README.md Normal file
View 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 TasksPC不要──────────────────┐
│ │
│ 毎朝 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 CronPCオン時の追加データ
│ ├── 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 ← SchemaLLM向けルール定義
├── 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 CodePro 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
View 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
View 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-DDISO 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
View file

@ -0,0 +1,22 @@
---
type: dreams
updated:
last_dreaming:
---
# Dreams
## Current Insights
<!-- weekly-dreaming が毎週自動更新 -->
## Emerging Patterns
| パターン | 観測回数 | 傾向 |
|---------|---------|------|
<!-- Dreamingが蓄積 -->
## Growth Trajectory
<!-- 月次サマリーが追記される -->
## Open Questions
<!-- Dreamingが検出した未解決課題 -->

View file

View file

View file

View file

View file

View file

View file

View file

View file

View 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

View 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からJSONtool_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

View 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

View 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

View 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

View file

View file

View file

@ -0,0 +1,17 @@
---
date: {{date}}
weekday: {{weekday}}
---
## Schedule
<!-- morning-briefing が自動記入 -->
## Log
<!-- Claude Code hooks が自動追記 -->
<!-- 手動で書き足してもOK -->
## Thoughts
<!-- 自分の考え・感想を自由に書く場所 -->
## Links
<!-- 今日作成/更新されたvaultページへの自動リンク -->

View file

@ -0,0 +1,17 @@
---
date: {{date}}
category: {{category}}
impact: {{impact}}
---
## 判断
-
## 背景
-
## 代替案と却下理由
-
## 結果
<!-- 判断後の結果を追記 -->

View file

@ -0,0 +1,16 @@
---
date: {{date}}
client: {{client}}
source: {{source}}
---
## 決定事項
-
## 宿題
-
## 気づき
-
## 関連