Skills & Agents

プロダクト横断のSkill・Agent一覧。共通化候補の発見と更新チェックに。

Total Skills109
Total Agents68
Projects with AI11/ 31
Shared Items8
---
name: admob-flutter
description: FlutterアプリにAdMob広告を実装するスキル。ネイティブ広告、バナー広告、インタースティシャル広告の実装手順をカバー。子供向けアプリのCOPPA準拠設定も含む。
---

# AdMob Flutter 実装スキル

FlutterアプリにGoogle AdMob広告を実装するための手順書。

## 公式ドキュメント

- [SDK設定ガイド](https://developers.google.com/admob/android/quick-start?hl=ja)
- [ネイティブ広告ガイド](https://developers.google.com/admob/android/native?hl=ja)
- [AdMobポリシー](https://support.google.com/admob/answer/6128543?hl=ja)
- [Flutter google_mobile_ads](https://pub.dev/packages/google_mobile_ads)

## 前提条件

- AdMobアカウント作成済み
- アプリ登録済み → アプリID取得
- 広告ユニット作成済み → 広告ユニットID取得

## テスト用ID(開発中は必ずこれを使用)

| 種類 | テスト用ID |
|------|-----------|
| アプリID | `ca-app-pub-3940256099942544~3347511713` |
| バナー | `ca-app-pub-3940256099942544/6300978111` |
| インタースティシャル | `ca-app-pub-3940256099942544/1033173712` |
| リワード | `ca-app-pub-3940256099942544/5224354917` |
| ネイティブ | `ca-app-pub-3940256099942544/2247696110` |

⚠️ **本番IDでテストクリックするとアカウントBANの可能性あり**

---

## 実装手順

### Step 1: パッケージ追加

`pubspec.yaml`:

```yaml
dependencies:
  google_mobile_ads: ^5.1.0
```

```bash
flutter pub get
```

### Step 2: Android設定

`android/app/src/main/AndroidManifest.xml` の `<application>` 内に追加:

```xml
<meta-data
    android:name="com.google.android.gms.ads.APPLICATION_ID"
    android:value="YOUR_APP_ID"/>
```

開発中はテスト用アプリID、リリース時に本番IDに変更。

### Step 3: 広告サービス作成

`lib/core/services/ad_service.dart`:

```dart
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:flutter/foundation.dart';

class AdService {
  static final AdService _instance = AdService._internal();
  factory AdService() => _instance;
  AdService._internal();

  bool _isInitialized = false;

  // ID定義(本番/テスト切り替え)
  static const String _testAppId = 'ca-app-pub-3940256099942544~3347511713';
  static const String _testNativeAdUnitId = 'ca-app-pub-3940256099942544/2247696110';
  
  // 本番ID(リリース時に設定)
  static const String _prodAppId = 'YOUR_PROD_APP_ID';
  static const String _prodNativeAdUnitId = 'YOUR_PROD_NATIVE_AD_UNIT_ID';
  
  String get nativeAdUnitId => kReleaseMode ? _prodNativeAdUnitId : _testNativeAdUnitId;

  Future<void> initialize({bool childDirected = false}) async {
    if (_isInitialized) return;
    
    await MobileAds.instance.initialize();
    
    if (childDirected) {
      // 子供向けアプリ設定(COPPA準拠)
      await MobileAds.instance.updateRequestConfiguration(
        RequestConfiguration(
          tagForChildDirectedTreatment: TagForChildDirectedTreatment.yes,
          maxAdContentRating: MaxAdContentRating.g,
        ),
      );
    }
    
    _isInitialized = true;
    debugPrint('AdMob initialized');
  }
}
```

### Step 4: main.dartで初期化

```dart
import 'core/services/ad_service.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 子供向けアプリの場合 childDirected: true
  await AdService().initialize(childDirected: true);
  
  runApp(const MyApp());
}
```

---

## ネイティブ広告の実装

### ネイティブ広告ウィジェット

`lib/core/widgets/native_ad_widget.dart`:

```dart
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../services/ad_service.dart';

class NativeAdWidget extends StatefulWidget {
  final TemplateType templateType;
  
  const NativeAdWidget({
    super.key,
    this.templateType = TemplateType.medium,
  });

  @override
  State<NativeAdWidget> createState() => _NativeAdWidgetState();
}

class _NativeAdWidgetState extends State<NativeAdWidget> {
  NativeAd? _nativeAd;
  bool _isAdLoaded = false;

  @override
  void initState() {
    super.initState();
    _loadAd();
  }

  void _loadAd() {
    _nativeAd = NativeAd(
      adUnitId: AdService().nativeAdUnitId,
      request: const AdRequest(),
      listener: NativeAdListener(
        onAdLoaded: (ad) {
          debugPrint('Native ad loaded');
          if (mounted) {
            setState(() => _isAdLoaded = true);
          }
        },
        onAdFailedToLoad: (ad, error) {
          debugPrint('Native ad failed: ${error.message}');
          ad.dispose();
        },
      ),
      nativeTemplateStyle: NativeTemplateStyle(
        templateType: widget.templateType,
        mainBackgroundColor: Colors.white,
        cornerRadius: 12.0,
        callToActionTextStyle: NativeTemplateTextStyle(
          textColor: Colors.white,
          backgroundColor: const Color(0xFF1a73e8),
          style: NativeTemplateFontStyle.bold,
          size: 14.0,
        ),
        primaryTextStyle: NativeTemplateTextStyle(
          textColor: Colors.black87,
          style: NativeTemplateFontStyle.bold,
          size: 16.0,
        ),
        secondaryTextStyle: NativeTemplateTextStyle(
          textColor: Colors.grey,
          style: NativeTemplateFontStyle.normal,
          size: 14.0,
        ),
      ),
    );

    _nativeAd!.load();
  }

  @override
  void dispose() {
    _nativeAd?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (!_isAdLoaded || _nativeAd == null) {
      return const SizedBox.shrink();
    }

    return Container(
      margin: const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
      decoration: BoxDecoration(
        color: Colors.grey[100],
        borderRadius: BorderRadius.circular(12),
      ),
      child: ConstrainedBox(
        constraints: BoxConstraints(
          minWidth: 320,
          minHeight: widget.templateType == TemplateType.small ? 90 : 200,
          maxHeight: widget.templateType == TemplateType.small ? 120 : 350,
        ),
        child: AdWidget(ad: _nativeAd!),
      ),
    );
  }
}
```

### 使用例

```dart
Column(
  children: [
    // コンテンツ
    Text('ここにコンテンツ'),
    
    // 広告
    const NativeAdWidget(templateType: TemplateType.medium),
  ],
)
```

---

## バナー広告の実装

```dart
class BannerAdWidget extends StatefulWidget {
  const BannerAdWidget({super.key});

  @override
  State<BannerAdWidget> createState() => _BannerAdWidgetState();
}

class _BannerAdWidgetState extends State<BannerAdWidget> {
  BannerAd? _bannerAd;
  bool _isLoaded = false;

  @override
  void initState() {
    super.initState();
    _loadAd();
  }

  void _loadAd() {
    _bannerAd = BannerAd(
      adUnitId: AdService().bannerAdUnitId,
      size: AdSize.banner,
      request: const AdRequest(),
      listener: BannerAdListener(
        onAdLoaded: (ad) {
          if (mounted) setState(() => _isLoaded = true);
        },
        onAdFailedToLoad: (ad, error) {
          ad.dispose();
        },
      ),
    )..load();
  }

  @override
  void dispose() {
    _bannerAd?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (!_isLoaded || _bannerAd == null) {
      return const SizedBox(height: 50);
    }
    return SizedBox(
      width: _bannerAd!.size.width.toDouble(),
      height: _bannerAd!.size.height.toDouble(),
      child: AdWidget(ad: _bannerAd!),
    );
  }
}
```

---

## インタースティシャル広告の実装

```dart
class InterstitialAdService {
  InterstitialAd? _interstitialAd;

  void loadAd() {
    InterstitialAd.load(
      adUnitId: AdService().interstitialAdUnitId,
      request: const AdRequest(),
      adLoadCallback: InterstitialAdLoadCallback(
        onAdLoaded: (ad) {
          _interstitialAd = ad;
        },
        onAdFailedToLoad: (error) {
          debugPrint('Interstitial failed: ${error.message}');
        },
      ),
    );
  }

  void showAd() {
    if (_interstitialAd != null) {
      _interstitialAd!.show();
      _interstitialAd = null;
      loadAd(); // 次の広告をプリロード
    }
  }
}
```

---

## 子供向けアプリの設定(COPPA準拠)

13歳未満が使用する可能性があるアプリでは必須:

```dart
await MobileAds.instance.updateRequestConfiguration(
  RequestConfiguration(
    tagForChildDirectedTreatment: TagForChildDirectedTreatment.yes,
    maxAdContentRating: MaxAdContentRating.g, // 全年齢向け
  ),
);
```

---

## リリース前チェックリスト

- [ ] AndroidManifest.xml のアプリIDを本番用に変更
- [ ] コード内の広告ユニットIDが本番用になっていることを確認
- [ ] `kReleaseMode` で正しく切り替わることを確認
- [ ] 子供向けアプリの場合、COPPA設定が有効か確認
- [ ] 実機でテスト広告が表示されることを確認

---

## トラブルシューティング

### 広告が表示されない

1. アプリIDが正しいか確認
2. 広告ユニットIDが正しいか確認
3. インターネット接続を確認
4. AdMobアカウントが有効か確認
5. 新しい広告ユニットは反映に数時間かかることがある

### クラッシュする

- `MobileAds.instance.initialize()` を呼び出しているか確認
- AndroidManifest.xml にアプリIDが設定されているか確認

### テスト広告しか表示されない

- リリースビルド(`flutter build`)で本番IDに切り替わるか確認

---

## 参考リンク

- [google_mobile_ads パッケージ](https://pub.dev/packages/google_mobile_ads)
- [AdMob ヘルプセンター](https://support.google.com/admob/)
- [Google Developers - AdMob](https://developers.google.com/admob)

---

*2026-01-29 作成*
---
name: agent-memory
description: "Use this skill when the user asks to save, remember, recall, or organize memories. Triggers on: '記憶して', '保存して', 'remember this', 'save this', 'note this', '思い出して', 'what did we discuss about...', 'check your notes', 'メモ確認して', 'clean up memories'. Also use proactively when discovering valuable findings worth preserving."
---

# Agent Memory

A persistent memory space for retaining knowledge across multiple conversations. Location: `~/.claude/skills/agent-memory/memories/`

## When to Use This Skill

**Triggers:**
- User explicitly asks: "remember this", "save this", "note this", "記憶して", "保存して"
- User wants to recall: "what did we discuss about...", "check your notes", "思い出して", "メモ確認して"
- Proactively when you discover valuable findings worth preserving

**What to Remember:**
- Research findings and investigation results
- Code patterns and architectural decisions
- Problem-solving approaches and solutions
- Work-in-progress that may be resumed later
- Important project decisions and their rationale
- Troubleshooting solutions

**When to Check Memory:**
- Before investigating a problem that seems familiar
- When resuming previous work
- When user asks about past discussions

## Directory Structure

Memories are organized in category folders using kebab-case naming:

```
~/.claude/skills/agent-memory/memories/
├── global/                          # Cross-project knowledge
│   ├── coding-patterns/
│   ├── best-practices/
│   └── personal-preferences/
└── life-project-management/         # Project-specific memories
    ├── mission/
    ├── workflows/
    ├── system-design/
    ├── troubleshooting/
    └── daily-learnings/
```

**Category Guidelines:**
- Use descriptive kebab-case names
- Create new categories as needed
- Organize by topic or project name
- Prefer project-specific folders for context isolation

## Memory File Format

Every memory file must have YAML frontmatter:

```yaml
---
summary: "Brief one-line description for searching"
created: YYYY-MM-DD
updated: YYYY-MM-DD  # optional, update when content changes
status: in-progress|resolved|blocked|abandoned  # optional
tags: [tag1, tag2]  # optional, for cross-category search
related: [file-path-1, file-path-2]  # optional, link to related files
project: life-project-management  # optional but recommended
---

# Title

## Context

Brief background of why this was saved.

## Details

Specific information, code snippets, file paths, commands, etc.

## Next Steps

What to do next (for in-progress items).
```

**Required Fields:**
- `summary`: Concise 1-2 line description (searchable)
- `created`: Date in YYYY-MM-DD format

**Optional Fields:**
- `updated`: Last modification date
- `status`: Track progress (in-progress, resolved, blocked, abandoned)
- `tags`: Array of keywords for search
- `related`: Array of file paths for context
- `project`: Project name for filtering

## Searching Memories

Use progressive disclosure approach with ripgrep:

**Step 1: Search summaries (fastest)**
```bash
rg --no-ignore --hidden "summary:.*keyword" ~/.claude/skills/agent-memory/memories/
```

**Step 2: Search by tags**
```bash
rg --no-ignore --hidden "tags:.*keyword" ~/.claude/skills/agent-memory/memories/
```

**Step 3: Search by project**
```bash
rg --no-ignore --hidden "project: project-name" ~/.claude/skills/agent-memory/memories/
```

**Step 4: Full content search**
```bash
rg --no-ignore --hidden "search-term" ~/.claude/skills/agent-memory/memories/
```

**Step 5: Read relevant files**
Use the Read tool to open files that match the search criteria.

**Important Flags:**
- `--no-ignore`: Don't skip gitignored files (memories/ is in .gitignore)
- `--hidden`: Search hidden directories

## Saving Memories

When saving a new memory:

1. **Determine the category folder**
   - Project-specific: `memories/life-project-management/[category]/`
   - Global knowledge: `memories/global/[category]/`
   - Create new category if needed

2. **Choose a descriptive filename**
   - Use kebab-case
   - Be specific: `para-structure.md` not `notes.md`

3. **Create the file with frontmatter**
   - Always include `summary` and `created`
   - Add `project` field for project-specific memories
   - Use `tags` for cross-category findability

4. **Check for existing files**
   - Before creating, search to avoid duplicates
   - Update existing memory if it already exists

5. **Write complete, self-contained content**
   - Include enough context to understand later
   - Link related files in `related` field
   - Add specific details (file paths, commands, code)

## Updating Memories

When updating an existing memory:

1. **Update the `updated` field** with current date
2. **Modify `status` if applicable** (in-progress → resolved)
3. **Add new information** while preserving original context
4. **Update `summary`** if the focus has changed

## Memory Maintenance

**Regular Review (Monthly):**
- Archive resolved items older than 6 months
- Delete abandoned items after 1 month
- Consolidate related memories
- Update outdated information

**Archive Strategy:**
- Move old resolved items to `memories/archives/`
- Keep frequently referenced memories active
- Use `status: resolved` and `updated` date for filtering

**Cleanup:**
- Remove duplicate information
- Merge similar memories
- Delete obsolete knowledge

## Best Practices

1. **Decisive Summaries**
   - Make summaries searchable
   - Include key terms and context
   - One clear sentence

2. **Complete Context**
   - Include background and rationale
   - Link to relevant files and docs
   - Note the situation that prompted saving

3. **Current Information**
   - Update when circumstances change
   - Mark status appropriately
   - Date all modifications

4. **Appropriate Sections**
   - Use sections that fit the content
   - Don't force all sections if not needed
   - Adapt template to actual needs

5. **Project Classification**
   - Always set `project` field for project-specific memories
   - Use folder structure for organization
   - Enable easy filtering by project

## Examples

### Example 1: Architectural Decision

```yaml
---
summary: "P.A.R.A. methodology structure for life-project-management"
created: 2026-01-11
project: life-project-management
tags: [para, architecture, project-management]
related: [90_System/フォルダ構成.md, README.md]
status: resolved
---

# P.A.R.A. Structure Implementation

## Context

Life-project-management uses P.A.R.A. methodology for organizing all content.

## Structure

- **Projects** (10_): Time-bound work with deliverables
- **Areas** (20_): Ongoing responsibilities
- **Resources** (30_): Reference materials
- **Archives** (50_): Completed projects

Additional folders:
- 35_MOCs: Maps of Content (Zettelkasten hubs)
- 40_Evergreen: Atomic permanent notes
- 45_Literature: Source notes

## Related Files

- Main structure: 90_System/フォルダ構成.md
- Overview: README.md
```

### Example 2: Problem Solution

```yaml
---
summary: "Fix for MCP server connection timeout in Claude Code"
created: 2026-01-11
updated: 2026-01-11
project: global
tags: [troubleshooting, mcp, claude-code]
status: resolved
---

# MCP Server Timeout Fix

## Problem

MCP servers timing out on connection with error "Failed to connect".

## Solution

Check settings.local.json for correct server configuration:

```json
{
  "enabledMcpjsonServers": ["slack", "github"]
}
```

Restart Claude Code after changes.

## Prevention

Always verify MCP server names match exactly in config files.
```

### Example 3: Work in Progress

```yaml
---
summary: "Agent-memory skill implementation progress"
created: 2026-01-11
updated: 2026-01-11
project: life-project-management
tags: [wip, agent-memory, skills]
status: in-progress
---

# Agent-Memory Skill Setup

## Goal

Install yamadashy's agent-memory skill globally on Mac mini.

## Completed

- ✅ Created directory structure in ~/.claude/skills/agent-memory/
- ✅ Defined SKILL.md with bilingual triggers

## Next Steps

1. Create .gitignore file
2. Add initial memory samples
3. Update CLAUDE.md documentation
4. Test memory save/recall functionality

## References

- Zenn article: https://zenn.dev/yamadashy/articles/claude-code-agent-skills-agent-memory
- Repository: https://github.com/yamadashy/repomix
```

## Project-Specific Integration

### Life-Project-Management

**P.A.R.A. Mapping:**
- `memories/life-project-management/mission/` → 20_Areas/一人の人間として/
- `memories/life-project-management/workflows/` → 90_System/Workflows/
- `memories/life-project-management/system-design/` → 90_System/
- `memories/life-project-management/troubleshooting/` → Operational docs
- `memories/life-project-management/daily-learnings/` → 01_Daily/

**Memory vs. Documentation:**
- **Agent Memory**: AI-searchable knowledge for quick recall
- **Obsidian Docs**: Human-readable comprehensive documentation
- **Strategy**: Cross-reference between both systems

## Tips

- Save early and often - easier to delete than recreate
- Use tags liberally for findability
- Keep summaries concise but descriptive
- Update status as work progresses
- Link related files for context
- Review and clean up monthly
---
name: ai-solo-builder-workflow
description: End-to-end workflow for AI Solo Builder daily operations: morning/evening digest publishing, weekday editorial slot, NVA Top10+Top3 process, product dictionary linking, validation, DB sync, and deploy checks.
---

# AI Solo Builder Workflow

AI Solo Builder(https://ai.essential-navigator.com)向けの実運用スキル。

このスキルは以下の3ジョブで使う前提:
- `asb-morning-digest`(07:30 JST, daily)
- `asb-midday-editorial`(12:30 JST, weekdays)
- `asb-evening-digest`(17:30 JST, daily)

## 1. 最初に読む正本

作業前に以下を確認する。

1. `/Users/satokeita/clawd-tifa/SOUL.md`
2. `/Users/satokeita/clawd-tifa/IDENTITY.md`
3. `/Users/satokeita/clawd-tifa/AGENTS.md`
4. `/Users/satokeita/clawd-tifa/MEMORY.md`
5. `/Users/satokeita/Dev/ai-navigator/specs/content-policy/spec.md`
6. `/Users/satokeita/Dev/ai-navigator/docs/OPERATIONS-PLAN-2026-02-12.md`
7. `/Users/satokeita/Dev/ai-navigator/docs/CLAUDE-CODE-ROUTINE.md`

## 2. 作業ディレクトリ

```bash
cd /Users/satokeita/Dev/ai-navigator
```

## 2.1 環境前提(DB同期必須)

- 記事公開前にDB同期を必ず行う
- `sync:content:db` は `.env.local` / `.env` を自動読込する
- 次の変数が必要:
  - `NEXT_PUBLIC_SUPABASE_URL`
  - `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`
  - `SUPABASE_SECRET_KEY`

## 3. コンテンツモデル(運用ルール)

### 3.1 トップ分類
- `news`
- `product`
- `digest`

### 3.2 Digestの要件
- 朝刊: `category: morning-summary`
- 夕刊: `category: evening-summary`
- 1本のDigestに必須:
  - Top10ランキング(NVA)
  - Top3深掘り
  - Top3を個別ニュース記事化

### 3.3 ニュースタグ運用
- `dev-knowledge`
- `case-study`
- `product-update`

移行期のため、`category` 互換は維持しつつ、可能なら canonical項目も併記する。

## 4. frontmatter(移行互換テンプレ)

### 4.1 Digest(朝刊/夕刊)

```yaml
---
title: "AIソロビルダー朝刊 — YYYY年M月D日(曜)..."
slug: "morning-news-YYYY-MM-DD"
date: "YYYY-MM-DD"
category: "morning-summary"
contentType: "digest"
digestEdition: "morning"
description: "要約"
readTime: 8
featured: true
relatedProducts: ["product-slug-a", "product-slug-b"]
relatedProduct: "product-slug-a"
---
```

夕刊は `category: evening-summary`, `digestEdition: evening`, `slug: evening-news-YYYY-MM-DD`。

### 4.2 Top3個別ニュース

```yaml
---
title: "..."
slug: "news-slug"
date: "YYYY-MM-DD"
category: "news"
contentType: "news"
tags: ["product-update"]
description: "要約"
readTime: 6
featured: false
relatedProducts: ["product-slug-a"]
relatedProduct: "product-slug-a"
---
```

### 4.3 平日編集枠(ナレッジ/事例)

```yaml
---
title: "..."
slug: "..."
date: "YYYY-MM-DD"
category: "dev-knowledge" # or case-study
contentType: "news"
tags: ["dev-knowledge"] # or case-study
description: "要約"
readTime: 7
relatedProducts: ["product-slug"]
relatedProduct: "product-slug"
---
```

## 5. NVAランキング運用

## 5.1 採点軸(5軸)
- Social
- Media
- Community
- Technical
- Solo Relevance

合計点でTop10を作る。Top3は必ず個別記事化する。

## 5.2 Digestに必須の見出し

以下の見出しは文字列を固定する。

```markdown
## 🏁 重要ニュースランキング(NVA)
```

`/news-value` はこの見出しと表構造を前提に解析する。

## 5.3 ランキング表テンプレ(Top10まで)

```markdown
| 順位 | NVA | ニュース | 出典 | 関連プロダクト |
|---|---:|---|---|---|
| 1 | 92 | [見出し](/news/news-slug-1) | [source](https://...) | [Product](/products/product-slug) |
| 2 | 88 | [見出し](/news/news-slug-2) | [source](https://...) | [Product](/products/product-slug) |
| 3 | 84 | [見出し](/news/news-slug-3) | [source](https://...) | [Product](/products/product-slug) |
```

## 5.4 Top3深掘りセクション

```markdown
## 🔥 Top 3 ピックアップ
```

各項目で「背景・数字・なぜ今・ソロビルダー行動」を示す。

## 6. プロダクト辞書連動(必須)

記事内に登場したプロダクトは必ず `/products/[slug]` へリンクする。

- 既存ページあり: 既存ページを利用
- 既存ページなし: `content/products/[slug].md` を新規作成

簡易テンプレ:

```yaml
---
title: "Product Name"
slug: "product-slug"
date: "YYYY-MM-DD"
category: "products"
contentType: "product"
description: "プロダクト概要"
readTime: 5
featured: false
---
```

## 7. スロット別実行手順

## 7.1 朝刊Digest(07:30開始 / 08:00公開目標)

1. 候補ニュース8〜15件収集
2. NVA採点・Top10決定
3. `morning-summary` Digest作成
4. Top3個別ニュース3本作成
5. プロダクト辞書不足を補完
6. 検証・同期・ビルド
7. push後に公開確認

## 7.2 平日編集枠(12:30, Mon-Fri)

曜日別に1本以上作成/更新する。

- 月/木: `dev-knowledge`
- 火/金: `case-study`
- 水: `products` 更新(必要なら `product-update` ニュース追加)

## 7.3 夕刊Digest(17:30開始 / 18:00公開目標)

1. 当日日中ニュース8〜15件収集
2. 朝刊トピックとの重複回避
3. `evening-summary` Digest作成
4. Top3個別ニュース3本作成
5. プロダクト辞書不足を補完
6. 検証・同期・ビルド
7. push後に公開確認

## 8. 公開前チェック(必須)

```bash
npm run publish:gate
```

`publish:gate` は `validate -> sync -> build` を順に実行する。  
いずれか失敗したら `git push` しない。

## 9. デプロイ

```bash
git add -A
git commit -m "publish: YYYY-MM-DD <slot>"
git push origin main
```

## 10. 公開後確認

最低限の確認:

```bash
curl -sS -o /dev/null -w '%{http_code}\n' 'https://ai.essential-navigator.com/api/v1/feed?limit=1'
```

画面確認:
- `https://ai.essential-navigator.com/category/morning-summary`
- `https://ai.essential-navigator.com/category/evening-summary`
- `https://ai.essential-navigator.com/news-value`

## 11. Slack報告ルール

- チャンネル: `#tifa (C0AELF58Z5E)`
- 開始投稿を作成して `threadId` を控える
- 進捗・完了は必ず同スレッド返信

開始例:
- `🌅 朝刊Digest作成開始(YYYY-MM-DD)`
- `🧠 平日編集枠開始(YYYY-MM-DD)`
- `🌆 夕刊Digest作成開始(YYYY-MM-DD)`

完了報告に必須:
- 公開URL
- 作成件数(Digest/News/Product)
- エラー有無

## 12. 禁止事項

- Top3個別記事を作らずにDigestだけ公開する
- プロダクトリンク欠落のまま公開する
- `publish:gate` なしで公開する
- 旧パス `/Users/satokeita/ai-solo-builder` を正本として扱う

## 13. 障害時の対応

- APIが404の場合: デプロイ反映待ち後に再確認
- ビルド失敗: 失敗ログを修正して再実行
- スロット遅延: まずDigest最小要件(Top10+Top3)を満たして公開し、補完を追って実施
---
name: analytics
description: GA4・Search Consoleのデータ取得・分析、サイトパフォーマンス計測、SEO分析を行う。「アクセス解析」「PV確認」「検索クエリ」「トラフィック分析」「SEO確認」「データ分析」「レポート生成」「パフォーマンス確認」「順位確認」「流入分析」などの作業に使う。初期セットアップ(GA4タグ設置、Search Console設定、API有効化)にも対応。
---

# Analytics Skill

## 環境情報

| 項目 | 値 |
|---|---|
| GA4 測定ID | G-W0S54FPGR5 |
| GA4 プロパティID | 522353049 |
| Search Console | sc-domain:essential-navigator.com |
| サービスアカウント | stevens-data@essential-navigator.iam.gserviceaccount.com |
| 認証JSON | ~/.openclaw/stevens-google-credentials.json |
| サイト | https://essential-navigator.com |
| WordPressサーバー | bitnami@13.159.76.234 (SSH鍵: ~/.ssh/LightsailDefaultKeyPair.pem) |

## データ取得

### GA4レポート

```bash
# サマリー(過去7日)
python3 scripts/ga4_report.py

# 期間指定
python3 scripts/ga4_report.py --start 2026-01-01 --end today

# ページ別PV(上位20)
python3 scripts/ga4_report.py --dimensions pagePath --metrics screenPageViews --limit 20

# 日別推移
python3 scripts/ga4_report.py --dimensions date --metrics activeUsers screenPageViews sessions

# 流入元別
python3 scripts/ga4_report.py --dimensions sessionSource

# デバイス別
python3 scripts/ga4_report.py --dimensions deviceCategory

# JSON出力(プログラム処理用)
python3 scripts/ga4_report.py --dimensions pagePath --json
```

スクリプトパス: `~/.openclaw/skills/analytics/scripts/ga4_report.py`

### Search Consoleレポート

```bash
# 検索クエリ別(過去28日、データは3日遅延)
python3 scripts/gsc_report.py

# ページ別パフォーマンス
python3 scripts/gsc_report.py --dimensions page

# 日別推移
python3 scripts/gsc_report.py --dimensions date

# 特定ページの検索クエリ
python3 scripts/gsc_report.py --page-filter "humidifier"

# 特定クエリのフィルタ
python3 scripts/gsc_report.py --query-filter "加湿器"

# JSON出力
python3 scripts/gsc_report.py --json
```

スクリプトパス: `~/.openclaw/skills/analytics/scripts/gsc_report.py`

### GA4 利用可能メトリクス(主要)

- `activeUsers` / `newUsers` / `totalUsers`
- `screenPageViews` / `sessions` / `engagedSessions`
- `averageSessionDuration` / `bounceRate` / `engagementRate`
- `conversions` / `eventCount`

### GA4 利用可能ディメンション(主要)

- `pagePath` / `pageTitle` / `landingPage`
- `date` / `dateHour`
- `sessionSource` / `sessionMedium` / `sessionCampaignName`
- `deviceCategory` / `operatingSystem` / `browser`
- `country` / `city`

## 分析パターン

### 日次チェック(毎日実行)
1. GA4サマリー取得(PV, ユーザー数, セッション)
2. 前日比・前週比の変動確認
3. 異常値があればけいた様に報告

### 週次レビュー(毎週実行)
1. GA4: ページ別PV、流入元別、デバイス別
2. GSC: 検索クエリTOP20、ページ別CTR・順位
3. 新規インデックス状況確認
4. 改善アクション策定

### SEO分析
1. GSCで順位10-20位のクエリ特定(改善余地大)
2. 対象ページのコンテンツ改善提案
3. 内部リンク構造の最適化検討

### コンテンツパフォーマンス分析
1. PVトップ記事の特徴分析
2. 直帰率の高い記事の改善候補特定
3. 滞在時間の長い記事からの学び抽出

## 初期セットアップ手順

新サイトへGA4/GSCを導入する場合の手順。

### GA4セットアップ
1. GA4プロパティ作成 → 測定ID取得
2. WordPressの`header.php`に`wp_head()`直後、`</head>`直前にgtagスニペット挿入
3. リアルタイムレポートで動作確認

**注意:** PHPの`echo`で`\n`を使う場合、ダブルクォート内でのみ改行として動作。シングルクォートでは文字列`\n`がそのまま出力される。mu-pluginsよりheader.php直接編集が安全。

### Search Consoleセットアップ
1. URLプレフィックスまたはドメインプロパティで追加
2. 所有権確認(GA4タグ経由 or HTMLタグ or DNSレコード)
3. サイトマップ送信: 完全URL `https://example.com/sitemap_index.xml` で送信

### APIアクセス設定
1. Google Cloud Consoleでサービスアカウント作成
2. JSON鍵ダウンロード → `~/.openclaw/` に配置
3. 以下のAPIを有効化:
   - Google Analytics Admin API (`analyticsadmin.googleapis.com`)
   - Google Analytics Data API (`analyticsdata.googleapis.com`)
   - Google Search Console API (`searchconsole.googleapis.com`)
4. GA4管理画面でサービスアカウントに「閲覧者」権限付与
5. Search Consoleでサービスアカウントに「フル」権限付与

### SSL/HTTPS設定
Bitnami WordPress on Lightsailの場合:
- 証明書は `/opt/bitnami/letsencrypt/certificates/` に存在
- `bncert-tool` は対話式でパイプ入力と相性が悪い → `certbot` 直接使用も注意(Bitnamiの Apache とポート競合)
- 証明書更新は自動(letsencrypt cron)
---
name: android-release
description: Flutter AndroidアプリをGoogle Playに公開するためのワークフロー。Internal testing(内部テスト)からProduction公開までをサポート。トリガー:「Android公開」「Google Play公開」「AABビルド」「署名設定」「Play Console」「Internal testing」「リリース準備」
---

# Android Release Skill

Flutter製AndroidアプリをGoogle Playに公開するための手順ガイド。

## ワークフロー概要

```
Phase 1: 事前準備
    ↓
Phase 2: 署名設定
    ↓
Phase 3: AABビルド
    ↓
Phase 4: Play Console設定
    ↓
Phase 5: Internal Testing
    ↓
Phase 6: Production公開
```

## Phase 1: 事前準備(コード修正)

### 1-1. applicationId確定
`flutter_app/android/app/build.gradle.kts`:
```kotlin
defaultConfig {
    applicationId = "com.yourapp.name"  // 公開後変更不可
}
```

### 1-2. AndroidManifest.xml修正
`flutter_app/android/app/src/main/AndroidManifest.xml`:
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET"/>
    <application android:label="アプリ名" ...>
```

### 1-3. MainActivity.kt移動
パッケージ名に合わせてディレクトリ構造を変更:
```
flutter_app/android/app/src/main/kotlin/com/yourapp/name/MainActivity.kt
```

### 1-4. プライバシーポリシー作成
`public/privacy.html`を作成。Data Safety申告と整合させる。

## Phase 2: 署名設定

### 2-1. Upload Key作成
```bash
cd flutter_app/android
/Applications/Android\ Studio.app/Contents/jbr/Contents/Home/bin/keytool \
  -genkey -v -keystore upload-keystore.jks -keyalg RSA -keysize 2048 \
  -validity 10000 -alias upload \
  -storepass <PASSWORD> -keypass <PASSWORD> \
  -dname "CN=AppName, OU=Development, O=AppName, L=Tokyo, ST=Tokyo, C=JP"
```

### 2-2. key.properties作成
`flutter_app/android/key.properties`:
```properties
storePassword=<PASSWORD>
keyPassword=<PASSWORD>
keyAlias=upload
storeFile=../upload-keystore.jks
```

### 2-3. build.gradle.kts修正
```kotlin
import java.util.Properties
import java.io.FileInputStream

// key.propertiesの読み込み
val keystorePropertiesFile = rootProject.file("key.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}

android {
    signingConfigs {
        create("release") {
            if (keystorePropertiesFile.exists()) {
                keyAlias = keystoreProperties.getProperty("keyAlias")
                keyPassword = keystoreProperties.getProperty("keyPassword")
                storeFile = file(keystoreProperties.getProperty("storeFile") ?: "")
                storePassword = keystoreProperties.getProperty("storePassword")
            }
        }
    }
    buildTypes {
        release {
            signingConfig = if (keystorePropertiesFile.exists()) {
                signingConfigs.getByName("release")
            } else {
                signingConfigs.getByName("debug")
            }
        }
    }
}
```

## Phase 3: AABビルド

### 3-1. ビルド実行
```bash
cd flutter_app
flutter clean && flutter pub get
flutter build appbundle --release
```
出力: `build/app/outputs/bundle/release/app-release.aab`

### 3-2. 署名確認
```bash
/Applications/Android\ Studio.app/Contents/jbr/Contents/Home/bin/jarsigner \
  -verify -verbose -certs app-release.aab | head -20
```

## Phase 4: Play Console設定

### 4-1. アカウント作成
1. https://play.google.com/console
2. 登録料: 25 USD(一度きり)

### 4-2. アプリ作成
- アプリ名、言語(日本語)、タイプ(アプリ)、無料/有料

### 4-3. ストア掲載情報
詳細は [references/store-listing.md](references/store-listing.md) 参照。

### 4-4. Data Safety申告
詳細は [references/data-safety.md](references/data-safety.md) 参照。

## Phase 5: Internal Testing

1. Play Console > テスト > 内部テスト > 新しいリリース作成
2. AABアップロード
3. テスターのGmailアドレス追加
4. 招待リンク共有
5. インストール・動作確認

## Phase 6: Production公開

1. コンテンツレーティング質問票回答
2. 製品版リリース作成
3. 審査提出(1-7日)
4. 公開

## チェックリスト

### 必須(Internal testing)
- [ ] applicationId確定・変更
- [ ] AndroidManifest.xml(INTERNET権限、アプリ名)
- [ ] Upload Key作成
- [ ] key.properties作成
- [ ] 本番署名AABビルド
- [ ] プライバシーポリシー公開
- [ ] アプリアイコン(512x512 PNG)
- [ ] スクリーンショット(2枚以上)
- [ ] Data Safety申告

### 推奨(Production)
- [ ] フィーチャーグラフィック(1024x500 PNG)
- [ ] コンテンツレーティング回答

## 注意事項

- **キーストア管理**: 紛失するとアプリ更新不可。パスワードは1Password等で管理。
- **key.propertiesと*.jks**: `.gitignore`に含める(機密情報)
- **Play App Signing推奨**: Upload Keyを紛失してもGoogleがリカバリー可能
# article-image-enricher

記事内のリンク先から画像を取得し、記事に添付するスキル。

## トリガー

- 記事作成完了後の画像エンリッチメント
- 「画像を追加」「リンク先の画像取得」

## 目的

- 記事内で紹介しているプロダクト/サービスの**公式画像**を取得
- 読者の理解度を上げる(文字だけより画像があると伝わる)
- 記事のグレードを上げる

---

## ワークフロー

### Step 1: 記事内のリンクを抽出

記事内の外部リンク(公式サイト、Product Huntなど)を特定。

```bash
# 記事からURLを抽出
grep -oE 'https?://[^)]+' <記事ファイル>
```

### Step 2: 公式サイトから画像URL探索

**優先順位:**
1. **公式サイト**(product.com)— 最も信頼性が高い
2. **Product Hunt** — レビューページに画像あり(ただし403になりやすい)
3. **GitHub README** — OSSプロダクトの場合

**画像URL取得方法:**

```bash
# HTMLソースから画像URLを抽出
curl -s <公式サイトURL> | grep -oE 'https?://[^"'\'']+\.(png|jpg|jpeg|gif|webp|svg)' | head -20
```

### Step 3: 画像の確認・選定

取得した画像URLを`image`ツールで確認:

```
image(url, "この画像の内容を説明してください。記事への適合性を評価してください。")
```

**選定基準:**
- ✅ プロダクトのUIスクリーンショット
- ✅ 機能説明画像
- ✅ ロゴ + キャッチコピー(ヒーロー画像)
- ❌ 単体のロゴ(小さすぎる)
- ❌ アイコンのみ
- ❌ 人物写真(肖像権)

### Step 4: 画像URLの有効性確認

```bash
curl -sI "<画像URL>" | head -5
# HTTP/2 200 を確認
```

### Step 5: 記事に追加

Markdownフォーマット:

```markdown
![説明テキスト](画像URL)
*出典: [サイト名](サイトURL)*
```

**追加位置:**
- プロダクト紹介の見出し直下
- 表の前(視覚的導入として)

---

## 注意事項

### 著作権・利用規約

- 公式サイトの素材を**紹介目的**で使用(フェアユース/引用)
- 必ず**出典リンク**を明記
- 不明な場合は省略

### 技術的制約

| サイト | 状況 |
|--------|------|
| Figma Community | SPA、web_fetchでは画像取得困難 |
| Product Hunt | Cloudflare保護、403になりやすい |
| 公式サイト | 多くの場合取得可能 |
| GitHub | README画像は取得可能 |

### 外部CDN画像のリスク

- 外部CDNの画像は**リンク切れリスク**あり
- 長期的には**Vercel Blobにコピー**を検討

---

## 例: Blocksプラグインの画像追加

### Before
```markdown
### 1. Blocks — チームのワイヤーフレームツール

**公式:** [blocks.pm](https://www.blocks.pm/)
```

### After
```markdown
### 1. Blocks — チームのワイヤーフレームツール

**公式:** [blocks.pm](https://www.blocks.pm/)

![Blocks — ドラッグ&ドロップでコンポーネントを配置](https://cdn.prod.website-files.com/6620c59ba96f73dbd38266cb/6620c59ba96f73dbd3826745_size_big_name_1.webp)
*出典: [blocks.pm](https://www.blocks.pm/)*
```

---

## ワークフロー統合

このスキルは以下のタイミングで呼び出す:

1. **article-writer** Step 4完了後(記事作成後)
2. **digest-writer** Top3個別記事作成後
3. **dev-knowledge記事**作成後

---

## 完了条件

- [ ] 記事内の主要プロダクト(1〜3個)に画像追加
- [ ] 画像URL有効性確認(200 OK)
- [ ] 出典リンク明記
- [ ] ビルド成功
---
name: article-quality-check
description: "記事投稿前の品質チェックと必須項目確認。サムネイル未設定、メタデータ不備、フォーマット問題を自動検出し、tifaなど新任エージェントのミス防止に特化。「記事チェック」「投稿前確認」「品質保証」「新任サポート」などの作業に使う。"
---

# Article Quality Check Skill

## 概要
記事投稿前の包括的品質チェック。特に新任エージェント(tifa等)のサムネイル設定忘れや必須項目の見落としを防ぐ。

## 🚨 tifa用:記事投稿前必須チェックリスト

### Step 1: サムネイル画像確認(最重要)
```bash
# 記事ファイルまたはWordPress投稿JSONをチェック
grep -E "(image|featured_media)" [記事ファイル]

# ✅ 正常例:
# "image": "https://images.unsplash.com/photo-xxx?w=800&h=420&fit=crop"
# "featured_media": 123

# ❌ NG例:
# "image": ""
# "featured_media": null
# サムネイル設定なし
```

**サムネイル未設定の場合の対処:**
1. Unsplash検索: `web_search("site:unsplash.com [記事テーマ] technology")`
2. 適切な画像ID取得
3. URL形式: `https://images.unsplash.com/photo-{ID}?w=800&h=420&fit=crop`
4. 記事に設定

### Step 2: 必須メタデータ確認
```bash
# チェック項目:
- [ ] タイトル設定済み
- [ ] スラッグ設定済み(英語)
- [ ] カテゴリ設定済み
- [ ] メタディスクリプション(120文字以内)
- [ ] サムネイル画像設定済み
```

### Step 3: コンテンツ品質確認
```bash
# AIニュース記事の場合(必須)
grep -E "(参考リンク|公式サイト|出典)" [記事ファイル]

# ✅ 必要な要素:
- [ ] ニュースソースURL
- [ ] 公式サイトリンク
- [ ] 参考リンクセクション
```

### Step 4: WordPress投稿データ検証
```bash
# JSON投稿データの確認(POST /wp/v2/posts)
cat post_data.json | jq '.featured_media'
# → null または 0 の場合はサムネイル未設定

cat post_data.json | jq '.excerpt'
# → 空文字の場合はメタディスクリプション未設定
```

## 自動チェック機能

### 使用例
```bash
# 記事ファイルのチェック
article-quality-check /path/to/article.md

# WordPress投稿JSONのチェック
article-quality-check --json post_data.json

# 投稿前の包括チェック
article-quality-check --pre-publish /path/to/article.md
```

### エラーパターンと対処

| エラー | 原因 | 対処法 |
|--------|------|--------|
| `THUMBNAIL_MISSING` | サムネイル未設定 | thumbnail-generatorスキルで画像設定 |
| `METADATA_INCOMPLETE` | メタデータ不備 | title, slug, category確認 |
| `SOURCE_LINKS_MISSING` | 出典リンクなし | 公式サイト・ニュースソースURL追加 |
| `EXCERPT_EMPTY` | メタディスクリプション空 | 120文字以内の要約作成 |
| `TABLE_LAYOUT_BROKEN` | テーブル列幅異常 | 下記テーブルガイドライン参照 |

---

## テーブルレイアウトチェック(AI Solo Builder記事用)

### Step 5: テーブル表示確認

CSSは `table-layout: auto` で**コンテンツに応じた自動幅**を採用。
異なる列構造のテーブルが混在しても正常表示される。

**確認項目:**
```bash
# 記事内のテーブルを目視確認
# 以下の問題がないかチェック:

# ❌ NG例:
# - 「合計」が「合」「計」で改行
# - 数値列(スコア、順位)が広すぎる
# - 説明・理由列が狭すぎて改行過多

# ✅ 正常例:
# - 短い単語は改行なし
# - 数値列はコンパクト
# - 説明列は十分な幅
```

**テーブル種類別の確認ポイント:**

| テーブル種類 | 列構造 | 確認ポイント |
|-------------|--------|-------------|
| Digestランキング | 順位/ニュース/NVA/Tier | 「ニュース」列が最も広い |
| NVA評価 | 軸/スコア/理由 | 「軸」「合計」が改行されない |
| ソース一覧 | #/ソース名/URL/種類/信頼度/要点 | URL・要点列が広い |
| 比較表 | 項目/対象A/対象B/... | 均等または内容に応じた幅 |

**問題発生時の対処:**
- CSSの `nth-child` 固定幅指定を削除
- `table-layout: auto` を確認
- 必要に応じて `min-width` / `max-width` のみで調整

### 緊急修正コマンド
```bash
# サムネイル緊急設定(汎用画像)
curl -X POST "https://essential-navigator.com/wp-json/wp/v2/posts/[POST_ID]" \
  --user "user:password" \
  -d '{"featured_media": [GENERIC_IMAGE_ID]}'

# メタディスクリプション緊急追加
curl -X POST "https://essential-navigator.com/wp-json/wp/v2/posts/[POST_ID]" \
  --user "user:password" \
  -d '{"excerpt": "記事の要約(120文字以内)"}'
```

## 新任エージェント向けガイド

### tifaへの注意事項
1. **記事投稿前は必ずこのスキルでチェックを実行**
2. **サムネイル未設定は読者の第一印象に直結する重要項目**
3. **「後で設定する」は禁止 → 投稿前に必ず完成させる**
4. **不明な点があれば他のエージェントに確認**

### よくあるミスパターン(tifa注意)
- [ ] サムネイル設定忘れ(最多)
- [ ] 英語スラッグ忘れ
- [ ] カテゴリ未設定
- [ ] 出典リンク忘れ(AIニュース)
- [ ] メタディスクリプション空白

## 統合ワークフローでの使用

```bash
# article-writerと組み合わせた安全な投稿
1. article-writer でコンテンツ作成
2. article-quality-check で事前検証 ← 新追加
3. 問題なければWordPress投稿実行
4. 投稿後の最終確認
```

---
*Created: 2026-02-10 for tifa onboarding and thumbnail issue prevention*
---
name: article-workflow-tracker
description: 記事作成ワークフローの進捗管理とSlackスレッド追跡。記事作成開始時のメッセージIDを記録し、完了時に同じスレッドに返信する仕組み。
---

# Article Workflow Tracker

記事作成の進捗を正しいSlackスレッド構造で管理するスキル。

## 基本ルール

1. **記事作成開始:** 新規投稿として報告、messageIdを記録
2. **作業進捗・完了:** 開始メッセージのスレッドに返信
3. **一つの記事 = 一つのスレッド**

## ワークフロー

### Step 1: 記事作成開始の報告

```javascript
// 新規投稿として開始報告
const startResult = await sessions_spawn({
  task: `Slack #nemo (C0ABPLBL04X) に記事作成開始を新規投稿し、投稿のmessageIdを返してください。

📝 *記事作成開始 - ${articleTitle}*

• テーマ: ${theme}
• パターン: ${pattern}  
• 推定所要時間: ${estimatedHours}時間`,
  label: "article-start-report"
});

// messageIdを記録
const messageId = extractMessageId(startResult);
await recordArticleStart(articleTitle, messageId);
```

### Step 2: メッセージID記録

```markdown
memory/YYYY-MM-DD.md に以下の形式で記録:

## 記事作成進行中

### [記事タイトル] - 開始: HH:MM
- **Slack messageId:** 1234567890.123456  
- **開始時刻:** YYYY-MM-DD HH:MM
- **パターン:** 選び方ガイド/おすすめ比較等
- **ステータス:** 作成中
```

### Step 3: 完了・進捗報告(スレッド返信)

```javascript
// メモリから messageId を取得
const messageId = await getArticleMessageId(articleTitle);

// 完了報告をスレッド返信
await message({
  action: "send",
  channel: "slack", 
  target: "C0ABPLBL04X", // #nemo
  threadId: messageId,
  message: `✅ **記事作成完了**

**記事情報:**
• タイトル: ${articleTitle}
• URL: ${articleUrl}
• Post ID: ${postId}
• パターン: ${pattern}

**作業時間:** ${actualHours}時間
**次回予定:** ${nextPlan}`
});

// ステータス更新
await updateArticleStatus(articleTitle, "completed");
```

## メモリ管理関数

### recordArticleStart(title, messageId)
```javascript
const today = new Date().toISOString().split('T')[0];
const memoryFile = `memory/${today}.md`;

const recordEntry = `
### ${title} - 開始: ${new Date().toTimeString().slice(0,5)}
- **Slack messageId:** ${messageId}
- **開始時刻:** ${new Date().toISOString()}  
- **ステータス:** 作成中
`;

await appendToFile(memoryFile, recordEntry);
```

### getArticleMessageId(title)
```javascript
const today = new Date().toISOString().split('T')[0];
const memoryContent = await readFile(`memory/${today}.md`);

const match = memoryContent.match(
  new RegExp(`### ${title}[\\s\\S]*?messageId:\\s*(\\d+\\.\\d+)`)
);

return match ? match[1] : null;
```

### updateArticleStatus(title, status)
```javascript
// memory/YYYY-MM-DD.md の該当エントリを更新
// ステータス: 作成中 → completed
```

## エラーハンドリング

### messageId取得失敗時
```javascript
if (!messageId) {
  // 新規投稿として完了報告(フォールバック)
  await message({
    action: "send", 
    channel: "slack",
    target: "C0ABPLBL04X",
    message: `⚠️ **記事作成完了** (スレッド追跡失敗)

${completionMessage}`
  });
}
```

### 既存記事のスレッド復旧
```javascript
// 過去の記事でmessageIdが不明な場合の対処
async function findExistingThread(articleTitle) {
  // Slack履歴を検索して該当するスレッドを特定
  // または新規スレッドとして開始
}
```

## 実装チェックリスト

記事作成ワークフロー修正時の確認項目:

- [ ] 開始報告で sessions_spawn を使用(新規投稿保証)
- [ ] messageId の確実な取得・記録
- [ ] memory/ ファイルへの進捗記録  
- [ ] 完了時のスレッド返信(threadId指定)
- [ ] エラー時のフォールバック処理
- [ ] 複数記事並行時の追跡管理

## 使用例

```bash
# 記事作成開始
startArticleWorkflow("ChatGPT活用ガイド", "使い方ガイド");

# 作業中の進捗報告  
reportProgress("ChatGPT活用ガイド", "リサーチ完了、執筆開始");

# 作業完了報告
completeArticle("ChatGPT活用ガイド", {
  url: "https://...",
  postId: "123",
  actualHours: 3
});
```

---

*2026-02-06 けいた様の指示により作成。記事作成のスレッド管理を標準化。*
---
name: article-writer
description: "SEO最適化された商品比較・おすすめ記事をWordPressに投稿する。消費者の購買検討プロセスに沿った構造化コンテンツを作成。口コミ原文掲載、マルチソースリサーチ、WordPress投稿を含む。「記事を書く」「ブログ投稿」「コンテンツ制作」「商品比較記事」などの作業に使う。"
---

# 記事作成ワークフロー — Essential Navigator

## 概要

essential-navigator.com に高品質な記事を作成・投稿するワークフロー。

**コアコンセプト:**
- 「しっかり調べたい人が、ここだけで完結できる」
- 情報量で妥協しない。それが構造化されていることが価値
- 口コミは原文で掲載する(サマリーでは不足)
- 消費者の購買検討プロセスに沿った構造

## 記事作成時のSlack投稿ルール(けいた様指示 2026-02-07)
**記事作成に関する全てのプロセスは、スレッド形式で整理すること:**
1. **記事作成開始の投稿** → 新規投稿
2. **中間プロセス報告** → 開始投稿へのスレッド返信
3. **完了報告** → 開始投稿へのスレッド返信

記事作成の全プロセス(ニュース収集、記事作成、デプロイ、サイト確認等)を開始投稿のスレッドに集約し、#nemoチャンネルの視認性を向上させる。

## 画像方針(2026-02-03 けいた様指示・確定)

| 種別 | 方針 |
|------|------|
| **ホーム画面サムネイル** | **必須**。全記事に高品質な画像を設定。読者の第一印象 |
| **記事内画像** | **バランスを見極める**。不適切な画像はかえって読みづらくなるリスクあり。無理に入れるより構造化テキストで担保 |

- 楽天API商品画像など、コンテンツに直接関連する画像は積極的に使用
- 意味のないストック写真や装飾目的だけの画像は入れない

## リンクスタイル(2026-02-16 追加)

**note/Zennライクな控えめリンク表現を採用**

- 通常時:本文と同じ色、薄い青のアンダーライン
- ホバー時:青色に変化、アンダーラインも濃くなる
- 外部リンク:小さな「↗」アイコン付き

CSSで自動適用されるため、Markdownで普通にリンクを書けばOK。

## コードブロック表示(2026-02-16 追加)

**⚠️ 重要:コードはMarkdownコードフェンスで記述すること**

記事内にコマンドやコード例を含める場合、必ずMarkdownのコードフェンス(` ``` `)を使用する。
普通のテキストとして記述すると、背景色やモノスペースフォントが適用されず読みにくくなる。

**正しい例:**

````markdown
```bash
brew install tursodatabase/tap/turso
turso auth login
```

```typescript
const db = createClient({
  url: process.env.TURSO_DATABASE_URL!,
});
```
````

**悪い例(禁止):**

```
brew install tursodatabase/tap/turso  ← 普通のテキスト、コードに見えない
```

**ルール:**
- コードフェンスを使用(` ``` `で囲む)
- 言語指定を明記(`bash`, `javascript`, `typescript`, `sql`, `json`等)
- インラインコードは `` `バッククォート` `` で囲む
- 長いコードは横スクロール対応(CSS側で処理済み)

## 必読ドキュメント

記事作成前に方針を確認:
- `docs/PURCHASE-DECISION-PROCESS.md` — 購買検討プロセス(最重要)
- `docs/BRAND-IDENTITY.md` — ブランドの人格・トーン
- `docs/RESEARCH-SOURCES.md` — リサーチソースと手順
- `skills/blog-article/SKILL.md` — 記事テンプレートと品質基準

## ワークフロー

### Step 1: テーマ決定

```
1. WordPress APIで全記事取得(GET /wp/v2/posts?per_page=100&status=publish)
2. 各記事をパターンに分類(タイトル・スラッグで判定)
3. パターン分布を算出 → 理想比率とのギャップで優先パターンを決定
4. カテゴリ内の充実度を確認
   → 選び方ガイドがないカテゴリ → まず選び方ガイド
   → おすすめ比較がないカテゴリ → 次にセグメント別おすすめ
5. テーマとパターンを確定
```

### Step 2: マルチソースリサーチ(必須・省略不可)

#### 🔴 料金・ポリシー・サービス変更系の記事は追加確認必須(2026-02-18追加)

**以下のキーワードを含む記事は、Step 2a を先に実行すること:**
- 料金、プラン、価格、pricing
- 変更、移行、廃止、終了
- 新機能、リリース、発表
- API、利用規約、ポリシー

**Step 2a: 最新公式発表の確認(料金・変更系は必須)**

```bash
# 1. 直近1週間のニュース検索(日本語・英語両方)
web_search query="[サービス名] 料金 変更 2026" freshness=pw count=10
web_search query="[Service] pricing change 2026" freshness=pw count=10

# 2. 公式発表を確認(必ず発表日を特定)
web_fetch url=[公式ブログ/ニュースルーム]
# → 「いつ発表されたか」を必ず記録

# 3. 公式Xアカウントの発表を確認
web_search query="site:twitter.com [公式アカウント] pricing OR 料金" freshness=pm

# 4. 日本語ニュースメディアの報道も確認
web_search query="[サービス名] site:gigazine.net OR site:itmedia.co.jp" freshness=pm
```

**⚠️ 確認必須項目(料金・変更系):**
- [ ] 公式発表の**日付**を特定した(「〇月〇日発表」)
- [ ] 発表日が**1ヶ月以内**なら最新情報として扱う
- [ ] 「Pilot」「Beta」「正式」の区別を確認した
- [ ] 日本語ニュースメディアの報道も確認した

**❌ 禁止事項:**
- 公式発表日を確認せずに「〇〇がある」と断定
- 「Pilot段階」と「正式リリース」を混同
- 古い情報(3ヶ月以上前)を最新として記載

---

**Step 2b: 類似サービス名・関連技術の区別(2026-02-18追加)**

**⚠️ 以下のような類似サービス名は別物として扱う:**

| 混同しやすい組み合わせ | 違い |
|----------------------|------|
| **FigJam** vs **Figma** | FigJam=ホワイトボード/ダイアグラム、Figma=デザインツール |
| **Claude** vs **Claude Code** | Claude=チャット/API、Claude Code=CLI開発ツール |
| **GitHub** vs **GitHub Copilot** | GitHub=リポジトリ、Copilot=AI補完 |

**関連事例を紹介する際の必須チェック:**

1. **公式発表の「具体的機能」と照合**
   - 入力→出力の流れが一致しているか
   - 同じプラットフォームで動作するか
   - 「同じエコシステム」だけでは不十分

2. **不一致の場合**
   - 「関連技術」として明確に区別
   - 「公式発表の機能とは異なる」と明記
   - 混同を避けるため比較表を追加

**❌ 禁止:**
- 「同じエコシステムだから同じ機能」と判断
- 類似サービス名の事例を区別なく紹介
- 関連事例が公式発表と同一機能か確認せず掲載

---

以下のソースを**すべて**調査する:

**a. カテゴリ概要の把握**
```bash
# マイベストで全体像
web_fetch url=https://my-best.com/[カテゴリ]
# 家電Watchで業界動向
web_search query="[カテゴリ] 最新 2026 site:kaden.watch.impress.co.jp"
```

**b. 楽天APIで商品情報取得**
```bash
curl "https://app.rakuten.co.jp/services/api/IchibaItem/Search/20220601\
?applicationId=1005382698954372332\
&affiliateId=463c2935.b0920fd0.463c2936.42e030ce\
&keyword=[検索キーワード]&sort=-reviewCount&hits=10"
```

**c. 口コミ調査(最重要)**
```
# Amazon口コミ
web_fetch url=https://amazon.co.jp/dp/[ASIN]

# 価格.com口コミ
web_search query="[製品名] site:kakaku.com"
→ 見つかったページを web_fetch

# X (Twitter) での生の声
web_search query="[製品名] (レビュー OR 感想 OR 買った OR 使ってみた)"
```

**d. 最新世代の確認**
```
web_search query="[製品名] 最新モデル 2025 2026"
```

**e. 競合記事の確認**
```
web_search query="[テーマのキーワード] おすすめ OR 比較 OR レビュー"
→ 上位1〜2記事を web_fetch して差分確認
```

### Step 3: 口コミの選定

各製品について以下を選定:
- **肯定的口コミ:** 3〜5件の原文
- **否定的口コミ:** 3〜5件の原文
- **体感差の口コミ:** スペック差と実際の使用感の違いに言及するもの
- **口コミ傾向:** ★分布、頻出する評価ポイント

### Step 4: 記事作成

`skills/blog-article/SKILL.md` のテンプレートに従い記事HTMLを作成。

**必須要素:**
- 結論ファースト
- 比較ポイントの明示と解説
- 口コミ原文の掲載(blockquote)
- 条件分岐型の推薦(「〇〇なら→A」)
- セグメント別マッチング
- 内部リンク(3本以上)
- **ニュースソースURL掲載(AI記事の場合必須)** — けいた様指示 2026-02-06

## 🔴 事例記事(case-study)の絶対ルール(けいた様指示 2026-02-15)

**読者に嘘を伝えることは絶対に避ける。**

### 必須要件

1. **実在の事例に基づくこと**
   - 架空のモデルケース禁止
   - 「複数事例を参考にした創作」も禁止
   - 実在する人物・プロダクト・企業を明記

2. **一次ソースを本文中に明記**
   - インタビュー元URL
   - 公式発表URL
   - ポッドキャスト/YouTube等の出典

3. **出典形式**
   ```markdown
   > この事例は [Indie Hackers](https://www.indiehackers.com/post/xxx) での
   > [開発者名] のインタビューに基づいています。
   ```

### 推奨ソース

- **Indie Hackers** — ソロビルダーのインタビュー・収益公開
- **X (Twitter)** — ビルダーの生の声、収益報告
- **Product Hunt** — ローンチ事例、makers のコメント
- **ポッドキャスト** — My First Million, Indie Bites 等

### 禁止事項

- ❌ 一般的なパターンを「事例」として記述
- ❌ 複数事例を混ぜた架空ストーリー
- ❌ frontmatterにsourceを書いて本文中に出典なし

---

## AIニュース記事の特別ルール(ai.essential-navigator.com用)

### ニュースソース掲載の必須化(けいた様指示 2026-02-06)

AIニュース・ツール紹介記事では以下を必ず記載:

1. **出典リンク:** 元記事・公式発表のURLを明記
2. **公式サイト:** ツールの公式サイトURL
3. **関連リンク:** GitHub, Product Hunt等の関連ページ

**記載形式:**
```markdown
## 参考リンク
- **公式発表:** [タイトル](URL)
- **公式サイト:** [サービス名](URL)
- **GitHub:** [リポジトリ名](URL)(該当する場合)
```

### 海外記事紹介の形式ルール(けいた様承認 2026-02-03)
- **形式:** 原文の要点紹介+日本市場への独自分析
- **禁止:** 全文翻訳の転載(著作権侵害リスク)
- **必須:** 出典リンクの明記、原文への敬意を示す構成
- **付加価値:** 日本のソロビルダー視点での実現可能性・注意点の独自分析を必ず追加
- **表記例:** 「本記事は翻訳ではなく、原文の紹介・解説記事です。詳細は原文(英語)をご覧ください。」

### Step 5: サムネイル画像設定(必須・自動化)

**⚠️ 重要:全記事にサムネイル設定は必須(けいた様指示 2026-02-03)**

記事作成時に自動的にサムネイル画像を設定する:

```bash
# 1. 記事内容に適したキーワードでUnsplash検索
web_search("site:unsplash.com [記事テーマ関連キーワード] technology")

# 例:AI記事の場合
web_search("site:unsplash.com artificial intelligence computer programming")
web_search("site:unsplash.com data technology digital coding")

# 2. 検索結果から画像IDを抽出し、適切なURLを構成
# 形式: https://images.unsplash.com/photo-{ID}?w=800&h=420&fit=crop

# 3. 記事のfrontmatter/メタデータに設定
# - md記事の場合: image: フィールドに設定
# - WordPress直接投稿の場合: featured_media に設定
```

**画像選択基準:**
- 記事テーマに合致
- プロフェッショナルで高品質
- テキストオーバーレイに適している(暗めの背景推奨)
- 同じ画像の重複使用を避ける

**自動化チェックリスト:**
- [ ] Unsplash画像検索完了
- [ ] 適切な画像ID特定
- [ ] フォーマットURL構成(?w=800&h=420&fit=crop)
- [ ] 記事メタデータに設定
- [ ] 画像URL動作確認(404エラーなし)

**重要:サムネイル未設定での記事公開は禁止**

### Step 5a: 記事内画像エンリッチメント(2026-02-21追加)

**🖼️ article-image-enricherスキルで記事内に公式画像を追加**

記事内で紹介しているプロダクト/サービスの公式サイトから画像を取得し、記事に追加する。

```bash
# 1. 記事内の外部リンク(公式サイト)を特定
grep -oE 'https?://[^)]+' <記事ファイル>

# 2. 公式サイトから画像URLを取得
curl -s <公式サイトURL> | grep -oE 'https?://[^"]+\.(png|jpg|jpeg|webp)' | head -10

# 3. 画像を確認・選定(imageツール)
image(url, "この画像の内容を説明してください。記事への適合性を評価してください。")

# 4. 画像URL有効性確認
curl -sI "<画像URL>" | head -5  # HTTP/2 200 を確認

# 5. 記事に追加
```

**追加フォーマット:**
```markdown
![説明テキスト](画像URL)
*出典: [サイト名](サイトURL)*
```

**対象:**
- 記事内で紹介している主要プロダクト(1〜3個)
- 公式サイトがあり、画像が取得可能なもの

**注意:**
- FigmaコミュニティはSPAで取得困難 → 公式サイトを探す
- 出典リンク必須
- 詳細は `~/.openclaw/skills/article-image-enricher/SKILL.md` 参照

### Step 6: 著作権チェック(必須・事例記事は特に厳格)

**🔍 copyright-check スキルで著作権・引用適正を確認**

```bash
# 著作権チェック実行(事例記事・海外ソース参照時は必須)
copyright-check [記事ファイルパス]

# チェック項目:
- [ ] 翻訳比率 30%未満
- [ ] 独自分析・考察 50%以上
- [ ] 引用箇所 3箇所以内
- [ ] 構成の独自性
- [ ] 複数ソース参照(事例記事)
```

**❌ チェック失敗時:**
- 翻訳比率超過 → 横断分析形式へ書き換え or 削除
- 単一ソース依存 → 複数ソースから再構成

**⚠️ 著作権チェック通過まで次Step進行禁止**

---

### Step 7: 投稿前品質チェック(tifa必須)

**🔍 新設:記事投稿前の必須チェック工程**

```bash
# article-quality-checkスキルで包括的チェック実行
article-quality-check --pre-publish [記事ファイルパス]

# チェック項目:
- [ ] サムネイル画像設定確認
- [ ] メタデータ完整性確認  
- [ ] 出典リンク確認(AIニュース記事)
- [ ] フォーマット確認
```

**❌ チェック失敗時の対処:**
- `THUMBNAIL_MISSING` → thumbnail-generatorスキルでUnsplash画像設定
- `METADATA_INCOMPLETE` → title, slug, category, excerpt補完
- `SOURCE_LINKS_MISSING` → 公式サイト・出典URL追加

**⚠️ 重要:チェック通過まで次Step進行禁止**

### Step 7: WordPress投稿

```bash
curl -X POST "https://essential-navigator.com/wp-json/wp/v2/posts" \
  --user "user:vAjb cYtM UemC 4Nu5 P8KW oI8q" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "記事タイトル",
    "content": "記事HTML",
    "status": "publish",
    "slug": "english-slug",
    "categories": [カテゴリID],
    "featured_media": メディアID,
    "excerpt": "メタディスクリプション(120文字以内)"
  }'
```

### Step 8: 公開後確認

```
1. browser action=open profile=clawd targetUrl=<記事URL>
2. モバイル表示確認:
   - resize 375x812
   - scrollWidth ≤ 375 を確認
   - レイアウト崩れ・コントラスト・テーブルはみ出しチェック
3. 競合記事と比較して情報の抜けがないか確認
4. 改善点があれば記事をPUT APIで更新
```

### Step 9: 記録とSlack報告(2026-02-12 けいた様指示反映)

```
1. memory/YYYY-MM-DD.md に記録
   - 記事タイトル、Post ID、URL、パターン、パターン分布
2. Slack報告(完了時は必ずURLを共有)
   **🔗 必須: アクセス可能URLの明記**
   - 記事完了報告時は必ず公開URLを記載
   - けいたがすぐにアクセスできるよう即座に共有
   - フォーマット: **公開URL:** [記事タイトル](https://実際のURL)
   
   報告例:
   ```
   ✅ 記事作成完了
   
   **公開URL:** [記事タイトル](https://ai.essential-navigator.com/news/slug)
   
   記事内容: [概要]
   作成本数: X本
   ```
```

## リファレンス記事(トーン・構成のベンチマーク)

記事品質の目標として以下のリファレンスを参照:

- **`references/laiso-openclaw-analysis.md`** — laisoさんのOpenClaw解説記事分析
  - URL: https://blog.lai.so/openclaw/
  - けいた評価:「素晴らしい記事、ベンチマークにしたい」(2026-02-19)
  - 学ぶべき点: 構造の明快さ、賞賛と批判のバランス、一次ソース引用、具体的な数字

**トーンの指針(laisoスタイル):**
- 「筆者の評価としては」と主観を明示しつつ客観性を保つ
- 専門用語を使いつつも必ず説明を添える
- 問いを立て、核心を3点に絞り、最後に行動指針を示す

---

## API情報

### WordPress
```
URL: https://essential-navigator.com/wp-json/wp/v2
User: user
Password: vAjb cYtM UemC 4Nu5 P8KW oI8q
```

### 楽天
```
App ID: 1005382698954372332
Aff ID: 463c2935.b0920fd0.463c2936.42e030ce
画像: mediumImageUrls の 128x128 → 400x400 に置換
```
---
name: asb-content-design
description: AI Solo Builder専用のコンテンツデザインスキル。noteデザイン分析・認知科学に基づく「読者体験設計」と、記事フォーマットの最適化を統合。Digest・個別ニュース・プロダクト記事のいずれにも適用。「記事改善」「読みやすさ向上」「UI最適化」「コンテンツチェック」などの作業に使う。
---

# ASB Content Design — AI Solo Builder 読者体験設計スキル

**コンセプト:** 「情報よりも体験を設計する」

noteのデザイン分析・認知科学の知見に基づき、AI Solo Builder記事の読者体験を最大化する。

---

## 🎯 適用対象

- **Digest(朝刊/夕刊)**: 全体像を掴ませる
- **個別ニュース**: 意思決定に必要な解像度を出す
- **プロダクト辞書**: 前提知識を蓄積する

---

## 📐 5つのデザイン原則

### 1. 呼吸感のある余白設計

**noteの知見:** 行間1.8-2.0、十分な段落間スペース

**Markdown実装:**
```markdown
<!-- ❌ NG: 詰まった印象 -->
OpenAIがモデルを廃止。80万ユーザーに影響。即座に移行が必要。

<!-- ✅ OK: 呼吸感がある -->
OpenAIがモデルを廃止する。

**80万ユーザー**に影響があり、即座に移行が必要になる。
```

**チェック:**
- 150語を超える段落は分割する
- 重要語句には`**太字**`で視覚アンカーを作る
- セクション間には十分な空行を入れる

---

### 2. 3層構造の情報階層

読者の「流し読み」を前提に設計する。

| 層 | 役割 | 要素 | 読了時間 |
|----|------|------|---------|
| **L1: ヘッドライン** | 何の話か | 見出し・順位表 | 2秒 |
| **L2: サマリー** | 要点 | 太字・箇条書き | 10秒 |
| **L3: 詳細** | 根拠・具体 | 本文・リンク | 1分+ |

**Digest実装例:**
```markdown
## 🔥 Top 3 ピックアップ       <!-- L1: 2秒で「重要ニュース」とわかる -->

### 1. OpenAI、レガシーモデル廃止

**本日10時(PT)**より5モデル廃止。 <!-- L2: 要点 -->
**80万ユーザー**に影響。

ソロビルダーへの影響:            <!-- L3: 詳細 -->
- APIでこれらのモデルを使っている場合は本日中に移行が必須
```

---

### 3. テーブルの3列ルール + モバイル自動カード変換

**noteの知見:** 情報密度を下げ、視覚的余裕を確保

**ルール:**
- 表は**3列以下**に抑える
- 最も重要な情報を左列に配置(モバイルでカードタイトルになる)
- ステータスは絵文字で視覚化

**📱 モバイル対応(2026-02-16 更新):**

640px以下の画面では、テーブルが**自動でカード形式**に変換される。

- ヘッダー行 → 非表示
- 各行 → 角丸カード(グリッドレイアウト)
- 先頭セル(順位)→ 左側にカラフルなバッジ(**Top3は金銀銅**)
- 2番目セル(タイトル)→ 右上に大きく表示
- 3番目以降(NVA/Tier)→ 右下にコンパクトなバッジ
- **各セルにラベル表示**(data-label属性で動的生成)

**→ 記事作成時にモバイル対応を意識する必要なし。CSSが自動処理。**

**📺 PC対応(2026-02-16 追加):**

- **記事コンテンツ全体: 最大幅680px**(noteライク)
- テーブル: `table-layout: auto`(コンテンツに応じた自然な幅)
- 短い列(順位/NVA/Tier): `width: 1%` + `nowrap`で最小幅
- 長い列(ニュース): 残りスペースを使用

**→ ワイドスクリーンでも読みやすいレイアウトを維持。**

**変換例:**
```markdown
<!-- ❌ NG: 4列以上で認知負荷大 -->
| 順位 | ニュース | NVA | Tier |

<!-- ✅ OK: 3列に凝縮、Tierを絵文字化 -->
| 順位 | ニュース | Tier |
|:----:|----------|:----:|
| 1 | OpenAI GPT-4o廃止 | 🔥 S |
| 2 | WebMCP早期プレビュー | 🔥 S |
| 3 | ChatGPT広告導入 | ⭐ A |
```

**Tier絵文字パターン:**
- `🔥 S` — 緊急/重大(即座に対応が必要)
- `⭐ A` — 重要(近日中に確認推奨)
- `📝 B` — 参考(余裕があれば確認)

**先頭列のベストプラクティス:**
- 順位番号、プロダクト名、日付など「識別子」を配置
- モバイルでカードタイトルになるため、その行が何かわかる内容に

---

### 4. スキャン最適化(F字パターン)

読者の視線はF字を描く。重要情報は**左上**に集中させる。

**実装パターン:**

```markdown
## 🏁 重要ニュースランキング(NVA)    <!-- 見出しで「何がわかるか」を明示 -->

| 順位 | ニュース | NVA | Tier |         <!-- 順位を左端に -->
|------|----------|-----|------|
| 1 | OpenAI... | 25 | S |             <!-- 最重要を最上部に -->
```

**チェック:**
- 各セクションの冒頭10語で内容が伝わるか?
- 視線が自然に下に流れるか?

---

### 5. アクション指向の構造

読了後に「何をすべきか」を明確に示す。

**パターン:**
```markdown
**🎯 ソロビルダーへの影響:**
- APIでこれらのモデルを使っている場合は**本日中に移行が必須**
- プロンプトチューニング済みの場合は**新モデルでの動作検証**が必要
- AIコンパニオン系アプリの「同調性」設計を**再考する機会**
```

**ポイント:**
- 見出しに`🎯`を付けて視覚的に目立たせる
- 各項目の**アクション部分を太字**にする
- 動詞(「移行する」「検証する」「再考する」)を含める

---

## 📝 コンテンツタイプ別ガイド

### Digest(朝刊/夕刊)

**構成テンプレート:**
```markdown
# 2026年X月X日 [朝刊/夕刊]AIダイジェスト

[1-2文の導入。季節感・タイミング・全体の空気感]

## 🏁 重要ニュースランキング(NVA)

[10件のランキング表 — 3列以下推奨]

## 🔥 Top 3 ピックアップ

### 1. [見出し]
[要点 + ソロビルダーへの影響]

---

### 2. [見出し]
...

---

### 3. [見出し]
...

## 📅 [明日への展望 / 週末への展望]
[締めの1-2段落]
```

**チェックリスト:**
- [ ] ランキング表が3列以下
- [ ] Top3各項目に「ソロビルダーへの影響」がある
- [ ] 出典・日付が明記されている
- [ ] 関連リンクが適切に配置されている

---

### 個別ニュース

**構成テンプレート:**
```markdown
# [見出し]

[リード文: 何が・なぜ・どう影響するか — 50語以内]

## 📌 要点

- **ポイント1**
- **ポイント2**
- **ポイント3**

## 💡 詳細

[本文 — 300-500語/セクション]

## 🎯 ソロビルダーへの影響

[アクション指向の箇条書き]

## 🔗 関連情報

- [リンク1]
- [リンク2]
```

---

### プロダクト辞書

**構成テンプレート:**
```markdown
# [プロダクト名]

[1文の説明]

## 📊 基本情報

| 項目 | 内容 |
|------|------|
| 開発元 | |
| 料金 | |
| 用途 | |

## ✨ 特徴

- **特徴1**
- **特徴2**

## 🔧 ソロビルダー向け活用法

[具体的なユースケース]

## 🔗 リンク

- [公式サイト](URL)
```

---

## 🔄 ワークフロー組み込み

### 記事作成時の適用タイミング

```
Phase 3: digest-writer(記事作成)
    ↓
Phase 3.5: asb-content-design(読者体験最適化)← このスキル
    ↓
Phase 4: publish-gate(品質チェック・公開)
```

### 実行手順

1. **構造チェック(2分)**
   - 見出し階層は適切か?
   - テーブルは3列以下か?
   - 段落は150語以下か?

2. **呼吸感チェック(2分)**
   - 重要語句に太字があるか?
   - セクション間に十分な余白があるか?

3. **アクション指向チェック(1分)**
   - 「ソロビルダーへの影響」が具体的か?
   - 読者が次に何をすべきか明確か?

---

## 📋 品質チェックリスト

### 必須項目

- [ ] テーブルが3列以下
- [ ] 150語を超える段落がない
- [ ] 重要語句に太字がある
- [ ] 各セクションに見出しがある
- [ ] 「ソロビルダーへの影響」が具体的

### 推奨項目

- [ ] セクション間に`---`区切りがある
- [ ] 絵文字で視覚アンカーが作られている
- [ ] リンクが適切に配置されている
- [ ] 締めの文で次のアクションが示唆されている

---

## 📊 期待効果(認知科学に基づく)

| 項目 | 改善幅 | 根拠 |
|------|--------|------|
| **読了時間** | 35-50%短縮 | 適切な行間・余白による視認性向上 |
| **理解度** | 35%向上 | 情報階層の明確化 |
| **実行率** | 191%向上 | 認知負荷軽減による行動促進 |
| **満足度** | 39%向上 | 読み体験の向上 |

---

## 📚 参照

- **ui-design-principles** — CSS/サイトレベルのUI設計方針
- **content-optimizer** — 詳細な最適化手法
- `/Users/satokeita/Dev/ai-navigator/docs/CHECKLIST.md` — 公開前チェックリスト

---

*「読者がゆったりとコンテンツを楽しめる体験を。情報の伝達ではなく、理解と実行を促すデザインを。」*

*最終更新: 2026-02-16(noteライクレイアウト・モバイルカード改善)*
---
name: chuzyuquiz-vercel-deploy
description: ChuzyuQuizのWeb版(React/Next.js)をVercelにデプロイする完全ワークフロー。設定ファイルの事前検証、デプロイ実行、動作確認、トラブルシューティングを含む。「Web版デプロイ」「Vercelデプロイ」「設定エラー修正」「デプロイ後確認」などの作業に使う。
---

# ChuzyuQuiz Vercel Deploy

ChuzyuQuizのWeb版をVercelに安全かつ確実にデプロイするためのワークフロー。

## Quick Start

### 基本デプロイフロー

1. **事前チェック**: 設定ファイルとビルド環境を検証
2. **デプロイ実行**: Git push → Vercel自動デプロイ
3. **動作確認**: 本番環境での基本機能テスト
4. **問題対処**: エラー発生時のトラブルシューティング

### 今すぐデプロイする場合

```bash
# プロジェクトディレクトリに移動
cd /Users/satokeita/chuzyuquiz/web

# 事前チェック実行
scripts/pre_deploy_check.py

# デプロイ実行
git add -A
git commit -m "Web版更新: [変更内容]"
git push origin main

# 2分待機後、動作確認実行  
scripts/verify_deployment.py
```

## 詳細ガイド

### 事前チェック項目

必ず確認すべき設定:

- **Supabase設定** (`src/utils/config.ts`)
  - `SUPABASE_URL`: プレースホルダー値 `YOUR_PROJECT_ID` でないこと
  - `SUPABASE_ANON_KEY`: 有効なキーが設定されていること
- **環境変数** (`.env.local` or Vercel環境変数)
- **ビルド設定** (`package.json`, `next.config.js`)

詳細は [CONFIG_CHECKLIST.md](references/CONFIG_CHECKLIST.md) を参照

### デプロイ後確認項目

本番環境で必ずテストする機能:

1. **時代一覧読み込み** - Supabase接続の基本確認
2. **クイズデータ取得** - API呼び出しの動作確認
3. **基本UI操作** - JavaScript実行とページ遷移

### トラブルシューティング

よくある問題と対処法は [TROUBLESHOOTING.md](references/TROUBLESHOOTING.md) を参照

**緊急時(本番エラー発生時):**

1. 問題の特定: Browser DevTools のNetwork/Console タブでエラー確認
2. 設定確認: `src/utils/config.ts` の値を点検
3. 緊急修正: 設定修正 → commit → push
4. 再確認: 2分後にデプロイ完了、動作確認実行

## Scripts

### `scripts/pre_deploy_check.py`

デプロイ前の自動チェック。設定ファイルの検証、ビルドテスト、環境変数確認を実行。

```bash
python3 scripts/pre_deploy_check.py
# または
python3 scripts/pre_deploy_check.py --fix  # 軽微な修正を自動実行
```

### `scripts/verify_deployment.py`

本番環境での動作確認。HTTP接続テスト、API呼び出し確認、基本機能テストを実行。

```bash
python3 scripts/verify_deployment.py
# または  
python3 scripts/verify_deployment.py --url https://chuzyuquiz.vercel.app  # 特定URL指定
```

## References

- **[CONFIG_CHECKLIST.md](references/CONFIG_CHECKLIST.md)** - 設定項目の完全チェックリスト
- **[TROUBLESHOOTING.md](references/TROUBLESHOOTING.md)** - よくある問題と対処法

## Project Context

- **本番URL**: https://chuzyuquiz.vercel.app
- **GitHub**: ksato8710/chuzyuquiz (webディレクトリ)
- **Vercel**: 自動デプロイ設定済み (main branch)
- **ローカル**: /Users/satokeita/chuzyuquiz/web
- **スタック**: React + Vite + TypeScript + Supabase

## Safety Notes

- デプロイ後は必ず2分待ってから動作確認(Vercelのビルド完了待ち)
- 設定エラーは本番で即座に影響するため、事前チェックを必須とする
- 緊急修正時も事後確認を怠らない(二次障害防止)
---
name: claude-code-e2e-automation
description: Claude CodeでE2E自動テストを実行するスキル。qa-engineerエージェントの正しい起動方法、権限問題の対処、pty監視体制の構築を含む。「E2Eテスト実行」「qa-engineer起動」「Claude Code自動化」「ブラウザテスト」「権限エラー対処」などの作業に使う。
---

# Claude Code E2E自動化スキル

## 概要

Claude Codeのqa-engineerエージェントでE2Eテストを自動実行するための完全ガイド。
ブラウザ操作を伴うテストの特性上、権限問題・停止・入力待ちへの対処が重要。

## 重要な前提知識

### ❌ backgroundでは実行不可
```bash
# これは失敗する
sessions_spawn(agentId="qa-engineer", task="E2Eテスト実行")
```

**理由:**
- ブラウザ操作の確認が必要
- エラー時の即座対応が必要
- 認証・セットアップの動的変更が必要

### ✅ ptyでリアルタイム実行が必須
```bash
# 正しい方法
exec command="claude --agent qa-engineer --dangerously-skip-permissions" pty=true
```

## 実行手順

### Step 1: Claude Code + qa-engineer起動

**推奨コマンド(けいたさん承認済み):**
```bash
cd /Users/satokeita/Dev/history-quiz-app && claude --agent qa-engineer --dangerously-skip-permissions
```

**オプション説明:**
- `--agent qa-engineer`: QA専門エージェント指定
- `--dangerously-skip-permissions`: 全権限チェックスキップ
- `pty=true`: リアルタイム対話モード

**代替オプション(権限制御したい場合):**
```bash
claude --agent qa-engineer --permission-mode acceptEdits
```

### Step 2: タスク指示

**テンプレート:**
```text
ChuzyuQuiz歴史アプリの本番環境E2Eテストを実行してください。

テスト実施内容:
1. docs/TEST-STRATEGY.md に従った戦略実行
/Users/satokeita/Dev/history-quiz-app/.claude/skills/web-e2e に準拠して、agent-browserを利用すること
2. web/e2e/README.md のE2E-01〜E2E-05テストケース実行
3. テスト用アカウント新規作成
4. 各テストのスクリーンショット・動画エビデンス取得
5. エビデンス保存:test/evidence/$(date +%Y%m%d)
6. 問題発見時の原因分析と修正提案
7. テスト結果レポート作成

よろしくお願いします。
```

**送信方法:**
```javascript
process("write", sessionId, data + "\n");
process("send-keys", sessionId, ["Return"]);
```

### Step 3: 監視体制構築

**必須:** 2分おきの監視cronを設定

```json
{
  "name": "qa-engineer-monitor",
  "agentId": "stevens",
  "schedule": {
    "kind": "cron",
    "expr": "*/2 * * * *",
    "tz": "Asia/Tokyo"
  },
  "sessionTarget": "isolated",
  "wakeMode": "next-heartbeat",
  "payload": {
    "kind": "agentTurn",
    "message": "qa-engineerセッション監視と自動対処",
    "deliver": true,
    "channel": "slack",
    "to": "channel:C0ACUDZCJJC"
  }
}
```

## 進捗報告ルール(重要)

### ❌ チャンネル本文への頻繁投稿禁止
- cronでの進捗報告を **チャンネル本文に直接投稿してはいけない**
- チャンネル全体が荒れる原因となる

### ✅ スレッド投稿を活用
- **E2Eテスト開始時:** チャンネル本文に「E2Eテスト開始」メッセージを投稿
- **進捗・監視報告:** 開始メッセージのスレッドに投稿
- **完了報告:** チャンネル本文に最終結果のみ投稿

### 実装方法

**1. E2Eテスト開始時:**
```javascript
// チャンネル本文に開始報告
const startMessage = message({
  action: "send",
  target: "#stevens",
  message: "🤖 Claude Code qa-engineer E2Eテスト開始\n\nテスト実施開始いたします。進捗はこのスレッドで報告いたします。"
});

// messageIdを取得してcronに設定
const messageId = startMessage.ts;
```

**2. 監視cronでのスレッド投稿:**
```javascript
// 監視結果をスレッドに投稿
message({
  action: "send",
  target: "#stevens",
  replyTo: messageId, // 開始メッセージへのスレッド返信
  message: "🔍 qa-engineer監視結果: 正常実行中 (E2E-03進行中)"
});
```

**3. 完了時:**
```javascript
// エビデンス・レポートファイルパスを確認
const evidenceDir = `/Users/satokeita/Dev/history-quiz-app/test/evidence/${new Date().toISOString().slice(0,10).replace(/-/g,'')}`;
const reportPath = `${evidenceDir}/e2e-test-report.md`;

// レポート内容を読み取り(結果要約用)
const reportContent = read(reportPath);

// 完了報告をスレッドに投稿(詳細版)
message({
  action: "send",
  target: "#stevens", 
  replyTo: messageId, // 開始メッセージのスレッド
  message: `✅ qa-engineer E2Eテスト完了

📁 **テスト結果ファイル:**
${reportPath}

📊 **結果要約:**
${reportContent.split('\n').slice(0, 10).join('\n')}

${reportContent.includes('FAILED') || reportContent.includes('エラー') ? 
  '⚠️ 問題検出あり。このレポートを元に修正作業に進めます。' : 
  '✅ 全テストケース正常完了'}

後続作業でこのレポートをご活用ください。`
});

// 完了報告はチャンネル本文(簡潔版)
message({
  action: "send", 
  target: "#stevens",
  message: "✅ qa-engineer E2Eテスト完了\n\n詳細レポート・エビデンスは上記スレッドをご確認ください。"
});

// 監視cronを削除
cron({action: "remove", jobId: "qa-engineer-monitor"});
```

## 問題発生パターンと対処法

### 1. 長時間停止状態

**症状:**
```
· Prestigitating…  (5分以上継続)
· Hullaballooing…  (5分以上継続)
```

**対処:**
```javascript
// 1. Enterキー送信
process("send-keys", sessionId, ["Return"]);

// 2. 30秒待機後、再確認
setTimeout(() => {
  process("log", sessionId, {limit: 10});
}, 30000);

// 3. まだ停止なら強制リセット
process("kill", sessionId);
```

### 2. 権限エラー

**症状:**
```
may only create directories in the allowed working directories
Reason: undefined
Suggestions:
● /Users/satokeita/Dev/history-quiz-app/test/evidence    Mode: Accept edits
```

**対処:**
```javascript
// 1. "a" (accept) キー送信
process("send-keys", sessionId, ["a"]);

// 2. Enterキー送信
process("send-keys", sessionId, ["Return"]);
```

### 3. Signal 9 強制終了

**症状:**
```
Exec failed (session-id, signal 9)
```

**対処:**
```javascript
// セッション完全リセット
process("kill", sessionId);

// 権限設定強化で再起動
exec({
  command: "claude --agent qa-engineer --dangerously-skip-permissions",
  pty: true,
  workdir: "/Users/satokeita/Dev/history-quiz-app"
});
```

### 4. エージェント認識エラー

**症状:**
```
@qa-engineer が反応しない
```

**原因と対処:**
- `.claude/agents/qa-engineer.md` の存在確認
- `--agent` オプションでの明示的指定が必須
- 大文字小文字に注意(`qa-engineer` が正確)

## 監視cronの実装

### 監視ロジック

```javascript
// 1. セッション状況確認
const log = process("log", sessionId, {limit: 20, offset: -20});

// 2. 完了状態検知
const isCompleted = log.includes("テスト完了") || 
                   log.includes("テスト結果レポート作成済み") ||
                   log.includes("all tests completed");

// 3. 停止状態検知
const isStuck = log.includes("Prestigitating") || 
                log.includes("Hullaballooing") ||
                log.includes("ctrl+g to edit");

// 4. 権限待ち検知
const needsPermission = log.includes("may only create") ||
                       log.includes("Mode: Accept edits");

// 5. 自動対処
if (isCompleted) {
  // テスト完了時の処理
  const evidenceDir = `/Users/satokeita/Dev/history-quiz-app/test/evidence/${new Date().toISOString().slice(0,10).replace(/-/g,'')}`;
  const reportPath = `${evidenceDir}/e2e-test-report.md`;
  
  // レポートが存在すれば内容を読み取り
  try {
    const reportContent = read(reportPath);
    const summary = reportContent.split('\n').slice(0, 15).join('\n');
    const hasIssues = reportContent.includes('FAILED') || reportContent.includes('エラー');
    
    // スレッドに詳細投稿
    message({
      action: "send",
      target: "#stevens",
      replyTo: "開始メッセージのmessageId", // 実際のmessageIdに置き換え
      message: `✅ qa-engineer E2Eテスト完了

📁 **テスト結果ファイル:**
${reportPath}

📊 **結果要約:**
${summary}

${hasIssues ? 
  '⚠️ 問題検出あり。このレポートを元に修正作業に進めます。' : 
  '✅ 全テストケース正常完了'}

後続作業でこのレポートをご活用ください。`
    });
    
    // チャンネル本文に完了報告
    message({
      action: "send",
      target: "#stevens",
      message: "✅ qa-engineer E2Eテスト完了\n\n詳細レポート・エビデンスは上記スレッドをご確認ください。"
    });
  } catch (error) {
    // レポートファイルがない場合
    message({
      action: "send",
      target: "#stevens", 
      replyTo: "開始メッセージのmessageId",
      message: "⚠️ テスト完了検知しましたが、レポートファイルが見つかりません。\n手動でエビデンス確認が必要です。"
    });
  }
  
  // 監視cronを削除
  cron({action: "remove", jobId: "qa-engineer-monitor"});
  
} else if (needsPermission) {
  process("send-keys", sessionId, ["a", "Return"]);
  
  // 権限対処をスレッドに報告
  message({
    action: "send",
    target: "#stevens",
    replyTo: "開始メッセージのmessageId",
    message: "🔧 権限待ち検知→自動承認実行"
  });
  
} else if (isStuck) {
  process("send-keys", sessionId, ["Return"]);
  
  // 停止対処をスレッドに報告
  message({
    action: "send",
    target: "#stevens",
    replyTo: "開始メッセージのmessageId", 
    message: "🔧 停止状態検知→リセット実行"
  });
  
} else {
  // 正常実行中(通常は報告なし、重要な進捗のみ)
  const currentTask = log.match(/E2E-\d+/g)?.pop();
  if (currentTask) {
    message({
      action: "send",
      target: "#stevens",
      replyTo: "開始メッセージのmessageId",
      message: `🔍 実行中: ${currentTask}`
    });
  }
}
```

## トラブルシューティング

### よくある失敗原因

1. **backgroundで実行**: E2Eテストは必ずptyでリアルタイム実行
2. **権限設定不足**: `--dangerously-skip-permissions` が最も確実
3. **監視なし**: 長時間実行では必ず監視cronをセット
4. **エージェント指定忘れ**: `--agent qa-engineer` は必須

### 成功の条件

✅ **正しいコマンド**: `claude --agent qa-engineer --dangerously-skip-permissions`  
✅ **ptyモード**: `pty=true` でリアルタイム対話  
✅ **監視体制**: 2分おきの自動チェック  
✅ **権限設定**: 完全スキップで中断なし

## 実行例(スレッド投稿対応版)

```javascript
// 1. E2Eテスト開始報告(チャンネル本文)
const startMessage = message({
  action: "send",
  target: "#stevens",
  message: "🤖 Claude Code qa-engineer E2Eテスト開始\n\nChuzyuQuiz本番環境でのE2Eテストを実施いたします。\n進捗・監視結果はこのスレッドで報告いたします。"
});

// messageId取得(スレッド投稿用)
const messageId = startMessage.ts;

// 2. qa-engineer起動
const session = exec({
  command: "cd /Users/satokeita/Dev/history-quiz-app && claude --agent qa-engineer --dangerously-skip-permissions",
  pty: true,
  yieldMs: 3000
});

// 3. 監視cron設定(スレッド投稿版)
cron({
  action: "add",
  job: {
    name: "qa-engineer-monitor",
    agentId: "stevens", 
    schedule: {kind: "cron", expr: "*/2 * * * *", tz: "Asia/Tokyo"},
    sessionTarget: "isolated",
    payload: {
      kind: "agentTurn",
      message: `qa-engineerセッション監視と自動対処を実行し、結果をスレッド(${messageId})に投稿`,
      deliver: true,
      channel: "slack",
      to: "channel:C0ACUDZCJJC",
      replyTo: messageId  // スレッド投稿
    }
  }
});

// 4. E2Eテスト指示
process("write", session.id, "ChuzyuQuiz E2Eテストを実行してください");
process("send-keys", session.id, ["Return"]);

// 5. 完了時の処理(cronで自動実行)
// テスト完了検知時に以下を自動実行:
// - エビデンスフォルダのレポートファイルを特定
// - レポート内容の読み取りと要約抽出  
// - スレッドに詳細レポート投稿(ファイルパス + 要約)
// - チャンネル本文に完了報告
// - 問題検出時の修正作業へのスムーズな移行
// - 監視cronの自動削除
```

## 応用と拡張

### 他のプロジェクトでの使用

```bash
# プロジェクトディレクトリを変更
cd /path/to/your/project && claude --agent qa-engineer --dangerously-skip-permissions
```

### 異なるテストタイプ

- **単体テスト**: `qa-engineerに単体テスト実行を指示`
- **統合テスト**: `qa-engineerに統合テスト実行を指示` 
- **パフォーマンステスト**: `qa-engineerにパフォーマンステスト実行を指示`

### 結果分析の自動化

```javascript
// テスト完了後の自動処理
const results = process("log", sessionId, {limit: 100});
if (results.includes("テスト完了")) {
  // レポート生成・Slack通知・課題抽出など
}
```

---

## まとめ

このスキルにより:

- **確実なE2E自動実行**: 権限・停止問題を事前回避
- **効率的な監視**: 人手介入なしで長時間実行
- **トラブル対応**: 典型的問題への自動対処
- **適切な進捗報告**: スレッド投稿でチャンネルを荒らさない
- **スムーズな後続作業**: レポートファイルパス+要約で修正作業に直結
- **自動完了処理**: テスト完了検知から結果投稿まで完全自動化
- **再現可能性**: 同じ手順で安定した結果

**完了後のワークフロー:**
1. テスト完了自動検知
2. エビデンスフォルダからレポートファイル特定
3. レポート要約の自動抽出
4. スレッドに詳細投稿(ファイルパス+要約+問題有無)
5. 問題発見時は即座に修正作業へ移行可能

**重要**: E2Eテストは複雑な処理のため、必ず監視体制とセットで実行すること。
---
name: claude-code-setup
description: Claude Code のサブエージェント(.claude/agents/)とスキル(.claude/skills/)をプロジェクト用にセットアップする。プロダクト開発・運用のための分業体制を設計・構築する。「サブエージェント設定」「agents設定」「skills設定」「Claude Code セットアップ」「分業体制の構築」などの作業に使う。
---

# Claude Code サブエージェント+スキル セットアップ

## 概要

プロジェクトのために Claude Code のサブエージェントとスキルを設計・構築するワークフロー。

## Skills と Subagents の関係

```
Skills = 「何を知っているか」(知識・手順の定義)
  → コンテキストに注入される。実行主体を持たない。
  → .claude/skills/<skill-name>/SKILL.md

Subagents = 「誰がどう実行するか」(独立した実行コンテキスト)
  → 独自のモデル・ツール・権限を持つ。
  → skills: フィールドで必要なスキルをプリロード。
  → .claude/agents/<name>.md
```

**重要な原則:**
- サブエージェントは親の会話からスキルを**継承しない** → 必要なスキルを `skills:` で明示的に指定
- スキルの SKILL.md body はスキル発火時にのみ読み込まれる → 軽量に保つ
- 詳細なリファレンスは別ファイル(reference.md 等)に分離

## セットアップ手順

### Step 1: プロジェクトの業務を分析

プロジェクトで必要な作業を洗い出す:
- どんな種類の作業があるか(リサーチ、実装、テスト、デプロイ等)
- どの作業が独立して実行できるか(→ サブエージェント候補)
- どの知識が複数の作業で共有されるか(→ スキル候補)

### Step 2: スキルを設計

**スキル = 再利用可能な知識・手順**

設計指針:
- 複数のサブエージェントが参照する知識 → スキルに切り出す
- プロジェクト固有の設定情報(API情報等)→ スキルに集約
- ブランドガイドライン、品質基準 → スキルとして定義
- 詳細は [references/skill-spec.md](references/skill-spec.md) を参照

スキルのディレクトリ構造:
```
.claude/skills/<skill-name>/
├── SKILL.md          ← 必須。フロントマター + 要約指示
├── reference.md      ← オプション。詳細なリファレンス(必要時のみ読み込み)
└── scripts/          ← オプション。実行スクリプト
```

### Step 3: サブエージェントを設計

**サブエージェント = 独立した実行者**

設計指針:
- 1エージェント = 1つの明確な責務
- モデルの選択: 定型作業 → haiku(安価・高速)、創造的作業 → sonnet
- ツールの制限: 必要最小限のツールのみ許可(読み取り専用なら Read, Grep, Glob のみ)
- 詳細は [references/subagent-spec.md](references/subagent-spec.md) を参照

サブエージェントファイルの構造:
```yaml
---
name: agent-name
description: いつこのエージェントに委譲するかの説明(重要!)
tools: Read, Bash, Grep, Glob      # 許可するツール
model: sonnet                       # sonnet / haiku / opus / inherit
skills:                             # プリロードするスキル
  - skill-name-1
  - skill-name-2
---

エージェントのシステムプロンプト(Markdown)
```

### Step 4: スキル→サブエージェントの紐付け

各サブエージェントに必要なスキルを `skills:` で指定:
- 設定情報系スキル → そのAPIを使うすべてのエージェントに
- ブランド/品質系スキル → コンテンツを作成・チェックするエージェントに
- ドメイン知識系スキル → その知識を必要とするエージェントに

### Step 5: ワークフロースキルの作成

サブエージェント間の連携方法をスキルとして定義:
- どの順番でサブエージェントを呼ぶか
- 並列実行可能なタスクはどれか
- メインエージェントの役割は何か

### Step 6: ディレクトリ作成と配置

```bash
mkdir -p .claude/agents .claude/skills
# スキルとサブエージェントのファイルを配置
```

## コスト最適化ガイド

| 作業の性質 | 推奨モデル | 例 |
|-----------|----------|-----|
| 定型チェック | haiku | 品質チェック、投稿、データ集計 |
| 情報統合・判断 | sonnet | リサーチ、記事作成、設計 |
| 高度な推論 | opus / inherit | 戦略立案、複雑な分析 |
| 読み取り専用調査 | haiku + 制限ツール | コードベース探索 |

## 実例

Essential Navigator での構成例は [references/example-essential-navigator.md](references/example-essential-navigator.md) を参照。
---
name: claude-usage-report
description: Claude利用量の実績・見通しを分析してレポートを生成するスキル。朝のDaily Reviewに組み込み、利用量監視と制限前の状況確認を行う。「利用量確認」「使用量分析」「API制限確認」「コスト分析」などの作業に使う。
---

# claude-usage-report

Claude利用量の実績・見通しを分析してレポートを生成するスキル。

## 使用タイミング
- 朝のDaily Review(cronジョブ)に組み込み
- 利用量が気になる時の随時チェック
- 週末の制限リセット前の状況確認

## 実行手順

### 1. 現在の使用状況取得
```javascript
// session_status で基本情報を取得
const status = await session_status();
```

### 2. 使用量分析
以下の情報を分析:
- **週間制限**: X% used / Y% left
- **5時間制限**: X% used / Y% left  
- **使用ペース**: 週のX日目でY%消費
- **予測**: 現在ペースだと週末時点でZ%使用予測

### 3. 主要消費要因の分析
- **cronジョブ**: `cron list`で確認
- **AI Solo Builder**: 1日6記事生成(朝刊・昼・夕刊・夜間開発2本・事例分析)
- **対話セッション**: 長時間のやり取り

### 4. アクション提案
使用率に応じた提案:
- **80%未満**: 現状維持
- **80-90%**: 記事生成頻度の調整検討
- **90%以上**: 緊急対策(記事生成一時停止等)

## 出力形式

Daily Review用の簡潔なサマリー:
```
📊 Claude利用量: 週X% (Y%残り) | 5h制限: Z%残り
📈 ペース: [順調/やや多め/要注意]
🎯 週末予測: W%使用見込み
💡 提案: [現状維持/調整検討/対策必要]
```

## 注意事項
- 数値は session_status から取得
- cronジョブ一覧は `cron list` で確認
- 予測計算は現在の曜日と使用率から算出
- 緊急時はSlack #claude連携に詳細レポート投稿を検討

## 使用例
```bash
# 朝のDaily Reviewで実行
node ~/.openclaw/skills/claude-usage-report/report.js
```

---
2026-02-04 作成: Daily Review cronへの組み込み用
---
name: claude-usage-reporter
description: Claude Code・Clawdbot利用状況の統合レポートを生成・分析するスキル。「claude の利用状況教えて」の問い合わせに対して、包括的な使用量分析とコスト最適化提案を自動生成する。「利用状況分析」「統合レポート」「コスト最適化」「使用量統計」などの作業に使う。
---

# claude-usage-reporter

Claude Code・Clawdbot利用状況の統合レポートを生成・分析するスキル。「claude の利用状況教えて」の問い合わせに対して、包括的な使用量分析とコスト最適化提案を自動生成する。

## 対象フレーズ
- 「claude の利用状況」
- 「claude利用状況」
- 「claude usage」
- 「トークン使用量」
- 「API使用量」
- 「クレジット残高」

## 実行内容

### 1. Clawdbot使用状況取得
- `session_status` でClawdbot現在状況
- `sessions_list` で各エージェントセッション確認
- OAuth認証ベースの制限状況把握

### 2. Claude Code使用状況推定
- Clawdbot使用量から同一OAuth認証の推定
- プロジェクトディレクトリでの `/usage` 確認(可能な場合)
- 週間・日間制限の残量計算

### 3. 使用量分析
- **コスト分析**: モデル別・エージェント別コスト
- **傾向分析**: Rate limit発生パターン、高使用セッション特定
- **効率性分析**: Token/Output比率、Cache活用率

### 4. 最適化提案
- **緊急提案**: Rate limit対策、高コストセッションクリーンアップ
- **中期提案**: モデル選択最適化、Cronスケジュール調整
- **長期提案**: ワークフロー見直し、コスト予算設定

## 出力フォーマット

```markdown
# 🔍 Claude利用状況レポート

## 📊 現在の使用状況
- **今日**: XX% 使用 (残りXX時間XX分)
- **今週**: XX% 使用 (残りXX日XX時間)
- **制限**: OAuth認証 (Max Plan)

## 💰 コスト分析
- **高コストセッション**: Top 3
- **モデル別使用量**: Opus vs Sonnet
- **エージェント別消費**: main/stevens/nemo/torishima

## ⚠️ 注意点・課題
- Rate limit履歴
- 長時間セッション
- 非効率なToken使用

## 🎯 最適化提案
1. **緊急**: 〜
2. **中期**: 〜  
3. **長期**: 〜
```

## スクリプト・ツール

`claude-usage-report.sh`: 利用状況データ収集スクリプト
`usage-analysis.js`: 使用データ分析・可視化

## セットアップ

初回実行時にスクリプト作成、以降は定期実行で履歴蓄積。

## 更新履歴
- 2026-02-04: 初期作成(けいた要望対応)
---
name: clawdbot-launcher
description: "Clawdbot (Slack連携AIボット) の起動・停止・ステータス確認を行う。「clawdbotを起動して」「ボットを起動」「clawdbot start」「clawdbot状態確認」「ボット止めて」など、clawdbotの操作を依頼された場合に使用する。"
---

# Clawdbot Launcher

Clawdbot(Slack連携AIボット)のデーモン管理スキル。

## Commands

### Start

```bash
clawdbot daemon start
```

Start after confirming status with `clawdbot status`. Report Gateway state, Slack channel status, and active session count from the status output.

### Stop

```bash
clawdbot daemon stop
```

### Status Check

```bash
clawdbot status
```

Key fields to report: Gateway (running/stopped), Slack channel (ON/OFF), Sessions count, Model.

### Troubleshooting

If start fails:

1. `source ~/.zshrc && echo $ANTHROPIC_API_KEY` - verify env var
2. `clawdbot doctor` - run diagnostics
3. `clawdbot logs --follow` - check logs

## Configuration

- Config: `~/.clawdbot/clawdbot.json`
- Model: `claude-opus-4-5` (200k ctx)
- Slack channel: `C08KHA4BQHW`
- Dashboard: http://127.0.0.1:18789/
# Codex Orchestrator Skill

Codex CLIをバックグラウンドで実行し、確実に完了まで待機するスキル。

## 概要

- **目的:** codexの長時間タスクを確実に監視・完了待機
- **セッション永続化:** セッション情報をファイルに記録し、エージェント再起動後も継続可能
- **待機ループ:** sleep + poll で完了まで待ち続ける

## セッション情報の保存先

```
~/.openclaw/codex-sessions.json
```

構造:
```json
{
  "sessions": [
    {
      "sessionId": "rapid-daisy",
      "workdir": "/Users/satokeita/Dev/ai-navigator",
      "task": "Build feature X",
      "startedAt": "2026-02-12T05:30:00Z",
      "status": "running",
      "pid": 12345
    }
  ]
}
```

## ワークフロー

### 1. 起動(Start)

```bash
# 1. codexをbackground + pty で起動
exec pty:true background:true workdir:<PROJECT_DIR> command:"codex exec '<TASK>'"

# 2. セッション情報を記録
# sessionIdを codex-sessions.json に追加
```

### 2. 待機ループ(Wait Loop)

```bash
# 基本パターン: 30秒間隔でpoll
while true:
  1. exec command:"sleep 30"
  2. process action:poll sessionId:<ID>
  3. "Process exited" を検出したら break
  4. まだ running なら continue
```

**重要:** 
- 待機中に返事を急がない
- pollの結果が "Process still running" なら必ず次のsleepへ
- "Process exited" が出るまで絶対に止めない

### 3. 完了確認(Complete)

```bash
# 最終ログ取得
process action:log sessionId:<ID>

# セッション情報を更新(status: completed)
# 結果をまとめてSlack報告
```

### 4. セッション管理

**起動時チェック(before_agent_start相当):**
```bash
# 既存セッションがあるか確認
cat ~/.openclaw/codex-sessions.json

# runningのセッションがあれば状態確認
process action:poll sessionId:<ID>
```

**明示的な終了:**
```bash
# ユーザーが終了を指示した場合のみkill
process action:kill sessionId:<ID>

# セッション情報からも削除
```

## 待機間隔の目安

| タスク種類 | 待機間隔 |
|-----------|---------|
| 簡単な確認(ファイル一覧等) | 5秒 |
| 中程度(コード生成、修正) | 15秒 |
| 重い処理(ビルド、テスト) | 30秒 |
| 長時間(大規模リファクタ) | 60秒 |

## Hook連携

### before_agent_start

エージェント起動時に既存codexセッションを確認:

```javascript
// hooks/before_agent_start.js
module.exports = async (event, ctx) => {
  const sessionsFile = `${process.env.HOME}/.openclaw/codex-sessions.json`;
  let prependContext = '';
  
  try {
    const data = require(sessionsFile);
    const running = data.sessions.filter(s => s.status === 'running');
    if (running.length > 0) {
      prependContext = `\n[Codex Sessions]\n実行中のcodexセッションがあります:\n`;
      running.forEach(s => {
        prependContext += `- ${s.sessionId}: ${s.task} (${s.workdir})\n`;
      });
      prependContext += `process action:poll で状態確認してください。\n`;
    }
  } catch (e) {
    // ファイルなし or パースエラーは無視
  }
  
  return { prependContext };
};
```

## エラーハンドリング

| 状況 | 対応 |
|------|------|
| codex起動失敗 | エラー内容を確認、workdirのgit状態チェック |
| poll timeout | セッションが存在するか確認、必要ならkill |
| 異常終了(exit code != 0) | ログを確認、エラー内容をSlack報告 |

## 使用例

### 例1: 記事作成タスク

```
1. exec pty:true background:true workdir:/Users/satokeita/Dev/ai-navigator \
   command:"codex exec 'content/news/に新しいニュース記事を作成して'"

2. sessionId記録 → codex-sessions.json

3. 待機ループ(30秒間隔)

4. 完了後:
   - git status で変更確認
   - 記事内容レビュー
   - publish:gate 実行
```

### 例2: バッチ処理

```
1. codex起動: frontmatter一括変換

2. 待機ループ(60秒間隔 - 重い処理)

3. 完了後:
   - 変更ファイル一覧確認
   - npm run validate:content
   - 問題なければコミット
```

## 禁止事項

- ❌ pollが "still running" なのに待機を中断
- ❌ セッション情報を記録せずに起動
- ❌ ユーザー確認なしでセッションをkill
- ❌ 完了報告をせずにタスク終了

## チェックリスト

起動時:
- [ ] workdirがgitリポジトリか確認
- [ ] セッション情報をJSONに記録
- [ ] 開始をSlack報告

待機中:
- [ ] 定期的にpollを実行
- [ ] "Process exited" まで待ち続ける
- [ ] 途中経過は必要に応じて報告

完了時:
- [ ] 最終ログを取得
- [ ] 結果をまとめてSlack報告
- [ ] セッション情報のstatusを更新

---

*作成: 2026-02-12*
---
name: content-generator
description: "分析結果からツイート候補・記事ネタを自動生成する。「ツイート生成」「コンテンツ作成」「投稿候補」などの作業に使う。"
metadata: {"clawdbot":{"requires":{"bins":["node"]}}}
---

# Content Generator

LifeLog Analyzerの分析結果を元に、ツイート候補や記事ネタを自動生成するスキル。

## 概要

分析結果(JSON)を読み込み、以下を生成:
1. **ツイート候補** - 280文字以内の短文(3-5件/日)
2. **記事ネタ** - タイトル+概要(週1-2件)

## 使い方

```bash
# 特定日の分析結果からコンテンツ生成
node ~/.openclaw/skills/content-generator/generate.js 2026-02-07

# デフォルト(昨日)
node ~/.openclaw/skills/content-generator/generate.js
```

## 出力

生成されたコンテンツは以下に保存:
- ツイート: `~/dev/life-project-management/08_Content_Queue/tweets/YYYY-MM-DD.md`
- 記事ネタ: `~/dev/life-project-management/08_Content_Queue/articles/YYYY-MM-DD.md`

## ツイートテンプレート

### 開発Tips
```
💡 今日の学び

[具体的な内容]

#AI開発 #Flutter #育休パパエンジニア
```

### ツール発見
```
🔧 発見したツール: [ツール名]

[使い方・感想]

#AIツール #開発効率化
```

### 育休パパの気づき
```
👶 育休パパの気づき

[エピソード・学び]

#育休 #4児パパ #ワークライフバランス
```

## 品質基準

- ツイートは140-280文字
- 具体的なエピソードを含む
- ハッシュタグは2-3個
- 自慢っぽくならない、学びを共有するトーン
---
name: content-optimizer
description: 既存記事の見せ方を最適化するスキル。表形式への変換、構造の改善、視覚的リズムの調整を行う。「記事の見せ方改善」「テーブル化」「記事リライト」「フォーマット最適化」「既存記事の改善」などの作業に使う。
---

# Content Optimizer

既存記事のUIレベルでの読みやすさを向上させる専門スキルです。特に長文記事において、視覚的なメリハリ、情報の階層化、スキャンしやすさを改善します。

## 🎯 適用場面

- 長文記事(5,000字以上)の読みやすさ改善
- 表組みや箇条書きの視覚的最適化
- 既存記事のリファクタリング
- 情報設計の改善

## 📝 5つの最適化手法

### 1. ビジュアル・ブロッキング(Visual Blocking)

**問題:** 長文が続き、読み手の視線が疲れる
**解決法:** 適切な間隔で視覚的な区切りを作る

#### Before:
```markdown
プロンプトエンジニアリングの情報は大量にある。問題は「どれが信頼でき、どれが時間の無駄か」がわかりにくいこと。以下、主要リソースを5段階で評価した。
```

#### After:
```markdown
プロンプトエンジニアリングの情報は**大量**にある。

問題は「**どれが信頼でき、どれが時間の無駄か**」がわかりにくいこと。

---

以下、主要リソースを5段階で評価した。
```

**ポイント:**
- 重要語句を**太字**で強調
- 段落間に適切な空行
- セクション区切りに `---` を使用

### 2. スキャン最適化(Scannable Structure)

**問題:** 流し読みでポイントが掴めない
**解決法:** 視線の動線に沿って情報を配置

#### 情報の3層構造:
1. **ヘッドライン**(2秒で理解できる見出し)
2. **サマリー**(要点の箇条書き)
3. **詳細**(説明・根拠)

#### 実装例:
```markdown
### 🥇 Tier 1: 公式ドキュメント(必読)

**このセクションで得られること:**
- Claude/OpenAIの公式ベストプラクティス
- 実践的なテンプレート集
- 英語リソースの活用法

| リソース | 信頼度 | 実用性 | 推奨度 |
|---------|-------|-------|--------|
| Anthropic Claude Docs | ★★★ | ★★★ | 必読 |
| OpenAI Guide | ★★★ | ★★☆ | 推奨 |

**評価詳細は[references/resource-evaluation.md](references/resource-evaluation.md)を参照**
```

### 3. テーブル・レイアウト最適化(Table Enhancement)

**問題:** 表組みが見づらい、情報密度が高すぎる
**解決法:** 視覚的ヒエラルキーと余白を活用

#### 📱 レスポンシブテーブル(2026-02-15 CSS実装済み)

AI Solo Builderでは、640px以下の画面で**テーブルが自動的にカード形式**に変換される。

**モバイル表示の仕組み:**
- ヘッダー行 → 非表示
- 各行 → 角丸カード(シャドウ付き)
- 先頭セル → カードタイトル(太字強調)
- その他セル → カード内に縦積み

**→ 記事最適化時にモバイル専用の調整は不要。3列以下を守ればOK。**

#### 改善前の表(問題あり):
```markdown
リソース | URL | 信頼度 | 実用性 | 日本語 | 推奨度
--- | --- | --- | --- | --- | ---
Anthropic Claude Docs | platform.claude.com/docs | ★★★ | ★★★ | ❌ | 必読
Interactive Tutorial | GitHub | ★★★ | ★★★ | ❌ | 必読
OpenAI Guide | platform.openai.com | ★★★ | ★★☆ | ❌ | 推奨
```

#### 改善後の表(最適化済み):
```markdown
### 📚 リソース評価表

| リソース | 評価 | ステータス |
|---------|------|-----------|
| **Anthropic Claude Docs** | 信頼度★★★ / 実用性★★★ | 🔥 **必読** |
| **Interactive Tutorial** | 信頼度★★★ / 実用性★★★ | 🔥 **必読** |
| **OpenAI Guide** | 信頼度★★★ / 実用性★★☆ | ✅ 推奨 |

**詳細比較は[こちら](#detailed-comparison)**
```

**改善ポイント:**
- 列数を3つに削減(認知負荷軽減 + モバイルカード最適化)
- 絵文字でステータス視覚化
- 重要度に応じた太字使用
- **先頭列は識別子**(モバイルでカードタイトルになる)

### 4. 情報階層の明確化(Information Hierarchy)

**問題:** 全て同じ重要度に見える
**解決法:** 重要度に応じた視覚的重み付け

#### 重要度の5段階表現:
1. **🔥 超重要** - 太字 + 絵文字 + ボックス
2. **✨ 重要** - 太字 + 絵文字
3. **📝 通常** - 通常テキスト + 適切な見出し
4. **💭 補足** - 引用ブロック `>`
5. **🔗 参照** - リンクまたは脚注

#### 実装例:
```markdown
## 🔥 最重要: 80/20ルール

> **この3つだけ覚えれば、成果の8割が出る**

1. **ゴール設定** - 何ができたら完了か
2. **具体例提示** - 期待する出力フォーマット  
3. **制約明示** - やってはいけないこと

詳細手順は[references/8020-rule.md](references/8020-rule.md)を参照。
```

### 5. 認知負荷軽減(Cognitive Load Reduction)

**問題:** 一度に処理する情報が多すぎる
**解決法:** プログレッシブ・ディスクロージャー

#### 基本パターン:
```markdown
### Step 1: 基本構造を理解する(1〜2時間)

**目標:** プロンプトの基本形を書けるようになる

**やること:**
- [ ] Anthropic Tutorial Chapter 1〜3を読む
- [ ] 基本テンプレートを1つ作る
- [ ] Claude Codeで実際に試す

**チェックポイント:**
- 「役割 + 指示 + 出力形式」が書けるか?
- 1回の出力で使える確率が30%以上か?

<details>
<summary>📖 詳細な学習リソース(クリックで展開)</summary>

- [Chapter 1: Basic Prompt Structure](URL)
- [Chapter 2: Being Clear and Direct](URL)  
- [Chapter 3: Assigning Roles](URL)

各章の要点と実践課題は[references/tutorial-guide.md](references/tutorial-guide.md)にまとめています。

</details>
```

## 🔧 ワークフロー実行手順

### Phase 1: 現状分析(5分)

1. **記事の構造確認**
   - 見出し階層は適切か?
   - セクション長は適度か?(300-500語)
   - 表や箇条書きの使用状況

2. **読み手視点チェック**
   - 5秒でざっと見て、何の記事かわかるか?
   - 重要ポイントが視覚的に強調されているか?
   - 途中で読むのを止めそうな箇所はないか?

### Phase 2: 構造最適化(10分)

1. **ビジュアル・ブロッキング適用**
   - 長文段落(150語超)を分割
   - 重要語句に太字適用
   - セクション間に適切な余白

2. **スキャン最適化**
   - 各セクションに「得られること」を追加
   - 表組みの列数を3つ以下に削減
   - 箇条書きに絵文字や記号を追加

### Phase 3: 階層化・軽量化(10分)

1. **情報階層の明確化**
   - 重要度に応じた視覚的重み付け
   - 補足情報の引用ブロック化
   - 参照リンクの整理

2. **認知負荷軽減**
   - 詳細情報のプログレッシブ・ディスクロージャー
   - チェックリストの追加
   - 段階的な学習パスの明示

### Phase 4: 品質確認(5分)

1. **視覚的バランス確認**
   - 空白と文字のバランス
   - 強調要素の適度な使用
   - 色々な文字装飾の使い分け

2. **実用性確認**
   - 行動に移しやすい構造か?
   - 必要な情報にすぐアクセスできるか?
   - 読了後の次のアクションが明確か?

## 📋 品質チェックリスト

### ✅ ビジュアル・チェック
- [ ] 見出しから内容が推測できる
- [ ] 重要箇所が視覚的に強調されている
- [ ] 表組みが3列以下で見やすい
- [ ] 段落間に適切な余白がある
- [ ] 絵文字・記号が効果的に使われている

### ✅ 構造チェック
- [ ] 各セクションが300-500語以内
- [ ] 情報の重要度が視覚的に表現されている
- [ ] 補足情報が適切に分離されている
- [ ] 参照リンクが整理されている

### ✅ ユーザビリティチェック
- [ ] 5秒でざっと見て要点がわかる
- [ ] 途中で読むのを止めたくならない
- [ ] 行動に移しやすい構造になっている
- [ ] 次のステップが明確に示されている

## 🔗 参考リソース

- **UI設計パターン:** [references/ui-patterns.md](references/ui-patterns.md)
- **認知科学の知見:** [references/cognitive-science.md](references/cognitive-science.md)
- **成功事例集:** [references/case-studies.md](references/case-studies.md)

---

**使用時の注意:**
- 最適化はコンテンツの価値を損なわない範囲で実施
- 読み手のリテラシーレベルに応じて調整
- 改善前後の比較を記録し、効果測定を行う
---
name: content-publisher
description: "承認されたコンテンツを自動投稿する。X(Twitter)投稿、記事公開の実行。「投稿実行」「ツイート投稿」「公開処理」などの作業に使う。"
metadata: {"clawdbot":{"requires":{"skills":["x-strategy-implementation"]}}}
---

# Content Publisher

承認されたコンテンツを自動投稿するスキル。

## 概要

Daily Review時に提示されたコンテンツ候補のうち、けいたが承認したものを投稿する。

## 投稿先

### 1. X (Twitter)
- **方法**: Browser Relay経由(x-strategy-implementationスキル)
- **プロファイル**: chrome(既存のログイン済みブラウザ)

### 2. AI Solo Builder
- **方法**: nemoエージェント経由
- **セッションキー**: `agent:nemo:slack:channel:c0abplbl04x`

### 3. Essential Navigator
- **方法**: torishimaエージェント経由
- **セッションキー**: `agent:torishima:...`(設定後追記)

## ワークフロー

### X投稿フロー

1. ツイート候補を提示
2. けいたが承認(「投稿して」「OK」等)
3. Browser Relay でX.comを開く
4. ツイートを投稿
5. 結果を報告
6. `published/`に移動

### 使い方(Clawdbot経由)

```
@misato 今日のツイート候補1を投稿して
```

または Daily Review 内で承認:

```
@misato 候補1と3を投稿
```

## 投稿後処理

投稿完了後:
1. 投稿内容を `08_Content_Queue/published/YYYY-MM-DD-tweet-N.md` に保存
2. 投稿結果(成功/失敗、URL等)を記録
3. MEMORY.md に投稿実績を追記

## 安全策

- **確認必須**: 自動投稿前に必ずけいたの承認が必要
- **プレビュー**: 投稿前に内容を再表示
- **取り消し不可通知**: X投稿は取り消しが面倒なことを事前通知
# copyright-check スキル

記事公開前の著作権・引用適正チェック。翻訳記事・事例記事の著作権侵害リスクを検出し、適切な対応を提案する。

## トリガー

- 「著作権チェック」「引用チェック」「翻訳比率確認」
- 事例記事(case-study)の作成・更新時
- 海外ソースを参照した記事の公開前

## チェック項目

### 1. 翻訳比率チェック

| 比率 | 判定 | 対応 |
|------|------|------|
| 30%未満 | ✅ OK | そのまま公開可 |
| 30-50% | ⚠️ 注意 | 独自分析を追加 |
| 50%超 | 🔴 NG | 書き換え必須 |

### 2. 引用の適正性(日本著作権法32条)

| 要件 | チェック内容 |
|------|-------------|
| 主従関係 | 自分の文章が「主」、引用が「従」か |
| 必然性 | その引用がなければ論旨が成立しないか |
| 出典明記 | ソースURL・著者名を明記しているか |
| 改変禁止 | 原文の意図を歪めていないか |

### 3. 構成の独自性

- 元記事と同じ構成・順序 → 🔴 NG
- 独自の切り口で再構成 → ✅ OK

## 合格基準

```
□ 独自分析・考察が50%以上
□ 引用は3箇所以内(各100字以内推奨)
□ 構成が元記事と異なる
□ 出典URLを明記
□ 複数ソースを横断している(事例記事の場合)
```

## 事例記事(case-study)の必須ルール

### ✅ 許可されるアプローチ

1. **一次ソース起点**
   - 本人のX/Twitter、ブログ、YouTube発言を直接引用
   - Indie Hackers等の二次記事ではなく、本人発信を参照

2. **横断分析形式**
   - 複数事例(3件以上)からパターン抽出
   - 各事例は2-3行の紹介 + 出典リンクのみ
   - 分析・考察が本文の主体(50%以上)

3. **国内事例**
   - note/Zenn/Xでの日本語発信を参照
   - 許可取得のハードルが低い

### 🔴 禁止されるアプローチ

- 海外記事の翻訳・要約が主体
- 単一ソースからの構成踏襲
- 「参考にした」が実質翻訳

## ワークフロー統合

`article-writer` スキルの公開前チェックに組み込み:

```
記事作成完了
    ↓
copyright-check 実行
    ↓
  NG → 書き換え or 削除
  OK → publish:gate へ
```

## チェック実行手順

1. 記事ファイルを読み込む
2. 参照ソース(frontmatter の source)を特定
3. 元ソースを web_fetch で取得(可能なら)
4. 翻訳比率・構成類似度を評価
5. 判定結果をレポート

## 判定テンプレート

```markdown
## 著作権チェック結果

**記事:** [slug]
**参照ソース:** [URL]

| 項目 | 判定 |
|------|------|
| 翻訳比率 | X% (OK/NG) |
| 主従関係 | ✅/❌ |
| 引用箇所数 | N箇所 |
| 構成独自性 | ✅/❌ |
| 複数ソース | ✅/❌ |

**総合判定:** ✅ 公開可 / ⚠️ 要修正 / 🔴 公開不可

**対応:** [具体的な修正指示]
```

---

*更新: 2026-02-15(初版作成)*
---
name: cron-management
description: Clawdbotのcronジョブを安全に作成・更新・管理するスキル。JSONパースエラーを防ぐためのテンプレートとバリデーション手順を含む。「cron追加」「cronジョブ設定」「定期実行」「スケジュール設定」「タスク監視cron」「リマインダー設定」などの作業に使う。
---

# Cron Management スキル

## 重要: JSON構文エラー防止

cronジョブのpayloadはJSON形式。構文エラーで行動不能になるリスクがある。
**必ずこのスキルのテンプレートに従うこと。**

## cron tool のパラメータ一覧

### action: "add"
```json
{
  "action": "add",
  "job": {
    "name": "ジョブ名(必須・短く明確に)",
    "agentId": "main|stevens|nemo|torishima",
    "schedule": {
      "kind": "cron",
      "expr": "0 9 * * *",
      "tz": "Asia/Tokyo"
    },
    "sessionTarget": "isolated",
    "wakeMode": "next-heartbeat",
    "payload": {
      "kind": "agentTurn",
      "message": "実行指示テキスト",
      "deliver": true,
      "channel": "slack",
      "to": "channel:CHANNEL_ID"
    }
  }
}
```

### action: "update"
```json
{
  "action": "update",
  "jobId": "既存ジョブのID",
  "patch": {
    "name": "新しい名前",
    "schedule": { "kind": "cron", "expr": "30 8 * * *", "tz": "Asia/Tokyo" },
    "payload": { "kind": "agentTurn", "message": "更新された指示" }
  }
}
```

### action: "remove"
```json
{
  "action": "remove",
  "jobId": "削除するジョブのID"
}
```

## スケジュール種類

### 1. cron式(定期実行)
```json
{ "kind": "cron", "expr": "0 9 * * *", "tz": "Asia/Tokyo" }
```
- 5フィールド: 分 時 日 月 曜日
- tzを省略するとホストのローカルTZ

### 2. at(一回限り)
```json
{ "kind": "at", "at": 1770213600000 }
```
- ミリ秒エポックタイム
- `deleteAfterRun: true` と併用推奨

### 3. every(固定間隔)
```json
{ "kind": "every", "ms": 300000 }
```

## セッション種類

| sessionTarget | payload.kind | 用途 |
|---|---|---|
| `"isolated"` | `"agentTurn"` | 独立セッションで実行(推奨) |
| `"main"` | `"systemEvent"` | メインセッション内で実行 |

## 配信先テンプレート

### Slack チャンネルに配信
```json
{
  "deliver": true,
  "channel": "slack",
  "to": "channel:C08KHA4BQHW"
}
```

### 配信なし(内部処理のみ)
```json
{
  "deliver": false
}
```

## よくあるチャンネルID

- `C08KHA4BQHW` → #claude連携
- `C0ACUDZCJJC` → #stevens
- `C0ABPLBL04X` → #nemo
- `C0ACAU1AMFU` → #torishima

## ⚠️ 必ず守るルール

1. **messageフィールドは短く保つ** — 長文の指示はスキルやファイルに外出しし、messageでは「〜スキルを読んで実行して」と書く
2. **messageに改行を含める場合は `\n` を使う** — 生の改行もJSON的には許容されるが、ツールパラメータでは `\n` エスケープが安全
3. **JSONの末尾カンマを入れない** — `{ "a": 1, }` はエラー
4. **文字列内のダブルクォートは `\"` でエスケープ** — `"message": "He said \"hello\""` 
5. **数値・真偽値にクォートをつけない** — `"deliver": true`(○)、`"deliver": "true"`(×)
6. **cronジョブ追加前に `cron list` で既存ジョブを確認** — 重複防止

## 監視cronのパターン

バックグラウンドタスクを監視する一時cronの定型パターン:

```json
{
  "action": "add",
  "job": {
    "name": "monitor-TASK_NAME",
    "schedule": { "kind": "every", "ms": 300000 },
    "sessionTarget": "isolated",
    "wakeMode": "next-heartbeat",
    "payload": {
      "kind": "agentTurn",
      "message": "タスクXXXの進捗を確認。完了/エラーならSlackに報告してこの監視cronを削除。実行中なら何もしない。",
      "deliver": false
    }
  }
}
```

完了検知後は必ず `cron remove` で監視ジョブを削除すること。
---
name: daily-digest
description: Obsidianのデイリーノートを分析・整理するスキル。Memoセクションから教訓・アイデア・タスクを抽出し、適切なフォルダに整理、タグ・リンクを追加する。「デイリー整理」「日記の整理」「メモの整理」「デイリーノート分析」などの作業に使う。朝のDaily Reviewで前日分を処理する際にも使用。
---

# Daily Digest

Obsidianのデイリーノート、Inbox、ルート直下のファイルを分析し、書きっぱなしのメモを整理・活用するスキル。
**フィードバック機能付き** — 単なる整理だけでなく、けいたの思考を深めるための視点や知識を提供する。

## 対象ファイル

1. **デイリーノート** (`01_Daily/YYYY-MM-DD.md`) — Memoセクションを分析
2. **Inbox** (`00_Inbox/`) — 未整理ファイルの内容も分析
3. **ルート直下** — 散らかっているファイルの内容も分析

---

## 共通: 内容分析フロー

**すべてのファイル**に対して以下を実行:

### 1. ファイルを読んで内容を把握

### 2. 教訓・アイデア・タスクを抽出

| 種類 | 識別キーワード | 処理 |
|------|---------------|------|
| **教訓・学び** | 「〜がわかった」「〜と感じる」「教訓」「学び」 | `40_Evergreen/` に永続化 |
| **アイデア** | 「アイディア」「〜したい」「〜できそう」 | 整理して残すか、発展させる |
| **タスク・TODO** | 「〜する」「〜やる」「TODO」「あとで」 | 抽出してリスト化 |
| **プロジェクト関連** | プロジェクト名への言及 | 該当プロジェクトにリンク |

### 3. 🎯 フィードバックを提供(重要!)

各ファイルの内容に対して、以下の観点でフィードバック:

#### 別の視点・知識の提供
- 「この考えには〇〇という理論/フレームワークが関連する」
- 「〇〇業界では△△というアプローチが一般的」
- 「反対の視点として、〇〇という考え方もある」

#### 深掘りの提案
- 「〇〇について、もう少し具体化すると?」
- 「なぜそう感じた?根本の理由は?」
- 「これを実現するための最初の一歩は?」

#### 繋がりの発見
- 「以前の〇〇というメモと関連がありそう」
- 「〇〇プロジェクトに活かせそう」
- 「これは〇〇の習慣化に繋がる」

#### 実行への後押し
- 「まずは小さく試してみては?」
- 「期限を決めると動きやすい」
- 「誰かに話してみると整理される」

---

## Part A: Inbox・ルート直下の整理

### 1. 対象ファイルを確認・読み込み

```bash
# Inboxのファイル一覧
ls "/Users/satokeita/dev/life-project-management/00_Inbox/"

# 各ファイルの内容を読む
cat "/Users/satokeita/dev/life-project-management/00_Inbox/ファイル名.md"
```

### 2. 各ファイルに対して

1. **内容を分析** — 教訓・アイデア・タスクを抽出
2. **フィードバック提供** — 視点・深掘り・繋がり
3. **振り分け先を決定** — 下記テーブル参照
4. **移動実行** — けいたの確認後

| 内容の特徴 | 振り分け先 |
|-----------|-----------|
| プロジェクト関連 | `10_Projects/該当プロジェクト/` |
| 継続的な責任領域 | `20_Areas/` |
| 教訓・永続的な知見 | `40_Evergreen/` |
| 完了・不要 | `99_Archives/` |
| 判断できない | そのまま残す |

---

## Part B: デイリーノートの整理

### 1. デイリーノートを読む

```bash
cat "/Users/satokeita/dev/life-project-management/01_Daily/YYYY-MM-DD.md"
```

### 2. Memoセクションを分析

`## Memo` から `----` までの内容に対して:

1. **内容を分析** — 教訓・アイデア・タスクを抽出
2. **フィードバック提供** — 視点・深掘り・繋がり
3. **整理アクション** — 教訓の永続化、タスク抽出等

### 3. 整理アクション

#### 教訓を永続化

```markdown
# 40_Evergreen/YYYY-MM-DD_タイトル.md

#lesson #evergreen

## 教訓
(内容)

## 背景・経緯
(元の記録からの引用)

## 💡 フィードバック
(ボットさんからの視点・深掘り)

## 関連リンク
- [[01_Daily/YYYY-MM-DD|元の記録]]
```

---

## 結果報告フォーマット

```
📋 Daily Digest - YYYY-MM-DD

✅ 整理:
• 教訓1件 → 40_Evergreen/
• Inboxから3件を振り分け

📝 抽出したタスク:
• タスク1
• タスク2

💭 フィードバック:

**〇〇について**
別の視点: ...
深掘り: ...

**△△について**
繋がり: ...
次の一歩: ...
```

---

## Vault構造

詳細は [references/vault-structure.md](references/vault-structure.md) を参照。

## 注意点

- 機密情報(APIキー等)は整理対象外
- 大きな変更は確認を取る
- フィードバックは押し付けず、選択肢を示す形で
---
name: daily-report
description: "日報を自動生成する。スクリーンキャプチャOCRログとClawdbotセッションログを統合してHTML形式の日報を作成。「日報生成」「日報作成」「レポート生成」などの作業に使う。"
metadata: {"clawdbot":{"requires":{"bins":["node"]}}}
---

# Daily Report Generator

日報自動生成スキル。スクリーンキャプチャOCRログとClawdbotセッションログを統合して、HTML形式の日報を生成する。

## 使い方

```bash
# 特定の日付を指定
node ~/.openclaw/skills/daily-report/generate.js 2026-01-29

# デフォルト(昨日)
node ~/.openclaw/skills/daily-report/generate.js
```

## 出力先

- HTML: `/Users/satokeita/dev/life-project-management/07_AI日報記録/YYYY-MM-DD.html`
- Markdown: `/Users/satokeita/dev/life-project-management/07_AI日報記録/YYYY-MM-DD-summary.md`

## データソース

1. **OCRログ**: `/Users/satokeita/dev/auto-screen-capture/logs/YYYY-MM-DD.jsonl`
   - 毎分のスクリーンキャプチャ+OCR結果
   - アプリ使用状況の推定に使用

2. **セッションログ**: `~/.openclaw/agents/main/sessions/*.jsonl`
   - Clawdbot会話ログ
   - Slackメッセージの抽出に使用

## 依存

- Node.js標準モジュールのみ(外部パッケージ不要)
- Node.js v25.5.0 対応
---
name: detail-design
description: detail.design のUIディテール集を活用して、プロダクトの品質を上げる。実装前のチェックリスト、UI改善アイデア出し、記事ネタ探しに使う。「UI改善」「ディテール確認」「detail.design」「プロダクト磨き」などの作業に使う。
---

# Detail Design — UIディテールリファレンス

**サイト:** https://detail.design/
**キュレーター:** [@renedotwang](https://x.com/renedotwang)
**コンセプト:** "A collection of small details that make big difference"
(大きな違いを生む小さなディテールのコレクション)

---

## 🎯 このスキルの用途

1. **プロダクト実装前のチェック** — UI/UXの細部を確認
2. **既存プロダクトの改善** — ディテールを追加して品質向上
3. **記事ネタ探し** — AI Solo Builder / Essential Navigator のネタとして
4. **学習・インスピレーション** — 世界のベストプラクティスを吸収

---

## 📚 カテゴリ別ディテール一覧

### Motion(アニメーション・動き)

| テクニック | 内容 | 活用シーン |
|----------|------|-----------|
| Shake Disabled Button | 無効ボタンクリック時に揺らす | フォームバリデーション |
| Closing Modal Respects Physics | モーダル閉じる時にスクロール位置を物理的に追従 | モーダルUI |
| ASCII loaders | ASCIIアートのローダー | ターミナル風UI |
| Smooth Number Counter | 数字のスムーズなカウントアップ | ダッシュボード |
| Magnetic Button | カーソルに引き寄せられるボタン | CTA強調 |

### Accessibility(アクセシビリティ)

| テクニック | 内容 | 活用シーン |
|----------|------|-----------|
| Larger Hit Area than It Appears | 見た目より大きなタップ領域 | モバイルUI全般 |
| Focus Visible Only on Keyboard | キーボード操作時のみフォーカスリング表示 | フォーム |
| Skip to Content Link | コンテンツへスキップリンク | サイト全体 |

### Optimization(パフォーマンス最適化)

| テクニック | 内容 | 活用シーン |
|----------|------|-----------|
| Prevent Layout Shift from Font Weight Change | フォント太さ変更時のレイアウトシフト防止 | ホバー効果 |
| Avoid Using webp for OG image | OG画像にWebPを使わない(SNS互換性) | SEO/SNS |
| Skeleton Loading | スケルトンローダー | データ読み込み |
| Optimistic Updates | 楽観的UI更新 | インタラクション |

### Design(ビジュアルデザイン)

| テクニック | 内容 | 活用シーン |
|----------|------|-----------|
| Outer and Inner Border Radius | 外側と内側のborder-radiusの関係 | カード/ボタン |
| Photo Response to Theme Mode | ダーク/ライトモードで写真も対応 | 画像表示 |
| Drop the WWW prefix | wwwプレフィックスを省く | ブランディング |
| Consistent Icon Stroke Width | アイコンの線幅を統一 | アイコンセット |

### Easter Egg(隠し機能・遊び心)

| テクニック | 内容 | 活用シーン |
|----------|------|-----------|
| Cast Ending | ランディングを99→100にする仕上げ | 遊び心 |
| Konami Code | コナミコマンドで隠し機能 | ファンサービス |

---

## ✅ 実装チェックリスト

### モバイル対応

- [ ] タップ領域が44x44px以上(見た目より大きく)
- [ ] フォントサイズ最小16px
- [ ] ボタン間隔8px以上

### アニメーション

- [ ] 無効ボタンにフィードバック(shake等)
- [ ] モーダル閉じる時の物理演算
- [ ] ローディング状態にスケルトン

### パフォーマンス

- [ ] OG画像はPNG/JPEG(WebP避ける)
- [ ] フォント太さ変更でレイアウトシフトなし
- [ ] 楽観的UI更新の検討

### ビジュアル

- [ ] 入れ子要素のborder-radius調整
- [ ] ダークモード対応(画像含む)
- [ ] アイコン線幅の統一

---

## 🔧 活用ワークフロー

### プロダクト開発時

```
1. 実装前に detail.design をブラウズ
2. 該当カテゴリのテクニックを確認
3. チェックリストで適用可能なものを特定
4. 実装に組み込み
```

### 記事作成時(AI Solo Builder / Essential Navigator)

```
1. detail.design で新しいテクニックを探す
2. 日本語で解説記事を作成
3. 実装例・コードサンプルを追加
4. ソロビルダー向けの活用法を提案
```

### UI改善時

```
1. 現状のUIを分析
2. detail.design のテクニックでギャップを特定
3. 優先度付け(影響大 & 実装コスト低を優先)
4. 段階的に適用
```

---

## 🔗 関連スキル

- **ui-design-principles** — CSS/サイトレベルのUI設計方針
- **asb-content-design** — AI Solo Builder記事の読者体験設計
- **web-design-guidelines** — Web Interface Guidelines準拠チェック

---

## 📝 メモ

- サイトは定期的に更新される — 新しいテクニックをチェック
- 各テクニックには動画/GIFがあり視覚的に学べる
- 実装難易度は低〜中程度のものが多い

---

*最終更新: 2026-02-20(けいた指示で作成)*
---
name: digest-writer
description: "AI Solo Builder用のDigest記事作成スキル。評価済み候補からDigest + Top3個別記事を作成。「朝刊作成」「夕刊作成」「Digest執筆」などの作業に使う。"
---

# digest-writer — Digest記事作成スキル

## 概要

`news-evaluation` で選定されたTop10からDigest記事とTop3個別記事を作成する。

**このスキルの責務:**
- Digestテンプレートに沿った執筆
- Top3個別記事の作成
- プロダクトリンクの整備

**入力:**
- `news_candidates` テーブルの `status = 'selected'` レコード

**出力:**
- `content/news/YYYY-MM-DD-morning-news-YYYY-MM-DD.md`
- `content/news/YYYY-MM-DD-[slug].md` × 3件

---

## 前提

`news-evaluation` スキルが完了していること。

---

## 手順

### Step 1: 選定結果の取得

```sql
SELECT * FROM news_candidates
WHERE edition = 'morning'
  AND target_date = '2026-02-12'
  AND status = 'selected'
ORDER BY rank ASC;
```

### Step 2: Digest執筆

**テンプレート構造(必須):**

```markdown
---
title: "2026年2月12日 朝刊AIダイジェスト"
slug: "morning-news-2026-02-12"
publishedAt: "2026-02-12T08:00:00+09:00"
summary: "..."
image: "https://images.unsplash.com/..."
contentType: "digest"
digestEdition: "morning"
readTime: 8
featured: true
tags: ["AIニュース", "開発ツール"]
relatedProducts: ["claude", "cursor"]
---

今日のAIソロビルダー向けニュースをお届けします。

## 🏁 重要ニュースランキング

**⚠️ 必須: 収集した全候補をランキング表に記載する**
- Top3: 個別記事あり(`/news/slug` リンク)
- 4位以降: 個別記事なし(1行サマリーのみ)
- 選定経緯を読者に透明化する目的

| 順位 | ニュース | スコア |
|------|----------|--------|
| 1 | [タイトル](/news/slug) | 23 |
| 2 | [タイトル](/news/slug) | 21 |
| 3 | [タイトル](/news/slug) | 19 |
| 4 | タイトル([ソース](URL))| 17 |
| 5 | タイトル([ソース](URL))| 15 |
| ... | ... | ... |

## 🔥 Top 3 ピックアップ

### 1. [タイトル](/news/slug)

**出典:** [ソース名](一次ソースURL) — 2026-02-11

[深掘り解説 200-300字]

**ソロビルダーへの影響:**
- ポイント1
- ポイント2

---

### 2. [タイトル](/news/slug)

...

---

### 3. [タイトル](/news/slug)

...

---

## 📅 明日への展望

[総括と明日への示唆 100字程度]
```

### Step 3: Top3個別記事の作成

各Top3候補について個別記事を作成:

**テンプレート構造:**

```markdown
---
title: "[何が起きたか]"
slug: "[slug]"
publishedAt: "2026-02-12T08:00:00+09:00"
summary: "..."
image: "https://images.unsplash.com/..."
contentType: "news"
readTime: 5
featured: false
tags: ["タグ1", "タグ2"]
relatedProducts: ["product-slug"]
---

## 概要

[リード文 100-150字]

**出典:** [ソース名](一次ソースURL) — 発表日

## 詳細

[本文 300-500字]

### ポイント

- ポイント1
- ポイント2
- ポイント3

## ソロビルダーへの示唆

[実用的な観点 150-200字]

## スコア内訳

| 軸 | スコア | 理由 |
|----|--------|------|
| Newsworthiness | 4/5 | ... |
| Value | 5/5 | ... |
| Actionability | 3/5 | ... |
| Credibility | 5/5 | ... |
| Timeliness | 4/5 | ... |
| **合計** | **21/25** | |
```

### Step 4: プロダクトリンクの整備

記事に登場するプロダクトの `/products/[slug]` を確認:

```bash
# 存在確認
ls content/products/[slug].md

# なければ作成
# → content/products/[slug].md を作成
```

### Step 5: サムネイル画像生成

**⚠️ Unsplash汎用画像は使用禁止。オリジナルサムネイルを生成する。**

スキル: `~/.openclaw/skills/thumbnail-generator/SKILL.md`

```bash
cd /Users/satokeita/Dev/ai-navigator

# 各記事のサムネイルを生成
npm run generate:thumbnail -- --slug "morning-news-YYYY-MM-DD" --no-ai
npm run generate:thumbnail -- --slug "[top1-slug]" --no-ai
npm run generate:thumbnail -- --slug "[top2-slug]" --no-ai
npm run generate:thumbnail -- --slug "[top3-slug]" --no-ai

# または一括生成
npm run generate:thumbnails:missing
```

**生成後:** 記事のfrontmatter `image` を `/thumbnails/[slug].png` に更新

**⚠️ 他の記事との重複禁止**(check:imagesで検証)

### Step 5a: 記事内画像エンリッチメント(2026-02-21追加)

**🖼️ Top3個別記事に公式画像を追加**

記事で紹介しているプロダクト/サービスの公式サイトから画像を取得:

```bash
# 1. 公式サイトから画像URLを取得
curl -s <公式サイトURL> | grep -oE 'https?://[^"]+\.(png|jpg|jpeg|webp)' | head -10

# 2. 画像を確認・選定
image(url, "この画像の内容を説明してください")

# 3. 記事に追加
```

**追加フォーマット:**
```markdown
![説明テキスト](画像URL)
*出典: [サイト名](サイトURL)*
```

**対象:** 公式サイトがあり、画像取得可能なプロダクト

詳細は `~/.openclaw/skills/article-image-enricher/SKILL.md` 参照

### Step 6: ソース情報自動登録(Phase 4: 運用最適化)

**新機能:** 記事作成と同時にソース情報をDBに自動登録

```bash
# 作成済み記事に対してソース検出・登録実行
cd /Users/satokeita/Dev/ai-navigator
node scripts/create-article-with-source-detection-fixed.mjs --article=[記事ファイルパス]
```

**実行内容:**
1. **記事内リンク解析** - Markdownから外部URLを抽出
2. **ソース分類実行** - URLパターンでprimary/secondary/tertiary判定
3. **信頼度算出** - ソースタイプ・ドメイン特性による1-10スコア計算
4. **自動DB登録** - `sources`テーブルへの新規ソース追加
5. **記事メタ設定** - `primary_source_id`, `source_credibility_score`, `source_verification_note`の自動設定

**記事Frontmatterに自動追加される項目:**
```yaml
primary_source_id: "d52dc237-4295-4300-8c88-8f02a6d63096"
source_credibility_score: 9.5
source_verification_note: "Auto-detected: OpenAI Blog (primary, confidence: 1.0)"
```

---

## 品質基準

### 🎨 UI/UXディテールチェック(detail.design 参照)

記事内でUIに言及する場合、detail.design のベストプラクティスを参照:
- https://detail.design/
- スキル: `~/.openclaw/skills/detail-design/SKILL.md`

**特に記事ネタとして活用できる例:**
- Motion: Shake Disabled Button、Magnetic Button
- Accessibility: Larger Hit Area、Focus Visible
- Optimization: Layout Shift防止、OG画像形式
- Design: Border Radius関係、ダークモード対応

| 項目 | 基準 |
|------|------|
| Digest構造 | テンプレート完全準拠 |
| Top3個別記事 | 3件すべて作成 |
| 一次ソースリンク | 全記事に明記 |
| プロダクトリンク | 404なし |
| **relatedProducts** | **必須: 関連プロダクトのslugを配列で指定** |
| 画像 | 全記事にユニーク画像 |
| 型チェック | `readTime` は数値、`featured` は boolean |
| テーブルレイアウト | 汎用CSSで正常表示(列幅の過不足なし) |

### relatedProducts の設定ルール(必須)

**全てのニュース・Digest記事に `relatedProducts` を設定すること。**

```yaml
relatedProducts:
  - claude-code    # 記事で言及しているプロダクトのslug
  - cursor
  - chatgpt
```

**手順:**
1. 記事内で言及・関連するプロダクトを特定
2. `/content/products/` に存在するslugを確認
3. frontmatterの `relatedProducts` に配列で追加

**確認コマンド:**
```bash
# プロダクト一覧確認
ls content/products/ | sed 's/.md//'

# 特定slugの存在確認
ls content/products/claude-code.md
```

**目的:**
- プロダクトページの「関連ニュース」に自動表示される
- 読者がプロダクト→ニュースを回遊できる

---

## テーブル作成ガイドライン

CSSは `table-layout: auto` で**コンテンツに応じた自動幅**を採用。
異なる列構造のテーブルが混在しても正常表示される。

### 原則

- **固定nth-child指定を避ける** — テーブル構造に依存しない汎用CSS
- **短いセルは短く** — 数値・スコアは自然に狭くなる
- **長いセルは長く** — 説明文・タイトルは自動で広がる

### テーブル種類別の列設計

**Digestランキングテーブル(3列):**
| 順位 | ニュース | スコア |
|------|----------|--------|
| 数値(狭) | テキスト(広) | 数値(狭) |

**スコア内訳テーブル(3列):**
| 軸 | スコア | 理由 |
|----|--------|------|
| 短単語(狭) | 数値(狭) | テキスト(広) |

### 確認事項

- [ ] 各列の幅がコンテンツに適している(数値列が広すぎない)
- [ ] 短い単語が改行されていない(「合計」→「合」「計」はNG)
- [ ] 長いテキスト列が十分な幅を持っている

---

## 禁止事項

- **誇張表現禁止**: 「永久無料化」等、一次ソースにない表現は使わない
- **期間外ニュース禁止**: 評価済み候補以外は使わない
- **未検証リンク禁止**: 存在しない `/news/slug` へのリンクは作らない

---

## 完了条件

- [ ] Digest記事作成完了
- [ ] Top3個別記事 3件作成完了
- [ ] 全記事に一次ソースURL明記
- [ ] 全記事に画像設定(重複なし)
- [ ] プロダクトリンク整備完了
- [ ] frontmatter型が正しい(readTime: 数値, featured: boolean)

---

## 次のスキル

→ **publish-gate**: 公開前の最終チェックと実行
---
name: figjam-export
description: "プロジェクトの構造をFigJamダイアグラムとして出力するためのプロンプトを生成する。Claude.ai のFigma Connector経由でFigJamに直接出力可能。トリガー:FigJamに出力、figjam、ダイアグラム生成、アーキテクチャ図、構成図を作って"
---

# FigJam Export

現在のプロジェクトを分析し、Claude.ai(Figma Connector接続済み)に貼り付けることでFigJamダイアグラムを自動生成できるプロンプトを出力する。

## 前提条件

- Claude.ai で Figma Connector が接続済みであること
- 対応プラン: Claude Pro / Max / Team / Enterprise
- 参考: https://claude.com/connectors/figma

## ワークフロー

### Step 1: プロジェクト構造の分析

以下のソースから現在のプロジェクトの全体像を把握する:

1. **CLAUDE.md** — プロジェクト概要・構成・設計原則を読み取る
2. **package.json(ルート + 各パッケージ)** — 依存関係・スクリプト・技術スタック
3. **ディレクトリ構造** — パッケージ構成・主要ファイル
4. **.github/workflows/** — CI/CD パイプライン(存在する場合)
5. **設定ファイル** — next.config.*, vite.config.*, tsconfig.json 等
6. **デプロイ設定** — vercel.json, Dockerfile, launchd plist 等

### Step 2: 情報の構造化

分析結果を以下の5層モデルで整理する:

| レイヤー | 内容 | 形状ヒント |
|---------|------|-----------|
| Layer 1: 外部サービス | API、SaaS、クラウドサービス | クラウド形状 |
| Layer 2: データ生成 | スクリプト、CLI、バッチ処理 | 長方形 |
| Layer 3: データストア | DB、JSON、ログファイル | シリンダー/ファイル |
| Layer 4: アプリケーション | Web、モバイル、CLIアプリ | 角丸長方形(大) |
| Layer 5: 公開エンドポイント | URL、連携先プロダクト | 六角形/ダイヤモンド |

### Step 3: プロンプト生成

以下のテンプレート構造でプロンプトを組み立てる:

```
## プロジェクト概要
[名前、ミッション、主要機能を2-3文で]

## 構成要素(5層構造で配置してください)

### Layer 1: 外部サービス(最上段、クラウド形状)
[箇条書きでサービス名 + 用途]

### Layer 2: データ生成(スクリプト層)
[箇条書きでスクリプト名 + 処理内容]

### Layer 3: データストア(中央)
[箇条書きでデータ名 + 形式]

### Layer 4: アプリケーション
[パッケージごとに技術スタック・主要機能・ページ構成]

### Layer 5: 公開エンドポイント & 外部プロダクト
[URL + 連携先]

## データフロー(矢印/コネクタで表現してください)
[A ──→ B ──→ C 形式で全フローを列挙]

## デザイン指示
[配色・レイアウト・アイコン・全体トーンの指示]
```

### Step 4: ファイル保存

生成したプロンプトを一時ファイルとして保存する:

```
{project-root}/docs/tmp-figjam-{対象の説明}-{YYYYMMDD}.md
```

例: `docs/tmp-figjam-architecture-20260218.md`

ファイル冒頭に以下のヘッダーを含める:

```markdown
<!-- tmp: FigJam生成用プロンプト({YYYY-MM-DD}生成) -->
<!-- 使い方: --- 以降を Claude.ai(Figma Connector接続済み)に貼り付け -->
```

### Step 5: ユーザーへの案内

出力完了後、以下を案内する:

1. ファイルパスと使い方
2. Claude.ai への貼り付け範囲(`---` 以降)
3. 生成後の調整方法(追加プロンプトで色・レイアウト変更可能)

## ダイアグラムの種類

ユーザーの要望に応じて、以下の図を生成できる:

| 種類 | 説明 | 適したケース |
|------|------|-------------|
| アーキテクチャ全体図 | 5層モデルによる俯瞰図 | プロジェクト全体の把握 |
| データフロー図 | データの流れに特化 | パイプライン設計の説明 |
| デプロイメント図 | 環境・インフラ構成 | 本番/ステージング構成 |
| コンポーネント関係図 | パッケージ/モジュール間の依存 | リファクタリング計画 |
| ユーザーフロー図 | ユーザー操作の流れ | UX設計・レビュー |
| シーケンス図 | 時系列のやり取り | API連携の設計 |

デフォルトは「アーキテクチャ全体図」。ユーザーが種類を指定した場合はそれに従う。

## デザインガイドライン

### 配色(デフォルト)

| レイヤー | 推奨色 |
|---------|--------|
| 外部サービス | 紫系 / グレー |
| データ生成 | オレンジ系 |
| データストア | 緑系 |
| アプリケーション | 青系(メインアプリは濃く) |
| 公開エンドポイント | ティール / シアン系 |

### レイアウト指示

- 上→下の5層フロー(各レイヤーをセクションで囲む)
- メインアプリケーションを最も大きく表示
- データフローは太い矢印、補助フローは細い矢印
- 定期実行ジョブはバッジ/ノートで表示(cron時刻、launchd間隔等)
- 各ノードに技術スタック名を副テキストで表示

## 参照

- FigJam Connector設定: [references/figjam-setup.md](references/figjam-setup.md)
---
name: flutter-ios-restart
description: "FlutterアプリをiOSシミュレータで再起動する。アプリの再起動、シミュレータ再起動、flutter run、iOSで実行のトリガーで発火。"
---

# Flutter iOS Simulator 再起動

FlutterアプリをiOSシミュレータで再起動する。

## 実行手順

### ステップ1: 既存プロセスを停止して再起動

```bash
pkill -f "flutter" 2>/dev/null
sleep 2
cd /Users/satokeita/Dev/history-quiz-app/flutter_app
flutter run -d 603DABE7-2CF6-4EF1-ADFF-CE0CA2232552 2>&1 &
sleep 35
echo "App restart complete"
```

### 補足

- デバイスID `603DABE7-2CF6-4EF1-ADFF-CE0CA2232552` は iPhone 17 Pro シミュレータ
- 起動完了まで約35秒待機
- バックグラウンドで実行されるため、ターミナルは引き続き使用可能

### デバイス一覧の確認

シミュレータが変わった場合は以下で確認:

```bash
flutter devices
```
---
name: gmail
description: "Gmail APIでメールの取得・検索・送信を行う。受信トレイのチェック、未読メール確認、メール送信に使う。「メール確認」「未読メール」「メール送信」「Gmailチェック」などの作業に使う。"
metadata: {"clawdbot":{"requires":{"bins":["node"]}}}
---

# Gmail Skill

Gmail APIを使ったメール操作スキル。Google Calendar と同じOAuth認証を共有。

## ツール

- `~/.openclaw/skills/gmail/gmail.js` — メイン操作スクリプト
- `~/.openclaw/skills/gmail/auth.js` — OAuth認証ヘルパー

## 使い方

```bash
# 未読メール一覧(デフォルト10件)
node ~/.openclaw/skills/gmail/gmail.js list

# 未読メールを件数指定
node ~/.openclaw/skills/gmail/gmail.js list 20

# メール検索
node ~/.openclaw/skills/gmail/gmail.js search "from:example@gmail.com"

# 特定メールの本文取得
node ~/.openclaw/skills/gmail/gmail.js read <messageId>

# メール送信
node ~/.openclaw/skills/gmail/gmail.js send "to@example.com" "件名" "本文"
```

## 認証

Google Calendar MCP と同じトークンを使用:
- トークン: `~/.config/google-calendar-mcp/tokens.json`
- OAuth鍵: `~/.openclaw/google-calendar/gcp-oauth.keys.json`

## 注意事項

- メール送信は**必ずけいたに確認**を取ってから実行
- 未読チェックはハートビートで定期的に実施可能
- Gmail APIのスコープが必要(初回は認証フローが必要な場合あり)
---
name: google-play-publish
description: Google Play Console でAndroidアプリを公開するワークフロー。Flutter/Androidアプリのリリースビルド作成、署名キー管理、ストア掲載情報の準備、審査提出までをカバー。「Androidアプリ公開」「Google Play にアップロード」「ストアリスト作成」「リリースビルド」などの作業に使う。
---

# Google Play Publish

FlutterまたはネイティブAndroidアプリをGoogle Playに公開するためのワークフロー。

## 前提条件

- Google Play Developer アカウント($25の登録料)
- 公開するアプリのソースコード
- Flutter SDK または Android Studio

## ワークフロー概要

```
1. 事前準備
   ├── アプリID(applicationId)の確定
   ├── バージョン番号の設定
   └── アイコン・スクリーンショットの準備

2. 署名キーの作成・設定
   ├── keystore ファイル生成
   ├── key.properties 作成
   └── build.gradle 署名設定

3. リリースビルド
   └── App Bundle (.aab) 生成

4. Google Play Console 設定
   ├── アプリ作成
   ├── ストアリスト情報入力
   ├── コンテンツレーティング
   ├── ターゲットユーザー設定
   └── プライバシーポリシー

5. リリース提出
   ├── 内部テスト or クローズドテスト
   └── 製品版リリース
```

## 1. 事前準備

### Application ID の確認・設定

`android/app/build.gradle.kts` (または `build.gradle`):

```kotlin
defaultConfig {
    applicationId = "com.yourcompany.yourapp"  // 世界で一意
    ...
}
```

**命名規則:**
- リバースドメイン形式: `com.company.appname`
- 小文字・数字・ドット・アンダースコアのみ
- 一度公開すると変更不可

### バージョン設定

`pubspec.yaml` (Flutter):

```yaml
version: 1.0.0+1  # versionName+versionCode
```

- `versionName`: ユーザーに表示(1.0.0)
- `versionCode`: 内部管理用、アップデートごとに増加

### アセット準備チェックリスト

- [ ] アプリアイコン(512x512 PNG、透過なし)
- [ ] フィーチャーグラフィック(1024x500 PNG/JPG)
- [ ] スクリーンショット(最低2枚、推奨4-8枚)
  - スマホ: 16:9 または 9:16
  - タブレット: 16:9(7インチ/10インチ用、任意)
- [ ] 短い説明文(80文字以内)
- [ ] 詳細な説明文(4000文字以内)

## 2. 署名キーの作成・設定

### 2.1 Keystore の生成

```bash
keytool -genkey -v \
  -keystore ~/keys/[app-name]-release.keystore \
  -alias [app-name] \
  -keyalg RSA \
  -keysize 2048 \
  -validity 10000
```

**重要:** keystoreファイルとパスワードは絶対にGitにコミットしない。紛失するとアプリのアップデートが永久に不可能になる。

### 2.2 key.properties の作成

`android/key.properties` (gitignore対象):

```properties
storePassword=YOUR_STORE_PASSWORD
keyPassword=YOUR_KEY_PASSWORD
keyAlias=YOUR_KEY_ALIAS
storeFile=/absolute/path/to/your-release.keystore
```

### 2.3 build.gradle.kts の署名設定

```kotlin
import java.util.Properties
import java.io.FileInputStream

// key.properties を読み込む
val keystorePropertiesFile = rootProject.file("key.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}

android {
    ...
    signingConfigs {
        create("release") {
            keyAlias = keystoreProperties["keyAlias"] as String?
            keyPassword = keystoreProperties["keyPassword"] as String?
            storeFile = keystoreProperties["storeFile"]?.let { file(it as String) }
            storePassword = keystoreProperties["storePassword"] as String?
        }
    }

    buildTypes {
        release {
            signingConfig = signingConfigs.getByName("release")
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}
```

## 3. リリースビルド

### App Bundle のビルド(推奨)

```bash
cd flutter_app
flutter build appbundle --release
```

出力: `build/app/outputs/bundle/release/app-release.aab`

### APK のビルド(代替)

```bash
flutter build apk --release --split-per-abi
```

### 難読化解除ファイル(ProGuard / R8 mapping)

リリースビルドで `isMinifyEnabled = true` を設定している場合、難読化解除ファイル(mapping.txt)が生成される。これをGoogle Play Consoleにアップロードすると、クラッシュログが読みやすくなる。

**ファイルの場所:**
```
build/app/outputs/mapping/release/mapping.txt
```

**アップロード方法:**
1. Google Play Console → アプリを選択
2. 「App Bundle エクスプローラ」または「リリース」画面
3. 「難読化解除ファイル」セクションで mapping.txt をアップロード

**注意:**
- 必須ではない(警告は無視してもリリース可能)
- ただしクラッシュ分析時に役立つので、本番リリース時はアップロード推奨
- ビルドごとに異なるので、リリースするaabと対応するmapping.txtをセットで管理すること

## 4. Google Play Console 設定

### 4.1 アプリの作成

1. Google Play Console → 「アプリを作成」
2. アプリ名、デフォルト言語、アプリ/ゲーム、無料/有料を選択
3. デベロッパープログラムポリシーに同意

### 4.2 ストアリスト

**メインのストアリスト:**
- アプリ名(30文字)
- 短い説明(80文字)
- 詳細な説明(4000文字)
- アプリアイコン
- フィーチャーグラフィック
- スクリーンショット

### 4.3 コンテンツレーティング

IAQRアンケートに回答 → レーティング自動算出
- 暴力表現
- 性的コンテンツ
- ギャンブル
- 広告の有無
- etc.

### 4.4 ターゲットユーザー

- ターゲット年齢層を選択
- 13歳未満を含む場合、追加の要件あり

### 4.5 プライバシーポリシー

- 外部URL必須
- 個人情報を収集しない場合でもポリシーページは必要
- GitHub Pagesやnotionでホスト可能

## 5. リリース提出

### ⚠️ 個人アカウントの本番公開要件(2023年11月以降作成)

**重要:** 2023年11月13日以降に作成された個人デベロッパーアカウントは、本番公開前に以下が必須:

1. **クローズドテスト**を実施
2. **12人のテスター**が**14日間連続**でオプトイン
3. **本番アクセス申請**(Dashboard → Apply for production)
4. 審査(通常7日以内)

内部テストだけでは本番公開できない。

**申請時に回答が必要な質問:**
- テスター募集の難易度
- テスターのエンゲージメント状況
- 受け取ったフィードバックのまとめ
- アプリの対象ユーザー
- アプリが提供する価値
- 1年目の予想インストール数
- テスト結果に基づく変更点
- 本番準備完了の判断理由

**参考:** https://support.google.com/googleplay/android-developer/answer/14151465

### テストトラックの種類

| トラック | 目的 | 要件 |
|---------|------|------|
| 内部テスト | 少人数での素早いテスト | なし |
| クローズドテスト | 管理されたグループでのテスト | アプリ設定完了 |
| オープンテスト | Google Playでテスト版公開 | 本番アクセス取得後 |
| 製品版 | 一般公開 | クローズドテスト要件クリア |

### 内部テスト

1. 「テスト」→「内部テスト」
2. テスターのメールリスト作成
3. aab をアップロード
4. テスターに共有リンクを送付

※ 内部テストは設定完了前でも可能。素早くビルドを配布できる。

### クローズドテスト

1. 「テスト」→「クローズドテスト」
2. テスターリスト作成(12人以上推奨)
3. aab をアップロード
4. 14日間テスター維持
5. 本番アクセス申請

### 製品版リリース

1. 「製品版」→「新しいリリースを作成」
2. aab をアップロード
3. リリースノート記入
4. 「審査に送信」

審査は通常数時間〜数日。

## トラブルシューティング

### ビルドエラー

**署名エラー:**
```
Execution failed for task ':app:validateSigningRelease'
```
→ key.properties のパスとパスワードを確認

**minSdk エラー:**
→ `flutter.minSdkVersion` を確認、必要に応じて明示的に設定

### 審査リジェクト

よくある理由:
- プライバシーポリシーURLが無効
- スクリーンショットがガイドライン違反
- コンテンツレーティングが実際と不一致
- 権限の説明不足

## References

詳細な手順や特定のケースについては `references/` を参照:

- `references/store-listing-tips.md` - ストアリスト最適化のコツ(TODO)
- `references/privacy-policy-template.md` - プライバシーポリシーテンプレート(TODO)

---

*このスキルは実際の公開作業を通じて継続的に更新される*
# Gym Memo スキル

Slackスレッドのジムメモを整理してObsidianデイリーノートに記録する。

## トリガー

- 「ジムメモ記録して」「ジムの記録」「トレーニング記録」
- Slackスレッドで「記録しておいて」とメンションされた時(親メッセージが「ジムメモ」で始まる場合)

## 入力フォーマット

Slackスレッドの形式:
```
[親メッセージ] ジムメモ YYYY/MM/DD

[返信] 種目名
[返信] 重量 回数
[返信] 重量 回数
...
[返信] 次の種目名
[返信] 重量 回数
...
```

### 対応パターン
- 重量: `65キロ`, `65kg`, `65`(数字のみ)
- 回数: `10回`, `10rep`, `10`
- 左右指定: `左`, `右` が単独行で来る場合
- ドロップセット: 同じ種目で重量が下がっていく場合

## 出力先

`/Users/satokeita/dev/life-project-management/01_Daily/YYYY-MM-DD.md`

Memoセクションに以下の形式で追記:

```markdown
### 🏋️ ジムメモ(YYYY/MM/DD)

**種目名**
- 重量kg × 回数回
- 重量kg × 回数回

**種目名**
- 左: 重量kg × 回数回
- 右: 重量kg × 回数回
```

## 処理手順

1. **スレッド内容の取得**
   - slack-thread-context または履歴から全メッセージを取得
   
2. **パース**
   - 種目名の検出(日本語のマシン名)
   - 重量・回数のペア抽出
   - 左右の指定があれば付与

3. **デイリーノート更新**
   - 該当日のデイリーノートを開く
   - Memoセクションに整形して追記
   - 既存の同日ジムメモがあれば上書き確認

4. **完了報告**
   - 記録した内容のサマリーをSlackに返信
   - 前回との比較があれば添える

## 既知の種目名

- シーテッドレッグプレス
- チェストプレス
- トーソローテーション
- ショルダープレス
- アブドミナル
- ラットプルダウン
- レッグエクステンション
- レッグカール
- ケーブルクロスオーバー

(新しい種目が出てきたら追加)

## 将来の拡張

- [ ] 週次サマリー生成
- [ ] 重量推移のグラフ化
- [ ] 種目別のPR(自己ベスト)追跡
- [ ] トレーニングボリューム計算
# Hatena AI Buzz Monitor

はてなブックマークで生成AI関連記事が50ブックマーク以上になったら自動通知するスキル。

## 目的
- 生成AI・機械学習分野の話題記事をリアルタイム検知
- バズり始めた記事を見逃さない
- 業界トレンドの早期キャッチアップ

## 監視対象
- **カテゴリ**: はてなブックマーク「AI・機械学習」
- **閾値**: 50ブックマーク以上
- **対象**: 新着記事のみ(重複通知回避)

## 使用方法

### 監視開始
```bash
# cronジョブに登録(10分おきにチェック)
cron add {
  name: "AI記事バズ監視",
  schedule: { kind: "cron", schedule: "*/10 * * * *" },
  payload: { 
    kind: "agentTurn", 
    message: "はてなブックマークでAI関連の50ブックマーク以上記事をチェックして、新着があればSlackに通知してください。"
  },
  sessionTarget: "isolated"
}
```

### 手動実行
```
hatena-ai-buzz-monitor で生成AI関連の話題記事をチェックしてください
```

## 監視フロー
1. はてなブックマークRSS取得
2. 50ブックマーク以上の記事抽出
3. 既通知記事と照合(重複チェック)
4. 新着記事があればSlack通知
5. 通知済み記事ID記録

## 使用API・URL
```
# AI・機械学習カテゴリ(50ブックマーク以上、人気順)
https://b.hatena.ne.jp/entrylist/it/AI%E3%83%BB%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92?threshold=50&sort=hot&mode=rss

# 代替URL(人気エントリー版)
https://b.hatena.ne.jp/hotentry/it/AI%E3%83%BB%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92.rss
```

## 通知形式
```
🚨 AI記事バズアラート!

📰 「記事タイトル」
🔥 XX users (50+ ブックマーク達成)
📅 2026-02-13 06:30
🔗 https://example.com/article

💬 主要コメント:
・「これは革命的」
・「実装してみたい」
・「業界が変わりそう」

#生成AI #バズ記事 #トレンド
```

## 状態管理ファイル
- **通知済み記事**: `~/.openclaw/skills/hatena-ai-buzz-monitor/notified_articles.json`
- **最終チェック時刻**: 重複チェック用タイムスタンプ

## 実装ポイント
1. **RSS解析**: XML/RSS パース処理
2. **重複回避**: 記事URL・IDベースの管理
3. **閾値判定**: ブックマーク数の正確な抽出
4. **通知調整**: 重要度に応じた通知頻度制御

## 拡張オプション
- **閾値変更**: 30, 100, 200ブックマーク等
- **カテゴリ追加**: プログラミング、エンジニア等
- **時間帯制限**: 営業時間内のみ通知
- **重要度判定**: タイトル・コメント内容による優先度

## 注意事項
- はてなブックマークAPIの利用制限に注意
- 過度なリクエストを避けるため適切な間隔設定
- 通知過多にならないよう閾値調整
# 個別記事作成スキル(dev-knowledge / case-study)

このスキルは、朝刊・夕刊Digestとは別の深掘り記事を作成する手順を定義する。

---

## 概要

| 項目 | 内容 |
|------|------|
| 対象 | dev-knowledge / case-study カテゴリの記事 |
| 目的 | 深さ・独自価値の提供 |
| 目標文字数 | 8,000〜20,000字 |
| 目標読了時間 | 10〜20分 |
| 所要時間 | 5〜9時間 |

---

## 3つの記事型

どの型で書くかを最初に決定する。

### 1. キュレーション型(★推奨)

> 既存の良質なリソースを評価・比較し、読者に最適な学習パスを案内

**特徴:**
- 一次ソースへの敬意を払いつつ、独自の評価軸で整理
- 「どれを読むべきか」「どの順番で学ぶべきか」を提示
- 原文リンク + 日本語での要点解説 + 独自の実践視点

**例:** 「プロンプトエンジニアリング完全ガイド — 公式ドキュメントから実践者の知見まで」

### 2. 事例分析型

> 実際の成功/失敗事例を深掘り分析し、再現可能な教訓を抽出

**特徴:**
- 具体的な数字(売上、ユーザー数、開発期間)
- 時系列での軌跡
- 「なぜうまくいったか/いかなかったか」の分析
- 読者が活かせる原則の明確化

**例:** 「Pieter Levelsの事例 — 従業員ゼロ・AIだけで年収3億円」

### 3. 実践ガイド型

> 特定のスキル・ツールを「使えるようになる」ための具体的手順

**特徴:**
- 実際に動くコード・設定例
- ビフォー/アフターの比較
- よくある失敗とその回避法
- 段階的な難易度設定

**例:** 「MCP実践ガイド — ゼロから動くサーバーまで」

---

## 5 Phaseワークフロー

### Phase 1: テーマ選定(30分)

**チェックリスト:**
- [ ] ターゲット読者(AIソロ開発者)にとって価値があるか
- [ ] 既存記事との差別化ポイントがあるか
- [ ] 一次ソースが十分に存在するか
- [ ] 自分(または参照可能な実践者)に実体験があるか

**テーマ発見ソース:**
- Hacker News(AI/dev関連で100+ポイント)
- X/Twitter(@levelsio, @karpathy, @simonw等)
- GitHub Trending
- ProductHunt
- 読者からの質問・リクエスト

**出力:** テーマ決定 + 記事型選択

### Phase 2: 一次ソースリサーチ(1〜2時間)

**収集対象:**
1. **公式ドキュメント** — 最も信頼性が高い
2. **作者本人の発言** — ブログ、ポッドキャスト、X投稿
3. **海外の質の高い記事** — Entrepreneur Loop, TechCrunch, The Verge等
4. **実践者の報告** — GitHub Issues, Reddit, HN comments
5. **ベンチマーク・データ** — 定量的な根拠

**記録フォーマット:**
```markdown
## ソース一覧
| # | ソース名 | URL | 種類 | 信頼度 | 要点 |
|---|---------|-----|------|--------|------|
| 1 | 公式ドキュメント | ... | 公式 | ★★★ | ... |
| 2 | 作者のX投稿 | ... | 一次 | ★★★ | ... |
| 3 | 海外記事 | ... | 二次 | ★★☆ | ... |
```

**出力:** ソースリスト(最低3つの一次ソース)

### Phase 3: 既存リソース評価(1時間)

**評価軸:**
| 軸 | 説明 |
|----|------|
| 正確性 | 情報が正確か、最新か |
| 深さ | 表面的 vs 本質的 |
| 実用性 | 読んだ後に行動できるか |
| 独自性 | 他で読めない視点があるか |
| 日本語対応 | 日本語で読めるか、日本向け解説があるか |

**出力:**
- どのリソースを推奨するか
- 各リソースの強み/弱み
- 読む順番の提案

### Phase 4: 独自価値の設計(30分)

**問い:**
> 「この記事でしか得られない価値は何か?」

**独自価値の出し方:**
1. **日本向けローカライズ** — 海外記事の日本市場への適用
2. **比較・評価** — 複数のリソースを横断的に評価
3. **実践検証** — 実際に試した結果を共有
4. **構造化** — 散らばった情報を体系的に整理
5. **学習パス提示** — 「次に何をすべきか」を明示

**出力:** 記事構成案(見出しレベル)

### Phase 5: 執筆・公開(2〜4時間)

**必須要素:**
- [ ] 冒頭で「この記事で得られること」を明示
- [ ] 一次ソースへのリンク(敬意を払う)
- [ ] 具体的な数字・データ
- [ ] 表形式での比較(読みやすさ)
- [ ] 実際のコード例・設定例(該当する場合)
- [ ] 「次のアクション」を明示
- [ ] 関連プロダクトへのリンク(relatedProducts)

**品質チェック:**
- [ ] 8,000字以上
- [ ] 読了時間10分以上
- [ ] 「どこでも読める内容」になっていないか
- [ ] 実証・データがあるか
- [ ] 読者が行動に移せるか

**画像エンリッチメント(公開前必須):**

スキル: `~/.openclaw/skills/article-image-enricher/SKILL.md`

記事内で紹介しているプロダクト/サービスの公式サイトから画像を取得し追加:

```bash
# 1. 記事内の公式サイトリンクを特定
grep -oE 'https?://[^)]+' <記事ファイル> | head -10

# 2. 公式サイトから画像URLを取得
curl -s <公式サイトURL> | grep -oE 'https?://[^"]+\.(png|jpg|jpeg|webp)' | head -10

# 3. 画像確認・選定(imageツール)
# 4. 記事に追加(出典リンク必須)
```

**公開:**
```bash
# article-quality-check で品質確認
# publish-gate を実行(Step 0で画像エンリッチメント確認含む)
cd /Users/satokeita/Dev/ai-navigator
npm run publish:gate
git add -A
git commit -m "publish: [category] [title]"
git push origin main
```

---

## 曜日別テーマ(平日編集枠 12:30)

| 曜日 | カテゴリ | 記事型の推奨 |
|------|---------|--------------|
| 月 | dev-knowledge | キュレーション型 or 実践ガイド型 |
| 火 | case-study | 事例分析型 |
| 水 | product | プロダクト辞書更新(ニュースとして出す場合あり) |
| 木 | dev-knowledge | キュレーション型 or 実践ガイド型 |
| 金 | case-study | 事例分析型 |

---

## 参照ドキュメント

| ドキュメント | 用途 |
|-------------|------|
| `docs/WORKFLOW-ARCHITECTURE.md` | 全体アーキテクチャ |
| `docs/CHECKLIST.md` | 品質基準 |
| `~/.openclaw/skills/publish-gate/SKILL.md` | 公開手順 |
| `~/.openclaw/skills/article-quality-check/SKILL.md` | 品質チェック |

---

## テーブル作成ガイドライン

CSSは `table-layout: auto` で**コンテンツに応じた自動幅**を採用。
異なる列構造のテーブルが混在しても正常表示される。

### 原則

- **固定nth-child指定を避ける** — テーブル構造に依存しない汎用CSS
- **短いセルは短く** — 数値・スコアは自然に狭くなる
- **長いセルは長く** — 説明文・URL・要点は自動で広がる

### テーブル種類別の列設計

**ソース一覧表(6列):**
| # | ソース名 | URL | 種類 | 信頼度 | 要点 |
|---|---------|-----|------|--------|------|
| 数値(狭) | テキスト(中) | URL(広) | 短単語(狭) | ★記号(狭) | テキスト(広) |

**評価軸表(3列):**
| 軸 | 説明 |
|----|------|
| 短単語(狭) | テキスト(広) |

**比較表(可変列):**
- 1列目(項目名): 適度な幅
- 2列目以降(比較対象): 均等に自動調整

### 確認事項

- [ ] 各列の幅がコンテンツに適している(数値列が広すぎない)
- [ ] 短い単語が改行されていない
- [ ] 長いテキスト列が十分な幅を持っている

---

*更新: 2026-02-15(テーブルガイドライン追加)*
---
name: lifelog-analyzer
description: "OCRログ・セッションログ・Gitコミットを分析し、コンテンツ化可能なポイントを抽出する。「行動ログ分析」「ライフログ解析」「コンテンツネタ抽出」などの作業に使う。"
metadata: {"clawdbot":{"requires":{"bins":["node"]}}}
---

# LifeLog Analyzer

けいたの日々の行動ログを分析し、コンテンツ化可能なポイントを抽出するスキル。

## 概要

以下のデータソースを統合分析:
1. **OCRログ** - スクリーンキャプチャからの行動記録
2. **セッションログ** - Clawdbotとの会話
3. **Gitコミット** - 開発進捗
4. **デイリーノート** - 手動メモ
5. **Chrome閲覧履歴** - 訪問URL・タイトル・時刻(2026-02-09追加)

## 使い方

```bash
# 特定日を分析
node ~/.openclaw/skills/lifelog-analyzer/analyze.js 2026-02-07

# デフォルト(昨日)
node ~/.openclaw/skills/lifelog-analyzer/analyze.js
```

## 出力

分析結果は以下に保存:
- `~/dev/life-project-management/08_Content_Queue/analysis/YYYY-MM-DD.json`

## 抽出カテゴリ

| カテゴリ | 説明 | ソース | アウトプット |
|----------|------|--------|--------------|
| dev_tips | 開発中の学び・Tips | OCR, Git, Chrome | X, AI Solo Builder |
| tool_discovery | 新ツール発見 | OCR, Chrome | X, AI Solo Builder |
| life_insight | 育児・生活の気づき | デイリーノート | X, Essential Navigator |
| ai_usage | AI活用パターン | セッション, Chrome | X, AI Solo Builder |
| learning | 読んだ記事・学習 | Chrome | X |

## データソースパス

- OCRログ: `/Users/satokeita/dev/auto-screen-capture/logs/YYYY-MM-DD.jsonl`
- セッションログ: `~/.openclaw/agents/main/sessions/*.jsonl`
- デイリーノート: `/Users/satokeita/dev/life-project-management/01_Daily/YYYY-MM-DD.md`
- Chrome履歴: `~/Library/Application Support/Google/Chrome/Default/History`(SQLite)
- Gitリポジトリ: `~/Dev/history-quiz-app`, `~/Dev/ai-essential-navigator`, `~/clawd`, `~/product-hub`
---
name: mobile-test
description: "Flutter モバイルアプリのE2Eテストを Maestro で実行し、動画エビデンスを取得する。テスト完了には動画取得が必須。ログインが必要なテストは必ずテストアカウントを使用し、スキップ禁止。トリガー:モバイルテスト、Flutterテスト、アプリテスト、E2Eテスト、maestroテスト、テストを実行、動作確認"
---

# モバイルテスト

Flutterアプリ(flutter_app/)のE2EテストをMaestroで実行し、動画エビデンスを取得する。

## 必須制約

### 1. 動画取得は必須

**テスト完了の定義**: `.maestro/recordings/` に動画ファイル(.mp4)が生成されていること。

動画が取得されていない場合、テストは未完了とみなす。

### 2. ログイン必須テストのスキップ禁止

認証が必要なテストを「ログインできないから」等の理由でスキップしてはならない。
テストアカウントでログインを実行し、認証後の機能を必ずテストする。

テストアカウント情報: [references/test-account.md](references/test-account.md)

## テスト実行手順

### ステップ1: 環境確認

```bash
cd /Users/satokeita/Dev/history-quiz-app/flutter_app
flutter devices
```

### ステップ2: テスト実行と動画取得

```bash
cd /Users/satokeita/Dev/history-quiz-app
maestro record .maestro/flows/<フロー名>.yaml --output .maestro/recordings/<フロー名>.mp4
```

### ステップ3: テスト完了確認

```bash
ls -la /Users/satokeita/Dev/history-quiz-app/.maestro/recordings/
```

**.mp4 ファイルが存在しなければテスト未完了。**

## 新規フロー作成

フローテンプレート: [references/flow-templates.md](references/flow-templates.md)

## チェックリスト

- [ ] `.maestro/recordings/` に動画ファイル(.mp4)が存在する
- [ ] ログインが必要なテストはテストアカウントでログイン済み
- [ ] 全てのアサーションが成功している
---
name: news-evaluation
description: "AI Solo Builder用のニュース評価・選定スキル。期間フィルタ、スコアリング、事実確認を行う。「スコア評価」「ニュース選定」「Top10選定」などの作業に使う。"
---

# news-evaluation — ニュース評価・選定スキル

## 概要

`news-research` で収集した候補を評価・選定し、Digest用のTop10を確定する。

**このスキルの責務:**
- 期間適切性の検証
- スコアリング(5軸評価)
- 事実確認(誇張・歪曲チェック)
- Top10/Top3の確定

**入力:**
- `news_candidates` テーブルの `status = 'collected'` レコード

**出力:**
- `status = 'selected'` に更新されたTop10
- スコアの付与

---

## 前提

`news-research` スキルが完了していること。

---

## 手順

### Step 1: 期間適切性フィルタ

```sql
-- 朝刊の場合
SELECT * FROM news_candidates
WHERE edition = 'morning'
  AND target_date = '2026-02-12'
  AND published_at >= '2026-02-11 18:00:00+09'
  AND published_at < '2026-02-12 08:00:00+09'
  AND status = 'collected';

-- 夕刊の場合
SELECT * FROM news_candidates
WHERE edition = 'evening'
  AND target_date = '2026-02-12'
  AND published_at >= '2026-02-12 08:00:00+09'
  AND published_at < '2026-02-12 18:00:00+09'
  AND status = 'collected';
```

**期間外の候補は `status = 'rejected'` に更新**

### Step 2: 事実確認

各候補について一次ソースを再確認:

```bash
web_fetch url=[source_url]

# 確認項目:
# 1. タイトルと内容が一致しているか
# 2. 誇張表現がないか
# 3. 定量データが正確か
```

**チェックリスト:**
- [ ] タイトルが事実を正確に反映
- [ ] 「永久無料化」等の誇張がない
- [ ] 数値データが一次ソースと一致

### Step 3: スコアリング(5軸評価)

各候補に5軸でスコア付け:

| 軸 | 説明 | 1-5点 |
|----|------|-------|
| **N**ewsworthiness | 新規性・話題性 | |
| **V**alue | ソロビルダーへの実用価値 | |
| **A**ctionability | 今日から試せるか | |
| **C**redibility | 情報源の信頼性 | |
| **T**imeliness | 即時性・緊急度 | |

```sql
-- スコア更新
UPDATE news_candidates
SET 
  nva_n = 4,
  nva_v = 5,
  nva_a = 3,
  nva_c = 5,
  nva_t = 4,
  nva_score = 21
WHERE id = '[candidate_id]';
```

**スコア目安:**
| 合計点 | 評価 |
|--------|------|
| 23-25 | 最高 |
| 20-22 | 高い |
| 16-19 | 中程度 |
| 15以下 | 低い |

### Step 4: Top10選定

```sql
-- Top10を選定
UPDATE news_candidates
SET status = 'selected', rank = [1-10]
WHERE id IN (
  SELECT id FROM news_candidates
  WHERE edition = 'morning'
    AND target_date = '2026-02-12'
    AND status = 'collected'
  ORDER BY nva_score DESC
  LIMIT 10
);

-- それ以外を rejected に
UPDATE news_candidates
SET status = 'rejected'
WHERE edition = 'morning'
  AND target_date = '2026-02-12'
  AND status = 'collected';
```

### Step 5: Top3確定

Top10のうち上位3件を `top3 = true` に:

```sql
UPDATE news_candidates
SET top3 = true
WHERE edition = 'morning'
  AND target_date = '2026-02-12'
  AND rank <= 3;
```

---

## 品質基準

| 項目 | 基準 |
|------|------|
| 期間適合率 | 100%(期間外は除外済み) |
| 事実確認率 | 100%(誇張なし確認済み) |
| Top10選定 | NVAスコア順で上位10件 |
| Top3選定 | NVAスコア順で上位3件 |
| テーブルレイアウト | 汎用CSSで正常表示 |

---

## テーブル作成ガイドライン

CSSは `table-layout: auto` で**コンテンツに応じた自動幅**を採用。

### 原則

- **固定nth-child指定を避ける** — テーブル構造に依存しない汎用CSS
- **短いセルは短く** — 数値・スコアは自然に狭くなる
- **長いセルは長く** — 説明文・理由は自動で広がる

### スコアリング表の列設計

| 軸 | 説明 | 1-5点 |
|----|------|-------|
| 短単語(狭) | テキスト(広) | 数値(狭) |

### スコア内訳テーブル(記事内)の列設計

| 軸 | スコア | 理由 |
|----|--------|------|
| 短単語(狭) | 数値(狭) | テキスト(広) |

### 確認事項

- [ ] 「軸」「スコア」列が過度に広がらない
- [ ] 「理由」「説明」列が十分な幅を持つ
- [ ] 短い単語(「合計」等)が改行されていない

---

## 完了条件

- [ ] 期間外候補を rejected に更新
- [ ] 全候補の事実確認完了
- [ ] 全候補にNVAスコア付与
- [ ] Top10を selected に更新
- [ ] Top3を確定

---

## 次のスキル

→ **digest-writer**: 選定結果からDigest記事を作成
---
name: news-research
description: "AI Solo Builder用のニュース調査スキル。一次ソースの特定・日付確認・構造化データ保存まで。「ニュース収集」「ソース調査」「候補収集」などの作業に使う。"
---

# news-research — ニュース調査スキル

## 概要

AI Solo Builder の朝刊/夕刊に向けたニュース候補を調査し、構造化データとして保存する。

**このスキルの責務:**
- 一次ソースの特定
- 発表日(publishedAt)の確認
- 構造化データとしてのDB保存

**次のスキルへの出力:**
- `news_candidates` テーブルに保存された調査済み候補

---

## 入力

| 項目 | 説明 |
|------|------|
| edition | `morning` または `evening` |
| targetDate | 対象日(YYYY-MM-DD) |

## 出力

Supabase `news_candidates` テーブルへの INSERT

```sql
-- news_candidates テーブル構造
CREATE TABLE news_candidates (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  edition TEXT NOT NULL,           -- 'morning' | 'evening'
  target_date DATE NOT NULL,       -- 対象日
  title TEXT NOT NULL,             -- ニュースタイトル
  summary TEXT,                    -- 概要(200字以内)
  source_url TEXT NOT NULL,        -- 一次ソースURL
  source_name TEXT,                -- ソース名(TechCrunch等)
  published_at TIMESTAMPTZ,        -- 発表日時
  collected_at TIMESTAMPTZ DEFAULT now(),
  status TEXT DEFAULT 'collected', -- collected | evaluated | selected | rejected
  created_at TIMESTAMPTZ DEFAULT now()
);
```

---

## 手順

### Step 1: 対象期間の確定

```
朝刊(morning):
  開始: 前日 18:00 JST(前夕刊公開時刻)
  終了: 当日 08:00 JST(今朝刊公開時刻)

夕刊(evening):
  開始: 当日 08:00 JST(今朝刊公開時刻)
  終了: 当日 18:00 JST(今夕刊公開時刻)
```

### Step 2: ソース巡回

以下を **すべて** 巡回する:

```bash
# 主要ソース
web_search query="AI developer tools" freshness=pd count=10
web_search query="Claude Anthropic" freshness=pd count=5
web_search query="OpenAI GPT developer" freshness=pd count=5
web_search query="GitHub Copilot" freshness=pd count=5

# 専門ソース
web_fetch url=https://techcrunch.com/category/artificial-intelligence/
web_fetch url=https://www.theverge.com/ai-artificial-intelligence
web_search query="AI site:dev.to" freshness=pd count=5
```

### Step 3: 一次ソース確認(必須)

各候補について以下を確認:

```bash
# 記事URLから一次ソースを辿る
web_fetch url=[記事URL]

# 確認項目:
# 1. 公式発表へのリンクがあるか
# 2. 発表日が明記されているか
# 3. 二次ソースの場合は原典を特定
```

**⚠️ 一次ソースが特定できない場合は候補から除外**

---

### Step 3a: 料金・ポリシー変更系の追加調査(2026-02-18追加)

**以下のキーワードを含むニュースは追加調査必須:**
- 料金、プラン、価格、pricing、課金
- 変更、移行、廃止、終了、deprecated
- API、利用規約、ポリシー

```bash
# 1. 公式発表の日付を必ず特定
web_fetch url=[公式ブログ/Developer Portal]
# → 「いつ発表されたか」を published_at に正確に記録

# 2. 公式Xアカウントの発表を確認
web_search query="from:[公式アカウント] pricing OR 料金 OR announcement" freshness=pm

# 3. 日本語メディアの報道で追加情報を確認
web_search query="[サービス名] site:gigazine.net OR site:itmedia.co.jp OR site:watch.impress.co.jp" freshness=pm
```

**⚠️ 料金変更系ニュースの必須確認項目:**

| 項目 | 確認内容 |
|------|----------|
| **発表日** | 公式発表の正確な日付(「〇月〇日」) |
| **ステータス** | Pilot/Beta/正式の区別 |
| **適用日** | いつから有効か(発表日≠適用日の場合あり) |
| **移行措置** | 既存ユーザーへの対応(猶予期間、バウチャー等) |

**❌ 禁止事項:**
- 「Pilot発表」を「正式リリース」と混同
- 発表日を確認せずに古い情報を記事化
- 日本語メディアの追加報道を無視

### Step 3b: 類似サービス名の区別(2026-02-18追加)

**以下のような類似サービス名は別物として扱う:**

| 混同しやすい組み合わせ | 違い |
|----------------------|------|
| **FigJam** vs **Figma** | FigJam=ホワイトボード/ダイアグラム、Figma=デザインツール |
| **Claude** vs **Claude Code** | Claude=チャット/API、Claude Code=CLI開発ツール |
| **GitHub** vs **GitHub Copilot** | GitHub=リポジトリ、Copilot=AI補完 |
| **Cursor** vs **VS Code** | Cursor=AIエディタ、VS Code=ベースエディタ |

**⚠️ 関連事例を収集する際の必須チェック:**

1. **公式発表の「具体的機能」を明確化**
   - 何が入力で、何が出力か
   - どのプラットフォームで動作するか
   - 対象ユーザーは誰か

2. **関連事例との照合**
   - 事例が使っているのは公式発表と「同じ機能」か
   - 「同じエコシステム」だけでは不十分
   - 機能の方向(入力→出力)が一致しているか

3. **不明な場合の対処**
   - 「関連技術」として明確に区別して記載
   - 「公式発表の機能とは異なる」と明記

**例:FigJam連携の場合**

```
公式発表: Claude → FigJamダイアグラム生成
         (チャットからダイアグラムを作る)

❌ 誤った関連事例:
   - Figma MCP連携(Figmaデザイン→コード変換)
   - Cline + Claude(FigmaプレビューURLからコンポーネント生成)
   → これらは「Figma連携」であり「FigJam連携」ではない

✅ 正しい関連事例:
   - FigJam Connectorの実践レポート(同じ機能)
   - なければ「日本語での実践レポートはまだ少ない」と記載
```

---

### Step 4: 構造化データ作成

各候補を以下の形式で記録:

```json
{
  "edition": "morning",
  "target_date": "2026-02-12",
  "title": "Claude Connectors が無料ユーザーに開放",
  "summary": "Anthropicは2月11日、有料プラン限定だったConnectors機能を無料ユーザーにも開放すると発表。",
  "source_url": "https://www.macrumors.com/2026/02/11/anthropic-claude-more-free-features/",
  "source_name": "MacRumors",
  "published_at": "2026-02-11T15:00:00Z"
}
```

### Step 5: 自動ソース検出・登録(Phase 4: 運用最適化)

**新機能:** 記事作成時に自動でソース情報を検出・分類・登録

```bash
# ソースメンテナンススクリプト使用
cd /Users/satokeita/Dev/ai-navigator
node scripts/source-detection-helper.mjs --url=[記事URL]
```

**実行内容:**
1. **ソース自動分類** - URLパターンでprimary/secondary/tertiary判定
2. **信頼度算出** - ソースタイプ・ドメイン特性で1-10スコア計算
3. **DB自動登録** - `sources`テーブルに新規ソース追加
4. **記事紐づけ** - `primary_source_id`, `source_credibility_score`設定

**ソース分類例:**
```json
{
  "openai.com/blog": {"type": "primary", "score": 10, "level": "official"},
  "techcrunch.com": {"type": "secondary", "score": 7, "level": "editorial"},
  "reddit.com": {"type": "tertiary", "score": 6, "level": "community"}
}
```

### Step 6: DB保存

```bash
# Supabase CLIまたはAPIで保存(ソース情報含む)
supabase-operations action=insert table=news_candidates data=[構造化データ+ソース情報]
```

---

## 品質基準

| 項目 | 基準 |
|------|------|
| 候補数 | 8〜15件 |
| 一次ソース率 | 100%(二次ソースのみは除外) |
| 発表日確認率 | 100% |
| 期間適合率 | 100%(期間外は除外) |
| テーブルレイアウト | 汎用CSSで正常表示 |

---

## テーブル作成ガイドライン

CSSは `table-layout: auto` で**コンテンツに応じた自動幅**を採用。

### 原則

- **固定nth-child指定を避ける** — テーブル構造に依存しない汎用CSS
- **短いセルは短く** — 数値・スコアは自然に狭くなる
- **長いセルは長く** — URL・説明文は自動で広がる

### ソースリスト表の列設計

| # | ソース名 | URL | 種類 | 信頼度 | 要点 |
|---|---------|-----|------|--------|------|
| 数値(狭) | テキスト(中) | URL(広) | 短単語(狭) | ★記号(狭) | テキスト(広) |

### 確認事項

- [ ] 各列の幅がコンテンツに適している
- [ ] 短い単語(#, 種類, 信頼度)が改行されていない
- [ ] URL列・要点列が十分な幅を持っている

---

## 完了条件

- [ ] 8〜15件の候補を収集
- [ ] 全候補に一次ソースURLあり
- [ ] 全候補に発表日(published_at)あり
- [ ] 全候補が対象期間内
- [ ] `news_candidates` テーブルに保存完了

---

## 次のスキル

→ **news-evaluation**: 収集した候補の評価・選定
---
name: org-chart
description: AIチーム組織体制図(ポンチ絵)の生成・更新・公開。HTMLで組織構成・cronジョブ・スキル/サブエージェント関係・コミュニケーションライン・ワークフローを可視化する。「体制図更新」「組織図」「ポンチ絵」「org-chart」「チーム構成の可視化」などの作業に使う。日次の自動更新(Obsidian日次レビューcronに組み込み済み)でも使われる。
---

# 組織体制図(org-chart)管理スキル

## ファイル構成

- **HTML本体:** `/Users/satokeita/product-hub/docs/org-chart.html`
- **リポジトリ:** `ksato8710/product-hub`(GitHub Pages: `docs/` ディレクトリ)
- **公開URL:** `https://ksato8710.github.io/product-hub/org-chart.html`
- **旧Gist:** `ffafc268d7176bf9303cd12cdcd059c7`(参考用、今後はproduct-hubを使用)
- **テンプレート:** [references/template-structure.md](references/template-structure.md)

## 更新手順

### 1. 現状データ収集
```bash
# cronジョブ一覧
cron list

# エージェント一覧
sessions_list
```
必要に応じて stevens/torishima/nemo のメモリや SOUL.md も確認。

### 2. 差分チェック
`/Users/satokeita/clawd/public/org-chart.html` を読み、以下を実態と比較:
- エージェント構成(追加・削除・役割変更)
- cronジョブ(スケジュール変更・新規・削除・エージェント移管)
- スキル/サブエージェント紐付け(torishima配下の変更)
- コミュニケーションライン(報告頻度・手段の変更)
- 運営サイト情報(記事数・ステータス変更)

### 3. HTML更新
差分がある場合のみ更新。更新時の注意:
- デザインシステムは [references/template-structure.md](references/template-structure.md) を参照
- フッターの `Last updated` 日時を更新
- セクション構成を変えない(順序: 組織図→サイト→Cron→ワークフロー)

### 4. GitHub Pages 公開
```bash
cd /Users/satokeita/product-hub && git add -A && git commit -m "update: org-chart" && git push origin main
```
push するだけで数秒で反映される。

(旧Gistも同期する場合)
```bash
gh gist edit ffafc268d7176bf9303cd12cdcd059c7 docs/essential-navigator/org-chart.html
```

## 体制図のセクション構成

1. **組織ヒエラルキー** — けいた → misato / stevens(並列)→ torishima / nemo(stevens配下)
2. **コミュニケーションライン** — 誰が誰とどう繋がるか(Slack / sessions_send / cron)
3. **運営サイト** — essential-navigator.com / ai.essential-navigator.com
4. **Cronジョブ** — エージェント別に全ジョブ一覧(保守系は別枠)
5. **ワークフロー** — 記事作成パイプライン(サブエージェント+スキル紐付き)

## 設計原則

- **misato と stevens は並列**(けいたが両方に直接コミュニケーション)
- **torishima / nemo は stevens 配下**(stevensの緑ボーダー枠内にネスト)
- **スキル↔サブエージェント紐付け**を明示(Torishimaカード内にマッピング表)
- **cronは実態を正確に反映**(スケジュール・ジョブ数・報告先)
- **ダークテーマ**、エージェントごとにカラー分け:
  - misato: 紫 (#d494ff)
  - stevens: 緑 (#6edca0)
  - torishima: オレンジ (#ffb43c)
  - nemo: 青 (#3ca0ff)
  - けいた: 青白 (#7ba4ff)
---
name: overnight-build
description: "Claude Codeをバックグラウンドで長時間走らせて、プロダクトを一晩でビルドするワークフロー。起動、cron定期監視、Slackスレッド報告、エラー対処、完了通知を含む。夜間ビルド、自動ビルド、バックグラウンドビルドに使う。"
---

# Overnight Build

Claude Codeを一晩走らせてプロダクトをビルドし、自動監視するスキル。

## 前提

- プロジェクト初期セットアップ済み(`project-init`スキル参照)
- Claude Codeがインストール済み、認証済み

## ワークフロー

### 1. Claude Code 起動

```
exec pty:true background:true workdir:<project-dir> timeout:14400 command:"claude --dangerously-skip-permissions '<タスクプロンプト>

完了したら以下のコマンドを実行して通知:
openclaw gateway wake --text \"<完了メッセージ>\" --mode now'"
```

**重要パラメータ:**
- `pty: true` — 必須。Claude Codeはインタラクティブターミナルアプリ
- `background: true` — バックグラウンド実行
- `timeout: 14400` — 4時間(必要に応じて調整)
- `--dangerously-skip-permissions` — 権限確認をスキップ(自動実行用)

**プロンプトのコツ:**
- フェーズ分けして順番に指示
- 各フェーズ完了時にgit commitさせる
- 最後にgit pushさせる
- `openclaw gateway wake` で完了通知させる

### 2. 定期監視 cron ジョブ設定

```json
{
  "action": "add",
  "job": {
    "name": "claude-code-monitor",
    "schedule": { "kind": "every", "everyMs": 300000 },
    "sessionTarget": "main",
    "wakeMode": "now",
    "payload": {
      "kind": "systemEvent",
      "text": "【自動監視】Claude Codeセッション <sessionId> の進捗を確認して。process action:log sessionId:<sessionId> で最新ログを取得し判断: 1.まだ動いてるか 2.入力待ちで止まってないか 3.エラーで止まってないか。動いてたらSlackに短い進捗報告。止まってたらSlackに報告して対処。完了してたらcronジョブ claude-code-monitor を削除。"
    }
  }
}
```

### 3. Slackスレッド固定報告

特定スレッドに報告を集約する:

```json
{
  "action": "send",
  "channel": "slack",
  "target": "<channelId>",
  "threadId": "<threadTs>",
  "message": "📊 進捗報告: Phase X 完了..."
}
```

### 4. 監視時の判断基準

**ログから読み取る状態:**
| 表示 | 状態 |
|------|------|
| `Musing…` / `Percolating…` | 考え中(正常) |
| ツール実行ログ | 作業中(正常) |
| `❯` プロンプトのみ | 入力待ち(要対処) |
| `API Error` | エラー(要対処) |

**入力待ちの場合:**
```
process action:submit sessionId:<id> data:"yes"
```

**認証エラーの場合:**
- セッションをkill
- ユーザーに `claude /login` を依頼
- 再起動

### 5. 完了時

1. cronジョブ削除: `cron action:remove jobId:claude-code-monitor`
2. git log確認で成果物チェック
3. Slackに最終報告

## よくあるエラーと対処

| エラー | 対処 |
|--------|------|
| OAuth token expired (401) | kill → ユーザーに `/login` 依頼 → 再起動 |
| プロセスタイムアウト | timeout値を増やして再起動 |
| ビルドエラーでループ | ログ確認 → submit で方針指示 |

## ⚠️ よくあるミスと防止策

### 1. HEARTBEAT.mdが空 → cronのsystemEventがスキップされる
`sessionTarget: "main"` のcronジョブはheartbeat経由で実行される。
HEARTBEAT.mdが空だと `lastError: "empty-heartbeat-file"` でスキップされる。

**対策**: 起動前にHEARTBEAT.mdに内容があることを確認。なければ追記:
```markdown
## 定期タスク
- cronジョブからのsystemEventを処理する
```

### 2. cronパラメータの形式ミス
正確な形式を守ること。特に以下に注意:
- `sessionTarget`: 文字列 `"main"` (オブジェクトではない)
- `payload.kind`: `"systemEvent"` (`"wake"` ではない)
- `payload.text`: テキストフィールド名は `text`(`message` ではない)
- `schedule.kind`: `"every"` / `"at"` / `"cron"` のいずれか

## 起動前チェックリスト

- [ ] `claude --version` で認証確認(401出ないか)
- [ ] プロジェクトディレクトリにCLAUDE.mdがあるか
- [ ] **HEARTBEAT.mdが空でないか確認**(空なら内容追記)
- [ ] `--dangerously-skip-permissions` で起動
- [ ] cron監視ジョブを設定(上記パラメータ形式を厳守)
- [ ] Slack報告先スレッドのthreadIdを控えた
- [ ] 完了通知に `openclaw gateway wake` を含めた
# Product Writer Skill

AI Solo Builder のプロダクト辞書ページを作成・更新するスキル。

## 使用タイミング

- 新規プロダクトページの作成
- 既存プロダクトページの品質改善
- 「プロダクト記事作成」「製品ページ追加」「product更新」などの作業

## リファレンス

- **ベンチマークサイト**: `references/BENCHMARKS.md`
  - SaaS Product Page Best Practices(Webstacks)
  - There's an AI for That(AIツールディレクトリ)
  - G2 / Capterra(レビューサイト)
  - 詳細レビュー記事の構成例

## 品質基準(4段階)

### Tier 1: 必須(これがないと低品質)
| # | 項目 | 説明 |
|---|------|------|
| 1 | 基本情報テーブル | `| 項目 | 詳細 |` 形式で種別・開発元・料金を記載 |
| 2 | 概要説明 | 「〜とは?」セクションでプロダクトを具体的に説明 |
| 3 | 主要機能 | 3項目以上のサブセクション(`###`)で機能を説明 |
| 4 | 料金プラン | 無料/有料プラン、価格帯を明記 |
| 5 | 公式リンク | 公式サイトへのリンク |

### Tier 2: 中品質(標準レベル)
| # | 項目 | 説明 |
|---|------|------|
| 6 | ソロビルダー向け活用 | 具体的なユースケースを記載 |
| 7 | 注意点・制限 | プロダクトの限界、デメリット |
| 8 | 競合比較 | 類似ツールとの比較表 |

### Tier 3: 高品質(差別化要素)
| # | 項目 | 説明 |
|---|------|------|
| 9 | ユーザーの声 | Reddit/HN等からの引用(3-5件) |
| 10 | Pros/Cons | メリット10+、デメリット5+ |
| 11 | FAQ/Q&A | よくある質問5-10問 |
| 12 | 関連ニュース | 関連ニュース記事へのリンク |

### Tier 4: 最高品質(業界トップレベル)
| # | 項目 | 説明 |
|---|------|------|
| 13 | Getting Started | 5ステップの始め方ガイド |
| 14 | ターゲットユーザー | ペルソナ別の適性(非エンジニア/創業者/デザイナー/開発者) |
| 15 | 総合スコア | ⭐評価(プロトタイプ速度、学習コスト等) |
| 16 | ワークフロー図解 | 使用手順の可視化 |
| 17 | コミュニティリンク | Discord/フォーラム/サポート |
| 18 | APIドキュメント | 開発者向けリソース |

## 品質ランク

| ランク | Tier達成 | 目安 |
|--------|----------|------|
| 最高品質 | Tier 1-4すべて | lovable.md(改善後) |
| 高品質 | Tier 1-3 | claude.md, bolt-new-ai-app-builder.md |
| 中品質 | Tier 1-2 | 大半のプロダクトページ |
| 低品質 | Tier 1のみ | 最低ライン |

## 最高品質テンプレート

```markdown
---
title: "プロダクト名 — 一言説明"
slug: product-slug
date: "YYYY-MM-DD"
contentType: "product"
type: product
description: "SEO用の説明文(120-160文字)"
readTime: 8
tags: ["ai-coding"]
image: "https://images.unsplash.com/photo-xxx?w=800&h=420&fit=crop"
---

> 最終情報更新: YYYY-MM-DD

| 項目 | 詳細 |
|------|------|
| 種別 | カテゴリ |
| 開発元 | 会社名 / 国 |
| 料金 | 無料版 / $XX/月 |
| 評価 | ⭐4.7/5(G2/Product Hunt等) |
| 利用者規模 | 推定ユーザー数 |

## プロダクト名とは?

2-3段落で概要説明。何ができるか、どんな特徴があるか、なぜ注目されているか。

## こんな人におすすめ

| ターゲット | 適性 | 理由 |
|------------|------|------|
| 非エンジニア | ⭐⭐⭐ | コード不要で〜 |
| スタートアップ創業者 | ⭐⭐⭐ | MVP構築が〜 |
| デザイナー | ⭐⭐ | Figmaから〜 |
| 経験豊富な開発者 | ⭐⭐ | フロント生成で〜 |

## 主要機能

### 機能1
説明...

### 機能2
説明...

### 機能3
説明...

## 使い方(Getting Started)

1. **サインアップ**: 公式サイトでアカウント作成
2. **プロジェクト作成**: 新規プロジェクトを開始
3. **プロンプト入力**: 作りたいものを自然言語で記述
4. **生成・調整**: AIが生成したものを微調整
5. **デプロイ**: ワンクリックで公開

## 料金プラン

| プラン | 月額 | 内容 |
|--------|------|------|
| 無料 | $0 | 基本機能、制限あり |
| Pro | $XX | 追加機能 |
| Team | $XX | チーム機能 |

## Pros(メリット)

- ✅ メリット1
- ✅ メリット2
- ✅ メリット3
...(10項目以上)

## Cons(デメリット)

- ⚠️ デメリット1
- ⚠️ デメリット2
...(5項目以上)

## ユーザーの声

> **「実際のユーザーコメント引用」**
> — Reddit r/xxx

> **「別のユーザーコメント引用」**
> — Hacker News

## FAQ

### Q: よくある質問1?
A: 回答...

### Q: よくある質問2?
A: 回答...

## 競合比較

| プラットフォーム | 価格 | 特徴 |
|-----------------|------|------|
| **このプロダクト** | $XX/月 | 特徴 |
| 競合A | $XX/月 | 特徴 |
| 競合B | $XX/月 | 特徴 |

## ソロビルダー向けの使いどころ

### ユースケース1
具体的な活用シーン...

### ユースケース2
具体的な活用シーン...

## 注意点・制限

- 制限事項1
- 制限事項2

## 公式リンク

- 公式サイト: https://example.com/
- ドキュメント: https://docs.example.com/
- コミュニティ: https://discord.gg/xxx

---

## 📰 関連ニュース

- [関連ニュース記事タイトル](/news/slug)(YYYY年MM月DD日)
```

## タグリスト(18カテゴリ)

### 開発系
- `ai-coding` - AIコード補完・生成
- `ai-ide` - AI統合開発環境
- `ai-agent` - 自律型AIエージェント
- `developer-tools` - 開発者ツール全般
- `automation` - 自動化ツール

### クリエイティブ系
- `ai-image` - AI画像生成
- `ai-video` - AI動画生成
- `ai-audio` - AI音声生成
- `ai-design` - AIデザインツール

### 生産性系
- `ai-writing` - AIライティング支援
- `ai-chat` - 対話型AI
- `ai-search` - AI検索エンジン
- `ai-productivity` - 生産性向上ツール
- `ai-meeting` - 会議支援AI
- `ai-presentation` - プレゼン作成AI

### ビジネス系
- `ai-marketing` - マーケティングAI
- `ai-data` - データ分析AI
- `no-code` - ノーコード開発

## 品質チェックコマンド

```bash
cd /Users/satokeita/Dev/ai-navigator
bash scripts/evaluate-products.sh | grep "プロダクトslug"
```

## ワークフロー

### 新規作成(最高品質を目指す場合)
1. テンプレートをコピー
2. 公式サイト・ドキュメントを調査
3. Reddit/HN でユーザーの声を収集(3-5件)
4. Pros/Cons を整理(10+/5+)
5. FAQを5-10問作成
6. 全項目を埋める
7. `npm run validate:content` 実行

### 既存改善
1. `evaluate-products.sh` でスコア確認
2. 現在のTierを特定
3. 次のTierに必要な項目を追加
4. 再度スコア確認

## 参照

- プロダクトディレクトリ: `/Users/satokeita/Dev/ai-navigator/content/products/`
- 評価スクリプト: `/Users/satokeita/Dev/ai-navigator/scripts/evaluate-products.sh`
- ベンチマークサイト: `references/BENCHMARKS.md`
- 最高品質サンプル: `lovable.md`(2026-02-16更新後)
---
name: project-init
description: "SDD対応プロジェクトの初期セットアップ。Git/GitHubリポジトリ作成、.claude/ディレクトリ構成(agents, commands, hooks, skills, settings.json)、CLAUDE.md、README.md の雛形生成。新しいプロジェクトを始めるときに使う。"
---

# Project Init

新しいプロジェクトのSDD対応初期セットアップを行うスキル。

## ワークフロー

### 1. プロジェクトディレクトリ作成

```bash
mkdir -p /Users/satokeita/dev/<project-name>
cd /Users/satokeita/dev/<project-name>
git init && git branch -m main
```

### 2. CLAUDE.md 作成

以下を含む:
- プロジェクト概要(ユーザー、提供価値、ユースケース)
- アーキテクチャ構成
- 技術スタック
- 開発コマンド
- SDD ワークフロー説明

### 3. .claude/ ディレクトリ構成

```
.claude/
├── settings.json       # hooks設定
├── agents/             # サブエージェント定義
├── commands/           # カスタムコマンド(sdd-workflow等)
├── hooks/              # セッション開始、pre/post実装チェック
└── skills/             # プロジェクト固有スキル
```

#### settings.json テンプレート

```json
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{ "type": "command", "command": ".claude/hooks/pre-implementation-check.sh" }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{ "type": "command", "command": ".claude/hooks/post-spec-update.sh" }]
      }
    ],
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hooks": [{ "type": "command", "command": ".claude/hooks/session-start.sh" }]
      }
    ]
  }
}
```

#### 必須 hooks

- **session-start.sh**: SDD状態サマリー表示(specs数、ブランチ情報)
- **pre-implementation-check.sh**: Write/Edit前のSpec存在確認
- **post-spec-update.sh**: Write/Edit後の通知

#### agents テンプレート

プロジェクトの技術スタックに応じて作成。各agentに:
- name, description, model, color
- 専門領域、プロジェクト構成理解、開発原則、品質チェックリスト

### 4. GitHubリポジトリ作成

```bash
git add -A && git commit -m "Initial commit: <project-name> project setup"
gh repo create <project-name> --private --source=. --push
```

### 5. README.md

プロジェクト概要、技術スタック、評価領域などを記載。

## 参考プロジェクト

history-quiz-appの.claude/構成: `/Users/satokeita/dev/history-quiz-app/.claude/`

## 注意事項

- プロジェクトディレクトリは `/Users/satokeita/dev/` 配下に作成
- GitHubリポジトリはデフォルトprivate
- hooksスクリプトには `chmod +x` を忘れずに
---
name: publish-gate
description: "AI Solo Builder用の公開ゲートスキル。チェックリスト照合、publish:gate実行、デプロイ確認まで。「公開チェック」「デプロイ」「publish:gate」などの作業に使う。"
---

# publish-gate — 公開ゲートスキル

## 概要

`digest-writer` で作成した記事を公開する前の最終チェックと実行。

**このスキルの責務:**
- チェックリスト照合
- `npm run publish:gate` 実行
- Git push & デプロイ確認
- Slack報告

**入力:**
- 作成済みの記事ファイル

**出力:**
- 本番サイトへの公開
- Slack完了報告

---

## 前提

記事作成スキル(`digest-writer` / `individual-article` / `article-writer`)が完了していること。

---

## 手順

### Step 0: 画像エンリッチメント(必須)

**⚠️ 公開前に必ず実行する。記事内に公式画像を追加して品質を向上させる。**

スキル: `~/.openclaw/skills/article-image-enricher/SKILL.md`

**対象記事:**
- 今回作成した全てのニュース記事(Digest含む)
- 記事内に外部リンク(公式サイト等)がある記事

**実行手順:**

```bash
# 1. 記事内の公式サイトリンクを特定
grep -oE 'https?://[^)]+' content/news/YYYY-MM-DD-*.md | grep -v unsplash | grep -v github.com/ksato

# 2. 各公式サイトから画像URLを取得
curl -s <公式サイトURL> | grep -oE 'https?://[^"]+\.(png|jpg|jpeg|webp)' | head -10

# 3. 画像を確認・選定(imageツール)
image(url, "この画像の内容を説明してください")

# 4. 画像URL有効性確認
curl -sI "<画像URL>" | head -5  # HTTP/2 200 を確認

# 5. 記事に追加
# フォーマット:
# ![説明テキスト](画像URL)
# *出典: [サイト名](サイトURL)*
```

**追加位置:**
- 「## 概要」の直下(本文の最初)
- プロダクト紹介の見出し直下

**スキップ条件:**
- 既に公式画像が追加済みの記事
- 公式サイトがSPA等で画像取得困難な場合

| 項目 | 確認 |
|------|------|
| Top3個別記事に公式画像を追加した | □ |
| 画像URLが有効(200 OK) | □ |
| 出典リンクを明記した | □ |

---

### Step 1: チェックリスト照合

**Frontmatter確認:**

```bash
# 各記事ファイルを確認
cat content/news/YYYY-MM-DD-*.md | head -30
```

| 項目 | 確認 |
|------|------|
| `contentType` が正しい | □ |
| Digestに `digestEdition` あり | □ |
| `readTime` が数値 | □ |
| `featured` が boolean | □ |
| `image` が設定済み | □ |
| `image` が `/thumbnails/` 形式(Unsplashではない) | □ |
| `relatedProducts` が配列 | □ |

**サムネイル確認:**

```bash
# サムネイルが生成されているか確認
ls public/thumbnails/ | grep "[slug]"

# Unsplash画像が残っていないか確認(警告)
grep -l "unsplash.com" content/news/YYYY-MM-DD-*.md && echo "⚠️ Unsplash画像が残っています"
```

**構造確認(Digestのみ):**

| 項目 | 確認 |
|------|------|
| `## 🏁 重要ニュースランキング(NVA)` あり | □ |
| Top10ランキング表あり | □ |
| `## 🔥 Top 3 ピックアップ` あり | □ |
| Top3リンク先が存在する | □ |

**テーブルレイアウト確認:**

| 項目 | 確認 |
|------|------|
| 各テーブルが異なる列構造でも正常表示 | □ |
| 短いセル(数値/スコア/軸)が過度に広がらない | □ |
| 長いセル(説明/理由/ニュース)が狭すぎて改行過多にならない | □ |
| 短い単語(「合計」等)が改行されていない | □ |

**リンク確認:**

```bash
# 内部リンクの存在確認
grep -oE '\(/news/[^)]+\)' content/news/YYYY-MM-DD-*.md | while read link; do
  slug=$(echo $link | sed 's|(/news/||;s|)||')
  if [ ! -f "content/news/*-${slug}.md" ]; then
    echo "❌ 404: $link"
  fi
done

# プロダクトリンクの存在確認
grep -oE '\(/products/[^)]+\)' content/news/YYYY-MM-DD-*.md | while read link; do
  slug=$(echo $link | sed 's|(/products/||;s|)||')
  if [ ! -f "content/products/${slug}.md" ]; then
    echo "❌ 404: $link"
  fi
done
```

**ソース整合性チェック(Phase 4: 運用最適化):**

```bash
# 記事のソース情報整合性確認
cd /Users/satokeita/Dev/ai-navigator

# 各記事のソース情報をチェック
for file in content/news/YYYY-MM-DD-*.md; do
  echo "チェック中: $file"
  
  # primary_source_idがsourcesテーブルに存在するか確認
  source_id=$(grep "primary_source_id:" $file | cut -d'"' -f2)
  if [ -n "$source_id" ]; then
    node -e "
      const { createClient } = require('@supabase/supabase-js');
      const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY);
      supabase.from('sources').select('id').eq('id', '$source_id').then(result => {
        if (result.data && result.data.length > 0) {
          console.log('✅ ソースID有効: $source_id');
        } else {
          console.log('❌ ソースID無効: $source_id');
        }
      });
    "
  fi
  
  # 信頼度スコアが適切な範囲か確認
  score=$(grep "source_credibility_score:" $file | awk '{print $2}')
  if [ -n "$score" ] && (( $(echo "$score < 1.0 || $score > 10.0" | bc -l) )); then
    echo "❌ 信頼度スコア範囲外: $score"
  else
    echo "✅ 信頼度スコア適正: $score"
  fi
done
```

| 項目 | 確認 |
|------|------|
| `primary_source_id` が `sources` テーブルに存在 | □ |
| `source_credibility_score` が 1.0〜10.0 範囲内 | □ |
| `source_verification_note` が設定済み | □ |
| 記事内ソースURLとDB登録ソースが一致 | □ |

### Step 2: publish:gate 実行

```bash
cd /Users/satokeita/Dev/ai-navigator
npm run publish:gate
```

**成功条件:**
- `validate:content` ✅
- `sync:content:db` ✅
- `build` ✅

**失敗時:**
- エラーメッセージを確認
- 該当箇所を修正
- 再実行

### Step 3: Git push

```bash
git add -A
git commit -m "publish: YYYY-MM-DD [morning/evening]"
git push origin main
```

### Step 3a: CI成功確認(必須)

**⚠️ CIが成功しないとデプロイされない。必ず確認する。**

```bash
cd /Users/satokeita/Dev/ai-navigator

# GitHub Actionsの最新実行結果を確認
gh run list --limit 3

# 最新runがsuccessでない場合はログを確認
gh run view <run-id> --log-failed
```

| 状況 | 対処 |
|------|------|
| `success` | Step 4へ進む |
| `failure` | ログを確認し、エラーを修正して再push |
| `in_progress` | 完了まで待機(最大2分) |

**よくあるCI失敗原因:**
- 環境変数未設定(例: RESEND_API_KEY)
- TypeScriptエラー
- ビルドエラー

### Step 4: デプロイ確認(URL fetch + 表示確認)

#### 4-0: URL存在確認(必須)

**⚠️ これを飛ばすと「ページが存在しません」と言われる。必ず実行する。**

```python
# web_fetch で各URLが200を返すか確認
web_fetch url=https://ai.essential-navigator.com/news/[digest-slug] maxChars=500
web_fetch url=https://ai.essential-navigator.com/news/[top1-slug] maxChars=500
web_fetch url=https://ai.essential-navigator.com/news/[top2-slug] maxChars=500
web_fetch url=https://ai.essential-navigator.com/news/[top3-slug] maxChars=500
```

| 結果 | 対処 |
|------|------|
| status: 200 | 次へ進む |
| status: 404 | CIを再確認、DBを確認、ファイルを確認 |
| その他エラー | Vercelステータス確認 |

#### 4-1: PC表示確認(1920×1080)

```javascript
// ブラウザでPC幅に設定
browser action=act profile=clawd request={"kind": "resize", "width": 1920, "height": 1080}
browser action=open profile=clawd targetUrl=https://ai.essential-navigator.com/news/[digest-slug]
browser action=screenshot  // PC版スクリーンショット
```

**PC確認項目:**
- [ ] ページが正常表示
- [ ] **記事コンテンツが中央に収まっている(横に間延びしていない)**
- [ ] **テーブルの各列幅が適切(順位/NVA/Tierが狭く、ニュースが広い)**
- [ ] サムネイル画像が表示
- [ ] Top3リンクが機能
- [ ] NVAランキング表が表示

#### 4-2: モバイル表示確認(375×812 iPhone風)

```javascript
// ブラウザでモバイル幅に設定
browser action=act profile=clawd request={"kind": "resize", "width": 375, "height": 812}
browser action=navigate profile=clawd targetUrl=https://ai.essential-navigator.com/news/[digest-slug]
browser action=screenshot  // モバイル版スクリーンショット
```

**モバイル確認項目:**
- [ ] **テーブルが画面幅に収まっている(横はみ出しなし)**
- [ ] **カードレイアウトで各項目にラベルが表示されている**
- [ ] **順位バッジが見やすい(Top3は金銀銅)**
- [ ] リンクテキストが適切に折り返されている
- [ ] タップ領域が十分な大きさ

#### 4-3: 問題発見時の対処

| 問題 | 対処 |
|------|------|
| PC横に間延び | `.article-container` クラス適用を確認 |
| テーブル列幅不正 | globals.cssの列幅設定を確認 |
| モバイルはみ出し | globals.cssのカード変換CSSを確認 |
| ラベル未表示 | ArticleContent.tsxのdata-label注入を確認 |

### Step 5: X投稿

**⚠️ このステップは `x-publisher` スキルを使用する。**

スキル: `~/.openclaw/skills/x-publisher/SKILL.md`

publish-gate完了後、x-publisherスキルに従ってX投稿を実行する。

---

### Step 6: Slack報告

#### 6-0: 投稿先判定(必須)

**⚠️ 話題が異なるスレッドに報告しない。必ず判定する。**

| 状況 | 投稿先 | 方法 |
|------|--------|------|
| cron実行(朝刊/夕刊の定期運用) | #tifa **新規投稿** | `sessions_spawn` で独立セッションから投稿 |
| 依頼対応(けいたさんからの記事依頼) | **依頼元スレッドに返信** | 通常のスレッド返信 |

**判定基準:**
- 現在のセッションがスレッドに紐づいている → そのスレッドの話題を確認
- スレッドの話題 = 今回の公開内容 → スレッド返信OK
- スレッドの話題 ≠ 今回の公開内容 → 新規投稿にする

#### 6-1: 報告内容

```
✅ [朝刊/夕刊] 公開完了

📊 作成内容:
- Digest: 1本
- News: 3本
- Product: X件作成/更新

🔍 品質チェック:
- サムネイル: 全記事設定済み ✅
- 画像重複: なし ✅
- Top10期間: 適切 ✅
- 一次ソース: 全記事明記 ✅

🔗 公開URL:
- https://ai.essential-navigator.com/news/morning-news-2026-02-12
- https://ai.essential-navigator.com/news/[top1-slug]
- https://ai.essential-navigator.com/news/[top2-slug]
- https://ai.essential-navigator.com/news/[top3-slug]

🐦 X投稿:
- https://x.com/kt_labs/status/XXXXX
```

---

## エラー対処

### validate:content 失敗

```
エラー例: "readTime must be a number"
対処: frontmatterの readTime: "8" → readTime: 8 に修正
```

### sync:content:db 失敗

```
エラー例: "duplicate key value violates unique constraint"
対処: slugの重複を確認・修正
```

### build 失敗

```
エラー例: "Cannot find module"
対処: npm install 実行後に再試行
```

---

## 完了条件

- [ ] チェックリスト全項目クリア
- [ ] `npm run publish:gate` 成功
- [ ] `git push` 完了
- [ ] **CI成功確認** ← 必須(`gh run list` で success 確認)
- [ ] **URL存在確認** ← 必須(`web_fetch` で全URL 200 確認)
- [ ] デプロイ確認完了(PC + モバイル表示)
- [ ] **X投稿完了** ← `x-publisher` スキル使用
- [ ] Slack報告完了

---

## 関連ドキュメント

- チェックリスト詳細: `/Users/satokeita/Dev/ai-navigator/docs/CHECKLIST.md`
- コンテンツポリシー: `/Users/satokeita/Dev/ai-navigator/specs/content-policy/spec.md`
---
name: quiz-creator
description: 中学受験特化の日本史クイズを作成し、Supabaseデータベースに登録する。5段階難易度フレームワーク・学習指導要領準拠。「クイズ作成」「問題追加」「歴史クイズ」「中学受験対策」などの作業に使う。
---

# Quiz Creator — 中学受験特化 日本史クイズ作成スキル

ChuzyuQuiz-歴史アプリ用のクイズを作成・登録するスキル。

---

## 🚨 最重要制約: 中学受験範囲厳守(2026-02-18 けいた様指示)

**本アプリの目的は中学受験である。中学受験に出てこない内容は絶対に問題にしてはいけない。**

### 判断基準
- **許可**: 小学校学習指導要領(第6学年 社会科 歴史)に含まれる内容
- **許可**: 中学入試で実際に出題される内容(過去問で確認できるもの)
- **禁止**: 高校日本史レベルの詳細、大学受験レベルの内容
- **禁止**: 学習指導要領に明記されていない出来事・人物・年号

### 具体的な禁止例
- 承久の乱の詳細な経過(後鳥羽上皇の挙兵自体は可、詳細は不可)
- 島原・天草一揆の詳細な経過(キリスト教禁止政策の結果として触れる程度は可)
- 朝鮮出兵(文禄・慶長の役)の詳細な経過
- 尊王攘夷運動の個別事件の詳細
- 大正デモクラシーの詳細(普通選挙法成立程度は可)
- 学習指導要領42人物以外のマイナー人物

### チェックリスト(問題作成時必須)
- [ ] この内容は学習指導要領に含まれているか?
- [ ] この内容は中学入試の過去問で出題されているか?
- [ ] 小学6年生が学ぶ範囲を超えていないか?
- [ ] 「知っていたら差がつく」ではなく「知らないと困る」内容か?

**迷ったら出題しない。中学受験範囲の確実な内容のみを問題にすること。**

---

## 1. 概要・目的

- **対象**: 中学受験を控えた小学生(主に5-6年生)
- **内容**: 日本の歴史(小学校学習指導要領 第6学年 社会科準拠)
- **品質基準**: 実際の中学入試に出題されるレベル — 日能研偏差値40〜65+まで5段階でカバー
- **目標**: 800問+のクイズプール構築(現在452問 → 新基準505問+既存分を段階的に拡充)
- **設計思想**: 同じテーマを難易度別に展開し、基礎固めから御三家対策までシームレスに学習できる構造

---

## 2. 難易度フレームワーク(5段階)

### Lv1 — 基礎知識(目標正答率 90%+)

| 項目 | 内容 |
|------|------|
| レベル感 | 学習指導要領の指定42人物の名前を答えるレベル |
| 知識の種類 | 教科書の太字に書いてある内容の直接的な再生 |
| 問い方 | 単純な一問一答「〜は誰?」「〜を何という?」 |
| 対応校 | 日能研偏差値40台の学校 |
| 選択肢設計 | 明らかに違うものを混ぜてOK。迷わせない |

**例**: 「鎌倉幕府を開いたのは誰?」→ 源頼朝

### Lv2 — 標準(目標正答率 70-90%)

| 項目 | 内容 |
|------|------|
| レベル感 | 教科書レベルの因果関係を理解している |
| **状態定義** | **Lv2をすべてクリアできれば、教科書に書いてあることの大半は網羅している** |
| 問い方 | 「なぜ」「何のために」が入る。選択肢に紛らわしいものあり |
| 対応校 | 日能研偏差値50台の学校 |
| 選択肢設計 | 同時代・同カテゴリの紛らわしい選択肢を1つ入れる |

**例**: 「参勤交代の目的は?」→ 大名の経済力・軍事力を弱める

### Lv3 — 応用(目標正答率 50-70%)

| 項目 | 内容 |
|------|------|
| レベル感 | 資料集レベル。出来事と出来事の繋がりを問う |
| 問い方 | 比較・関連付け。複数の知識を組み合わせる |
| 対応校 | 日能研偏差値55-60、中堅〜上位校 |
| 選択肢設計 | もっともらしい誤答を複数含める。消去法が必要 |

**例**: 「享保の改革・寛政の改革・天保の改革の共通点は?」→ 幕府財政の立て直し

### Lv4 — 難関(目標正答率 30-50%)

| 項目 | 内容 |
|------|------|
| レベル感 | 御三家・難関校レベル。思考力・推論が必要 |
| 問い方 | 「なぜ〜にも関わらず」「この結果何が変わったか」。選択肢が巧妙 |
| 対応校 | 偏差値60-65、開成・桜蔭等の標準問題 |
| 選択肢設計 | 全選択肢がもっともらしい。正確な理解がないと選べない |

**例**: 「なぜ江戸幕府は鎖国政策をとったのに長崎でオランダとの貿易を続けたのか?」

### Lv5 — 最難関(目標正答率 30%以下)

| 項目 | 内容 |
|------|------|
| レベル感 | 御三家の差がつく問題。過去問のひねった出題に相当 |
| 知識の種類 | 複数時代の横断比較、資料の批判的読解、当時の社会構造への深い理解 |
| 問い方 | 記述相当の思考を4択に変換。「一般的に〜と言われるが、実際には…」 |
| 対応校 | 偏差値65+、開成・灘・筑駒の難問レベル |
| 選択肢設計 | 表面的には正しく見える誤答。深い理解で初めて区別できる |

---

## 3. 同じテーマ × 難易度マトリクス

**核心的な設計思想**: 同じトピックでも問い方・求める思考レベルを変えることで、Lv1〜Lv5まで展開できる。これにより、基礎から積み上げて同じテーマの理解を深められる。

### 例1: テーマ「参勤交代」

| Lv | 問い | 答え |
|----|------|------|
| Lv1 | 参勤交代を制度化した将軍は? | 徳川家光 |
| Lv2 | 参勤交代の主な目的は? | 大名統制(経済力・軍事力を弱める) |
| Lv3 | 参勤交代が結果的に発展させたものは? | 五街道と宿場町 |
| Lv4 | 参勤交代が財政負担になったにも関わらず廃止されなかった理由は? | 幕藩体制の根幹であり、廃止は幕府の支配力低下を意味するため |
| Lv5 | 参勤交代の緩和(文久の改革)が幕末の政治にどう影響したか? | 大名の在国期間が長くなり、雄藩の独自行動が可能に→倒幕運動の加速 |

### 例2: テーマ「聖徳太子」

| Lv | 問い | 答え |
|----|------|------|
| Lv1 | 十七条の憲法を制定したのは誰? | 聖徳太子 |
| Lv2 | 冠位十二階の制度の目的は? | 家柄ではなく才能や功績で人材を登用する |
| Lv3 | 遣隋使の派遣で聖徳太子が目指したことは? | 対等な外交関係の構築と大陸文化の導入 |
| Lv4 | 「日出づる処の天子」の国書が隋の皇帝を怒らせたにも関わらず、なぜ外交は続いたか? | 隋も高句麗との戦争を控え、日本との関係悪化を避けたかった |
| Lv5 | 聖徳太子の政治改革が後の大化の改新にどう繋がったか? | 天皇中心の政治体制の理念を示し、中央集権化の方向性を定めた |

### クイズ作成時の実践ルール
- 1つのテーマにつき、最低2段階(Lv1-2 or Lv2-3)は作成する
- 重要テーマ(参勤交代、鎖国、明治維新など)は3段階以上を目指す
- Lv4-5は無理に全テーマに作らない。思考力を問える良問のみ

---

## 4. 学習指導要領リファレンス

### 小学校学習指導要領(平成29年告示)第6学年 社会科 — 歴史内容

| 記号 | 内容 | 対応時代 |
|------|------|----------|
| ア | 狩猟・採集から農耕への変化、古墳、大和朝廷による統一 | 縄文〜古墳 |
| イ | 大陸文化の摂取、大化の改新、大仏造営、貴族の生活 | 飛鳥〜平安 |
| ウ | 源平の戦い、鎌倉幕府の始まり、元との戦い | 鎌倉 |
| エ | 室町幕府、代表的な建造物・絵画 | 室町 |
| オ | キリスト教の伝来、織田・豊臣の天下統一、江戸幕府の始まり、参勤交代と鎖国 | 安土桃山〜江戸初期 |
| カ | 歌舞伎や浮世絵、国学や蘭学 | 江戸文化 |
| キ | 黒船の来航、明治維新、文明開化 | 幕末〜明治初期 |
| ク | 大日本帝国憲法の発布、日清・日露の戦争、条約改正 | 明治中〜後期 |
| ケ | 日中戦争(日華事変)、第二次世界大戦、日本国憲法、オリンピック | 昭和〜戦後 |

### 指定42人物リスト

学習指導要領で「取り上げるようにする」と明記されている人物。**Lv1問題の核**となる。

| 時代 | 人物 |
|------|------|
| 古代 | 卑弥呼 |
| 飛鳥 | 聖徳太子、小野妹子、中大兄皇子、中臣鎌足 |
| 奈良 | 聖武天皇、行基、鑑真 |
| 平安 | 藤原道長、紫式部、清少納言 |
| 鎌倉 | 平清盛、源頼朝、源義経、北条時宗 |
| 室町 | 足利義満、足利義政、雪舟 |
| 安土桃山〜江戸初期 | ザビエル、織田信長、豊臣秀吉、徳川家康、徳川家光 |
| 江戸文化 | 近松門左衛門、歌川広重、本居宣長、杉田玄白、伊能忠敬 |
| 幕末〜明治 | ペリー、勝海舟、西郷隆盛、大久保利通、木戸孝允、明治天皇、福沢諭吉、大隈重信、板垣退助、伊藤博文、陸奥宗光、東郷平八郎、小村寿太郎 |
| 近代 | 野口英世 |

**42人物の活用ルール**:
- 全42人物について最低Lv1の問題を1問は作成する
- 重要人物(太字で示される人物)はLv2-3も作成
- 人物同士の関係性を問う問題はLv3以上

---

## 5. 中学受験の出題傾向

### 頻出時代ランキング

```
江戸 ★★★★★ > 明治 ★★★★ > 昭和 ★★★★ > 安土桃山 ★★★ > 鎌倉 ★★★ > 室町 ★★ > 奈良 ★★
```

### 出題の特徴

1. **因果関係重視**: 年号の暗記だけでなく「なぜ起きたか」「結果どうなったか」を問う
2. **記述式・資料読み取り増加**: 4択でも記述的思考力を問う出題が増加 → Lv4-5で対応
3. **クロス出題**: 人物の行動 × 時代 × 制度を組み合わせた出題
4. **時事関連**: ○○年前の出来事として出題(例: 2025年入試なら1945年から80年)
5. **比較問題**: 異なる時代の類似制度・出来事を比較させる

### 難関校の出題パターン(参考)

| パターン | 例 | 対応Lv |
|----------|-----|--------|
| 単純知識 | 「〜を行ったのは誰?」 | Lv1 |
| 理由説明 | 「なぜ〜を行ったか?」 | Lv2 |
| 結果・影響 | 「〜の結果、何が起きたか?」 | Lv2-3 |
| 比較 | 「AとBの共通点/相違点は?」 | Lv3 |
| 逆説・推論 | 「なぜ〜にも関わらず…」 | Lv4 |
| 構造理解 | 「この制度が社会にどう影響したか」 | Lv4-5 |
| 横断・批判的読解 | 複数時代にまたがる変化の本質 | Lv5 |

### 過去問リファレンス

- **保存先**: `/Users/satokeita/dev/history-quiz-app/reference/kakomon/`
- 11校×5年の社会科過去問を分析材料として利用可能
- **注意**: 問題そのものは転載しない。出題テーマ・形式・難易度のパターンを抽出して参考にする

---

## 6. 目標クイズ数・時代別配分

### 全体目標: 800問+

新基準での最低目標: 505問

| 時代 | category_id | Lv1 | Lv2 | Lv3 | Lv4 | Lv5 | 合計 | 備考 |
|------|-------------|-----|-----|-----|-----|-----|------|------|
| 縄文・弥生 | `11111111-0001-0001-0001-000000000001` | 5 | 10 | 8 | 4 | 3 | **30** | |
| 古墳・飛鳥 | `11111111-0001-0001-0001-000000000002` | 5 | 12 | 10 | 5 | 3 | **35** | |
| 奈良 | `11111111-0001-0001-0001-000000000003` | 5 | 12 | 10 | 5 | 3 | **35** | |
| 平安 | `11111111-0001-0001-0001-000000000004` | 5 | 15 | 12 | 6 | 4 | **42** | |
| 鎌倉 | `11111111-0001-0001-0001-000000000005` | 5 | 15 | 12 | 6 | 4 | **42** | |
| 室町 | `11111111-0001-0001-0001-000000000006` | 5 | 12 | 10 | 5 | 3 | **35** | |
| 戦国 | `11111111-0001-0001-0001-000000000007` | 5 | 12 | 10 | 5 | 3 | **35** | |
| 江戸 | `11111111-0001-0001-0001-000000000008` | 10 | 25 | 20 | 12 | 8 | **75** | ★最頻出 |
| 明治 | `11111111-0001-0001-0001-000000000009` | 8 | 20 | 18 | 10 | 6 | **62** | ★頻出 |
| 大正 | `11111111-0001-0001-0001-000000000010` | 5 | 10 | 8 | 4 | 3 | **30** | |
| 昭和 | `11111111-0001-0001-0001-000000000011` | 8 | 18 | 15 | 8 | 5 | **54** | ★頻出 |
| 平成・令和 | `11111111-0001-0001-0001-000000000012` | 5 | 10 | 8 | 4 | 3 | **30** | |
| **合計** | | **71** | **171** | **141** | **74** | **48** | **505** | |

### 難易度別の比率

- Lv1(基礎): 14% — 土台固め
- Lv2(標準): 34% — 最大ボリューム。教科書内容の網羅
- Lv3(応用): 28% — 中堅〜上位校対策
- Lv4(難関): 15% — 難関校対策
- Lv5(最難関): 9% — 御三家・最難関対策

---

## 7. ジャンル比率(各時代内)

| ジャンル | 比率 | 説明 |
|----------|------|------|
| 人物問題 | 30% | 誰が何をしたか。42人物を中心に |
| 出来事・事件 | 30% | いつ・何が起きたか。戦い、改革、条約など |
| 文化・制度 | 25% | 建築、文学、法律、社会制度など |
| 年代・因果関係 | 15% | 時系列の理解、なぜ→どうなった |

**ジャンルタグの付け方**(explanation内に含める):
- 問題作成時、各問題がどのジャンルに該当するか意識する
- 1つの問題が複数ジャンルにまたがる場合は主要なものを1つ選ぶ
- 時代ごとにジャンル比率が大きく偏らないようにする

---

## 8. クイズ作成ワークフロー

### Step 1: 現状把握

```bash
# 既存クイズの確認(時代別・難易度別の集計)
PROJECT_REF="ltjiitmfishpgcnlmonr"
ANON_KEY=$(grep "VITE_SUPABASE_ANON_KEY" /Users/satokeita/dev/history-quiz-app/web/.env | cut -d'=' -f2)

curl -s "https://${PROJECT_REF}.supabase.co/rest/v1/quizzes?select=category_id,difficulty" \
  -H "apikey: ${ANON_KEY}" \
  -H "Authorization: Bearer ${ANON_KEY}" | \
  python3 -c "
import sys, json
from collections import Counter
data = json.load(sys.stdin)
print(f'Total: {len(data)}')
cats = Counter(d['category_id'] for d in data)
for k, v in sorted(cats.items()):
    print(f'  {k}: {v}')
diffs = Counter(d['difficulty'] for d in data)
print('By difficulty:')
for k, v in sorted(diffs.items()):
    print(f'  Lv{k}: {v}')
"
```

### Step 2: ギャップ分析

目標数(セクション6の表)と現状を比較し、不足しているところを特定:
- 時代 × 難易度のマトリクスで空きを確認
- 優先度: 最頻出時代(江戸・明治・昭和)の不足分を先に埋める

### Step 3: テーマ選定とリサーチ

指定された時代について、以下をリサーチ:
- 学習指導要領の該当内容(ア〜ケ)
- 該当する42人物
- 中学受験で頻出のトピック
- 過去問リファレンス(`/Users/satokeita/dev/history-quiz-app/reference/kakomon/`)

### Step 4: クイズ作成

1. テーマごとに難易度マトリクスを意識して問題を設計
2. ジャンル比率(人物30%/出来事30%/文化制度25%/因果15%)を守る
3. 選択肢は難易度に応じた設計(セクション2参照)
4. 解説は充実させる(関連知識・因果関係・発展情報を含む)

### Step 5: 品質チェック(セクション11参照)

### Step 6: SQL生成 & デプロイ(セクション10参照)

---

## 9. JSON/SQL形式

### JSONフォーマット

```json
{
  "question": "問題文(明確で簡潔に)",
  "answer": "正解(教科書的な表現で)",
  "explanation": "解説(なぜその答えなのか、背景知識・因果関係を含む。200-400字目安)",
  "hint": "ヒント(任意。答えを直接示さず、思考の方向を示す)",
  "type": "multiple_choice",
  "options": ["選択肢1(正解)", "選択肢2", "選択肢3", "選択肢4"],
  "difficulty": 1,
  "category_id": "11111111-0001-0001-0001-000000000001"
}
```

### フィールド仕様

| フィールド | 型 | 必須 | 説明 |
|-----------|-----|------|------|
| question | text | ✅ | 問題文。明確で簡潔に |
| answer | text | ✅ | 正解。教科書的な表現で統一 |
| explanation | text | ✅ | 解説。200-400字目安。因果関係・関連知識を含む |
| hint | text | ❌ | ヒント。答えを直接示さない |
| type | text | ✅ | `multiple_choice` / `text` / `true_false` |
| options | jsonb | ※ | 選択肢配列。multiple_choiceの場合必須。4択 |
| difficulty | int | ✅ | 1-5(Lv1〜Lv5に対応) |
| category_id | uuid | ✅ | 時代カテゴリID |
| display_order | int | ❌ | 表示順 |

### 選択肢の設計ルール

- **正解は必ずoptionsの中に含める**(options[0]が正解である必要はない。ランダム表示される)
- **answerフィールドの値とoptions内の正解選択肢の表記を完全一致させる**
- 誤答はもっともらしいものを選ぶ(難易度に応じて調整)
- 同じカテゴリ・同時代の用語を誤答に使う(ランダムな時代の用語を混ぜない)

### SQL生成形式

```sql
-- [時代名] Lv[難易度] [ジャンル]
INSERT INTO quizzes (question, answer, explanation, hint, type, options, difficulty, category_id, display_order)
VALUES (
  '鎌倉幕府を開いたのは誰?',
  '源頼朝',
  '源頼朝は1185年に全国に守護・地頭を置く権利を得て、1192年に征夷大将軍に任命されました。壇ノ浦の戦いで平氏を滅ぼした後、鎌倉を拠点に武家政権を確立しました。',
  '壇ノ浦の戦いで平氏を滅ぼした人物です',
  'multiple_choice',
  '["源頼朝", "源義経", "平清盛", "北条時宗"]',
  1,
  '11111111-0001-0001-0001-000000000005',
  1
);
```

### SQLシンタックス注意事項

- **INSERT文の中にコメントを入れない**
- **各INSERT文は個別に記述**: `INSERT INTO quizzes (...) VALUES (...);`
- **複数VALUESを1つのINSERTにまとめない**(コメント挿入でエラーになる)
- シングルクォート内のシングルクォートは `''` でエスケープ
- optionsはJSON文字列としてシングルクォートで囲む: `'["A", "B", "C", "D"]'`

---

## 10. Supabaseデプロイ手順

### 接続情報

- **PROJECT_REF**: `ltjiitmfishpgcnlmonr`
- **ANON_KEY**: `/Users/satokeita/dev/history-quiz-app/web/.env` の `VITE_SUPABASE_ANON_KEY` から取得
- **リージョン**: ap-northeast-1(東京)

### デプロイフロー

```bash
# 1. SQLファイルを作成
# ファイル名規則: quizzes_[時代]_lv[難易度].sql
# 例: quizzes_edo_lv2.sql

# 2. Supabase CLIで実行
cd /Users/satokeita/dev/history-quiz-app
supabase db execute --project-ref ltjiitmfishpgcnlmonr < quizzes.sql

# または psql で直接実行
# psql "postgresql://postgres.[PROJECT_REF]:[PASSWORD]@aws-0-ap-northeast-1.pooler.supabase.com:6543/postgres" -f quizzes.sql

# 3. db push(マイグレーションがある場合)
supabase db push
```

### 動作確認(必須)

```bash
PROJECT_REF="ltjiitmfishpgcnlmonr"
ANON_KEY=$(grep "VITE_SUPABASE_ANON_KEY" /Users/satokeita/dev/history-quiz-app/web/.env | cut -d'=' -f2)

# 全体数の確認
curl -s "https://${PROJECT_REF}.supabase.co/rest/v1/quizzes?select=category_id,difficulty" \
  -H "apikey: ${ANON_KEY}" \
  -H "Authorization: Bearer ${ANON_KEY}" | \
  python3 -c "
import sys, json
from collections import Counter
data = json.load(sys.stdin)
print(f'Total: {len(data)}')
cats = Counter(d['category_id'] for d in data)
for k, v in sorted(cats.items()):
    print(f'  {k}: {v}')
diffs = Counter(d['difficulty'] for d in data)
print('By difficulty:')
for k, v in sorted(diffs.items()):
    print(f'  Lv{k}: {v}')
"

# 追加した問題の確認(直近N件)
curl -s "https://${PROJECT_REF}.supabase.co/rest/v1/quizzes?select=question,difficulty,category_id&order=created_at.desc&limit=10" \
  -H "apikey: ${ANON_KEY}" \
  -H "Authorization: Bearer ${ANON_KEY}" | python3 -m json.tool
```

**デプロイ忘れ禁止**: 作成 → デプロイ → 動作確認まで完了して初めて完了。

---

## 11. 品質チェックリスト

クイズ作成後、デプロイ前に必ず確認:

### 内容チェック

- [ ] **事実の正確性**: 問題・答え・解説に誤りがないか
- [ ] **難易度の妥当性**: Lv定義に合っているか(Lv1が難しすぎないか、Lv5が簡単すぎないか)
- [ ] **解説の充実度**: 単に正解を示すだけでなく、因果関係・関連知識が含まれているか
- [ ] **選択肢の質**: 難易度に応じた紛らわしさになっているか。明らかに不正解とわかるものばかりでないか
- [ ] **answerとoptionsの一致**: answer の値が options 配列内に完全一致で存在するか

### 構造チェック

- [ ] **重複チェック**: 既存のクイズと問題文が重複していないか
- [ ] **category_id**: 正しい時代のUUIDが指定されているか
- [ ] **difficulty**: 1-5の整数になっているか
- [ ] **type**: `multiple_choice` / `text` / `true_false` のいずれか
- [ ] **options**: multiple_choiceの場合、正しいJSON配列になっているか(4択)

### バランスチェック

- [ ] **ジャンル比率**: 人物30%/出来事30%/文化制度25%/因果15% に近いか
- [ ] **難易度分布**: 目標数(セクション6)に沿った配分か
- [ ] **テーマの偏り**: 特定のテーマに集中していないか

### 表記統一

- [ ] **人名**: 教科書表記に統一(例: 聖徳太子 ※「厩戸皇子」は解説内で触れる程度)
- [ ] **地名**: 教科書表記(例: 鎌倉、京都、江戸)
- [ ] **年号**: 西暦を基本。元号は補足的に(例: 「1192年(建久3年)」)
- [ ] **用語**: 教科書で使われている表現を優先(例: 「鎖国」「参勤交代」)

---

## 12. 注意事項

### 重複チェックの方法

```bash
# 既存クイズの問題文一覧を取得して重複確認
PROJECT_REF="ltjiitmfishpgcnlmonr"
ANON_KEY=$(grep "VITE_SUPABASE_ANON_KEY" /Users/satokeita/dev/history-quiz-app/web/.env | cut -d'=' -f2)

curl -s "https://${PROJECT_REF}.supabase.co/rest/v1/quizzes?select=question&category_id=eq.[TARGET_CATEGORY_ID]" \
  -H "apikey: ${ANON_KEY}" \
  -H "Authorization: Bearer ${ANON_KEY}" | python3 -m json.tool
```

### 表記統一ルール

| 項目 | 統一表記 | NG例 |
|------|----------|------|
| 聖徳太子 | 聖徳太子 | 厩戸皇子、厩戸王 |
| 中大兄皇子 | 中大兄皇子 | 天智天皇(即位前の場合) |
| 中臣鎌足 | 中臣鎌足 | 藤原鎌足(賜姓前の場合) |
| 源頼朝 | 源頼朝 | 源氏の棟梁 |
| 徳川家康 | 徳川家康 | 松平元康 |
| 大日本帝国憲法 | 大日本帝国憲法 | 明治憲法 |
| 日本国憲法 | 日本国憲法 | 新憲法、戦後憲法 |

※ 解説文内では別名・旧名に触れてOK(例:「中臣鎌足(のちの藤原鎌足)」)

### やってはいけないこと

1. **過去問の丸写し**: 出題パターンを参考にするのはOK。問題文の転載はNG
2. **大学受験レベルの出題**: あくまで小学生が対象。Lv5でも中学受験の範囲内
3. **曖昧な選択肢**: 「正解が2つある」「どれも正解に見える」は品質不良
4. **解説なしの登録**: explanationは必須。空欄での登録は禁止
5. **一度に大量投入**: 1回のデプロイは50問以内を推奨(品質管理のため)

### バリエーション作成のコツ

同じ事項を違う角度から問う:
- **人物 → 出来事**: 「源頼朝が開いたものは?」→「鎌倉幕府を開いた人物は?」
- **原因 → 結果**: 「なぜ元寇が起きた?」→「元寇の結果、幕府はどうなった?」
- **制度 → 目的**: 「参勤交代とは?」→「参勤交代の目的は?」
- **時系列**: 「〜の前に起きた出来事は?」→「〜の後に起きた出来事は?」

---

## カテゴリID一覧(クイックリファレンス)

| 時代 | category_id |
|------|-------------|
| 縄文・弥生時代 | `11111111-0001-0001-0001-000000000001` |
| 古墳・飛鳥時代 | `11111111-0001-0001-0001-000000000002` |
| 奈良時代 | `11111111-0001-0001-0001-000000000003` |
| 平安時代 | `11111111-0001-0001-0001-000000000004` |
| 鎌倉時代 | `11111111-0001-0001-0001-000000000005` |
| 室町時代 | `11111111-0001-0001-0001-000000000006` |
| 戦国時代 | `11111111-0001-0001-0001-000000000007` |
| 江戸時代 | `11111111-0001-0001-0001-000000000008` |
| 明治時代 | `11111111-0001-0001-0001-000000000009` |
| 大正時代 | `11111111-0001-0001-0001-000000000010` |
| 昭和時代 | `11111111-0001-0001-0001-000000000011` |
| 平成・令和時代 | `11111111-0001-0001-0001-000000000012` |
---
name: review-codex
description: "Codex CLIを使用してコード変更をレビューする。実装したコード、未コミットの変更、特定のコミットをレビューしたい場合に使用。トリガー:codexでレビュー、コードレビュー、変更をレビュー、レビューして"
---

# Codex レビュー

`codex review` を実行してコード変更を分析し、フィードバックを提供する。

## ワークフロー

1. レビュー対象を決定:
   - 引数なし → `--uncommitted` を使用(最も一般的)
   - PRコンテキスト → `--base <対象ブランチ>` を使用
   - 特定のコミット → `--commit <sha>` を使用

2. 適切なオプションで `codex review` を実行

3. レビュー結果をユーザーに提示

## クイックスタート

```bash
# 未コミットの変更をレビュー(デフォルト)
codex review --uncommitted

# ベースブランチと比較してレビュー
codex review --base main

# 特定のコミットをレビュー
codex review --commit <SHA>
```

## オプション

詳細なオプション: [references/options.md](references/options.md)
---
name: session-cleanup
description: Clawdbotのセッションファイルを安全にクリーンアップし、パフォーマンスとAPI利用量を最適化するスキル。高トークン消費セッション・エラーセッションのアーカイブ、手順書と半自動化スクリプト付き。「セッションクリーンアップ」「API利用量削減」「パフォーマンス最適化」「セッションアーカイブ」などの作業に使う。
---

# Session Cleanup Skill

Clawdbotのセッションファイルを安全にクリーンアップし、パフォーマンスとAPI利用量を最適化するスキル。

## 概要

Clawdbotは全ての会話履歴を `~/.openclaw/agents/*/sessions/` にJSONLファイルで永続化している。時間が経つにつれ、以下の問題が発生する:

- **高トークン消費セッション**(10万tokens超)の蓄積
- **エラー状態セッション**(API制限等で動作不能)
- **完了済みタスクセッション**(継続不要)
- **パフォーマンス低下**(`sessions_list`の応答遅延)

このスキルでは、重要なセッションを残しつつ、不要なセッションを安全にアーカイブする。

## ⚠️ 注意事項

- **完全にバックアップしてから実行**
- **進行中プロジェクトのセッションは絶対に削除しない**
- **メインチャンネルセッションは慎重に判断**
- **アーカイブファイルは復旧可能な場所に保存**

## 🚀 **最も効果的な方法: sessions.json リネーム**

**2026-02-04 けいた発見**: `sessions.json`ファイルのサイズがClawdbotパフォーマンスに**最も影響度が大きい**ことが判明。

### sessions.jsonアーカイブ(推奨第一手順)

```bash
# 現在時刻でsessions.jsonをリネーム(全エージェント)
datetime=$(date '+%Y%m%d_%H%M%S')

# Main
mv ~/.openclaw/agents/main/sessions/sessions.json ~/.openclaw/agents/main/sessions/sessions.json_${datetime}

# Stevens  
mv ~/.openclaw/agents/stevens/sessions/sessions.json ~/.openclaw/agents/stevens/sessions/sessions.json_${datetime}

# Nemo
mv ~/.openclaw/agents/nemo/sessions/sessions.json ~/.openclaw/agents/nemo/sessions/sessions.json_${datetime}

# その他のエージェント
find ~/.openclaw/agents/*/sessions/ -name "sessions.json" -exec mv {} {}_${datetime} \;

echo "✅ sessions.json全アーカイブ完了: ${datetime}"
```

**効果**: 一気にセッション情報が軽くなり、パフォーマンスが大幅改善。

**復旧方法**:
```bash
# 最新のアーカイブファイルを確認
ls -la ~/.openclaw/agents/main/sessions/sessions.json_*

# 復旧(必要な場合のみ)
datetime="20260204_154500"  # 復旧したいタイムスタンプ
cp ~/.openclaw/agents/main/sessions/sessions.json_${datetime} ~/.openclaw/agents/main/sessions/sessions.json
```

## 🔍 事前分析

### 1. 現在のセッション状況確認

```javascript
// sessions_listでセッション一覧を取得
sessions_list({
  limit: 50,
  messageLimit: 1
})
```

**確認ポイント:**
- `totalTokens`(高い順にソート)
- `abortedLastRun: false`(エラー状態)
- `updatedAt`(最終更新時刻)
- `displayName`(内容の推定)

### 2. クリーンアップ対象の特定

**削除対象(優先順):**
1. **エラー状態**: `"errorMessage"`がある、または明らかに動作不能
2. **高トークン消費**: 15万tokens以上(コンテキスト制限近い)
3. **完了済みタスク**: 記事作成・プロジェクト完了報告済み
4. **7日以上非アクティブ**: 重要性の低い古いセッション

**保持対象:**
- メインチャンネル(継続的会話)
- 進行中プロジェクト
- 重要な設定・決定記録
- 直近3日の主要セッション

## 🗂️ アーカイブ手順

### 1. アーカイブディレクトリ作成

```bash
# 日付付きアーカイブディレクトリを作成
mkdir -p ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/{stevens,main,nemo,torishima}
```

### 2. 個別エージェントのクリーンアップ

#### Stevens(記事作成・高トークン)
```bash
echo "=== Stevens エラー・高トークンセッション移動 ==="
# エラーセッション
mv ~/.openclaw/agents/stevens/sessions/cbdb893e-9a02-4371-bdb5-5e3286478f7b* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/stevens/ 2>/dev/null && echo "✅ エラーセッション移動完了"
# 高トークンセッション(159K, 162K tokens)
mv ~/.openclaw/agents/stevens/sessions/8ff0d5d0-c564-482b-8b77-7ce67aac99ae* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/stevens/ 2>/dev/null && echo "✅ 159K tokens移動完了"
mv ~/.openclaw/agents/stevens/sessions/fd7eed06-2edb-43a0-a871-89aacae03748* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/stevens/ 2>/dev/null && echo "✅ 162K tokens移動完了"
```

#### Main(エラー・高トークン)
```bash
echo "=== Main エラー・高トークンセッション移動 ==="
# エラーセッション
mv ~/.openclaw/agents/main/sessions/b75f1fe7-8627-4fdc-a0d6-51ab16fbbc69* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/main/ 2>/dev/null && echo "✅ エラーセッション移動完了"
# 高トークンセッション(148K, 140K, 86K tokens)  
mv ~/.openclaw/agents/main/sessions/6436ff4d-04b5-45c6-9463-985d7262ce04* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/main/ 2>/dev/null && echo "✅ 148K tokens移動完了"
mv ~/.openclaw/agents/main/sessions/0d15ffea-2614-419a-a9f2-8a4c042d92b1* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/main/ 2>/dev/null && echo "✅ 140K tokens移動完了"
mv ~/.openclaw/agents/main/sessions/357fe75d-7c97-49b8-8f2c-ffb1db35dd14* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/main/ 2>/dev/null && echo "✅ 86K tokens移動完了"
```

#### Nemo(記事作成完了)
```bash
echo "=== Nemo 高トークンセッション移動 ==="
mv ~/.openclaw/agents/nemo/sessions/f696bc67-0d51-452b-9180-0d1030546e75* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/nemo/ 2>/dev/null && echo "✅ 88K tokens移動完了"
mv ~/.openclaw/agents/nemo/sessions/53fd8d9f-fa4e-4753-b5cc-10f9996b9654* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/nemo/ 2>/dev/null && echo "✅ 78K tokens移動完了"
```

#### Torishima(高トークン)
```bash
echo "=== Torishima 高トークンセッション移動 ==="
mv ~/.openclaw/agents/torishima/sessions/960300f9-86c0-4339-ae39-122ef08daa62* ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/torishima/ 2>/dev/null && echo "✅ 49K tokens移動完了"
```

### 3. アーカイブ確認

```bash
echo "=== アーカイブ完了ファイル数 ==="
echo "Stevens: $(ls ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/stevens/ | wc -l) files"
echo "Main: $(ls ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/main/ | wc -l) files"
echo "Nemo: $(ls ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/nemo/ | wc -l) files"  
echo "Torishima: $(ls ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/torishima/ | wc -l) files"
echo "Total: $(find ~/.openclaw/sessions_archive/$(date '+%Y-%m-%d')/ -name "*.jsonl" | wc -l) files archived"
```

## ✅ 効果確認

### 1. セッション数の変化
```javascript
// クリーンアップ前後のセッション数確認
sessions_list({limit: 50})
```

### 2. API利用量確認
```javascript
// 現在のAPI使用状況確認
session_status()
```

### 3. パフォーマンステスト
- `sessions_list`の応答時間
- Gateway再起動時間
- メモリ使用量

## 🔄 復旧方法

アーカイブしたセッションを復旧する場合:

```bash
# 特定エージェントのセッション復旧
cp ~/.openclaw/sessions_archive/YYYY-MM-DD/stevens/* ~/.openclaw/agents/stevens/sessions/

# 特定セッションファイルのみ復旧
cp ~/.openclaw/sessions_archive/YYYY-MM-DD/main/session-id.jsonl ~/.openclaw/agents/main/sessions/
```

**注意**: 復旧後はGateway再起動が推奨。

## 📊 実績

### 2026-02-04(sessions.jsonリネーム手法発見)
- **最大の効果**: `sessions.json`ファイルサイズがパフォーマンス最大要因と判明
- **リネーム効果**: 一気にセッション情報が軽量化、レスポンス大幅改善
- **影響範囲**: `/Users/satokeita/.openclaw/agents/main/session/sessions.json`が最重要

### 従来手法の実績(参考)
- **セッション数**: 50個 → 20個(60%削減)
- **アーカイブファイル**: 31個
- **週間API利用量**: 59% → 25-30%(予想)
- **エラーセッション**: 全て除去
- **最大セッション**: 162K tokens → 121K tokens以下

## 🕐 実行タイミング・優先順位

### **第一選択: sessions.jsonリネーム**
以下の症状が出たら即座に実行:
- `sessions_list`の応答が遅い(3秒以上)
- Gateway起動時間が長い
- Clawdbot全体のレスポンス低下

### **第二選択: 個別セッションアーカイブ**
**推奨頻度**: 月1回または以下の状況時
- 週間API利用量が50%を超えた
- エラーセッションが蓄積している
- 特定エージェントのトークン使用量が異常に高い

### **実行前チェック**
- 重要プロジェクトの進行状況確認
- 最近の主要会話の識別
- sessions.jsonの現在サイズ確認: `ls -lah ~/.openclaw/agents/*/sessions/sessions.json`

## 📝 カスタマイズ

環境に応じて以下をカスタマイズ:

1. **トークン閾値**: 15万tokens → 10万tokensに調整
2. **保持期間**: 7日 → 3日または14日に調整
3. **アーカイブ場所**: 外部ストレージへの移動
4. **自動化**: cronジョブでの定期実行

## 🔍 トラブルシューティング

**セッション移動に失敗した場合:**
```bash
# ファイル存在確認
ls ~/.openclaw/agents/*/sessions/session-id*

# 権限確認
ls -la ~/.openclaw/agents/*/sessions/
```

**Gateway認識しない場合:**
```bash
# Gateway再起動
openclaw gateway restart

# セッション再読み込み確認
sessions_list({limit: 5})
```
---
name: site-checker
description: "ブラウザ(clawd profile)でサイトを直接確認する。スクリーンショット撮影、スナップショット取得、UI要素の検証に使う。「サイト確認」「ページチェック」「表示確認」「スクリーンショット」「見た目の確認」「ホーム画面確認」などの作業に使う。"
---

# Site Checker — ブラウザ直接確認スキル

agent-browser(clawd profile)を使って、サイトの表示状態を直接確認する。
web_fetchでは取得できないビジュアル要素(レイアウト、画像表示、CSS、レスポンシブ)を検証できる。

## 最重要ルール(2026-02-03 けいた様指示・確定)

**サイトに変更を加えたら、必ずこのスキルを使ってブラウザで巡回確認する。**
- `web_fetch` のテキスト確認だけでは**不十分**
- エンドユーザーの気持ちになって同じ行動をする
- 確認観点: 表示崩れ、リンク切れ、導線の自然さ、情報の見やすさ、改善ポイント
- これは「やったほうがいい」ではなく**「必ずやる」ルール**

## 基本フロー

### 1. ページを開く

```tool
browser action=open profile=clawd targetUrl="https://example.com"
```

→ `targetId` を取得。以降のすべての操作で `targetId` を指定する。

### 2. スクリーンショット撮影

```tool
browser action=screenshot profile=clawd targetId=<targetId>
```

- フルページ: `fullPage=true`
- 通常は viewport のみで十分

### 3. スナップショット(DOM構造確認)

```tool
browser action=snapshot profile=clawd targetId=<targetId>
```

- インタラクティブ要素のみ: `interactive=true compact=true`
- 効率モード: `mode=efficient`

### 4. 特定要素の確認

```tool
browser action=screenshot profile=clawd targetId=<targetId> ref=<ref>
```

- `ref` はスナップショットで取得した要素ID

### 5. ページ内操作

```tool
browser action=act profile=clawd targetId=<targetId> request={"kind":"click","ref":"<ref>"}
browser action=act profile=clawd targetId=<targetId> request={"kind":"type","ref":"<ref>","text":"hello"}
```

## よくある確認パターン

### ホーム画面全体確認
```
1. open → targetId取得
2. screenshot → ファーストビュー確認
3. screenshot fullPage=true → 全体確認
```

### 特定記事の表示確認
```
1. open targetUrl="https://site.com/article-slug/" → targetId取得
2. screenshot → ファーストビュー
3. snapshot → 構造確認(見出し、リンク、画像)
4. screenshot fullPage=true → 全ページ
```

### モバイル表示確認
```
1. open → targetId取得
2. act request={"kind":"evaluate","fn":"window.innerWidth"} → 現在の幅確認
3. ブラウザのviewportを変更してscreenshot
```

### 画像・アイキャッチ確認
```
1. open → ホームページ
2. screenshot → サムネイル一覧の表示状態を目視確認
3. snapshot → img要素のsrc/alt属性を構造的に確認
```

## 注意点

- **profile="clawd"** を必ず指定する(chrome profileではなく管理されたブラウザを使う)
- `targetId` はナビゲーション後も同じタブで有効
- ref はスナップショット間で変わる可能性がある — 操作前に再取得推奨
- スクリーンショットは `MEDIA:` パスで返される — image tool で分析可能
- clawd ブラウザは常時稼働している(`browser action=status profile=clawd` で確認可能)

## トラブルシューティング

### ブラウザが起動していない場合
```tool
browser action=start profile=clawd
```

### タブが多すぎる場合
```tool
browser action=tabs profile=clawd
browser action=close profile=clawd targetId=<不要なtargetId>
```
---
name: slack-history
description: "Slackの過去メッセージを正しく取得する方法。チャンネル履歴、特定メッセージ周辺、期間指定検索に対応。「Slack履歴取得」「過去メッセージ確認」「Slackログ検索」などの作業に使う。"
---

# Slack History Retrieval Skill

## 概要
Slackの過去メッセージを適切に取得するスキル。
Clawdbot `message` toolの正しいパラメータ使用方法と、よくある失敗パターンの回避方法を記録。

## 重要:正しいパラメータ名

### ✅ 正しい使用方法
```javascript
message(action=read, channelId=C0ACUDZCJJC, limit=10)
```

### ❌ よくある間違い
```javascript
message(action=read, channel=C0ACUDZCJJC, limit=10)     // ← Error: Unknown channel
message(action=read, channel=stevens, limit=10)         // ← Error: Unknown channel
```

**重要:** `channel` ではなく `channelId` を使用する

## 基本的な取得方法

### 1. 最新メッセージの取得
```javascript
message(action=read, channelId=C0ACUDZCJJC, limit=10)
```

### 2. 特定時点前のメッセージ取得
```javascript
message(action=read, channelId=C0ACUDZCJJC, before=1770159737, limit=5)
```

### 3. 特定時点後のメッセージ取得
```javascript
message(action=read, channelId=C0ACUDZCJJC, after=1770159737, limit=5)
```

### 4. 特定メッセージ周辺の取得
```javascript
message(action=read, channelId=C0ACUDZCJJC, around=1770159737435, limit=5)
```

## チャンネルID一覧(TOOLS.md参照)

| チャンネル名 | チャンネルID | 用途 |
|-------------|-------------|------|
| #stevens | C0ACUDZCJJC | けいた様との主要なやり取り |
| #claude連携 | C08KHA4BQHW | メインエージェント(ボットさん)のチャンネル |

## メッセージIDとタイムスタンプの理解

### Slackタイムスタンプ形式
- **形式:** `UNIX秒.マイクロ秒` (例:`1770159737.435309`)
- **注意:** URLに含まれるIDは通常、ピリオドが除去された形式
- **変換:** `1770159737435309` → `1770159737.435309`

### タイムスタンプ操作
```javascript
// 1時間前のメッセージを取得
const oneHourAgo = Math.floor(Date.now() / 1000) - 3600;
message(action=read, channelId=C0ACUDZCJJC, before=oneHourAgo, limit=10)
```

## 実用的な検索パターン

### パターン1: 過去24時間のメッセージ
```javascript
const yesterday = Math.floor(Date.now() / 1000) - 86400;
message(action=read, channelId=C0ACUDZCJJC, after=yesterday, limit=50)
```

### パターン2: 特定日のメッセージ
```javascript
const startOfDay = Math.floor(new Date('2026-02-03').getTime() / 1000);
const endOfDay = startOfDay + 86400;
message(action=read, channelId=C0ACUDZCJJC, after=startOfDay, before=endOfDay, limit=100)
```

### パターン3: スレッド内のメッセージ
```javascript
message(action=read, channelId=C0ACUDZCJJC, threadId=1770159737.435309, limit=20)
```

## トラブルシューティング

### エラー: "Unknown channel"
- **原因:** `channel` パラメータを使用している
- **解決:** `channelId` に変更

### エラー: 古いメッセージが取得できない
- **原因:** Slackの保存期間制限
- **解決:** より新しい期間で検索するか、Slack管理者に確認

### メッセージが見つからない
- **原因1:** タイムスタンプ形式が間違っている
- **原因2:** 指定したタイムスタンプにメッセージが存在しない
- **解決:** `around` パラメータで周辺検索、または `before`/`after` で範囲検索

## 使用例

### 特定の話題に関する過去メッセージを探す
```javascript
// 1. 期間を指定して広めに取得
message(action=read, channelId=C0ACUDZCJJC, after=1770000000, limit=100)

// 2. 結果を確認し、関連するメッセージのタイムスタンプを特定

// 3. そのメッセージ周辺を詳細取得
message(action=read, channelId=C0ACUDZCJJC, around=1770046697.689349, limit=10)
```

## 注意事項

- **レート制限:** 連続した大量取得は避ける
- **プライバシー:** 取得したメッセージの取り扱いに注意
- **権限:** アクセス権限のないチャンネルは取得不可
- **保存期間:** Slackワークスペースの設定により古いメッセージは取得不可の場合あり

---

*Created: 2026-02-04*
*Based on: message tool parameter analysis and error debugging*
---
name: slack-multi-files
description: "Fetch all file attachments from a Slack message when Clawdbot only delivers the first one. Use automatically when a received Slack message has image/file attachments — Clawdbot currently only delivers the first file, so run this to check for and retrieve any additional files. Also use when the user mentions missing attachments or says 'I attached multiple files/images'."
---

# Slack Multi-File Fetcher

Clawdbot's Slack integration only delivers the first file attachment per message (see [issue #4282](https://github.com/moltbot/moltbot/issues/4282)). This skill retrieves all attachments.

## When to Run

**Automatically** when you receive a Slack message that includes an image or file attachment. The check is lightweight — if there's only 1 file, it returns quickly.

## How to Use

### Option 1: Script (preferred for automation)

```bash
~/.openclaw/skills/slack-multi-files/scripts/fetch-slack-files.sh <channel_id> <message_ts>
```

Returns JSON array of all downloaded files with paths. Use `image` tool to analyze each.

### Option 2: Manual curl

```bash
curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  "https://slack.com/api/conversations.replies?channel=CHANNEL&ts=TS&limit=1&inclusive=true" \
  | jq '.messages[0].files[] | {name, url_private, mimetype}'
```

Then download each `url_private` with the same auth header.

## Parameters

- `channel_id`: Slack channel ID (e.g. `C08KHA4BQHW`)
- `message_ts`: Message timestamp (e.g. `1769734297.476489`)
- Bot token is auto-extracted from `~/.openclaw/openclaw.json`

## After Fetching

- Use the `image` tool to analyze image files
- Report all attachments to the user, not just the first one
---
name: slack-notify
description: Slack APIでチャネルにメッセージを送信する。「Slackに通知」「Slack通知を追加」「Slackに送って」「チャネルに投稿」などの作業に使う。プロジェクト横断で利用可能。
---

# Slack Notify スキル

Slack Web API (`chat.postMessage`) を使ってチャネルにメッセージを送信するスキル。プロジェクト横断で利用可能。

## できること

- テキストメッセージ送信
- リッチメッセージ送信(Block Kit)
- 複数チャネルへの通知
- イベント通知の組み込み(API Route / サーバーサイド処理への統合)

## セットアップ

### 環境変数

```bash
# プロジェクトの .env.local に追加
SLACK_BOT_TOKEN=xoxb-xxxx-xxxx-xxxx
SLACK_NOTIFICATION_CHANNEL=C0XXXXXXXXX
```

Vercel 等のホスティングサービスにも同じ値を設定すること。

### Bot Token の取得元

- **openclaw 設定ファイル**: `/Users/satokeita/.openclaw/openclaw.json` → `channels.slack.botToken`
- **Slack App 管理画面**: https://api.slack.com/apps → 対象 App → OAuth & Permissions → Bot User OAuth Token

### Bot に必要な権限(OAuth Scopes)

| Scope | 用途 |
|-------|------|
| `chat:write` | メッセージ送信 |
| `chat:write.public` | Bot が参加していないパブリックチャネルへの送信(任意) |

### チャネル ID の確認方法

Slack デスクトップ/Web でチャネルを右クリック → 「チャネル詳細を表示」→ 最下部の「チャネル ID」をコピー。

## 実装パターン

### パターン1: シンプルな通知関数(TypeScript / Next.js)

サーバーサイドで使用する fire-and-forget 型の通知関数。

```typescript
export async function notifySlack(text: string) {
  const token = process.env.SLACK_BOT_TOKEN;
  const channel = process.env.SLACK_NOTIFICATION_CHANNEL;
  if (!token || !channel) return;

  try {
    await fetch('https://slack.com/api/chat.postMessage', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ channel, text }),
    });
  } catch (e) {
    console.error('[slack] Notification failed:', e);
  }
}
```

**使い方:**

```typescript
// API Route 等から呼び出し(失敗しても本処理に影響しない)
notifySlack(`📬 新規登録: ${email}`).catch(() => {});
```

**設計ポイント:**
- `fetch` のみ使用(追加ライブラリ不要)
- 環境変数が未設定の場合は何もしない(開発環境で安全)
- `catch(() => {})` で呼び出し元のエラーハンドリングを不要に

### パターン2: チャネル指定付き通知関数

複数チャネルに送り分ける場合。

```typescript
export async function notifySlack(text: string, channelOverride?: string) {
  const token = process.env.SLACK_BOT_TOKEN;
  const channel = channelOverride || process.env.SLACK_NOTIFICATION_CHANNEL;
  if (!token || !channel) return;

  try {
    const res = await fetch('https://slack.com/api/chat.postMessage', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ channel, text }),
    });
    const data = await res.json();
    if (!data.ok) {
      console.error('[slack] API error:', data.error);
    }
  } catch (e) {
    console.error('[slack] Notification failed:', e);
  }
}
```

### パターン3: Block Kit リッチメッセージ

構造化された通知を送る場合。

```typescript
export async function notifySlackRich(params: {
  channel?: string;
  text: string;        // フォールバック用テキスト
  blocks: unknown[];   // Block Kit ブロック配列
}) {
  const token = process.env.SLACK_BOT_TOKEN;
  const channel = params.channel || process.env.SLACK_NOTIFICATION_CHANNEL;
  if (!token || !channel) return;

  try {
    await fetch('https://slack.com/api/chat.postMessage', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        channel,
        text: params.text,
        blocks: params.blocks,
      }),
    });
  } catch (e) {
    console.error('[slack] Rich notification failed:', e);
  }
}

// 使用例
notifySlackRich({
  text: '新規ユーザー登録',
  blocks: [
    {
      type: 'section',
      text: {
        type: 'mrkdwn',
        text: '*新規ユーザー登録* :tada:\nメール: user@example.com',
      },
    },
    {
      type: 'context',
      elements: [
        { type: 'mrkdwn', text: `登録日時: ${new Date().toLocaleString('ja-JP')}` },
      ],
    },
  ],
});
```

### パターン4: curl(シェルスクリプト / CI)

```bash
curl -s -X POST https://slack.com/api/chat.postMessage \
  -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"channel\": \"$SLACK_NOTIFICATION_CHANNEL\", \"text\": \"デプロイ完了\"}"
```

### パターン5: Python

```python
import os, requests

def notify_slack(text: str, channel: str | None = None):
    token = os.environ.get("SLACK_BOT_TOKEN")
    ch = channel or os.environ.get("SLACK_NOTIFICATION_CHANNEL")
    if not token or not ch:
        return
    try:
        requests.post(
            "https://slack.com/api/chat.postMessage",
            headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
            json={"channel": ch, "text": text},
        )
    except Exception as e:
        print(f"[slack] Notification failed: {e}")
```

## 導入チェックリスト

プロジェクトに Slack 通知を追加する際の手順:

1. **環境変数を追加**: `.env.local` に `SLACK_BOT_TOKEN` と `SLACK_NOTIFICATION_CHANNEL`
2. **通知関数を実装**: 上記パターンから選択し、`lib/` 等に配置
3. **呼び出しを追加**: イベント発生箇所で fire-and-forget で呼び出し
4. **ホスティング環境変数を設定**: Vercel / AWS 等に同じ値を追加
5. **動作確認**: テストイベントで通知が届くことを確認

## 既知のチャネル ID

| チャネル | ID | 用途 |
|---------|-----|------|
| stevens(メイン) | `C0ACUDZCJJC` | AI Solo Builder 通知 |
| torishima | `C0ACAU1AMFU` | ニュース |
| nemo | `C0ABPLBL04X` | — |
| tifa | `C0AELF58Z5E` | — |

## API リファレンス

### chat.postMessage

```
POST https://slack.com/api/chat.postMessage
Authorization: Bearer xoxb-...
Content-Type: application/json

{
  "channel": "C0XXXXXXXXX",
  "text": "メッセージ本文",
  "blocks": [],           // 任意: Block Kit
  "thread_ts": "...",     // 任意: スレッド返信
  "unfurl_links": false,  // 任意: リンクプレビュー制御
  "mrkdwn": true          // 任意: Markdown 有効化(デフォルト true)
}
```

### レスポンス

```json
// 成功
{ "ok": true, "channel": "C0XXXXXXXXX", "ts": "1234567890.123456" }

// 失敗
{ "ok": false, "error": "channel_not_found" }
```

### よくあるエラー

| error | 原因 | 対処 |
|-------|------|------|
| `not_authed` | トークンが無効 | `SLACK_BOT_TOKEN` を確認 |
| `channel_not_found` | チャネル ID が不正 | ID を再確認 |
| `not_in_channel` | Bot がチャネルに未参加 | Bot をチャネルに招待、または `chat:write.public` scope を追加 |
| `missing_scope` | 権限不足 | Slack App 設定で scope を追加 |

## 関連リンク

- [Slack API: chat.postMessage](https://api.slack.com/methods/chat.postMessage)
- [Block Kit Builder](https://app.slack.com/block-kit-builder)(ビジュアルエディタ)
- [Slack API: OAuth Scopes](https://api.slack.com/scopes)
# Slack返信スキル — 必須手順

**description**: Slackメッセージへの返信前に必ず実行する手順。文脈確認を省略した返信は致命的ミスにつながる。

---

## 🚨 これは省略禁止

Slackで返信する前に、**必ず**以下を実行すること。

---

## 必須手順(3ステップ)

### Step 1: スレッド履歴を取得

```
message action=read threadId=<受信メッセージのts> limit=20
```

- `threadId` は受信メッセージの `ts`(タイムスタンプ)
- スレッドがない場合は `around=<ts>` で周辺を取得

### Step 2: 親メッセージを確認

- スレッドの最初の投稿(`thread_ts` と `ts` が一致するもの)を読む
- **何を依頼されているか**を把握する
- 添付ファイル、リンク、引用も確認

### Step 3: 文脈を理解してから返信

- 依頼内容を正確に理解したか確認
- 不明点があれば**質問する前にスレッドを再読**
- 「とりあえず返信」は絶対ダメ

---

## チェックリスト(返信前)

- [ ] `message action=read` を実行した
- [ ] 親メッセージの内容を把握した
- [ ] 依頼内容を正確に理解した
- [ ] 文脈に沿った返答になっている

---

## 失敗事例

### Stevens (2026-02-07)
- 状況: けいたが2つのアイデアについてスレッドで議論中
- 失敗: 文脈を読まず「どちらのアイデアですか?」と質問
- 問題: スレッドを読めば明らかな情報を聞いてしまった

### misato (2026-02-08)
- 状況: けいたが「Zellijをインストールして」と依頼
- 失敗: 親メッセージを読まず「Zellij試そうとしてるのかしら?」と質問
- 問題: 明確な指示を見逃して意味のない質問をした

---

## なぜこれが重要か

- **けいたの信頼を損なう** — 同じことを繰り返し説明させる
- **時間の無駄** — 確認すれば1回で済むやり取りが2-3回に
- **エージェントの品質低下** — 「使えない」と判断される

---

## 例外なし

「急いでいるから」「簡単な質問だから」「たぶんわかってる」

→ 全部ダメ。必ず確認してから返信。

---

*2026-02-08 けいた指示により作成。misato失敗を受けて徹底化。*
# Slack Thread Reader

Slack Web API (`conversations.replies`) を直接叩いてスレッドの返信を取得するスキル。

## 背景

OpenClawの `message action=read threadId=xxx` は、Slackプラグインでは機能しない(`messageActions` が未接続のため)。
このスキルは、Slack APIを直接叩くことでスレッドの返信を取得するワークアラウンド。

## スクリプト

### slack-thread.sh
スレッドの返信をJSON形式で取得。

```bash
~/.openclaw/skills/slack-thread-reader/slack-thread.sh <channel_id> <thread_ts> [limit]
```

### slack-thread-text.sh
人間のメッセージのみテキストで抽出(botメッセージ除外)。

```bash
~/.openclaw/skills/slack-thread-reader/slack-thread-text.sh <channel_id> <thread_ts> [limit]
```

**パラメータ:**
- `channel_id`: チャンネルID(例: C08KHA4BQHW)
- `thread_ts`: 親メッセージのタイムスタンプ(例: 1771060628.083249)
- `limit`: 取得件数(デフォルト: 100)

**出力:** JSON配列(親メッセージ + 返信)

### slack-thread-pretty.sh
人間が読みやすい形式で出力。

```bash
~/.openclaw/skills/slack-thread-reader/slack-thread-pretty.sh <channel_id> <thread_ts> [limit]
```

## 使用例

```bash
# ジムメモスレッドの取得
~/.openclaw/skills/slack-thread-reader/slack-thread.sh C08KHA4BQHW 1771060628.083249

# 整形版
~/.openclaw/skills/slack-thread-reader/slack-thread-pretty.sh C08KHA4BQHW 1771060628.083249 50
```

## 必要条件

- `jq` がインストールされていること
- `~/.openclaw/openclaw.json` に `channels.slack.botToken` が設定されていること
- Bot Token が `conversations:history` スコープを持っていること

## チャンネルID一覧

| チャンネル | ID |
|-----------|-----|
| #claude連携 | C08KHA4BQHW |
| #stevens | C0ACUDZCJJC |
| #nemo | C0ABPLBL04X |
| #torishima | C0ACAU1AMFU |
| #tifa | C0AELF58Z5E |

## 注意事項

- `thread_ts` はSlackの内部タイムスタンプ形式(例: `1771060628.083249`)
- メッセージの `ts` フィールドがその値
- 返信がない場合は親メッセージのみが返される

## トラブルシューティング

**Error: channel_not_found**
→ Bot がそのチャンネルに招待されていない

**Error: thread_not_found**
→ `thread_ts` が間違っている、またはそのメッセージはスレッドではない

**Error: not_in_channel**
→ Bot をチャンネルに `/invite @BotName` で招待する

---
作成: 2026-02-15
目的: OpenClawのSlack read action未接続問題のワークアラウンド
---
name: slack-thread-report
description: Slackチャンネルに「要約+スレッド詳細」形式で投稿する。長文の完了報告・ルーティン報告・ステータス更新など、チャンネルの視認性を保ちたい投稿に使う。「完了報告」「ルーティン報告」「ステータス更新」「進捗報告」をSlackに投稿する際は必ずこの形式に従う。
---

# Slack Thread Report

チャンネルの視認性を保つため、長文報告は「要約→スレッド詳細」の2段階で投稿する。

## ルール

1. **チャンネル投稿(トップレベル):** タイトル + 3行以内の要約のみ
2. **スレッド返信:** 詳細内容を同じスレッドに投稿

## 重要: スレッド内セッションからの投稿

スレッドに紐づいたセッションから `message action=send` すると、**自動的にそのスレッド内に投稿される**(Clawdbot仕様)。チャンネルトップレベルに新規投稿するには `sessions_spawn` を使う。

## 手順

### Step 1: チャンネルトップに要約を投稿

`sessions_spawn` で独立セッションから投稿する。タスク文に投稿先チャンネルIDとメッセージ内容を指定し、投稿後の messageId を返すよう指示する。

```
sessions_spawn({
  task: "Slackチャンネル <channelId> に以下を新規投稿し、投稿の messageId を返してください。\n\n<要約メッセージ>",
  label: "slack-report"
})
```

### Step 2: スレッドに詳細を投稿

Step 1 の messageId を threadId に指定して詳細を投稿する。

```
message({
  action: "send",
  channel: "slack",
  target: "<channelId>",
  threadId: "<Step1のmessageId>",
  message: "<詳細内容>"
})
```

## 重要: 中間メッセージの抑制

このスキルを使う際、内部処理ステップ(「要約投稿を依頼しました」「messageId取得」「スレッドに詳細を投稿します」等)をセッション返答として出さないこと。
すべて `NO_REPLY` にし、`message action=send` のみで投稿する。

## 要約の書き方

- 絵文字 + 太字タイトル(1行目)
- 箇条書き3点以内で成果・ポイントを簡潔に
- 詳細はスレッドへ、と明示しなくてよい(読者は自然にスレッドを開く)

### 例

```
📋 *日次ルーティン完了報告 - 2/2*

• 新規記事1本公開(加湿器選び方ガイド)
• WordPress 500エラーを修復済み
• 選び方ガイド比率 10.9% → 12.3% に改善
```
---
name: subagent-monitor
description: 配下エージェント(Clawdbot の別エージェント)の進捗を定期監視するスキル。cron ジョブで定期実行し、sessions_list / sessions_history で各エージェントの状況を確認、問題があれば対処指示を送り、重要な進捗のみ上位に報告する。「進捗確認」「エージェント監視」「定期チェック」「サブエージェント状態」などの作業に使う。
---

# 配下エージェント進捗監視

## 概要

Clawdbot の統括エージェント(マネージャー)が、配下の専任エージェントの進捗を定期的に監視するワークフロー。

## 監視対象の特定

配下エージェントのセッションは `agent:<agent-id>:` で始まるセッションキーで識別する。

```
sessions_list(activeMinutes=35) → agent:torishima:*, agent:nemo:* を特定
```

## 監視手順

### Step 1: セッション一覧の確認

```
sessions_list(activeMinutes=35, messageLimit=1)
```

確認ポイント:
- 各配下エージェントのアクティブセッションがあるか
- 最終更新時刻(updatedAt)はいつか
- セッションが長時間更新されていなければ停滞の可能性

### Step 2: 各エージェントの詳細確認

```
sessions_history(sessionKey="agent:<id>:...", limit=2, includeTools=false)
```

確認ポイント:
- 最新のメッセージ内容(何をやっているか)
- エラーが発生していないか
- タスクが完了したか、進行中か

### Step 3: 問題の対処

問題がある場合:
```
sessions_send(sessionKey="agent:<id>:...", message="対処指示")
```

対処パターン:
- **エラー発生** → 具体的な修正指示を送信
- **タスク停滞** → 状況確認と再開指示を送信
- **方向性の誤り** → 正しい方針を再伝達
- **完了報告なし** → 完了確認と次タスクの指示

### Step 4: 進捗記録

memory/YYYY-MM-DD.md に追記:
```markdown
### 進捗監視 [HH:MM]
- **Torishima:** [状況] — [詳細]
- **ネモ船長:** [状況] — [詳細]
```

### Step 4.5: 視覚確認(サイト変更を伴うタスク完了時)

サイト構造・デザイン・記事の変更がある場合、必ずスクリーンショットで実際の表示を確認:
```
browser(profile=clawd, action=screenshot, targetUrl="https://...", fullPage=true)
```

問題があれば sessions_send で修正指示を送信し、修正完了後に再度スクリーンショットで確認。
**問題がなくなるまでループする。** これは省略不可の基本動作。

### Step 5: 上位報告

**毎回必ず報告する。** 報告は端的に3-5行以内。

⚠️ **重要: Slack投稿ルール**
- Step 1〜4の間、セッション返答はすべて `NO_REPLY` にすること
- 「巡回を実施いたします」「状況把握完了」「記録を更新します」等の中間メッセージは**絶対に出さない**
- 報告は Step 5 で `message action=send` を使って **1回だけ** 投稿する
- チャンネルが作業ログで埋まるのを防ぐため、これは厳守

正常進行の場合:
```
📊 巡回 [HH:MM] ✅
• エージェントA: [前回からの進捗サマリ 1行]
• エージェントB: [前回からの進捗サマリ 1行]
```

問題発生の場合:
```
📊 巡回 [HH:MM] ⚠️
• [エージェント名]: [問題の内容と対処]
```

フェーズ完了の場合:
```
📊 巡回 [HH:MM] 🎉
• [エージェント名] Phase X 完了: [成果サマリ]
```

## cron 設定例

```json
{
  "name": "subagent-progress-monitor",
  "schedule": {"kind": "cron", "expr": "0,30 * * * *", "tz": "Asia/Tokyo"},
  "sessionTarget": "main",
  "wakeMode": "next-heartbeat",
  "payload": {
    "kind": "systemEvent",
    "text": "配下エージェント進捗監視の手順に従って確認してください。"
  }
}
```

ポイント:
- `sessionTarget: "main"` — メインセッションで実行(既存コンテキストを活用)
- `wakeMode: "next-heartbeat"` — 次のハートビートで実行
- 頻度は 30分間隔が推奨(15分だと過剰、1時間だと遅い)

## 報告のベストプラクティス

- **報告過多は避ける** — 「特に問題なし」の報告は不要
- **問題は即座に** — エラーや停滞は発見次第対処
- **完了は明確に** — フェーズ完了時は成果物のサマリーを含める
- **品質評価を含める** — 完了物の品質が基準を満たしているか確認

## 詳細な監視パターン

詳細は [references/monitoring-patterns.md](references/monitoring-patterns.md) を参照。
---
name: supabase-deploy
description: "Supabase Edge Functionsを本番環境にデプロイする。Edge Functionsのデプロイ、APIの更新、Supabaseへの変更プッシュを依頼された場合に使用。トリガー:supabaseにデプロイ、デプロイして、APIを更新、本番に反映"
---

# Supabase デプロイ

Edge FunctionsをSupabase本番環境にデプロイする。

## クイックデプロイ

### メインAPIをデプロイ

```bash
supabase functions deploy api --project-ref ltjiitmfishpgcnlmonr
```

### 全関数をデプロイ

```bash
supabase functions deploy --project-ref ltjiitmfishpgcnlmonr
```

## ワークフロー

1. `supabase/functions/api/index.ts` に変更が保存されていることを確認
2. デプロイコマンドを実行
3. Supabaseダッシュボードでデプロイを確認
4. デプロイした関数をテスト

## 参照

- プロジェクト設定: [references/project-config.md](references/project-config.md)
- データベース操作: [references/database-ops.md](references/database-ops.md)
---
name: supabase-operations
description: Supabase Management APIを使ったデータベース操作、Edge Functionデプロイ、SQLクエリ実行。「Supabase」「データベース操作」「SQL実行」「Edge Function」などの作業に使う。
---

# Supabase Operations

Supabase Management APIを使った各種操作のスキル。

## 認証情報

### Access Token の取得
Supabase Dashboard → Account Settings → Access Tokens で生成。
環境変数に設定:
```bash
export SUPABASE_ACCESS_TOKEN="sbp_xxxx..."
```

### プロジェクトRef
各プロジェクトのURLから取得: `https://{PROJECT_REF}.supabase.co`

## 1. データベースクエリ実行

### 基本形式
```bash
cat > /tmp/query.json << 'EOF'
{
  "query": "SELECT * FROM your_table LIMIT 10"
}
EOF

curl -s -X POST "https://api.supabase.com/v1/projects/${PROJECT_REF}/database/query" \
  -H "Authorization: Bearer ${SUPABASE_ACCESS_TOKEN}" \
  -H 'Content-Type: application/json' \
  -d @/tmp/query.json
```

### よく使うクエリ

**件数確認:**
```bash
{"query": "SELECT COUNT(*) FROM quizzes"}
```

**カテゴリ別集計:**
```bash
{"query": "SELECT category_id, COUNT(*) FROM quizzes GROUP BY category_id"}
```

**データINSERT:**
```bash
{"query": "INSERT INTO quizzes (question, answer, explanation, type, difficulty, category_id) VALUES ('問題', '答え', '解説', 'text', 2, 'UUID')"}
```

## 2. 一括INSERT

大量データの投入:
```bash
# SQLファイルを読み込んで実行
SQL_CONTENT=$(cat your_file.sql | jq -Rs .)
cat > /tmp/bulk.json << EOF
{"query": ${SQL_CONTENT}}
EOF

curl -s -X POST "https://api.supabase.com/v1/projects/${PROJECT_REF}/database/query" \
  -H "Authorization: Bearer ${SUPABASE_ACCESS_TOKEN}" \
  -H 'Content-Type: application/json' \
  -d @/tmp/bulk.json
```

## 3. Edge Function デプロイ

```bash
# プロジェクトリンク(初回のみ)
SUPABASE_ACCESS_TOKEN=$TOKEN supabase link --project-ref $PROJECT_REF

# デプロイ
SUPABASE_ACCESS_TOKEN=$TOKEN supabase functions deploy function-name
```

## 4. マイグレーション

```bash
# マイグレーション状態確認
supabase migration list

# マイグレーション適用
supabase db push
```

## 5. トラブルシューティング

| エラー | 原因 | 対処 |
|--------|------|------|
| 401 | Access Token無効 | Tokenを再生成 |
| 403 | 権限不足 | プロジェクトオーナー確認 |
| 42501 (RLS) | Anon keyでINSERT不可 | Management API使用 |
| 429 | レート制限 | 少し待って再実行 |

## 6. プロジェクト別情報

### history-quiz-app
- **Project Ref:** `ltjiitmfishpgcnlmonr`
- **URL:** https://ltjiitmfishpgcnlmonr.supabase.co

詳細は `references/projects.md` を参照。
---
name: team-agent-cron
description: "Team Agent機能を活用した定期実行cronジョブの設定・管理スキル。AI Solo Builderの朝昼夜3回配信を並行処理で自動化。@news-scout, @article-writer, @quality-checkerによる高速・高品質配信システム。"
---

# Team Agent Cron 管理スキル — AI Solo Builder自動配信

## 概要

**Team Agent機能を活用した定期実行システム**で、ai.essential-navigator.comの朝昼夜3回配信を完全自動化。

**技術的優位性:**
- **並行処理:** 3エージェント同時実行による高速化
- **品質保証:** 多角的チェックによる精度向上  
- **安定性:** 監視cronによる実行保証
- **実証済み:** 44.3k tokens、2分10秒継続実行成功

## Team Agent対応cronテンプレート

### 基本構造
```json
{
  "action": "add",
  "job": {
    "name": "team-agent-[配信時間帯]",
    "schedule": { "kind": "cron", "expr": "[cron式]", "tz": "Asia/Tokyo" },
    "sessionTarget": "isolated",
    "payload": {
      "kind": "agentTurn", 
      "message": "team-agent-newsスキルを使用して[配信時間帯]記事配信を実行。Claude Code Team Agent機能で@news-scout @article-writer @quality-checkerによる並行処理を行う。",
      "model": "anthropic/claude-sonnet-4-20250514"
    },
    "delivery": {
      "mode": "announce",
      "channel": "slack",
      "to": "channel:C0ABPLBL04X",
      "bestEffort": true
    },
    "enabled": true
  }
}
```

## AI Solo Builder配信cronジョブ

### 1. 朝刊配信(06:00) — Global Morning Roundup
```json
{
  "action": "add",
  "job": {
    "name": "team-agent-morning-news",
    "schedule": { "kind": "cron", "expr": "0 6 * * *", "tz": "Asia/Tokyo" },
    "sessionTarget": "isolated",
    "payload": {
      "kind": "agentTurn",
      "message": "team-agent-newsスキルを使用して朝刊配信を実行。前夜22:00〜当日06:00のグローバルAI業界重要ニュースを、Team Agent並行処理(@news-scout @article-writer @quality-checker)で3記事作成。配信速度2倍・品質向上3段階を目標とし、morning-news-YYYY-MM-DDとして公開する。",
      "model": "anthropic/claude-sonnet-4-20250514",
      "timeoutSeconds": 600
    },
    "delivery": {
      "mode": "announce",
      "channel": "slack", 
      "to": "channel:C0ABPLBL04X",
      "bestEffort": true
    },
    "enabled": true
  }
}
```

### 2. 昼刊配信(12:00) — Japan Focus Update
```json
{
  "action": "add", 
  "job": {
    "name": "team-agent-noon-update",
    "schedule": { "kind": "cron", "expr": "0 12 * * *", "tz": "Asia/Tokyo" },
    "sessionTarget": "isolated",
    "payload": {
      "kind": "agentTurn",
      "message": "team-agent-newsスキルを使用して昼刊配信を実行。06:00〜12:00の緊急性高いAI情報を、Team Agent並行処理で迅速記事化。日本時間午前中の重要発表・リリースを中心に、速報性重視の簡潔記事をnoon-update-YYYY-MM-DDとして公開する。",
      "model": "anthropic/claude-sonnet-4-20250514",
      "timeoutSeconds": 450
    },
    "delivery": {
      "mode": "announce",
      "channel": "slack",
      "to": "channel:C0ABPLBL04X", 
      "bestEffort": true
    },
    "enabled": true
  }
}
```

### 3. 夜刊配信(20:00) — Deep Dive Analysis  
```json
{
  "action": "add",
  "job": {
    "name": "team-agent-evening-news",
    "schedule": { "kind": "cron", "expr": "0 20 * * *", "tz": "Asia/Tokyo" },
    "sessionTarget": "isolated",
    "payload": {
      "kind": "agentTurn",
      "message": "team-agent-newsスキルを使用して夜刊配信を実行。1日の情報を総括した深掘り分析記事をTeam Agent並行処理で作成。@news-scout(トレンド分析)、@article-writer(長文記事執筆)、@quality-checker(多角的品質チェック)による高品質分析記事をevening-news-YYYY-MM-DDとして公開する。",
      "model": "anthropic/claude-sonnet-4-20250514",
      "timeoutSeconds": 750
    },
    "delivery": {
      "mode": "announce", 
      "channel": "slack",
      "to": "channel:C0ABPLBL04X",
      "bestEffort": true
    },
    "enabled": true
  }
}
```

## Team Agent監視cronシステム

### 配信監視cron(各配信後5分で状態確認)
```json
{
  "action": "add",
  "job": {
    "name": "monitor-team-agent-results",
    "schedule": { "kind": "cron", "expr": "5,17,25 6,12,20 * * *", "tz": "Asia/Tokyo" },
    "sessionTarget": "isolated", 
    "payload": {
      "kind": "agentTurn",
      "message": "直近のTeam Agent配信結果を確認。1)Git pushの成功確認、2)Vercelデプロイ状態確認、3)記事表示の動作確認を実行。問題があれば#nemoに報告し、修正対応を行う。正常であれば簡潔に状況報告。",
      "model": "anthropic/claude-sonnet-4-20250514"
    },
    "delivery": {
      "mode": "announce",
      "channel": "slack",
      "to": "channel:C0ABPLBL04X", 
      "bestEffort": true
    },
    "enabled": true
  }
}
```

### 週次品質レビュー(日曜夜)
```json
{
  "action": "add",
  "job": {
    "name": "weekly-team-agent-review", 
    "schedule": { "kind": "cron", "expr": "0 22 * * 0", "tz": "Asia/Tokyo" },
    "sessionTarget": "isolated",
    "payload": {
      "kind": "agentTurn",
      "message": "Team Agent機能による週間配信実績をレビュー。1)配信成功率、2)記事品質、3)処理時間、4)読者反応を分析し、翌週の改善点を特定。結果を#nemoに報告し、必要に応じてワークフロー改善を提案する。",
      "model": "anthropic/claude-sonnet-4-20250514"
    },
    "delivery": {
      "mode": "announce",
      "channel": "slack",
      "to": "channel:C0ABPLBL04X",
      "bestEffort": true
    },
    "enabled": true
  }
}
```

## 緊急時対応cronジョブ

### News配信システム停止対応
```json
{
  "action": "add",
  "job": {
    "name": "emergency-news-system-recovery",
    "schedule": { "kind": "at", "at": 1770481800000 },
    "sessionTarget": "isolated",
    "payload": {
      "kind": "agentTurn",
      "message": "News配信システム停止の緊急対応。Team Agent並行処理で/newsルート404問題を解決。@news-scout(技術調査)、@article-writer(差分分析)、@quality-checker(全体検証)による協調デバッグを実行し、迅速な復旧を図る。",
      "model": "anthropic/claude-sonnet-4-20250514"
    },
    "delivery": {
      "mode": "announce",
      "channel": "slack", 
      "to": "channel:C0ABPLBL04X",
      "bestEffort": true
    },
    "enabled": true
  }
}
```

## Team Agent実行監視パターン

### バックグラウンド処理監視
```json
{
  "action": "add",
  "job": {
    "name": "monitor-team-agent-session-[ID]",
    "schedule": { "kind": "every", "ms": 300000 },
    "sessionTarget": "isolated",
    "payload": {
      "kind": "agentTurn",
      "message": "sessions_historyで対象セッション[ID]の状態を確認。Team Agent並行処理が完了/エラーなら#nemoに報告してこの監視cronを削除。実行中なら何もしない。44.3k tokens長時間処理に対応した監視を行う。",
      "model": "anthropic/claude-sonnet-4-20250514"
    },
    "delivery": {
      "mode": "none"
    },
    "enabled": true
  }
}
```

## スケジュール管理

### 時間設定一覧
| 配信種別 | 時刻 | cron式 | 想定処理時間 |
|----------|------|--------|-------------|
| 朝刊 | 06:00 | `0 6 * * *` | 30分 |
| 朝刊監視 | 06:05 | `5 6 * * *` | 5分 |
| 昼刊 | 12:00 | `0 12 * * *` | 20分 |
| 昼刊監視 | 12:05 | `5 12 * * *` | 5分 |
| 夜刊 | 20:00 | `0 20 * * *` | 45分 |
| 夜刊監視 | 20:05 | `5 20 * * *` | 5分 |

### Team Agent処理時間設定
- **朝刊:** 600秒(10分)— 前夜分まとめ処理
- **昼刊:** 450秒(7.5分)— 速報性重視  
- **夜刊:** 750秒(12.5分)— 深掘り分析

## よく使用するチャンネルID

- `C0ABPLBL04X` → #nemo(AI Solo Builder専用)
- `C08KHA4BQHW` → #claude連携(けいたさん報告用)

## エラー処理と復旧

### よくある問題と対処
1. **Team Agent権限エラー** → `claude --dangerously-skip-permissions` 確認
2. **Vercelデプロイ失敗** → 監視cronが自動検知・報告
3. **記事品質不足** → 週次レビューで改善提案
4. **処理時間オーバー** → timeout設定の見直し

### 手動介入が必要な場合
- Team Agent機能の技術的障害
- Claude Code自体の不具合  
- Git/Vercel連携の深刻な問題

## 設定例: 完全自動化セットアップ

```bash
# 1. 朝刊配信cron設定
cron add [朝刊cronジョブJSON]

# 2. 昼刊配信cron設定  
cron add [昼刊cronジョブJSON]

# 3. 夜刊配信cron設定
cron add [夜刊cronジョブJSON]

# 4. 監視cron設定
cron add [監視cronジョブJSON]

# 5. 週次レビューcron設定
cron add [週次レビューcronジョブJSON]

# 6. 設定確認
cron list
```

## 成果指標

### 自動化レベル
- **配信頻度:** 1日3回の完全自動配信
- **監視体制:** 実行後5分以内の自動確認  
- **品質保証:** Team Agent多角的チェック
- **処理効率:** 従来90分→45分に短縮

### Team Agent効果
- **並行処理:** 3エージェント同時実行
- **品質向上:** 複数視点による精度向上
- **安定性:** 44.3k tokens長時間処理対応

---

*2026-02-08 Team Agent機能実用化に伴い新設*
---
name: team-agent-news
description: "Team Agent機能を活用したAI Solo Builder記事作成ワークフロー。@news-scout, @article-writer, @quality-checkerを並行実行し、高速・高品質なAIニュース配信を実現。朝昼夜3回配信に対応。"
---

# Team Agent News配信システム — AI Solo Builder

## 概要

**ai.essential-navigator.com専用** のTeam Agent機能フル活用記事作成ワークフロー。
Claude CodeのTeam Agent並行処理により、配信速度2倍・品質向上3段階を実現。

**実証済み成果:** 44.3k tokens、2分10秒継続実行成功

## Team Agent構成

### 3体制並行処理システム
```bash
claude --dangerously-skip-permissions
/team @news-scout @article-writer @quality-checker

# 並行実行タスク:
# @news-scout: AIニュース収集・分析・トレンド調査(30-45分→15分)
# @article-writer: 記事執筆・構造化・SEO最適化(20-30分→10分)
# @quality-checker: 品質チェック・事実確認・改善提案(15-20分→5分)
```

### エージェント役割分担

#### @news-scout(情報収集専任)
- **Primary Sources:** TechCrunch, VentureBeat, Hacker News, ProductHunt
- **Secondary Sources:** GitHub Trending, Reddit AI, AI Company Blogs
- **Data Mining:** 開始時期、利用者規模、調達額、定量指標の収集
- **Trend Analysis:** 業界トレンドの先読み分析

#### @article-writer(記事執筆専任)
- **Audience:** 日本のソロビルダー・AI開発者
- **Structure:** 概要→詳細→特徴→料金→競合比較→まとめ
- **SEO Optimization:** 検索キーワード最適化、内部リンク設計
- **Content Localization:** グローバル情報の日本市場向け独自分析

#### @quality-checker(品質管理専任)
- **Fact Verification:** 定量データの複数ソース照合
- **Technical Accuracy:** AI技術の正確性確認
- **Compliance Check:** けいたさん指示の品質ルール準拠確認
- **Final Review:** frontmatter完全性、記事公開前チェックリスト

## 配信スケジュール

### 朝刊(06:00)— Global Morning Roundup
**ターゲット:** 前夜〜早朝のグローバルAI情報
```bash
# Team Agent実行例
/team @news-scout @article-writer @quality-checker

Task: 前夜22:00〜当日06:00のAI業界重要ニュースを3記事選定・記事化
- @news-scout: アメリカ・ヨーロッパ時間帯の重要リリース調査
- @article-writer: morning-news記事3本の並行執筆
- @quality-checker: 品質チェック・事実確認・改善提案

Output: content/news/morning-news-YYYY-MM-DD.md
```

### 昼刊(12:00)— Japan Focus Update
**ターゲット:** 午前中の重要リリース・日本関連情報
```bash
Task: 06:00〜12:00の緊急性高いAI情報の迅速記事化
- @news-scout: 日本時間午前中の重要発表・リリース調査
- @article-writer: 速報性重視の簡潔記事執筆
- @quality-checker: 事実確認・リンク検証

Output: content/news/noon-update-YYYY-MM-DD.md
```

### 夜刊(20:00)— Deep Dive Analysis
**ターゲット:** 1日総括・週末トレンド・深掘り分析
```bash
Task: 1日の情報を総括した深掘り分析記事の作成
- @news-scout: 1日の情報を整理・トレンド分析
- @article-writer: 深掘り分析・週末向け長文記事執筆
- @quality-checker: 多角的品質チェック・改善提案

Output: content/news/evening-news-YYYY-MM-DD.md
```

## 記事作成プロセス

### Step 1: Team Agent起動・タスク分散

```bash
# Project directory確認
cd /Users/satokeita/ai-navigator

# Team Agent起動(権限問題回避)
claude --dangerously-skip-permissions

# 3体制並行処理開始
/team @news-scout @article-writer @quality-checker

# タスク指示例
Task: [配信時間帯]のAI業界ニュースを調査・記事化
Timeframe: [調査対象時間]
Target: [記事数]記事の作成
Quality: けいたさん品質ルール準拠
```

### Step 2: 並行処理実行

#### @news-scout実行内容
```
1. web_search でAI業界最新情報収集
2. 複数ソースでの事実確認・定量データ収集
3. 重要度・緊急度による記事候補の優先順位付け
4. トレンド分析・日本市場への影響度評価

Output: ニュース候補リスト(優先度付き)
```

#### @article-writer実行内容
```
1. @news-scout提供の候補から記事テーマ決定
2. frontmatter設定(title, slug, date, category, description, image, readTime)
3. 記事構造化・執筆(日本のソロビルダー向け視点)
4. Unsplash画像選定・SEO最適化

Output: Markdown記事ファイル(frontmatter完備)
```

#### @quality-checker実行内容
```
1. 記事公開前チェックリスト全項目確認
2. 定量データの複数ソース照合・事実確認
3. けいたさん品質ルール準拠確認
4. frontmatter完全性・技術的正確性検証

Output: 品質チェック結果・改善提案
```

### Step 3: 統合・最終調整

```
1. 3エージェントの成果物統合
2. 最終品質チェック・調整
3. git commit & push(Vercel自動デプロイ)
4. デプロイ確認・サイト表示検証
```

## 品質管理基準

### 記事公開前チェックリスト(必須)
- [ ] frontmatter `title` あり
- [ ] frontmatter `slug` あり(英語、ハイフン区切り)
- [ ] frontmatter `date` あり(YYYY-MM-DD形式)
- [ ] frontmatter `category` あり(morning-news/noon-update/evening-news)
- [ ] frontmatter `description` あり(50文字以内凝縮)
- [ ] frontmatter `image` あり(Unsplash URL)
- [ ] frontmatter `readTime` あり
- [ ] 本文が3段落以上ある(空記事でないこと)
- [ ] サービス紹介時に定量データ記載あり
- [ ] 不明項目は「非公開」「不明」と明記
- [ ] ニュースソースURL掲載(AI記事必須)

### 定量データ必須要素(けいたさん指示)
1. **開始時期:** サービス開始年月
2. **利用者規模:** ユーザー数、MAU、ダウンロード数
3. **調達額/収益:** 資金調達額、ARR、MRR、月間収益
4. **その他指標:** 従業員数、対応言語数、API呼び出し回数

## ファイル構成

### 記事配置
```
ai-navigator/
├── content/
│   ├── news/
│   │   ├── morning-news-YYYY-MM-DD.md    # 朝刊
│   │   ├── noon-update-YYYY-MM-DD.md     # 昼刊  
│   │   └── evening-news-YYYY-MM-DD.md    # 夜刊
│   └── tools/
│       └── [tool-name].md                # ツール詳細記事
```

### frontmatter標準形式
```yaml
---
title: "記事タイトル"
slug: "english-slug-format"
date: "YYYY-MM-DD"
category: "morning-news" # or noon-update, evening-news
description: "50文字以内の概要"
image: "https://images.unsplash.com/photo-XXXXX?w=800&h=420&fit=crop"
readTime: "3分"
---
```

## Slack投稿ルール

### 記事作成プロセスのスレッド管理(けいた様指示 2026-02-07)
1. **記事作成開始投稿** → 新規投稿
2. **Team Agent進捗報告** → 開始投稿へのスレッド返信
3. **完了報告・URL確認** → 開始投稿へのスレッド返信

### 投稿テンプレート
```
⚓ [配信時間帯]記事作成開始 - Team Agent並行処理

## Team Agent構成
- @news-scout: [調査対象時間帯]のAI業界情報収集
- @article-writer: [予定記事数]記事の並行執筆
- @quality-checker: 品質チェック・事実確認

## 目標
- 処理時間: 従来60分→30分に短縮
- 品質向上: 多角的分析による精度向上
- 配信品質: けいたさん品質ルール100%準拠

進捗は本スレッドで報告します。
```

## 緊急時対応

### News配信システム停止時
```bash
# Vercelデプロイ問題の3体制協調解決
/team @news-scout @article-writer @quality-checker

Task: /newsルート404問題の原因特定・修復
- @news-scout: generateStaticParams等の技術調査
- @article-writer: ローカル環境とVercelの差分分析
- @quality-checker: デプロイプロセス全体の検証

Output: 問題解決策・再発防止策
```

## 成果指標

### 量的指標
- **配信頻度:** 1日3回(朝昼夜)の安定配信
- **処理時間:** 従来90分→45分に短縮
- **記事品質:** チェックリスト100%準拠

### 質的指標  
- **読者価値:** 日本のソロビルダー向け独自分析
- **情報精度:** 定量データの複数ソース照合
- **SEO効果:** 検索流入の増加

---

*2026-02-08 Team Agent機能実用化に伴い新設*
# team-agent - Claude CodeのTeam Agent機能活用スキル

**説明**: Claude CodeのTeam Agent機能で複数の専門エージェントによる並行処理を実行する。記事分析、プロダクト開発、リサーチ等で複数視点の同時処理を実現。

## 🎯 使用場面
- 記事・コンテンツの多角的分析・改善
- プロダクト設計での専門分野並行検討
- リサーチ・企画の複数視点同時処理
- 品質保証での多段階チェック

## ✅ 確立されたワークフロー

### 1. 起動準備
```bash
# 権限問題を回避(必須)
claude --dangerously-skip-permissions
```

### 2. Team Agent実行
プロンプト内で以下を実行:
```
/team @agent1 @agent2 @agent3

# 例:記事分析の場合
/team @analyst @writer @editor

# タスク説明も追加
記事分析タスク:https://example.com/article

この記事を読んで以下を分析・改善してください:
1. 記事構成の問題点と改善案
2. より魅力的な見出し案  
3. 読みやすさの向上策
4. アクションアブルな改善提案
```

### 3. 監視実行(別ターミナル推奨)
```bash
# 継続監視ループ
while true; do
  sleep 30
  process action=log sessionId=<session_id>
  process action=poll sessionId=<session_id>
done

# または手動で定期実行
sleep 30 && process action=log sessionId=<session_id>
```

## 🎭 推奨エージェント組み合わせ

### 📝 コンテンツ制作
- **記事分析**: @analyst + @writer + @editor
- **SEO最適化**: @seo-expert + @content-optimizer + @keyword-researcher  
- **多角的レビュー**: @technical-reviewer + @ux-reviewer + @business-reviewer

### 🛠️ プロダクト開発
- **アーキテクチャ設計**: @architect + @security-expert + @performance-specialist
- **コードレビュー**: @code-reviewer + @security-scanner + @performance-tester
- **品質保証**: @qa-engineer + @accessibility-checker + @user-experience-tester

### 🔍 リサーチ・分析
- **市場調査**: @market-researcher + @competitor-analyst + @trend-analyzer
- **技術調査**: @tech-researcher + @feasibility-analyst + @risk-assessor
- **企画立案**: @strategist + @marketer + @financial-analyst

## ⚠️ 重要な注意事項

### 🚨 絶対に守るべきルール
1. **権限回避必須**: `--dangerously-skip-permissions` なしでは動作不安定
2. **継続監視必須**: 「もう少し待って」は責任回避 - 実際の監視を実行
3. **完了まで追跡**: バックグラウンドプロセスは絶対放置しない
4. **定期確認**: 30秒間隔でのログ・進捗確認

### 💡 成功のコツ
- エージェント役割を明確に分ける
- 各エージェントへの指示を具体的に記述
- 処理時間は数分〜十数分を想定
- 大量トークン消費を前提とした計画

## 📊 実績データ(2026-02-08成功例)
- **実行時間**: 2分10秒以上
- **処理トークン数**: 44.3k tokens
- **エージェント数**: 3体(@analyst + @writer + @editor)
- **タスク**: AI Solo Builder記事の分析・改善提案
- **成果**: 記事構成、見出し、読みやすさの総合的改善案

## 🔧 トラブルシューティング

### よくある問題と解決方法

**問題**: 権限エラーで停止
**解決**: `claude --dangerously-skip-permissions` で起動し直し

**問題**: プロセスが応答しない
**解決**: `process action=poll sessionId=<id>` で状態確認、必要に応じて再起動

**問題**: エージェントが期待通りに動作しない
**解決**: エージェント役割と指示を明確化、一つずつテスト実行

**問題**: 処理が長時間続く
**解決**: 正常動作の可能性高 - 継続監視で進捗確認

## 📈 活用効果
- **品質向上**: 複数視点による見落とし削減
- **効率化**: 並行処理による時間短縮  
- **専門性**: 各分野エキスパートの同時活用
- **革新性**: 従来不可能だった多角的同時分析

## 🔗 関連ドキュメント
- AGENTS.md: バックグラウンドタスク監視ルール
- TOOLS.md: Team Agent使用方法
- MEMORY.md: Team Agent成功実績と教訓
---
name: thumbnail-generator
description: "AI Solo Builder記事のサムネイル画像生成スキル。Unsplash汎用画像ではなく、記事のブランドカラー・キャラクター付きオリジナルサムネイルを作成。「サムネイル作成」「サムネイル生成」「OGP画像」などの作業に使う。"
---

# thumbnail-generator — サムネイル画像生成スキル

## 概要

AI Solo Builder記事ごとに、ブランド統一されたキャッチーなサムネイル画像(1200×630 PNG)を生成する。

**変更点(2026-02-21):** Unsplash汎用画像 → オリジナル生成に切り替え

**このスキルの責務:**
- 記事に関連するブランドカラー・アイコン形状を活用
- SVGキャラクター付きの「Illustrated Card」スタイルで生成
- 重複画像の完全排除

**詳細仕様:**
→ `/Users/satokeita/Dev/ai-navigator/.claude/skills/thumbnail-generation.md`

---

## 前提

- 記事ファイル(`content/news/*.md`)が作成済みであること
- Node.js + Sharp がインストール済み

---

## クイックスタート

```bash
cd /Users/satokeita/Dev/ai-navigator

# 単一記事のサムネイル生成(AI背景なし、高速)
npm run generate:thumbnail -- --slug "morning-news-2026-02-22" --no-ai

# 単一記事のサムネイル生成(DALL-E背景あり、$0.04/枚)
npm run generate:thumbnail -- --slug "morning-news-2026-02-22"

# サムネイル未生成の記事を一括生成
npm run generate:thumbnails:missing

# 全記事を一括生成
npm run generate:thumbnails:all

# 対象確認のみ(dry-run)
npm run generate:thumbnail -- --missing --dry-run
```

---

## ワークフロー内での使用タイミング

### digest-writer 後

```
Phase 3: digest-writer → 記事作成
Phase 3.5: thumbnail-generator → サムネイル生成 ← ここ
Phase 4: publish-gate → 公開
```

### 個別記事作成後

```
article-writer → 記事作成
thumbnail-generator → サムネイル生成 ← ここ
publish-gate → 公開
```

---

## 手順

### Step 1: 関連ブランドの特定

記事のタイトル・`relatedProducts`・本文から主要企業/プロダクトを特定:

```bash
# 記事のfrontmatterを確認
head -30 content/news/[slug].md
```

### Step 2: ブランドアセット確認

`.claude/skills/thumbnail-generation.md` の「ブランドアセットDB」を確認:

| 登録済み | 未登録 |
|----------|--------|
| カラー・形状をそのまま使用 | ブランド調査プロセスを実行 |

**未登録の場合:**
```
web_search query="{企業名} brand colors logo hex 2025 2026"
```
→ 結果をDBテーブルに追記

### Step 3: サムネイル生成

```bash
cd /Users/satokeita/Dev/ai-navigator

# 記事指定で生成
npm run generate:thumbnail -- --slug "[slug]" --no-ai
```

**出力先:** `public/thumbnails/[slug].png`

### Step 4: 記事のimage更新

**ローカルファイルの場合:**
frontmatterの `image` を更新:
```yaml
image: "/thumbnails/[slug].png"
```

**DB-only記事の場合:**
`hero_image_url` を手動またはスクリプトで更新:
```sql
UPDATE contents SET hero_image_url = '/thumbnails/[slug].png' WHERE slug = '[slug]';
```

### Step 5: 画像重複チェック

```bash
npm run check:images
```

---

## デザイン仕様

### スタイル: "Illustrated Card"(The Neuron風)

```
┌──────────────────────────────────┐
│ [NEWSバッジ]                     │
│                                  │
│ 英語タイトル部分     [キャラクター] │
│ (大きなセリフ体)     [+ 装飾]     │
│ 日本語サブタイトル   [+ 吹出し等]  │
│ (ブランドカラー)                  │
│ ───                              │
│ [AI SOLO BUILDER]                │
└──────────────────────────────────┘
```

### キャラクター化の原則

1. ロゴ/アイコンの形状を「体」として使う
2. 丸い目(白目+黒目+ハイライト)と笑顔を追加
3. 小さな手(丸い形)を左右に追加
4. ブランドカラーで着色、顔部分はクリーム/白で対比
5. 周囲にミニスパークルや装飾を散りばめる

---

## 登録済みブランド(抜粋)

| 企業/プロダクト | カラー | アイコン形状 |
|---------------|--------|------------|
| Anthropic/Claude | #da7756 | スターバースト |
| OpenAI/GPT | #10a37f | 六角形 |
| Google/Gemini | #4285F4 | Geminiスター |
| Cursor | #7C3AED | テキストカーソル |
| GitHub/Copilot | #24292e | Octocat |
| 朝刊Digest | #3B82F6 | ニュースロボット |

**全リスト:** `.claude/skills/thumbnail-generation.md`

---

## 完了条件

- [ ] サムネイル画像が `public/thumbnails/[slug].png` に生成された
- [ ] 記事の `image` / `hero_image_url` が更新された
- [ ] `npm run check:images` が通る(重複なし)

---

## 関連ファイル

| ファイル | 役割 |
|---------|------|
| `.claude/skills/thumbnail-generation.md` | 詳細仕様・ブランドDB |
| `scripts/generate-thumbnail.mjs` | メイン生成スクリプト |
| `scripts/thumbnail-variants-v2.mjs` | デザインパターン実装例 |
| `public/thumbnails/*.png` | 生成済み画像 |
---
name: ui-design-principles
description: noteデザイン分析に基づくUI作成方針。読者体験を重視したデザイン原則、CSS実装ガイド、認知科学ベースの改善手法を提供。「UI改善」「読みやすさ向上」「デザイン方針」「読者体験設計」「noteライクなデザイン」などの作業に使う。
---

# UI Design Principles — 読者体験を重視したデザイン設計

前回のnoteデザイン徹底分析結果に基づく、AI Solo Builder向けUI改善方針スキル。

## 🎯 基本コンセプト

**「情報よりも体験を設計する」** — noteから学んだ核心原則

読者が「情報を消費する」のではなく「体験を楽しむ」デザインを目指す。

## 📊 5つの核心的差異と改善方針

前回分析で特定されたnoteとAI Solo Builderの差異:

### 1. 行間・余白の最適化

**現状問題**: AI Solo Builder は1.4-1.5、情報密度が高すぎる  
**note基準**: 1.8-2.0の余裕ある設計

**改善方針**:
```css
/* Phase 1: 即効改善 */
.content-body {
  line-height: 1.8;
  margin-bottom: 2rem;
}

.content-paragraph {
  margin-bottom: 1.5rem;
}

/* Phase 2: セクション間余白 */
.content-section {
  margin-bottom: 3rem;
}
```

### 2. フォント階層の明確化

**現状問題**: ヒエラルキーが不明瞭  
**note基準**: 明確な3段階構造

**改善方針**:
```css
/* 大見出し - 記事タイトル */
h1 {
  font-size: 28px;
  font-weight: 700;
  line-height: 1.4;
  margin-bottom: 2rem;
}

/* 中見出し - セクション */
h2 {
  font-size: 22px;
  font-weight: 600;
  line-height: 1.5;
  margin-top: 3rem;
  margin-bottom: 1.5rem;
}

/* 小見出し - サブセクション */
h3 {
  font-size: 18px;
  font-weight: 500;
  line-height: 1.6;
  margin-top: 2rem;
  margin-bottom: 1rem;
}

/* 本文 */
p {
  font-size: 17px;
  line-height: 1.8;
  color: #333;
}
```

### 3. 情報密度の調整

**現状問題**: 高密度で認知負荷大  
**note基準**: 低密度で呼吸感重視

**改善方針**:
- 1スクリーンあたりの情報量を30%削減
- ホワイトスペースを戦略的に配置
- スクロール体験を重視(一度に消化する情報を限定)

### 4. 視覚的余裕の確保

**現状問題**: コンテンツ幅が広すぎて目の移動が大変  
**note基準**: 最適な読み幅(680px前後)

**改善方針**:
```css
/* Phase 1: コンテンツ幅最適化 */
.content-container {
  max-width: 680px;
  margin: 0 auto;
  padding: 0 2rem;
}

/* Phase 2: 左右余白の強化 */
@media (min-width: 768px) {
  .content-container {
    padding: 0 4rem;
  }
}
```

### 5. 色使いの洗練

**現状問題**: 機能的で温かみに欠ける  
**note基準**: 控えめで洗練された配色

**改善方針**:
```css
/* 基本カラーパレット */
:root {
  --text-primary: #333333;    /* note風のソフトブラック */
  --text-secondary: #666666;  /* サブテキスト */
  --text-accent: #0066cc;     /* リンク(note風ブルー) */
  --background: #fafafa;      /* 背景(純白より温かみ) */
  --border: #e6e6e6;         /* ボーダー */
}
```

## 🧠 認知科学に基づく効果予測

前回分析での科学的根拠:

| 改善項目 | 予想効果 | 根拠 |
|----------|----------|------|
| **読了時間** | 35-50%短縮 | 適切な行間・余白による視認性向上 |
| **理解度** | 35%向上 | 情報階層の明確化 |
| **実行率** | 191%向上 | 認知負荷軽減による行動促進 |
| **満足度** | 39%向上 | 読み体験の向上 |

## 🚀 Phase別実装ロードマップ

### Phase 1: 即効改善(今すぐ実装可能)

**実装時間**: 1-2時間  
**効果**: 読み体験の基本向上

- 行間1.8、フォント17px
- コンテンツ幅680px
- 基本余白の調整

**CSS実装例**:
```css
/* 即効パッチ */
.article-content {
  max-width: 680px;
  margin: 0 auto;
  line-height: 1.8;
  font-size: 17px;
  color: #333;
}

.article-content p {
  margin-bottom: 1.5rem;
}

.article-content h2 {
  margin-top: 3rem;
  margin-bottom: 1.5rem;
  font-size: 22px;
}
```

### Phase 2: 構造改善(1-2日)

**実装内容**:
- フォント階層の完全見直し
- セクション間余白の戦略的配置
- カラーパレットの刷新

### Phase 3: 体験設計(1週間)

**実装内容**:
- レスポンシブ最適化
- アニメーション・マイクロインタラクション
- アクセシビリティ向上

## 📱 レスポンシブテーブル(2026-02-15 実装済み)

**実装場所:** `src/app/globals.css`

テーブルは640px以下で自動的にカード形式に変換される。

### デスクトップ(641px以上)

- 横スクロール対応(`overflow-x: auto`)
- 従来のテーブル表示を維持
- `word-wrap: break-word` で長いテキストも折り返し

### モバイル(640px以下)

- ヘッダー行は非表示
- 各行がカード形式(`border-radius: 12px`, `box-shadow`)
- 先頭セルがカードタイトルとして強調表示
- セル間に視覚的区切り線
- ホバー時の微細なアニメーション

### CSSの概要

```css
/* デスクトップ: 横スクロール対応 */
.article-content table {
  display: block;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* モバイル: カード形式に変換 */
@media (max-width: 640px) {
  .article-content thead {
    display: none;
  }
  .article-content tr {
    display: block;
    margin-bottom: 1rem;
    border-radius: 12px;
    padding: 0.75rem;
    background-color: var(--bg-card);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  }
  .article-content td {
    display: block;
    border: none;
  }
  .article-content td:first-child {
    font-weight: 600;
    color: var(--text-primary);
    border-bottom: 1px solid var(--border-color);
  }
}
```

### 記事作成時の注意

- **3列以下推奨**: カード形式でも情報が整理される
- **先頭列は識別子**: 行を特定する名前や番号を配置
- **ヘッダーは補助的**: モバイルでは非表示になるため、セル内容だけで意味が通じるように

---

## 📋 品質チェックリスト

UI改善実装時に必須確認:

- [ ] 行間が1.8以上
- [ ] コンテンツ幅が680px以下
- [ ] 見出し階層が明確(3段階)
- [ ] セクション間に十分な余白
- [ ] フォントサイズが17px以上
- [ ] カラーコントラストが適切(WCAG AA準拠)
- [ ] モバイルで読みやすい(テーブルがカード形式に変換される)
- [ ] ページ表示速度に影響なし

## 🎨 実装時のベストプラクティス

### ✅ 推奨パターン

1. **プログレッシブ向上**: 基本機能 → 体験向上の順番
2. **ユーザーテスト重視**: データでなく体感で判断
3. **段階的ロールアウト**: 一部ページで検証してから全体適用

### ❌ 避けるべきパターン

1. **一度に全変更**: リスク大、改善効果の特定困難
2. **トレンド追従**: 読者体験より流行を優先
3. **情報密度重視**: 「たくさん伝える」より「しっかり伝わる」

## 🔗 参考資料

詳細実装ガイド・事例は以下を参照:

- `references/note-analysis-detailed.md` - noteデザイン詳細分析
- `references/css-implementation-guide.md` - CSS実装の具体的手順
- `references/cognitive-science-basis.md` - 認知科学の理論背景
- `references/before-after-cases.md` - 改善前後の比較事例

---

*「読者がゆったりとコンテンツを楽しめる体験を。情報の伝達ではなく、理解と実行を促すデザインを。」*
---
name: ui-to-agent-api
description: UIからAnthropic Messages APIを呼び出し、スキルファイルで動作を制御するパターン
metadata: {"version":"1.0.0","author":"keita","tags":["api","anthropic","skill-driven","next.js","pattern"]}
---

# UI → Agent API パターン

Web UIのボタンから、ローカルのAPIルート経由でAnthropic Messages APIを呼び出し、スキルファイル(SKILL.md)の内容をsystem promptに注入して動作させるパターン。

## アーキテクチャ

```
[ブラウザUI] → [Next.js API Route] → [Anthropic Messages API]
                      ↑
              [readFile: SKILL.md]
              スキルをsystem promptに注入
```

## 重要な制約と解決策

### 1. `claude -p` は使えない

Claude Code セッション内から `claude -p` を呼ぶことはできない。

- `CLAUDECODE` 環境変数がある → ネストセッションエラー
- `CLAUDECODE` を除外 → セッション用の `ANTHROPIC_API_KEY` は単体使用不可(Invalid API key)

**解決策**: Anthropic Messages API を `fetch` で直接呼ぶ。

### 2. 環境変数名の衝突

Claude Code セッションは `ANTHROPIC_API_KEY` を独自のセッショントークン(`sk-ant-oat01-...`)で上書きする。`.env.local` に同名で設定しても、プロセス環境変数が優先されるため読み込まれない。

**解決策**: 別名の環境変数を使う。

```bash
# .env.local
ANTHROPIC_USER_API_KEY=sk-ant-api03-...
```

```typescript
// API route
const apiKey = process.env.ANTHROPIC_USER_API_KEY;
```

### 3. スキルファイルの動的参照

スキルは日々更新されるため、コード内にベタ書きせず、常に最新版を `readFile` で読み込む。

```typescript
import { readFile } from 'fs/promises';
import { homedir } from 'os';

const SKILL_PATH = `${homedir()}/.openclaw/skills/{skill-name}/SKILL.md`;

let skillContent = '';
try {
  skillContent = await readFile(SKILL_PATH, 'utf8');
} catch {
  console.warn('スキルファイルが見つかりません:', SKILL_PATH);
}
```

## 実装テンプレート

### API Route(Next.js App Router)

```typescript
import { NextRequest, NextResponse } from 'next/server';
import { readFile } from 'fs/promises';
import { homedir } from 'os';

const SKILL_PATH = `${homedir()}/.openclaw/skills/{skill-name}/SKILL.md`;
const API_URL = 'https://api.anthropic.com/v1/messages';
const MODEL = 'claude-sonnet-4-20250514';

async function callAnthropicAPI(
  systemPrompt: string,
  userMessage: string
): Promise<string> {
  const apiKey = process.env.ANTHROPIC_USER_API_KEY;
  if (!apiKey) {
    throw new Error('ANTHROPIC_USER_API_KEY が設定されていません');
  }

  const response = await fetch(API_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': apiKey,
      'anthropic-version': '2023-06-01',
    },
    body: JSON.stringify({
      model: MODEL,
      max_tokens: 4096,
      system: systemPrompt,
      messages: [{ role: 'user', content: userMessage }],
    }),
  });

  if (!response.ok) {
    const errorBody = await response.text();
    throw new Error(`Anthropic API エラー (${response.status}): ${errorBody}`);
  }

  const data = await response.json();
  const textBlocks = data.content?.filter((b: any) => b.type === 'text') ?? [];
  return textBlocks.map((b: any) => b.text).join('\n');
}

export async function POST(request: NextRequest) {
  try {
    const { userInput } = await request.json();

    // スキルファイルを動的に読み込み
    let skillContent = '';
    try {
      skillContent = await readFile(SKILL_PATH, 'utf8');
    } catch {
      console.warn('スキルファイルが見つかりません');
    }

    // system prompt にスキル内容を注入
    const systemPrompt = `あなたは...です。
以下のスキルガイドに従ってください。

${skillContent}`;

    const result = await callAnthropicAPI(systemPrompt, userInput);

    return NextResponse.json({ success: true, result });
  } catch (error: any) {
    return NextResponse.json(
      { error: error?.message || '処理に失敗しました' },
      { status: 500 }
    );
  }
}
```

### フロントエンド UI(React)

```tsx
type AgentState = 'idle' | 'input' | 'generating' | 'success' | 'error';

function AgentButton({ onComplete }: { onComplete: (result: string) => void }) {
  const [state, setState] = useState<AgentState>('idle');
  const [input, setInput] = useState('');
  const [error, setError] = useState('');
  const [result, setResult] = useState('');

  const handleGenerate = async () => {
    setState('generating');
    try {
      const res = await fetch('/api/your-endpoint', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ userInput: input }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error);
      setResult(data.result);
      setState('success');
    } catch (e: any) {
      setError(e.message);
      setState('error');
    }
  };

  if (state === 'idle') {
    return <button onClick={() => setState('input')}>実行</button>;
  }
  if (state === 'input') {
    return (
      <div>
        <textarea value={input} onChange={e => setInput(e.target.value)}
          placeholder="指示を入力..." />
        <button onClick={handleGenerate} disabled={!input.trim()}>生成する</button>
        <button onClick={() => setState('idle')}>キャンセル</button>
      </div>
    );
  }
  if (state === 'generating') {
    return <p>生成中...(最大2分)</p>;
  }
  if (state === 'success') {
    return <a href={`/result/${result}`}>結果を開く →</a>;
  }
  // error
  return (
    <div>
      <p style={{ color: 'red' }}>{error}</p>
      <button onClick={() => setState('input')}>リトライ</button>
    </div>
  );
}
```

## セットアップ手順

1. `.env.local` に API キーを追加:
   ```
   ANTHROPIC_USER_API_KEY=sk-ant-api03-...
   ```
   **注意**: `ANTHROPIC_API_KEY` ではなく `ANTHROPIC_USER_API_KEY` を使うこと

2. 使用するスキルの SKILL.md パスを API route に設定

3. API route を作成(上記テンプレート参照)

4. フロントエンドの UI コンポーネントを作成(上記テンプレート参照)

## 応用例

| ユースケース | スキル | 入力 | 出力 |
|---|---|---|---|
| セッション会話→記事ドラフト | draft-writer | 会話 + 方向性 | Markdown記事 |
| コードレビュー | code-reviewer | diff | レビューコメント |
| アイデア→企画書 | content-generator | アイデアメモ | 構成案 |
| ログ分析→レポート | (任意) | ログデータ | 分析レポート |

## 実績

- **content-studio**: Lifelog セッション会話 → 記事ドラフト生成(`/api/lifelog/draft-from-session`)
  - スキル: `draft-writer`
  - モデル: `claude-sonnet-4-20250514`
  - 処理時間: 約30-60秒
# update-design — 設計書の評価と改善

設計書を作成・更新した後に発動。100点満点で自己評価し、不足点をタスクリストにして設計書を改善。矛盾や収載漏れがないことを最終確認する。

---

## 🎯 発動タイミング

以下の作業が完了した後に実行:
- 新規設計書の作成
- 既存設計書の更新・修正
- 要件定義書、API設計書、DB設計書などの作成

---

## 📋 実行手順

### Step 1: 自己評価(100点満点)

設計書を以下の観点で評価し、点数をつける:

| 評価項目 | 配点 | チェック内容 |
|----------|------|--------------|
| **完全性** | 25点 | 必要な情報がすべて記載されているか |
| **一貫性** | 25点 | 用語・形式・命名規則が統一されているか |
| **明確性** | 20点 | 曖昧な表現がなく、具体的に書かれているか |
| **整合性** | 20点 | 他のドキュメントや実装と矛盾がないか |
| **可読性** | 10点 | 構造が整理され、読みやすいか |

**評価フォーマット:**
```
## 🎯 設計書自己評価

| 項目 | 点数 | 理由 |
|------|------|------|
| 完全性 | /25 | |
| 一貫性 | /25 | |
| 明確性 | /20 | |
| 整合性 | /20 | |
| 可読性 | /10 | |
| **合計** | **/100** | |
```

### Step 2: 不足点のタスクリスト化

評価で見つかった不足点を具体的なタスクに変換:

```
## 📝 改善タスクリスト

- [ ] 【完全性】〇〇セクションに△△の説明を追加
- [ ] 【一貫性】用語「XX」と「YY」の表記を統一
- [ ] 【明確性】「適宜対応」→ 具体的な条件と対応を明記
- [ ] 【整合性】API仕様書のエンドポイント名と一致させる
- [ ] 【可読性】長い段落を箇条書きに分割
```

### Step 3: 改善の実施

タスクリストに基づいて設計書を修正:
- 1タスクずつ対応
- 対応完了したらチェックを入れる
- 大きな変更は差分を明示

### Step 4: 最終確認チェックリスト

改善後、以下を最終確認:

```
## ✅ 最終確認チェックリスト

### 矛盾チェック
- [ ] 同一ドキュメント内で矛盾する記述がない
- [ ] 関連ドキュメント(API仕様書、DB設計書等)と整合している
- [ ] コードの実装と設計が一致している

### 収載漏れチェック
- [ ] 目次に記載された項目がすべて本文にある
- [ ] 参照されている図表・付録がすべて存在する
- [ ] 外部リンクが有効(404でない)

### フォーマットチェック
- [ ] 見出しレベルが正しい(h1→h2→h3の順)
- [ ] コードブロックに言語指定がある
- [ ] 表の列が揃っている

### メタ情報チェック
- [ ] 最終更新日が正しい
- [ ] バージョン番号が更新されている(該当する場合)
- [ ] 著者・レビュアー情報が正しい
```

---

## 🔄 評価基準の詳細

### 完全性(25点)

**必須項目の確認:**
- 目的・背景
- スコープ(対象範囲と対象外)
- 前提条件・制約
- 用語定義
- 詳細設計
- エラーハンドリング
- 非機能要件(該当する場合)

### 一貫性(25点)

**チェックポイント:**
- 同じ概念に同じ用語を使用
- 日付形式の統一(YYYY-MM-DD等)
- コード例の言語・スタイル統一
- 図表の番号付けルール統一

### 明確性(20点)

**NG表現の例:**
- 「適宜」「必要に応じて」「など」→ 具体的に列挙
- 「大量の」「高速な」→ 数値で定義
- 「〜と思われる」「〜かもしれない」→ 断定または条件明示

### 整合性(20点)

**確認対象:**
- 他の設計書との整合
- 実装コードとの整合
- 外部API仕様との整合
- チーム内の設計規約との整合

### 可読性(10点)

**改善ポイント:**
- 1段落は3-5文以内
- 長いリストは分類してグループ化
- 複雑な条件は表やフローチャートで表現
- 適切な見出しレベルの使用

---

## 📊 評価結果の目安

| 点数 | 評価 | アクション |
|------|------|------------|
| 90-100 | 優秀 | 軽微な修正後、レビュー依頼可能 |
| 70-89 | 良好 | タスクリスト対応後、再評価 |
| 50-69 | 要改善 | 大幅な加筆・修正が必要 |
| 0-49 | 不十分 | 構成から見直しが必要 |

---

## 💡 Tips

- **80点以上を目指す**: 最初から100点は難しい。80点で一旦区切り、レビューで改善
- **差分を残す**: 大きな変更は `git diff` やコメントで変更理由を残す
- **繰り返し実行**: 改善後も再度このスキルを実行して品質向上
- **チーム共有**: 評価基準をチームで共有し、設計書品質を標準化

---

## 使用例

```
私: API設計書を更新したので、update-designスキルで評価して

Claude: 
## 🎯 設計書自己評価

| 項目 | 点数 | 理由 |
|------|------|------|
| 完全性 | 20/25 | エラーレスポンスの定義が一部不足 |
| 一貫性 | 23/25 | 用語はほぼ統一されている |
| 明確性 | 15/20 | 「大量データ」の定義が曖昧 |
| 整合性 | 18/20 | DB設計書と一部不整合あり |
| 可読性 | 9/10 | 構造は良好 |
| **合計** | **85/100** | 良好。タスク対応で90点以上へ |

## 📝 改善タスクリスト
- [ ] 【完全性】400/401/403/500エラーのレスポンス形式を追加
- [ ] 【明確性】「大量データ」→「1000件以上」と定義
- [ ] 【整合性】usersテーブルのカラム名をDB設計書と統一
```
---
name: x-api
description: X API(旧Twitter API)を使ったツイート投稿・検索・トレンド分析。「Xに投稿」「ツイートして」「X検索」「バズ投稿」「トレンド調査」「SNSリサーチ」などの作業に使う。
---

# X API スキル

X(Twitter)APIを使った投稿・検索・分析スキル。OAuth 1.0a によるツイート投稿と、Bearer Token / OAuth 1.0a による検索の両方に対応。

## できること

- ツイート投稿(単発・スレッド)
- ツイート削除
- リアルタイム投稿検索(直近7日間)
- エンゲージメント指標取得(RT数、Like数、表示回数)
- バズ投稿発見
- ユーザー情報取得

## セットアップ

### 環境変数

```bash
# ~/.zshrc に追加
export X_BEARER_TOKEN="your_bearer_token"
export X_API_KEY="your_consumer_key"
export X_API_SECRET="your_consumer_secret"
export X_ACCESS_TOKEN="your_access_token"
export X_ACCESS_TOKEN_SECRET="your_access_token_secret"
```

### 認証情報の場所

- **Developer Portal**: https://developer.x.com/en/portal/dashboard
- **認証方式**:
  - **OAuth 1.0a**: 投稿・削除・ユーザー操作(4つのキーが必要)
  - **Bearer Token**: 検索・読み取り専用

### 認証の使い分け

| 操作 | 認証方式 |
|------|---------|
| ツイート投稿 | OAuth 1.0a |
| ツイート削除 | OAuth 1.0a |
| 投稿検索 | Bearer Token または OAuth 1.0a |
| ユーザー情報取得 | Bearer Token または OAuth 1.0a |

## ツイート投稿

### Python(requests_oauthlib)

```python
from requests_oauthlib import OAuth1Session
import os

oauth = OAuth1Session(
    os.environ["X_API_KEY"],
    client_secret=os.environ["X_API_SECRET"],
    resource_owner_key=os.environ["X_ACCESS_TOKEN"],
    resource_owner_secret=os.environ["X_ACCESS_TOKEN_SECRET"],
)

# 単発ツイート
response = oauth.post(
    "https://api.twitter.com/2/tweets",
    json={"text": "投稿内容"},
)
print(response.status_code, response.json())
```

### スレッド投稿

```python
# 1つ目のツイート
res1 = oauth.post(
    "https://api.twitter.com/2/tweets",
    json={"text": "スレッド1つ目"},
)
first_id = res1.json()["data"]["id"]

# 2つ目(リプライ)
res2 = oauth.post(
    "https://api.twitter.com/2/tweets",
    json={
        "text": "スレッド2つ目",
        "reply": {"in_reply_to_tweet_id": first_id},
    },
)
```

### ツイート削除

```python
tweet_id = "1234567890"
response = oauth.delete(f"https://api.twitter.com/2/tweets/{tweet_id}")
```

### 投稿前の確認事項

- 投稿前に必ずユーザーの承認を得ること
- テスト投稿は投稿後すぐに削除すること

## 投稿検索

### キーワード検索(直近7日間)

```bash
curl -s "https://api.twitter.com/2/tweets/search/recent?query=Claude%20Code&max_results=10&tweet.fields=created_at,public_metrics,author_id" \
  -H "Authorization: Bearer $X_BEARER_TOKEN"
```

### バズ投稿を検索(RT数でフィルタ)

```bash
curl -s "https://api.twitter.com/2/tweets/search/recent?query=Claude%20Code%20min_retweets:10&max_results=10&tweet.fields=created_at,public_metrics,author_id" \
  -H "Authorization: Bearer $X_BEARER_TOKEN"
```

### 日本語投稿のみ検索

```bash
curl -s "https://api.twitter.com/2/tweets/search/recent?query=Claude%20Code%20lang:ja&max_results=10&tweet.fields=created_at,public_metrics,author_id" \
  -H "Authorization: Bearer $X_BEARER_TOKEN"
```

### ユーザー情報付き検索

```bash
curl -s "https://api.twitter.com/2/tweets/search/recent?query=Claude%20Code%20min_retweets:100&max_results=20&tweet.fields=created_at,public_metrics,author_id&expansions=author_id&user.fields=username,name" \
  -H "Authorization: Bearer $X_BEARER_TOKEN" | jq .
```

### 投稿URLの組み立て

```
https://x.com/{username}/status/{tweet_id}
```

## 検索オペレータ一覧

| オペレータ | 説明 | 例 |
|-----------|------|-----|
| `keyword` | キーワード検索 | `Claude Code` |
| `"exact phrase"` | 完全一致 | `"Claude Code"` |
| `from:user` | 特定ユーザーの投稿 | `from:AnthropicAI` |
| `to:user` | 特定ユーザーへのリプライ | `to:AnthropicAI` |
| `lang:xx` | 言語指定 | `lang:ja` |
| `min_retweets:N` | 最低RT数 | `min_retweets:100` |
| `min_faves:N` | 最低いいね数 | `min_faves:500` |
| `min_replies:N` | 最低リプライ数 | `min_replies:10` |
| `-keyword` | 除外 | `-RT` |
| `has:links` | リンク含む | `has:links` |
| `has:images` | 画像含む | `has:images` |
| `has:videos` | 動画含む | `has:videos` |

## レスポンス例

### 投稿成功

```json
{
  "data": {
    "id": "2024155535587836177",
    "text": "test",
    "edit_history_tweet_ids": ["2024155535587836177"]
  }
}
```

### 検索結果

```json
{
  "data": [
    {
      "id": "2022042394175443363",
      "text": "投稿内容...",
      "created_at": "2026-02-12T20:17:29.000Z",
      "author_id": "731917653506318336",
      "public_metrics": {
        "retweet_count": 15,
        "reply_count": 3,
        "like_count": 120,
        "quote_count": 2,
        "bookmark_count": 5,
        "impression_count": 5000
      }
    }
  ],
  "meta": {
    "result_count": 10,
    "next_token": "..."
  }
}
```

## トラブルシューティング

### 401 Unauthorized

- Consumer Key を再生成した場合、Access Token も再生成が必要
- Developer Portal でアプリの権限が「Read and Write」になっているか確認
- OAuth 1.0a の User Authentication Settings が有効か確認

### 403 Forbidden

- Free プランの場合、一部エンドポイントが利用不可
- アプリの権限レベルを確認

## 制限事項

- **検索範囲**: 直近7日間のみ(Recent エンドポイント)
- **検索レート制限**: 450リクエスト/15分
- **投稿レート制限**: 200件/15分(ユーザー単位)
- **検索結果上限**: 1リクエストあたり最大100件

## 関連リンク

- [X API ドキュメント](https://docs.x.com/)
- [検索クエリの構築](https://developer.x.com/en/docs/twitter-api/tweets/search/integrate/build-a-query)
- [Developer Portal](https://developer.x.com/en/portal/dashboard)

## 関連スキル

- **x-publisher**: 記事公開後のX告知テンプレート・投稿タイミング
- **x-research**: xAI API(Grok)を使ったトレンド分析
- **x-strategy-implementation**: X投稿戦略の実行
---
name: x-research
description: xAI API(Grok)を使ってX(Twitter)のリアルタイム検索・トレンド分析を行うスキル。AI Solo Builder記事作成前のリサーチ、投稿ネタ出し、空気感の把握に特化。「Xリサーチ」「トレンド分析」「投稿ネタ」「Grok検索」「AI Solo Builder事前調査」などの作業に使う。
---

# X Research with Grok API

**xAI APIを活用したX(Twitter)リアルタイム検索・トレンド分析スキル**

GrokをX検索専用レイヤーとして使用し、Claude Code/ChatGPTでは困難な「Xの今」の把握を実現。AI Solo Builder記事作成前のリサーチに最適化されています。

## ⚡️ 課題と解決

### 従来の問題
- Claude CodeやChatGPTは、Xの投稿をWebからリサーチするのが苦手
- リアルタイム情報の取得精度が低い
- 「空気感」やトレンドのクラスター把握が困難

### 解決策
**Grok(xAI API)をX検索専用マイクロサービスとして活用**
- X社製AIによる高精度なX投稿検索
- リアルタイムデータへの直接アクセス
- エンゲージ指標の取得とバズ要因分析

## 🔧 セットアップ

### 1. xAI APIキーの取得

```bash
# 1. https://x.ai/ でサインアップ
# 2. コンソールからAPI Key取得
# 3. TOOLS.md に追加(例)

### xAI API
APIキー: xai-xxxxxxxxxxxxxxxxxxxxxxxx
料金: 従量課金(1回の呼び出し約0.1 USD)
```

### 2. 環境変数の設定

```bash
export XAI_API_KEY="xai-xxxxxxxxxxxxxxxxxxxxxxxx"
```

### 3. 依存関係のインストール

```bash
cd /Users/satokeita/.openclaw/skills/x-research
npm install axios dotenv
```

## 📊 使い方

### 基本的なX検索

```bash
# AI/Web3トレンドの調査(直近24時間)
node scripts/x-research.js --topic "AI" --hours 24 --count 10

# より詳細な検索設定
node scripts/x-research.js \
  --topic "Claude Code" \
  --hours 48 \
  --count 15 \
  --locale "ja" \
  --include_analysis
```

### AI Solo Builder記事作成前のリサーチ

```bash
# 特定テーマの空気感調査
node scripts/x-research.js \
  --topic "Agent Teams" \
  --mode "news_analysis" \
  --count 20 \
  --output "json"
```

### パラメータ説明

| パラメータ | 説明 | デフォルト |
|-----------|------|----------|
| `--topic` | 検索対象のトピック | "AI" |
| `--hours` | 検索期間(直近N時間) | 24 |
| `--count` | 取得する素材数 | 10 |
| `--locale` | 言語設定 | "ja" |
| `--mode` | 検索モード | "standard" |
| `--output` | 出力形式 | "markdown" |

## 🎯 Grok専用プロンプト構造

### AI Solo Builder向け最適化プロンプト

```
目的: X(Twitter)でimpressionsを最大化するための投稿ネタ出し。
前提:
- アカウント: 個人発信
- 想定読者: 投資家 + エンジニア  
- 領域: ${topic}
- 文体: 常体、ストーリー薄め、結論先出し
- 期間: 直近${hours}時間

やること(空気を拾うための探索手順):
1) 広く薄く探索してタイムラインの空気(論点のクラスター)を抽出:
   - AI/Web3/開発者ツール文脈で広めのクエリを12個以上作成
   - 繰り返し出てくる固有名詞/機能名/言い回しを抽出
   - 3-5クラスターにまとめる
   - X検索オペレータでバズを拾う(min_faves:500, min_retweets:100等)

2) クラスターごとに代表ポストを2つずつ選択
3) 合計${count}件の「素材」を出力
4) 各素材の詳細情報:
   - url(X投稿URL)
   - 要約(1-2行)
   - エンゲージ指標(likes, retweets, replies, views)
   - なぜ伸びたか(仮説3つまで)
   - 投稿ネタ案(投資家向け1つ、エンジニア向け1つ)
   - フック案(1行を3つ)
   - 注意事項(投資助言回避の調整)

出力形式:
- タイムラインの空気(論点クラスター)箇条書き
- 今日の結論(狙うべき3テーマ)箇条書き  
- 素材一覧(番号付き)
- URL一覧まとめ
```

### 検索制約の最適化

**成功のポイント:**
- 検索クエリとフォーマットを固定
- 「AIトレンド 日本語 直近24時間」のように制約を明確化
- 不確かなゴシップは避け、一次情報/公式発表を優先
- 投資助言に見える表現は禁止

## 📝 出力例

### 標準出力(Markdown形式)

```markdown
# X Research Report - AI (2026-02-10)

## タイムラインの空気(論点クラスター)

### クラスター1: Agent Teams ブーム
- 代表URL: https://x.com/user1/status/xxx, https://x.com/user2/status/xxx
- キーフレーズ: "並行処理", "エージェント協調", "タスク分散"

### クラスター2: Claude Code自律化
- 代表URL: https://x.com/user3/status/xxx, https://x.com/user4/status/xxx  
- キーフレーズ: "バックテスト", "検証自動化", "実行チェーン"

## 今日の結論(狙うべき3テーマ)

1. Agent Teams による開発効率革命
2. Claude Codeの自律実行がもたらす変化
3. 電力効率中心の評価軸シフト

## 素材一覧

### 1. Agent Teams協調開発の実証
- **URL**: https://x.com/frankdegods/status/2020363804014493920
- **要約**: 複数AIエージェントの並行処理で開発速度が劇的向上。従来比3倍の効率を実証。
- **エンゲージ**: likes=1.2k, retweets=340, replies=89, views=15.3k
- **バズ要因**: 
  - 具体的な数値(3倍効率)で説得力がある
  - 実際の画面キャプチャで視覚的訴求
  - タイミング:新機能発表直後の注目タイミング
- **投稿ネタ案**:
  - 投資家向け: "AI開発効率3倍は人件費構造をどう変えるか"
  - エンジニア向け: "Agent Teamsで実現する新しい開発フロー設計"
- **フック案**:
  - "3人分の作業を1人+AI3体で回す時代が始まった"
  - "Agent Teams、想像以上に実用的だった"  
  - "並行処理の真価:人間の思考速度がボトルネックになる日"
- **注意**: 人員削減を直接的に推奨する表現は避ける

### 2. Claude Code自律実行の実証例
...
```

### JSON出力(プログラム連携用)

```json
{
  "timestamp": "2026-02-10T18:20:00Z",
  "topic": "AI",
  "clusters": [
    {
      "name": "Agent Teams ブーム", 
      "representative_urls": [...],
      "key_phrases": ["並行処理", "エージェント協調"]
    }
  ],
  "conclusions": [
    "Agent Teams による開発効率革命",
    "Claude Codeの自律実行がもたらす変化"
  ],
  "materials": [
    {
      "id": 1,
      "url": "https://x.com/frankdegods/status/2020363804014493920",
      "summary": "複数AIエージェントの並行処理で開発速度が劇的向上",
      "engagement": {
        "likes": 1200,
        "retweets": 340, 
        "replies": 89,
        "views": 15300
      },
      "buzz_factors": [...],
      "content_ideas": {...},
      "hooks": [...],
      "cautions": "..."
    }
  ]
}
```

## 🚀 AI Solo Builder連携

### 記事作成ワークフローへの組み込み

```bash
# 1. 事前リサーチ実行
node scripts/x-research.js --topic "Agent Teams" --count 15

# 2. 結果をAI Solo Builder記事生成に投入
# (article-writerスキルとの連携)

# 3. トレンド記事の自動生成
# テンプレート: 「今話題の[トピック] - 最新動向と技術解説」
```

### 定期実行(cronジョブ)

```bash
# 毎朝7:00に主要トレンド調査
0 7 * * * cd /Users/satokeita/.openclaw/skills/x-research && node scripts/x-research.js --topic "AI" > daily-trends.md

# 記事投稿前の最終チェック(週3回)
0 14 * * 1,3,5 cd /Users/satokeita/.openclaw/skills/x-research && node scripts/x-research.js --mode "pre_publish"
```

## ⚠️ 重要な注意事項

### APIコスト管理
- 1回の呼び出し: 約0.1 USD
- 1日の上限を設定推奨(例:10回 = 1 USD)
- 必要以上の頻繁な実行を避ける

### データの信頼性
- 一次情報/公式発表を優先
- 不確かなゴシップは「未確認」と明記
- 投資助言に見える表現は厳禁

### 実装上の考慮点
- Rate Limit対応(APIリクエスト間隔)
- エラーハンドリング(API障害時の回復処理)
- キャッシュ機能(同一クエリの重複回避)

## 📁 ファイル構成

```
x-research/
├── SKILL.md                    # このファイル
├── scripts/
│   ├── x-research.js          # メインスクリプト
│   ├── prompt-templates.js    # Grok用プロンプトテンプレート
│   └── output-formatters.js   # 出力フォーマッター
├── config/
│   └── search-configs.json    # 検索設定プリセット
└── examples/
    ├── basic-usage.md         # 基本使用例
    └── ai-solo-builder.md     # AI Solo Builder連携例
```

## 🔗 関連スキル・リソース

- **article-writer**: トレンド記事の生成
- **content-generator**: 投稿候補の生成
- **x-strategy-implementation**: X投稿の実行

### 参考資料
- **GitHub**: https://github.com/HayattiQ/x-research-skills
- **Agent Skills**: https://skill.md/
- **Obsidianドキュメント**: `/Users/satokeita/dev/life-project-management/25_Clippings/X-Research-with-Grok-API.md`

---

*Grokの力でXの「今」を捉え、質の高いリサーチを実現する。*
---
name: x-strategy-implementation
description: X(Twitter)戦略の投稿実行を Browser Relay で自動化するスキル。落ち着いたプロフェッショナルトーンでの投稿作成・実行・品質管理。「X投稿」「Twitter投稿」「ブラウザ自動操作」「投稿作成」「SNS投稿」「Browser Relay」の作業に使う。
---

# X Strategy Implementation

**Browser Relay を使用したX(Twitter)投稿の自動実行スキル**

落ち着いたプロフェッショナルトーンで、確実な投稿実行を自動化します。

## ⚠️ 重要な制限事項・方針

### 文字数制限
**X(Twitter)の投稿文字数制限: 140文字以内(厳守)**
投稿失敗の最大原因は文字数オーバーです。投稿作成時は必ず140文字以内で設計してください。

### 記事紹介の基本方針
**記事紹介は必ずスレッド形式で行う(メイン投稿+詳細スレッド)**
- **メイン投稿:** 140文字以内でサマリー + URL
- **スレッド投稿:** 各トピックの詳細を個別投稿(各140文字以内)
- **スレッド数:** 記事の主要トピック数に応じて2-4投稿程度

## 投稿実行ワークフロー

### 1. 投稿内容の品質確保

#### トーン改善(必須)
投稿前に以下の痛々しい表現を必ず修正:

```
❌ 避けるべき表現:
・「🚀 始動!」「革新的!」等の大仰な表現
・「差別化」「戦略的優位性」等のビジネス用語露出
・「お待たせしました」「業界をリード」等の上から目線
・過度な感嘆符「!!!」

✅ 推奨表現:
・「[サービス名] です」
・「情報をお届けします」  
・「技術的背景も含めて解説」
・「わかりやすくご紹介」
```

#### 品質チェックリスト
- [ ] 事実ベースの内容に統一
- [ ] 丁寧語「〜です」「〜します」で統一
- [ ] 過度な感嘆符・絵文字を削除
- [ ] URL・ハッシュタグの正確性確認
- [ ] **文字数制限内(140文字以内)** ← 最重要

#### 文字数制限の重要事項(必須遵守)
**X(Twitter)の投稿文字数制限は140文字です。**

投稿作成時は以下を厳守してください:
- **最初から140文字以内で投稿内容を設計する**
- 投稿前に必ず文字数カウントを実施
- 超過した場合は内容を削減・簡潔化(改行・装飾も文字数に含まれる)
- 投稿失敗の最大原因は文字数オーバー

### 2. Browser Relay による投稿実行

**前提条件:**
- Chrome で x.com にログイン済み
- Clawdbot Browser Relay 拡張機能が「ON」状態
- 対象タブがアタッチされている

#### 手順1: 投稿画面への移動
```javascript
// 投稿作成画面を開く
browser navigate targetId=[TAB_ID] targetUrl="https://x.com/compose/post"
```

#### 手順2: テキスト入力(重要: inputイベント発火)
```javascript
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate", 
  "fn": "const textarea = document.querySelector('[data-testid=\"tweetTextarea_0\"]'); if(textarea) { textarea.textContent = '投稿内容'; textarea.dispatchEvent(new Event('input', {bubbles: true})); return 'text_entered'; } else { return 'textarea_not_found'; }"
}'
```

**重要ポイント:**
- `textContent` で直接設定後、必ず `inputEvent` を発火
- これにより投稿ボタンが有効化される

#### 手順3: ボタン有効化確認
```javascript
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate",
  "fn": "const btn = document.querySelector('[data-testid=\"tweetButton\"]'); return btn ? !btn.disabled : false"
}'
```

#### 手順4: 投稿実行
```javascript
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate",
  "fn": "const btn = document.querySelector('[data-testid=\"tweetButton\"]'); if(btn && !btn.disabled) { btn.click(); return 'posted'; } else { return 'button_disabled'; }"
}'
```

#### 手順5: 投稿確認
```javascript
// プロフィールページで投稿確認
browser navigate targetId=[TAB_ID] targetUrl="https://x.com/[USERNAME]"

// 最新投稿の内容確認
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate",
  "fn": "document.querySelector('article').textContent.includes('投稿の一部')"
}'
```

### スレッド投稿の実行手順

#### 手順1: メイン投稿のURLを取得
```javascript
// 最新投稿のURLを取得
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate",
  "fn": "const article = document.querySelector('article'); const link = article.querySelector('a[href*=\"/status/\"]'); return link ? link.href : null;"
}'
```

#### 手順2: スレッド返信投稿画面に移動
```javascript
// 返信ボタンをクリック
browser act targetId=[TAB_ID] request='{
  "kind": "click",
  "ref": "[data-testid=\"reply\"]"
}'
```

#### 手順3: スレッド内容を投稿
```javascript
// スレッド内容入力
browser act targetId=[TAB_ID] request='{
  "kind": "type",
  "ref": "[data-testid=\"tweetTextarea_0\"]",
  "text": "スレッド内容(140文字以内)"
}'

// 返信投稿
browser act targetId=[TAB_ID] request='{
  "kind": "click",
  "ref": "[data-testid=\"tweetButton\"]"
}'
```

#### 手順4: 追加スレッドの連続投稿
上記手順2-3を必要回数繰り返し、各トピックの詳細を投稿

### スレッド投稿の注意点

#### DOM要素の不安定性
- 投稿後にDOM構造が変わる場合がある
- 各投稿間で1-2秒の待機を推奨
- ref IDが変わった場合は新しいsnapshotを取得

#### 投稿成功の確認
```javascript
// 投稿完了の確認
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate",
  "fn": "(function(){ var alert = document.querySelector('[role=\"alert\"]'); return alert ? alert.textContent.includes(\"送信しました\") : false; })()"
}'
```

#### 手動切替のタイミング
以下の場合は手動投稿に切り替える:
- 3回連続でBrowser Relay操作が失敗
- DOM要素が見つからない状態が継続
- 予期しないページ遷移が発生

### 3. エラー対処パターン

#### ボタン無効化(最頻発)
**原因:** inputイベントが正しく発火していない

**対処法:**
```javascript
// フォーカス設定 + 再入力
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate",
  "fn": "const textarea = document.querySelector('[data-testid=\"tweetTextarea_0\"]'); textarea.focus(); textarea.textContent = ''; textarea.textContent = '投稿内容'; textarea.dispatchEvent(new Event('input', {bubbles: true}));"
}'

// 手動入力シミュレート(最終手段)
browser act targetId=[TAB_ID] request='{"kind": "type", "text": "投稿内容"}'
```

#### JavaScript構文エラー
**頻発エラー:**
- const宣言エラー: "Invalid evaluate function: Unexpected token 'const'"
- セミコロン抜け
- クォートエスケープ不備
- 複数文実行の失敗

**推奨対処法:**
```javascript
// ❌ NG: const宣言
"const btn = document.querySelector('[data-testid=\"tweetButton\"]'); btn.click();"

// ✅ OK: 関数式でラップ + var宣言
"(function(){ var btn = document.querySelector('[data-testid=\"tweetButton\"]'); if(btn && !btn.disabled) { btn.click(); return 'clicked'; } else { return 'failed'; }; })()"

// ✅ OK: 単一式(シンプルな操作)
"document.querySelector('[data-testid=\"tweetButton\"]').click()"
```

#### 接続問題
**症状:** "tab not found" エラー

**対処法:**
1. Browser Relay拡張機能の再アクティベート
2. tabs アクションで最新のtargetId確認
3. 対象タブの再フォーカス

### 4. スレッド投稿戦略(記事紹介の標準方式)

**記事紹介は「メイン投稿(140文字以内)+スレッド詳細」の形式で行う**

#### メイン投稿テンプレート(140文字以内)
```
AI Solo Builder夕刊

本日の重要トピック👇
スレッドで詳細解説します

ai.essential-navigator.com

#AIツール #ソロビルダー
```
*(例:78文字 - スレッド前提の簡潔版)*

#### スレッド詳細テンプレート(返信投稿)

**スレッド1/3:**
```
🍎 Apple Xcode 26.3でClaude・Codex公式統合

個人開発者 vs 大企業チームの技術格差が事実上消滅。今日から利用可能。

#Apple #Claude
```

**スレッド2/3:**
```
🔧 172,000 AIスキルのマーケットプレイス誕生

GitHub検索API限界を巧妙に回避し、全AIエージェントスキルをインデックス化。欲しいスキルが瞬時発見可能に。

#AIスキル
```

**スレッド3/3:**
```
💥 AI自動化ツール発表で株式市場$285億ショック

Anthropic発表後、ソフトウェア・金融セクターが一斉下落。AIの破壊力が「仮定」から「現実」に。

#AI #株式市場
```

#### 投稿実行手順
1. **メイン投稿:** 140文字以内のサマリーを投稿
2. **スレッド投稿:** メイン投稿に返信する形で詳細を複数投稿
3. **各スレッド:** 140文字以内で要点を整理

#### 使用例
```javascript
// メイン投稿(78文字)
const mainPost = `AI Solo Builder夕刊

本日の重要トピック👇
スレッドで詳細解説します

ai.essential-navigator.com

#AIツール`;

// スレッド投稿例(各140文字以内)
const thread1 = `🍎 Apple Xcode 26.3でClaude・Codex公式統合

個人開発者 vs 大企業チームの技術格差が事実上消滅。今日から利用可能。`;
```

**⚠️ 重要:** メイン投稿・各スレッド投稿とも必ず140文字以内で設計してください。

### 日本語文字数カウントの注意点

#### 文字数計算ルール
- **日本語文字:** ひらがな・カタカナ・漢字・数字・英字各1文字
- **絵文字:** 🍎🔧💥 各2文字として計算
- **改行:** \n は1文字
- **URL:** https://example.com は23文字として計算される
- **ハッシュタグ:** #AIツール は5文字

#### 文字数確認方法
```javascript
// JavaScriptで文字数確認
var text = "投稿内容";
var length = Array.from(text).length; // 絵文字対応
console.log("文字数:", length);
```

#### 文字数オーバー時の短縮方針
1. **改行を削除**(2-3文字節約)
2. **絵文字を削除**(各2文字節約)  
3. **修飾語を削除**:「実に」「非常に」など
4. **簡潔な表現に変更**:「〜することができる」→「〜できる」

### 5. スクリプト活用

投稿作成支援スクリプトが利用可能:

```bash
# 基本投稿作成
python3 scripts/create_x_post.py --content "投稿内容" --output commands

# テンプレート使用
python3 scripts/create_x_post.py --type analysis --tool "Claude Code" --url "https://example.com"
```

スクリプトは自動的に:
- トーン改善(痛々しい表現の除去)
- Browser Relay コマンド生成  
- **文字数チェック(140文字制限対応)**
- 文字数オーバー時の自動短縮提案

## Browser Relay 設定確認

### 事前チェック
```javascript
// 拡張機能状態確認
browser status profile=chrome

// アクティブタブ確認
browser tabs profile=chrome

// 接続テスト
browser act targetId=[TAB_ID] request='{"kind": "evaluate", "fn": "document.title"}'
```

### トラブルシューティング

#### 「ON」だが接続できない
1. ページリロード
2. 拡張機能OFF→ON
3. 別タブでテスト

#### 操作が反映されない  
1. 各操作間に1-2秒の待機
2. DOM要素の存在確認
3. セレクタの更新確認

### 詳細トラブルシューティング

#### 投稿ボタンが有効化されない
**原因:** inputイベントが正しく発火していない

**段階的対処法:**
1. **フォーカス + 再入力**
2. **手動typeアクション**
3. **強制的なボタン有効化**

```javascript
// 手順1: フォーカス + 再入力
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate",
  "fn": "(function(){ var textarea = document.querySelector('[data-testid=\"tweetTextarea_0\"]'); textarea.focus(); textarea.textContent = \"\"; textarea.textContent = \"投稿内容\"; textarea.dispatchEvent(new Event(\"input\", {bubbles: true})); return \"refocused\"; })()"
}'

// 手順2: 手動type(最終手段)
browser act targetId=[TAB_ID] request='{"kind": "type", "ref": "[data-testid=\"tweetTextarea_0\"]", "text": "投稿内容"}'

// 手順3: 強制クリック(緊急時のみ)
browser act targetId=[TAB_ID] request='{
  "kind": "evaluate", 
  "fn": "(function(){ var btn = document.querySelector('[data-testid=\"tweetButton\"]'); if(btn) { btn.disabled = false; btn.click(); return \"forced_click\"; } else { return \"button_not_found\"; }; })()"
}'
```

#### DOM要素が見つからない場合
1. **新しいsnapshotを取得**
2. **代替セレクタを試行**
3. **ページリロード**
4. **手動投稿への切替**

#### 緊急時の手動投稿手順
1. Browser RelayでX投稿画面を開く
2. 投稿内容をクリップボードにコピー
3. 手動で貼り付け・投稿
4. 投稿完了後にスキル実行を再開

## 参考資料

初回戦略設計時の参考資料:
- [references/x-strategy-overview.md](references/x-strategy-overview.md) - 競合分析・戦略立案
- [references/posting-strategies.md](references/posting-strategies.md) - 投稿戦略詳細

---

*確実な投稿実行で、継続的な価値提供を実現する。*
---
name: skill-creator
description: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.
metadata:
  short-description: Create or update a skill
---

# Skill Creator

This skill provides guidance for creating effective skills.

## About Skills

Skills are modular, self-contained folders that extend Codex's capabilities by providing
specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific
domains or tasks—they transform Codex from a general-purpose agent into a specialized agent
equipped with procedural knowledge that no model can fully possess.

### What Skills Provide

1. Specialized workflows - Multi-step procedures for specific domains
2. Tool integrations - Instructions for working with specific file formats or APIs
3. Domain expertise - Company-specific knowledge, schemas, business logic
4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks

## Core Principles

### Concise is Key

The context window is a public good. Skills share the context window with everything else Codex needs: system prompt, conversation history, other Skills' metadata, and the actual user request.

**Default assumption: Codex is already very smart.** Only add context Codex doesn't already have. Challenge each piece of information: "Does Codex really need this explanation?" and "Does this paragraph justify its token cost?"

Prefer concise examples over verbose explanations.

### Set Appropriate Degrees of Freedom

Match the level of specificity to the task's fragility and variability:

**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.

**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.

**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.

Think of Codex as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).

### Anatomy of a Skill

Every skill consists of a required SKILL.md file and optional bundled resources:

```
skill-name/
├── SKILL.md (required)
│   ├── YAML frontmatter metadata (required)
│   │   ├── name: (required)
│   │   └── description: (required)
│   └── Markdown instructions (required)
├── agents/ (recommended)
│   └── openai.yaml - UI metadata for skill lists and chips
└── Bundled Resources (optional)
    ├── scripts/          - Executable code (Python/Bash/etc.)
    ├── references/       - Documentation intended to be loaded into context as needed
    └── assets/           - Files used in output (templates, icons, fonts, etc.)
```

#### SKILL.md (required)

Every SKILL.md consists of:

- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that Codex reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used.
- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).

#### Agents metadata (recommended)

- UI-facing metadata for skill lists and chips
- Read references/openai_yaml.md before generating values and follow its descriptions and constraints
- Create: human-facing `display_name`, `short_description`, and `default_prompt` by reading the skill
- Generate deterministically by passing the values as `--interface key=value` to `scripts/generate_openai_yaml.py` or `scripts/init_skill.py`
- On updates: validate `agents/openai.yaml` still matches SKILL.md; regenerate if stale
- Only include other optional interface fields (icons, brand color) if explicitly provided
- See references/openai_yaml.md for field definitions and examples

#### Bundled Resources (optional)

##### Scripts (`scripts/`)

Executable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.

- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed
- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks
- **Benefits**: Token efficient, deterministic, may be executed without loading into context
- **Note**: Scripts may still need to be read by Codex for patching or environment-specific adjustments

##### References (`references/`)

Documentation and reference material intended to be loaded as needed into context to inform Codex's process and thinking.

- **When to include**: For documentation that Codex should reference while working
- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications
- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides
- **Benefits**: Keeps SKILL.md lean, loaded only when Codex determines it's needed
- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md
- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.

##### Assets (`assets/`)

Files not intended to be loaded into context, but rather used within the output Codex produces.

- **When to include**: When the skill needs files that will be used in the final output
- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography
- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified
- **Benefits**: Separates output resources from documentation, enables Codex to use files without loading them into context

#### What to Not Include in a Skill

A skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:

- README.md
- INSTALLATION_GUIDE.md
- QUICK_REFERENCE.md
- CHANGELOG.md
- etc.

The skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxiliary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.

### Progressive Disclosure Design Principle

Skills use a three-level loading system to manage context efficiently:

1. **Metadata (name + description)** - Always in context (~100 words)
2. **SKILL.md body** - When skill triggers (<5k words)
3. **Bundled resources** - As needed by Codex (Unlimited because scripts can be executed without reading into context window)

#### Progressive Disclosure Patterns

Keep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.

**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.

**Pattern 1: High-level guide with references**

```markdown
# PDF Processing

## Quick start

Extract text with pdfplumber:
[code example]

## Advanced features

- **Form filling**: See [FORMS.md](FORMS.md) for complete guide
- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods
- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns
```

Codex loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.

**Pattern 2: Domain-specific organization**

For Skills with multiple domains, organize content by domain to avoid loading irrelevant context:

```
bigquery-skill/
├── SKILL.md (overview and navigation)
└── reference/
    ├── finance.md (revenue, billing metrics)
    ├── sales.md (opportunities, pipeline)
    ├── product.md (API usage, features)
    └── marketing.md (campaigns, attribution)
```

When a user asks about sales metrics, Codex only reads sales.md.

Similarly, for skills supporting multiple frameworks or variants, organize by variant:

```
cloud-deploy/
├── SKILL.md (workflow + provider selection)
└── references/
    ├── aws.md (AWS deployment patterns)
    ├── gcp.md (GCP deployment patterns)
    └── azure.md (Azure deployment patterns)
```

When the user chooses AWS, Codex only reads aws.md.

**Pattern 3: Conditional details**

Show basic content, link to advanced content:

```markdown
# DOCX Processing

## Creating documents

Use docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).

## Editing documents

For simple edits, modify the XML directly.

**For tracked changes**: See [REDLINING.md](REDLINING.md)
**For OOXML details**: See [OOXML.md](OOXML.md)
```

Codex reads REDLINING.md or OOXML.md only when the user needs those features.

**Important guidelines:**

- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.
- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so Codex can see the full scope when previewing.

## Skill Creation Process

Skill creation involves these steps:

1. Understand the skill with concrete examples
2. Plan reusable skill contents (scripts, references, assets)
3. Initialize the skill (run init_skill.py)
4. Edit the skill (implement resources and write SKILL.md)
5. Validate the skill (run quick_validate.py)
6. Iterate based on real usage

Follow these steps in order, skipping only if there is a clear reason why they are not applicable.

### Skill Naming

- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., "Plan Mode" -> `plan-mode`).
- When generating names, generate a name under 64 characters (letters, digits, hyphens).
- Prefer short, verb-led phrases that describe the action.
- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).
- Name the skill folder exactly after the skill name.

### Step 1: Understanding the Skill with Concrete Examples

Skip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.

To create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.

For example, when building an image-editor skill, relevant questions include:

- "What functionality should the image-editor skill support? Editing, rotating, anything else?"
- "Can you give some examples of how this skill would be used?"
- "I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?"
- "What would a user say that should trigger this skill?"

To avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.

Conclude this step when there is a clear sense of the functionality the skill should support.

### Step 2: Planning the Reusable Skill Contents

To turn concrete examples into an effective skill, analyze each example by:

1. Considering how to execute on the example from scratch
2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly

Example: When building a `pdf-editor` skill to handle queries like "Help me rotate this PDF," the analysis shows:

1. Rotating a PDF requires re-writing the same code each time
2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill

Example: When designing a `frontend-webapp-builder` skill for queries like "Build me a todo app" or "Build me a dashboard to track my steps," the analysis shows:

1. Writing a frontend webapp requires the same boilerplate HTML/React each time
2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill

Example: When building a `big-query` skill to handle queries like "How many users have logged in today?" the analysis shows:

1. Querying BigQuery requires re-discovering the table schemas and relationships each time
2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill

To establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.

### Step 3: Initializing the Skill

At this point, it is time to actually create the skill.

Skip this step only if the skill being developed already exists. In this case, continue to the next step.

When creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.

Usage:

```bash
scripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]
```

Examples:

```bash
scripts/init_skill.py my-skill --path skills/public
scripts/init_skill.py my-skill --path skills/public --resources scripts,references
scripts/init_skill.py my-skill --path skills/public --resources scripts --examples
```

The script:

- Creates the skill directory at the specified path
- Generates a SKILL.md template with proper frontmatter and TODO placeholders
- Creates `agents/openai.yaml` using agent-generated `display_name`, `short_description`, and `default_prompt` passed via `--interface key=value`
- Optionally creates resource directories based on `--resources`
- Optionally adds example files when `--examples` is set

After initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.

Generate `display_name`, `short_description`, and `default_prompt` by reading the skill, then pass them as `--interface key=value` to `init_skill.py` or regenerate with:

```bash
scripts/generate_openai_yaml.py <path/to/skill-folder> --interface key=value
```

Only include other optional interface fields when the user explicitly provides them. For full field descriptions and examples, see references/openai_yaml.md.

### Step 4: Edit the Skill

When editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Codex to use. Include information that would be beneficial and non-obvious to Codex. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Codex instance execute these tasks more effectively.

#### Start with Reusable Skill Contents

To begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.

Added scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.

If you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.

#### Update SKILL.md

**Writing Guidelines:** Always use imperative/infinitive form.

##### Frontmatter

Write the YAML frontmatter with `name` and `description`:

- `name`: The skill name
- `description`: This is the primary triggering mechanism for your skill, and helps Codex understand when to use the skill.
  - Include both what the Skill does and specific triggers/contexts for when to use it.
  - Include all "when to use" information here - Not in the body. The body is only loaded after triggering, so "When to Use This Skill" sections in the body are not helpful to Codex.
  - Example description for a `docx` skill: "Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Codex needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks"

Do not include any other fields in YAML frontmatter.

##### Body

Write instructions for using the skill and its bundled resources.

### Step 5: Validate the Skill

Once development of the skill is complete, validate the skill folder to catch basic issues early:

```bash
scripts/quick_validate.py <path/to/skill-folder>
```

The validation script checks YAML frontmatter format, required fields, and naming rules. If validation fails, fix the reported issues and run the command again.

### Step 6: Iterate

After testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.

**Iteration workflow:**

1. Use the skill on real tasks
2. Notice struggles or inefficiencies
3. Identify how SKILL.md or bundled resources should be updated
4. Implement changes and test again
---
name: skill-installer
description: Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos).
metadata:
  short-description: Install curated skills from openai/skills or other repos
---

# Skill Installer

Helps install skills. By default these are from https://github.com/openai/skills/tree/main/skills/.curated, but users can also provide other locations. Experimental skills live in https://github.com/openai/skills/tree/main/skills/.experimental and can be installed the same way.

Use the helper scripts based on the task:
- List skills when the user asks what is available, or if the user uses this skill without specifying what to do. Default listing is `.curated`, but you can pass `--path skills/.experimental` when they ask about experimental skills.
- Install from the curated list when the user provides a skill name.
- Install from another repo when the user provides a GitHub repo/path (including private repos).

Install skills with the helper scripts.

## Communication

When listing skills, output approximately as follows, depending on the context of the user's request. If they ask about experimental skills, list from `.experimental` instead of `.curated` and label the source accordingly:
"""
Skills from {repo}:
1. skill-1
2. skill-2 (already installed)
3. ...
Which ones would you like installed?
"""

After installing a skill, tell the user: "Restart Codex to pick up new skills."

## Scripts

All of these scripts use network, so when running in the sandbox, request escalation when running them.

- `scripts/list-skills.py` (prints skills list with installed annotations)
- `scripts/list-skills.py --format json`
- Example (experimental list): `scripts/list-skills.py --path skills/.experimental`
- `scripts/install-skill-from-github.py --repo <owner>/<repo> --path <path/to/skill> [<path/to/skill> ...]`
- `scripts/install-skill-from-github.py --url https://github.com/<owner>/<repo>/tree/<ref>/<path>`
- Example (experimental skill): `scripts/install-skill-from-github.py --repo openai/skills --path skills/.experimental/<skill-name>`

## Behavior and Options

- Defaults to direct download for public GitHub repos.
- If download fails with auth/permission errors, falls back to git sparse checkout.
- Aborts if the destination skill directory already exists.
- Installs into `$CODEX_HOME/skills/<skill-name>` (defaults to `~/.codex/skills`).
- Multiple `--path` values install multiple skills in one run, each named from the path basename unless `--name` is supplied.
- Options: `--ref <ref>` (default `main`), `--dest <path>`, `--method auto|download|git`.

## Notes

- Curated listing is fetched from `https://github.com/openai/skills/tree/main/skills/.curated` via the GitHub API. If it is unavailable, explain the error and exit.
- Private GitHub repos can be accessed via existing git credentials or optional `GITHUB_TOKEN`/`GH_TOKEN` for download.
- Git fallback tries HTTPS first, then SSH.
- The skills at https://github.com/openai/skills/tree/main/skills/.system are preinstalled, so no need to help users install those. If they ask, just explain this. If they insist, you can download and overwrite.
- Installed annotations come from `$CODEX_HOME/skills`.
---
name: frontend-design
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
license: Complete terms in LICENSE.txt
---

This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.

The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.

## Design Thinking

Before coding, understand the context and commit to a BOLD aesthetic direction:
- **Purpose**: What problem does this interface solve? Who uses it?
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
- **Constraints**: Technical requirements (framework, performance, accessibility).
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?

**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.

Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
- Production-grade and functional
- Visually striking and memorable
- Cohesive with a clear aesthetic point-of-view
- Meticulously refined in every detail

## Frontend Aesthetics Guidelines

Focus on:
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.

NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.

Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.

**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.

Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
---
name: mac-disk-pressure-recovery
description: Diagnose and recover disk space on macOS safely. Use when the Mac reports low storage, disk pressure, ENOSPC/build failures, or the user asks for storage cleanup. Prioritize non-destructive cache cleanup, detect unusual growth in /private/var/folders (especially com.google.Chrome.code_sign_clone), and report before/after capacity with exact paths.
---

# Mac Disk Pressure Recovery

Use this skill to run a fast, safe disk-pressure investigation on macOS and reclaim space with minimal risk.

## Trigger Conditions
- User reports "disk is full", "storage pressure", "空き容量がない", "容量逼迫"
- Build/install failures caused by `ENOSPC` or low free space
- macOS warns about low disk space and the user asks for cleanup

## Safety Rules
1. Measure first (`df`, `du`) and keep before/after numbers.
2. Delete only re-creatable data by default: caches, temp files, build artifacts.
3. Do not delete user documents, repositories, or app data without explicit user approval.
4. For high-impact cleanup (simulators, SDK components, backups, large apps), propose and ask.
5. If protected paths fail with `Operation not permitted`, continue with deletable targets and report skipped paths.

## Workflow
### 1. Baseline Capacity
```bash
df -h / /System/Volumes/Data
```

Urgent threshold:
- `/System/Volumes/Data` free < 15 GiB, or
- capacity > 90%

### 2. Identify Hotspots Quickly
Run the bundled report script first:
```bash
./scripts/disk_hotspots.sh
```

Or manual probes:
```bash
du -h -d 1 "$HOME" | sort -hr | head -n 40
du -h -d 1 "$HOME/Library" | sort -hr | head -n 40
du -h -d 1 /Library | sort -hr | head -n 30
du -h -d 1 /Applications | sort -hr | head -n 30
du -h -d 1 /private | sort -hr | head -n 30
```

### 3. Reclaim Safe Space First
Use dry-run first:
```bash
./scripts/cleanup-safe-caches.sh
```

Apply:
```bash
./scripts/cleanup-safe-caches.sh --apply
```

This targets:
- `~/Library/Caches` (best effort)
- `~/.npm/_cacache`, `~/.npm/_npx`
- `~/.gradle/caches`, `~/.gradle/wrapper/dists`
- `~/Library/Developer/Xcode/DerivedData`
- `~/.cache`
- Optional tool cleanup when available: `brew cleanup -s`, `pnpm store prune`

### 4. Check Known High-Impact Anomaly
From this incident, a major leak pattern was Chrome code-sign clones under `/private/var/folders`.

Inspect:
```bash
./scripts/cleanup-chrome-code-sign-clone.sh
```

Apply cleanup:
```bash
./scripts/cleanup-chrome-code-sign-clone.sh --apply
```

Notes:
- Close Chrome first when possible.
- This can reclaim tens of GiB if stale clone folders accumulated.

### 5. Optional Cleanup Requiring User Confirmation
Only do these after explicit approval:
- `/Library/Developer/CoreSimulator` pruning/reset
- Android SDK component pruning (`ndk`, `system-images`, old platforms)
- Old backup directories (`~/backup/*`)
- Unused large apps in `/Applications`

### 6. Verify and Report
```bash
df -h /System/Volumes/Data
```

Always report:
1. Before/after free space with exact numbers.
2. Paths cleaned and estimated reclaimed size.
3. Remaining large directories and next optional actions.

## Bundled References
- `references/case-chrome-code-sign-clone.md`: concrete case notes from this incident.
# Article Template — 記事テンプレートスキル

## 概要
コンテンツ種類別の記事構造テンプレートと、frontmatter仕様。

## Frontmatter(全記事共通)

> **正規定義:** `specs/content-policy/spec.md`

```yaml
---
title: "記事タイトル"
slug: "url-friendly-slug"
date: "YYYY-MM-DD"
contentType: "digest"            # news | product | digest(必須)
digestEdition: "morning"         # morning | evening(digest時のみ必須)
tags: ["dev-knowledge"]          # news時に分類タグを先頭に(dev-knowledge / case-study / product-update)
relatedProducts: ["product-slug"] # 関連プロダクト(/products/[slug])
description: "記事の要約(120文字以内)"
readTime: 5
featured: false
image: "/images/xxx.jpg"
---
```

補足:
- `contentType` / `digestEdition` / `tags` / `relatedProducts` が canonical V2 フィールド
- レガシー互換: `category`, `relatedProduct`(単数)は既存記事に残存するが、新規記事では使用しない
- 記事内で登場するプロダクトは必ず `/products/[slug]` にリンクする

## 種類別テンプレート

### 🗞️ 朝夕のまとめ(contentType: digest, digestEdition: morning / evening)

```markdown
# AIソロビルダー[朝刊/夕刊] — YYYY年M月D日(曜)[メインテーマ]

導入(今日の結論を1〜3行)

## 🏁 重要ニュースランキング(NVA)

(この表は最大10件。Top 3は個別ニュース記事(`category: news`)も作成し、Digestと `/news-value` からリンクする)

| 順位 | NVA | ニュース | 出典 | 関連プロダクト |
|------|-----|----------|------|----------------|
| 1 | 86 | [タイトル](/news/your-news-slug) | [リンク] | [/products/slug](/products/slug) |
| 2 | 78 | [タイトル](/news/your-news-slug) | [リンク] | [/products/slug](/products/slug) |
| 3 | 72 | [タイトル](/news/your-news-slug) | [リンク] | — |
| 4 | 65 | タイトル | [リンク] | — |
| 5 | 61 | タイトル | [リンク] | — |
| 6 | 58 | タイトル | [リンク] | — |
| 7 | 55 | タイトル | [リンク] | — |
| 8 | 49 | タイトル | [リンク] | — |
| 9 | 44 | タイトル | [リンク] | — |
| 10 | 40 | タイトル | [リンク] | — |

## 🔥 Top 3 ピックアップ

### 1位: [タイトル]
- **何が起きたか:** ...
- **数字で理解:** ...
- **なぜ重要か:** ...
- **ソロビルダー視点:** ...
- **関連プロダクト:** [/products/slug](/products/slug)
- **個別ニュース記事:** [/news/your-news-slug](/news/your-news-slug)

#### ニュースバリュー評価(NVA)
| 評価軸 | スコア |
|--------|--------|
| SNS反応量 | XX/20 |
| メディアカバレッジ | XX/20 |
| コミュニティ反応 | XX/20 |
| 技術的インパクト | XX/20 |
| ソロビルダー関連度 | XX/20 |
| **合計** | **XX/100 (Tier X)** |

**所見:** ...

**出典:** [リンク]

## ✅ 今日のアクション(読者が今すぐやること)
- 1つ目
- 2つ目
- 3つ目
```

### 📰 ニュース(contentType: news)

```markdown
# [主語]、[何が起きたか] — [一言の文脈・意味]

## TL;DR
- 要点1
- 要点2
- 要点3

## 何が起きたか
[事実の整理。出典リンクと定量データをセットで。]

## なぜ今重要か
[市場/技術/コミュニティ文脈]

## ソロビルダー視点(どう使うか / 何が変わるか)
[具体的なユースケース、注意点]

## 関連プロダクト
→ [/products/slug](/products/slug)

## ニュースバリュー評価(NVA)
| 評価軸 | スコア |
|--------|--------|
| SNS反応量 | XX/20 |
| メディアカバレッジ | XX/20 |
| コミュニティ反応 | XX/20 |
| 技術的インパクト | XX/20 |
| ソロビルダー関連度 | XX/20 |
| **合計** | **XX/100 (Tier X)** |

**所見:** ...

🗣 **生の声(日本語)**
- 「...」

**出典:** [リンク]
```

### 🏷️ プロダクト(contentType: product)

```markdown
# [プロダクト名] — [一言で定義]

> 最終情報更新: YYYY-MM-DD

| 項目 | 詳細 |
|------|------|
| サービス開始 | YYYY年MM月 |
| 運営 | 企業名/個人名 |
| 調達額/収益 | ... |
| 利用者規模 | ... |
| GitHub | ... |

## これは何?
[概要。何ができるか、誰向けか。]

## 主な機能
- ...

## 料金
- ...

## ユースケース(ソロビルダー視点)
- ...

## 注意点・限界
- ...

## 公式リンク
- 公式サイト: ...
- ドキュメント: ...
```

### 🧠 AI開発ナレッジ(contentType: news, tags: [dev-knowledge])

```markdown
# [タイトル — 読者が何を得るか]

## この記事で分かること
- [ポイント1]
- [ポイント2]
- [ポイント3]

## 背景・前提
[テーマの背景説明]

## 手順/解説
[詳細な解説、手順、分析]

## 実践
[ソロビルダーが今すぐ活かせる具体的なアクション]

## 関連プロダクト
- [/products/slug](/products/slug)

## まとめ
[要点の整理 + 次のステップ]

**参考リンク:** [出典一覧]
```

### 📊 ソロビルダー事例紹介(contentType: news, tags: [case-study])

```markdown
# [ビルダー名/プロダクト名] — [成果の要約]

## プロフィール
| 項目 | 内容 |
|------|------|
| ビルダー | [名前] |
| プロダクト | [名前] |
| 開始 | [時期] |
| 現在のMRR | [$XX] |
| ユーザー数 | [数値] |
| 技術スタック | [使用ツール] |

## ストーリー
[どうやって始めたか、どう成長したか]

## 収益モデル
[どうやって稼いでいるか、料金体系]

## 成功要因の分析
[なぜうまくいったか、再現可能性]

## ソロビルダーへの教訓
[この事例から学べること、注意すべきこと]

## 関連プロダクト
- [/products/slug](/products/slug)

**出典:** [リンク]
```

## 参照ドキュメント
- `specs/content-policy/spec.md` — frontmatter・taxonomy の正規定義
- `docs/operations/EDITORIAL.md` — タイトルルール
- `docs/business/BRAND-IDENTITY.md` — トーン・文体
- `docs/operations/CONTENT-STRATEGY.md` — SEO・内部リンク戦略
- `docs/business/CONCEPT.md` — 最重要ポリシー

## 公開前ゲート(必須)

```bash
npm run publish:gate
```

`validate:content`、`sync:content:db`、`build` がすべて通過した変更のみ公開する。
# Brand Voice — ブランドトーンスキル

## 概要
AI Solo Builder のブランドパーソナリティに沿った文章作成のガイドライン。

## トーン

### 基本姿勢: 「テック界の情報通な仲間」
- 「教える」のではなく「共有する」感覚
- テクノロジーへのワクワク感を素直に表現
- データで裏付けされた確かな情報

### 文体ルール
- **ですます調ベース**(テンション高い箇所は「だ/である」も可)
- **読者呼称:** 「ソロビルダーにとって」「個人開発者なら」(「あなた」は不使用)
- **専門用語:** 説明なしでOK(ターゲットはテック層)
- **英語固有名詞:** そのまま使用(Claude Code, Vercel, Next.js)
- **数字:** 半角、カンマ区切り($1,000,000 / 100万MAU)

### OK表現
- 「これはゲームチェンジャーだ」(根拠があれば)
- 「ソロビルダーにとって見逃せない」
- 「注目すべきは〇〇という数字だ」
- 「Reddit では早くも〇〇件のコメントが付いている」

### NG表現
- 「すごいツールです」(何がすごいか具体的に)
- 「話題になっています」(どこで、どれくらい)
- 「おすすめです」(誰に、なぜ)
- 「〜かもしれません」(データで語れないなら書かない)

## 定量データの表記

### 必須項目(ツール紹介時)
- サービス開始時期
- MAU or ユーザー数
- 調達額 or 評価額
- GitHub Stars(OSS の場合)

### 表記例
```
Cursor は2023年3月にローンチされ、現在MAU 200万を突破。
2024年にSeries Aで$60M調達(評価額$400M)。
```

## 出典の扱い

- 海外記事: 「本記事は翻訳ではなく、原文の紹介・解説記事です。詳細は原文(英語)をご覧ください。」
- 定量データ: 出典元を明記(「Product Hunt調べ」「Crunchbase調べ」等)
- 口コミ・コメント: 日本語で紹介(英語原文は sources.md に保存)

## 参照ドキュメント
- docs/business/BRAND-IDENTITY.md — ブランドアイデンティティ全体
- docs/operations/EDITORIAL.md — タイトルルール
# Editorial Standards — 編集基準スキル

## 概要
記事の品質を保証するためのチェックリストと基準。

## タイトルルール(EDITORIAL.md準拠)

### 構造
```
[主語] + [何が起きたか] — [一言の文脈・意味]
```

### パターン別
- **資金調達:** `[社名]、[金額]調達(評価額$XX) — [意味]`
- **新機能:** `[プロダクト] [バージョン]リリース — [何が変わった]`
- **買収:** `[買収企業]、[被買収企業]を買収 — [業界への意味]`
- **急成長:** `[社名]、ARR $XX達成 — [なぜ伸びている]`
- **オリジナル:** 「読者が何を得るか」をタイトルに

## 品質チェックリスト

### 必須(全記事)
- [ ] タイトルに「何が起きたか」or「何を得るか」
- [ ] 定量データ最低1つ
- [ ] サービス開始時期の明記
- [ ] 出典リンク
- [ ] 「なぜ今」の文脈
- [ ] frontmatter 正確性
- [ ] canonical frontmatter(contentType / digestEdition / tags / relatedProducts)を必要分設定
- [ ] slug のURL安全性(英数字+ハイフンのみ)

### 必須(Digest Top 3 / ニュース個別)
- [ ] NVA評価セクション(スコア表+所見)
- [ ] NVA中間資料の保存(research/)
- [ ] 関連プロダクトがある場合は /products/[slug] にリンク(無ければ作成)

### 必須(公開前)
- [ ] `npm run publish:gate` 実行済み
- [ ] `sync:content:db` 成功ログを確認(DB登録完了)

### 必須(海外記事紹介)
- [ ] 全文翻訳ではなく要点紹介+独自分析
- [ ] 出典リンク明記
- [ ] 「翻訳ではなく紹介・解説記事」の表記
- [ ] 日本のソロビルダー向け独自分析

## NG集

- ❌ プロダクト名だけのタイトル(「Perplexity — AI検索エンジン」)
- ❌ 定量データなしの「すごい」「話題」
- ❌ 開始時期の記載漏れ
- ❌ 出典なしの情報
- ❌ 全文翻訳の転載

## 参照ドキュメント
- `docs/operations/EDITORIAL.md` — タイトルルール詳細
- `specs/content-policy/spec.md` — frontmatter・taxonomy の正規定義
- `docs/operations/CHECKLIST.md` — 品質チェックリスト(自動化状況含む)
- `docs/operations/CONTENT-STRATEGY.md` — SEO・内部リンク戦略
# News Curation — ニュースキュレーションスキル

## 概要
グローバルのAI情報ソースを効率的に巡回し、記事化すべきニュースを選定する手順。

## 重要原則(ニュースレター運用時)
- ニュースレターは検知レイヤーとして扱い、最終ソースにしない
- 記事化前に必ず一次情報(公式)へ戻って事実確認する
- 日本向け配信では EN一次 + JP補足リンクを併記する

## 巡回手順

### Step 1: 主要ソースのスキャン
1. **Hacker News** — AI関連でupvote 100+の記事を抽出
2. **Reddit** — r/solopreneur, r/SideProject, r/artificial の直近24h人気投稿
3. **X** — @levelsio, @marc_louvion, @dannypostma 等の投稿 + "AI tool" "vibe coding" 検索
4. **Product Hunt** — デイリーAI系ランキング上位

### Step 2: 一次スクリーニング
以下の基準で候補を5-10本に絞る:
- コミュニティの反応量(upvote/RT/コメント数)
- ソロビルダーとの関連度
- 情報の鮮度(24h以内を優先)
- 既存記事との重複チェック

### Step 3: NVA概算スコアリング
各候補にNVAの5軸でざっくりスコアをつける:
- SNS反応量 (0-20)
- メディアカバレッジ (0-20)
- コミュニティ反応 (0-20)
- 技術的インパクト (0-20)
- ソロビルダー関連度 (0-20)

### Step 4: 記事化決定
- Digestに載せる重要ニュースを選び、NVAでランキング化する(Top 10まで表示、Top 3を確定)
- Tier A (80+): Digestの上位枠で優先、原則Top 3候補(個別ニュース記事化)
- Tier B (55-79): Digest掲載候補。枠に応じてTop 3入り or 一覧枠
- Tier C (30-54): Digestの「一覧」枠で補完するか検討
- Tier D (1-29): 原則スキップ

### Step 5: プロダクト記事チェック
- プロダクトに関するニュースの場合、/products/[slug] の有無を確認
- 無ければ先にプロダクト記事を作成し、Digest/ニュースからリンクする
- 関連プロダクトのslug候補を `relatedProducts` 用に明示して引き渡す

## ソースデータの保存
- research/YYYY-MM-DD-slug/ に sources.md を作成
- URL・数値・引用原文を保存(将来のリファレンス資産)

## 参照ドキュメント
- `docs/operations/RESEARCH-SOURCES.md` — 巡回先の詳細リスト
- `docs/operations/NEWSLETTER-CURATION-WORKFLOW.md` — ニュースレター検知→検証→再編集フロー
- `docs/operations/NEWSLETTER-GUARDRAILS.md` — 法務・配信ガードレール
- `specs/content-policy/spec.md` — コンテンツ分類の正規定義
- `docs/operations/WORKFLOW-DIGEST.md` — Digest ワークフロー(Phase 1-2 で本スキルを使用)
- `docs/operations/CONTENT-STRATEGY.md` — SEO・内部リンク戦略
# Newsletter Curation Workflow — ニュースレター検知再編集スキル

## 概要
複数ニュースレターを購読し、配信後にトピックを検知して、一次情報検証 + 日本語ローカライズを行い、
AI Solo Builder向けのニュースレターを作成するための運用スキル。

## 使うタイミング
- 「複数ニュースレターを統合して配信したい」
- 「公式発表(原文) + 日本語の解説記事を併記したい」
- 「速報をソロビルダー向けに再編集したい」

## 基本原則
1. ニュースレターは **検知レイヤー** として扱う(最終ソースにしない)。
2. 重要トピックは必ず **一次情報(公式)** で事実確認する。
3. 日本向け配信では **日本語の解説記事リンク** を併記する。
4. 1トピックにつき最低2リンク(公式発表(原文) + 日本語の解説記事)。
5. 日本向け配信では、他媒体の固有見出し語を残さない。
6. 受信口は当面 `ktlabworks@gmail.com` の単一構成で運用する。

## 実行手順

### Step 1: 検知
- `ktlabworks@gmail.com` で受信した競合ニュースレターを確認。
- `/admin/collection` に受信ログを記録(source / observed_at / subject / from)。
- 同じ話題が複数レターで言及されているかを確認。

### Step 2: 一次情報検証
- 公式発表・原典へ遷移し、数値・日付・機能差分を確認。
- 「ニュースレター側の言い回し」をそのまま断定文にしない。

### Step 3: 日本語ローカライズ
- `docs/operations/JAPANESE-MEDIA-SOURCES.md` の優先メディアからJP文脈を補完。
- JP一次がない場合は、JP編集メディアを補助参照として明示。

### Step 4: 記事種別へ振り分け
- digest: 速報統合(Top10 + Top3)
- news(dev-knowledge): 実装手順重視
- news(case-study): 事例分解重視
- product: 辞書更新

### Step 5: 出力フォーマット
各トピックを以下で統一:
- 何が起きたか(1行)
- なぜ重要か(2行)
- Solo Builderへの影響(1行)
- 今日やること(3ステップ)
- 公式発表(原文)リンク / 日本語の解説記事リンク

### Step 6: 配信前チェック
- `docs/operations/NEWSLETTER-GUARDRAILS.md` の必須項目を確認。
- One-click unsubscribe ヘッダー、送信ログ、同日重複送信防止を確認。

## 連携先
- 受信運用: `docs/operations/COMPETITOR-NEWSLETTER-COLLECTION.md`
- ワークフロー定義: `docs/operations/NEWSLETTER-CURATION-WORKFLOW.md`
- 朝刊統合仕様: `docs/operations/MORNING-DIGEST-INTEGRATION-SPEC.md`
- 法務/配信: `docs/operations/NEWSLETTER-GUARDRAILS.md`
- 日本メディア管理: `docs/operations/JAPANESE-MEDIA-SOURCES.md`
- 全体フロー: `docs/operations/WORKFLOW-OVERVIEW.md`
# NVA Process — ニュースバリュー評価スキル

## 概要
記事化する元ネタのニュースが世の中でどれくらい注目されているかを100点満点で定量評価する。
Digest(朝夕のまとめ)のランキングとTop 3選定にも使用する。
Digest公開のたびに `/news-value` のランキング(最大Top 10)を更新し、Top 3は深掘り(Digest内 + 個別ニュース記事)に使う。

## 評価軸(5軸 × 各20点 = 100点満点)

### 1. SNS反応量 (0-20)
- X (Twitter): RT数・いいね数・引用RT数
- 主要アカウントの言及有無
- バズの規模感

### 2. メディアカバレッジ (0-20)
- TechCrunch, The Verge, Ars Technica 等の報道有無
- 日本語メディアでの言及
- 報道の深さ(速報 vs 分析記事)

### 3. コミュニティ反応 (0-20)
- Hacker News: upvote数・コメント数
- Reddit: upvote数・コメント数・クロスポスト
- Product Hunt: upvote数・ランキング順位

### 4. 技術的インパクト (0-20)
- 技術的な新規性
- 既存の技術・市場への影響度
- 長期的なインパクトの可能性

### 5. ソロビルダー関連度 (0-20)
- 個人開発者が使えるか
- 収益化に繋がるか
- 学習・スキルアップに貢献するか
- ソロビルダーコミュニティでの言及

## Tier分類

| Tier | スコア | 判断 |
|------|--------|------|
| A | 80-100 | 必ず記事化。詳細分析付き |
| B | 55-79 | 記事化推奨。当日のネタ量で判断 |
| C | 30-54 | 条件付き。他にネタがなければ |
| D | 1-29 | スキップ |

## 中間資料の保存

```
research/YYYY-MM-DD-slug/
├── assessment.md   # 評価結果(スコア表+所見)
└── sources.md      # 生データ(URL・数値・引用原文)
```

### assessment.md フォーマット
```markdown
# NVA: [ニュースタイトル]
日付: YYYY-MM-DD

## スコア
| 軸 | スコア | 根拠 |
|----|--------|------|
| SNS反応量 | XX/20 | [具体的な数値] |
| メディアカバレッジ | XX/20 | [報道メディア名] |
| コミュニティ反応 | XX/20 | [HN upvote数等] |
| 技術的インパクト | XX/20 | [根拠] |
| ソロビルダー関連度 | XX/20 | [根拠] |
| **合計** | **XX/100** | **Tier X** |

## 所見
[総合的な評価コメント]
```

## 記事への掲載
- DigestのTop 3 / ニュース個別の末尾に「ニュースバリュー評価」セクション
- スコア表 + 所見 + 🗣 生の声(**日本語で**紹介、英語原文はsources.mdに保存)

## 参照ドキュメント
- `docs/operations/WORKFLOW-DIGEST.md` — Digest ワークフロー(NVA は Phase 2 で使用)
- `docs/operations/WORKFLOW-INDIVIDUAL.md` — 個別記事ワークフロー
- `docs/operations/CHECKLIST.md` — NVA 関連チェック項目
# Research Sources — リサーチソーススキル

## 概要
AI関連ニュースの情報ソースと巡回手順のクイックリファレンス。

## 主要巡回先

### 毎日必須
| ソース | 対象 | 注目指標 |
|--------|------|----------|
| Hacker News | AI関連記事 | upvote 100+, コメント 50+ |
| Reddit | r/solopreneur, r/SideProject, r/buildinpublic, r/artificial | 人気投稿(24h) |
| X | @levelsio, @marc_louvion + "AI tool" 検索 | RT数, 引用数 |
| Product Hunt | AI系デイリーランキング | upvote数, ランキング順位 |

### ニュースメディア
| ソース | 用途 |
|--------|------|
| TechCrunch | 資金調達、企業発表 |
| The Verge | 大手テックのAI動向 |
| Ars Technica | 技術的に深い分析 |

### ベンチマーク
| ソース | 参考ポイント |
|--------|-------------|
| Ben's Bites | AIキュレーションのトーン |
| TLDR | キュレーション形式・UI |
| There's An AI For That | ツールディレクトリの網羅性 |

## 巡回の優先順位
1. Hacker News(最重要 — テック界の重要度指標)
2. X(リアルタイムの熱気)
3. Reddit(コミュニティの深い議論)
4. Product Hunt(新プロダクト発見)
5. ニュースメディア(裏取り・補足)

## 詳細
- docs/operations/RESEARCH-SOURCES.md — 巡回手順の完全版
# Site Config — サイト設定スキル

## 概要
AI Solo Builder の技術仕様・デプロイ手順・運用ルール。

## 基本情報

| 項目 | 値 |
|------|-----|
| URL | https://ai.essential-navigator.com |
| Vercel URL | https://ai-solo-builder.vercel.app |
| GitHub | ksato8710/ai-solo-builder |
| スタック | Next.js (App Router) + Tailwind CSS + TypeScript + SSG |
| ローカル | /Users/satokeita/Dev/ai-navigator |

## コンテンツ管理

### 記事ファイル
- パス:
  - `content/news/*.md`(Digest/ニュース)
  - `content/products/*.md`(プロダクト辞書)
- フォーマット: Markdown + YAML frontmatter
- 読み取り: `src/lib/posts.ts`(gray-matter + remark)

### 正式データモデル(canonical V2)
- `contentType`: `news | product | digest`
- `digestEdition`: `morning | evening`(digest時のみ)
- `tags`: `dev-knowledge` / `case-study` / `product-update`(news時に分類タグとして使用)
- 正規定義: `specs/content-policy/spec.md`

### DB登録(必須)
- 記事公開前に `npm run publish:gate` を必ず実行
- `publish:gate` は `validate:content -> sync:content:db -> build` を強制実行
- `sync:content:db` が失敗したら `git push` しない

必要な環境変数(`.env.local` または `.env`):
- `NEXT_PUBLIC_SUPABASE_URL`
- `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`
- `SUPABASE_SECRET_KEY`

### NVA評価データ
- `/news-value`(ランキング):
  - 参照元: 最新のDigest記事(`contentType: digest`)にある「重要ニュースランキング(NVA)」の表
  - 読み取り: `src/lib/digest.ts`
- `research/`(中間資料):
  - パス: `research/YYYY-MM-DD-slug/`(assessment.md + sources.md)
  - 目的: NVAの根拠保存(任意だが推奨)

### ツールディレクトリ
- データ: `src/data/tools.ts`(ハードコード、67件)

## デプロイ手順

```bash
# 1. 記事追加
git add content/news/YYYY-MM-DD-slug.md
git add content/products/your-product.md  # 必要なら(プロダクト辞書)
git add research/YYYY-MM-DD-slug/  # NVA対象の場合

# 2. 公開前ゲート(失敗時は公開中止)
npm run publish:gate

# 3. コミット & プッシュ
git commit -m "記事タイトル"
git push

# 4. デプロイ確認(1-2分待つ)
# https://ai.essential-navigator.com/news/[slug] または /products/[slug] にアクセス
```

## 注意事項
- URL共有前に必ずブラウザで表示確認
- ビルドエラー時は `npm run build` でローカル確認
- 画像がない記事はカテゴリ別デフォルト画像を使用

## 参照ドキュメント
- CLAUDE.md — プロジェクト全体の技術仕様
- `specs/content-policy/spec.md` — コンテンツ分類の正規定義
- `docs/technical/ARCHITECTURE.md` — サイト構成詳細
- `docs/operations/WORKFLOW-OVERVIEW.md` — ワークフロー全体像
- `docs/operations/CHECKLIST.md` — 品質チェックリスト
# Thumbnail Generation — サムネイル画像生成スキル

## 概要
記事ごとにブランド統一されたキャッチーなサムネイル画像(1200x630 PNG)を生成する。
記事の関連企業・プロダクトのブランドカラー・アイコン・ロゴ形状を活用し、SVGキャラクター付きのイラスト風デザインで作成する。

## デザイン方針

### 採用スタイル: "Illustrated Card"(The Neuron風)
- **レイアウト**: 左にテキスト、右にキャラクター/イラスト
- **キャラクター**: 記事の関連プロダクトのアイコン・ロゴをキャラクター化したSVGマスコット
- **テキスト**: 大きなセリフ体タイトル + カテゴリバッジ + ブランドラベル
- **背景**: 関連企業のブランドカラーを活用したグラデーションまたは単色
- **装飾**: ミニスパークル、コンフェッティ、ドットパターン

---

## ブランドアセットDB(自動拡張)

> **重要ルール**: このテーブルに存在しないブランドが記事に登場した場合、
> 必ず「ブランド調査プロセス」を実行し、結果をこのテーブルに追記すること。
> スキルは使うたびに進化し続ける。

### 登録済みブランド

| 企業/プロダクト | プライマリ | セカンダリ | 背景推奨 | アイコン形状 | SVGキャラ実装ヒント |
|---------------|----------|----------|---------|------------|-------------------|
| Anthropic/Claude | #da7756 (テラコッタ) | #F4F3EE (パンパス), #B1ADA1 (Cloudy) | クリーム/テラコッタ | スターバースト/ピンホイール(放射状4弁花) | `claudeSparkle()` — 4つの楕円ペタル + 中心円。顔を入れてキャラ化。実装例: `thumbnail-variants-v2.mjs` pattern2 |
| OpenAI/GPT/Codex | #10a37f (グリーン) | #1a1a1a, #ffffff | ダーク/グリーン | 六角形ロゴ(hexagonal aperture) | 6辺ポリゴン + 中央に開口部。グリーングロー効果。目を入れてキャラ化 |
| Google/Gemini | #4285F4 (ブルー) | #EA4335 (赤), #FBBC04 (黄), #34A853 (緑) | ホワイト/ブルー | Geminiスター(2つの交差する弧)/ Google 4色ドット | 4色グラデーションの星形。各ポイントに異なる色 |
| Microsoft/Copilot | #0078D4 (ブルー) | #50E6FF (シアン), #005A9E | ブルー/ダーク | 4分割ウィンドウ(田の字) | 4つの正方形を少し離して配置。各色微妙に変える |
| Cursor | #7C3AED (パープル) | #1a1a2e | ダーク/パープル | テキストカーソル(I-beam)+ コードブラケット | `<>` ブラケット + 点滅カーソル線。パープルグロー |
| Vercel/Next.js | #000000 | #ffffff | ダーク/ホワイト | 三角形(▲ Vercelロゴ) | 正三角形。白黒のコントラスト。シャープな印象 |
| Meta/LLaMA | #0668E1 (ブルー) | #1877F2 | ブルー系 | インフィニティマーク(∞) | 横8の字パス。グラデーションストローク |
| GitHub/Copilot | #24292e (ダークグレー) | #6e5494 (パープル), #f0f6fc | ダーク/パープル | Octocat(猫+タコ) | 丸い顔 + 触手風の脚 + 猫耳。目は大きく丸い |
| Apple/Xcode | #147EFB (ブルー) | #53D769 (グリーン), #FC3D39 (赤) | ブルー/ホワイト | ハンマー(Xcodeアイコン)/ Swiftロゴ(鳥) | Swiftの鳥形状をキャラ化。翼を広げたシルエット |

### 汎用カテゴリ(特定企業なし)

| カテゴリ | カラー | キャラクター | SVG実装ヒント |
|---------|--------|------------|--------------|
| 朝刊Digest | #3B82F6 ブルー | ニュースペーパー持ちロボット | LED目の四角ロボット + 新聞アイコン |
| 夕刊Digest | #F97316 オレンジ | サンセット背景のロボット | 暖色グラデーション + ロボット |
| ニュース | #6366F1 インディゴ | LEDロボット | v1のPattern Cスタイルのロボット |
| ナレッジ | #10b981 エメラルド | 本を読むロボット | ロボット + 開いた本のアイコン |
| 事例 | #f59e0b アンバー | グラフを見せるロボット | ロボット + 上昇チャート |
| プロダクト | #8B5CF6 バイオレット | プロダクトショーケースロボット | ロボット + 展示台 |

---

## ブランド調査プロセス(未登録ブランドの場合)

> サムネイル作成時に「ブランドアセットDB」に該当企業がない場合、**必ず**以下を実行する。

### Step 1: ブランド情報の収集
```
WebSearch: "{企業名} brand colors logo hex 2025 2026"
WebSearch: "{企業名} logo icon design identity"
WebSearch: "{プロダクト名} brand color palette hex"
```

### Step 2: 以下の情報を特定
- [ ] **プライマリカラー**: HEXコード
- [ ] **セカンダリカラー**: HEXコード(1-3色)
- [ ] **ロゴ/アイコン形状**: 具体的な形(例: 六角形、スター、動物等)
- [ ] **ロゴの特徴的ディテール**: 色の使い方、線の太さ、角丸具合
- [ ] **ブランドの雰囲気**: 温かい/クール/テック/アカデミック等
- [ ] **推奨背景**: ブランドカラーに合う背景色

### Step 3: SVGキャラクター設計
収集した情報をもとに、アイコン形状をキャラクター化する:
- ロゴの形状をベースにした「体」
- 丸い目と笑顔の「顔」を追加(親しみやすさ)
- 「手」をつけてサインボードや吹き出しを持たせる
- ブランドカラーで着色

### Step 4: スキルファイルへの記録(必須)
**調査結果を必ず「ブランドアセットDB」テーブルに追記する。**

```bash
# このスキルファイルを編集して新しい行を追加
Edit .claude/skills/thumbnail-generation.md
# → 「登録済みブランド」テーブルに新しい行を追記
```

記録フォーマット:
```
| {企業/プロダクト} | {プライマリ HEX} | {セカンダリ HEX} | {背景推奨} | {アイコン形状の説明} | {SVGキャラ実装のヒント} |
```

### Step 5: 実装例の保存(推奨)
特に良くできたキャラクターSVGは、`scripts/thumbnail-variants-v2.mjs` 等に
関数として保存しておくと、次回以降再利用できる。

---

## デザインテンプレート構造

```
┌──────────────────────────────────┐
│ [NEWSバッジ]                     │
│                                  │
│ 英語タイトル部分     [キャラクター] │
│ (大きなセリフ体)     [+ 装飾]     │
│ 日本語サブタイトル   [+ 吹出し等]  │
│ (ブランドカラー)                  │
│ ───                              │
│ [AI SOLO BUILDER]                │
└──────────────────────────────────┘
```

**テキスト配置**:
- カテゴリバッジ: 左上 `(x:60, y:80)` — 丸角の塗りつぶしバッジ
- タイトル英語部分: 大きなセリフ体 `font-size:56-58` font-weight:900
- タイトル日本語部分: sans-serif `font-size:40-42` font-weight:700、ブランドカラーで着色
- ディバイダー: 小さなアクセントバー
- ブランドラベル: 丸角ピル内に「AI SOLO BUILDER」

**キャラクター配置**:
- 右側 `(x:850-950, y:240-280)` に配置
- サイズ: 高さ約300px
- 吹き出しやサインボードで記事のキーワードを表示
- ブランドのアイコン形状をベースにしたマスコット

**キャラクター化の原則**:
1. ロゴ/アイコンの形状を「体」として使う
2. 丸い目(白目+黒目+ハイライト)と笑顔を追加
3. 小さな手(丸い形)を左右に追加
4. ブランドカラーで着色し、顔部分はクリーム/白で対比
5. 周囲にミニスパークルや装飾を散りばめる

## 技術仕様

### ツール
- **Sharp** (0.34.5) — SVG→PNG変換・合成
- **OpenAI DALL-E 3** (オプション) — AI背景生成($0.04/枚)

### SVGでの注意事項
- **絵文字禁止**: Sharp/PangoがSVG内の絵文字をレンダリングできない(クラッシュする)
- **フォント**: `font-family="serif"` と `font-family="sans-serif"` のみ使用
- **XML特殊文字**: `escapeXml()` で `& < > " '` をエスケープ必須
- **出力サイズ**: 1200x630px PNG

### ファイル構成

| ファイル | 役割 |
|---------|------|
| `scripts/generate-thumbnail.mjs` | メインCLIスクリプト |
| `scripts/thumbnail-variants-v2.mjs` | Claude Elegant デザインの実装例(パターン参考) |
| `public/thumbnails/{slug}.png` | 生成された画像ファイル |
| `src/app/news/[slug]/opengraph-image.tsx` | OGP動的画像(フォールバック) |

### CLIコマンド

```bash
# 単一記事(フォールバック背景)
npm run generate:thumbnail -- --slug "slug-name" --no-ai

# 単一記事(DALL-E背景)
npm run generate:thumbnail -- --slug "slug-name"

# 未生成記事を一括
npm run generate:thumbnails:missing

# 全記事
npm run generate:thumbnails:all

# 対象確認のみ
npm run generate:thumbnail -- --missing --dry-run
```

### DB-only記事の対応
- `content/news/` にローカルファイルがない記事はSupabaseから取得
- サムネイル生成後、frontmatter更新はスキップ(ファイルがないため)
- DBの `hero_image_url` を手動またはスクリプトで `/thumbnails/{slug}.png` に更新する

## ワークフロー

### 新規記事のサムネイル作成手順

1. **関連企業の特定**: 記事のタイトル・`relatedProducts`・本文から主要企業を特定
2. **ブランドアセット確認**: 上記「ブランドアセットDB」を参照
   - **登録済み** → カラー・アイコン形状・SVGヒントをそのまま使う
   - **未登録** → 「ブランド調査プロセス」を実行し、結果をDBに追記
3. **最高の1案を設計・生成**: ブランドのアイコンをキャラクター化し、最も記事内容に合ったSVGを1つ設計・生成する(複数案は作らない)
4. **保存**: `public/thumbnails/{slug}.png` に保存
5. **DB更新**: `hero_image_url` を `/thumbnails/{slug}.png` に更新
6. **スキル更新**: 新たに調査したブランド情報があれば、このスキルファイルのテーブルに追記

## 参照ファイル

| ファイル | 内容 |
|---------|------|
| `scripts/generate-thumbnail.mjs` | メインCLIスクリプト(フォールバック+DALL-E) |
| `scripts/thumbnail-variants-v2.mjs` | Claude Elegant デザインの実装例 |
| `src/lib/types.ts` L34-41 | CATEGORIESマッピング(カラー定義) |
| `src/app/news/[slug]/opengraph-image.tsx` | OGP画像生成 |
| `docs/business/BRAND-IDENTITY.md` | サイト全体のブランドカラー |
# UI Design System — 記事ページUIデザインスキル

## 概要
AI Solo Builder の記事ページにおけるUIデザインパターン・CSS設計ルール。
2025-2026年のモダンUIトレンド(Linear/Vercel/Stripe系)に準拠。

## デザイン原則(5つの柱)

1. **ボーダーで深度を表現** — ダークモードではシャドウが見えにくい。`rgba(255,255,255,0.06-0.12)` の半透明ボーダーが主要な深度シグナル
2. **グラデーション背景** — フラットな単色(`#1e293b`)ではなく、微細なグラデーション(`145deg, rgba alpha 0.08 → 0.03`)で表面に生命感を出す
3. **insetハイライト** — `inset 0 1px 0 rgba(255,255,255,0.03-0.05)` がモダンなガラス風カードの特徴。上辺に光が当たるシミュレーション
4. **大きいborder-radius** — 16-20px。12px以下は2020年代前半の印象
5. **見出しのタイトなletter-spacing** — `-0.01em` 〜 `-0.02em` で意図的・プロフェッショナルな印象

## CSS設計パターン

### H2 見出し
```css
/* グラデーション下線フェード(Linear/Stripe style) */
border-bottom: 1px solid transparent;
border-image: linear-gradient(90deg,
  rgba(59, 130, 246, 0.5) 0%,
  rgba(139, 92, 246, 0.3) 40%,
  transparent 80%
) 1;
letter-spacing: -0.02em;
```
- 左ボーダー(`border-left`)は2018年代パターン。使わない
- `padding-bottom` でテキストと下線の間に余白を確保

### ブロック引用(Blockquote)
```css
/* ガラスカード + グラデーション左アクセント */
border-left: none;
border: 1px solid rgba(139, 92, 246, 0.15);
border-radius: 16px;
font-style: normal;  /* italic は古い印象 */
background: linear-gradient(145deg,
  rgba(139, 92, 246, 0.06) 0%,
  rgba(59, 130, 246, 0.03) 100%
);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15),
  inset 0 1px 0 rgba(255, 255, 255, 0.03);
```
- `::before` の巨大引用符(`\201C`)は使わない
- `::after` で左端にグラデーションアクセントライン(violet → blue)

### リスト(UL)
```css
/* グラデーションドットバレット */
list-style: none;
li::before {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: linear-gradient(135deg, #3B82F6, #8B5CF6);
  box-shadow: 0 0 6px rgba(59, 130, 246, 0.3);
}
```

### リスト(OL)
```css
/* バイオレット番号バッジ */
counter-reset: item;
li::before {
  content: counter(item);
  color: #a78bfa;
  background: rgba(139, 92, 246, 0.1);
  border-radius: 6px;
  font-variant-numeric: tabular-nums;
}
```

### デスクトップテーブル
```css
/* 角丸コンテナ + 下線のみ */
border-collapse: separate;
border-spacing: 0;
border-radius: 16px;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.06);
background: rgba(255, 255, 255, 0.02);
/* セル: border-bottom のみ、左右ボーダーなし */
/* ヘッダー: uppercase, letter-spacing: 0.05em */
```

### モバイルカード(Generic Table → Card変換)
```css
/* ガラスグラデーション + 多層シャドウ */
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 16px;
background: linear-gradient(145deg,
  rgba(30, 41, 59, 0.8) 0%,
  rgba(30, 41, 59, 0.5) 100%
);
box-shadow:
  0 2px 8px rgba(0, 0, 0, 0.2),
  inset 0 1px 0 rgba(255, 255, 255, 0.04);
```
- ラベル: `text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.6875rem`
- ホバー効果(transform)はモバイルでは不要

### インラインコード
```css
border-radius: 6px;
border: 1px solid rgba(139, 92, 246, 0.12);
background: rgba(139, 92, 246, 0.1);
color: #c4b5fd;
```

### HR 区切り線
```css
/* グラデーションフェード */
background: linear-gradient(90deg,
  transparent,
  rgba(255, 255, 255, 0.1) 20%,
  rgba(255, 255, 255, 0.1) 80%,
  transparent
);
```

## テーブル分類ロジック(ArticleContent.tsx)

`src/components/ArticleContent.tsx` でテーブルを3種に自動分類:

| 分類 | CSSクラス | 判定条件 | モバイル表示 |
|------|-----------|----------|------------|
| ランキング | `table-ranking` | 3列以上 + 1列目が数値(`/^\d{1,3}(位|\.)?$/`) | バッジ付きカード |
| KV | `table-kv` | 2列のみ(80%以上の行が2セル) | コンパクトKVリスト |
| 汎用 | `table-generic` | 上記以外 | ガラスカード |

### 重要な実装ルール
- **汎用カードの1列目にはdata-labelを付与しない**(カードタイトルとして使うため)
- 年号(`2024年`)がランキングと誤判定されないよう、正規表現を `\d{1,3}` に制限
- `headers.length < 3` のガードでKVテーブルとの混同を防止

## タイポグラフィ間隔

| 要素 | margin-top | margin-bottom | 備考 |
|------|-----------|--------------|------|
| h2 | 3rem(モバイル: 2.5rem) | 1.25rem | セクション間に十分な空気 |
| h3 | 2rem | 0.875rem | h2より控えめ |
| p | — | 1.25rem | line-height: 1.85 |
| blockquote | — | — | margin: 2rem 0 |
| table | — | — | margin: 2rem 0 |

## ライトモード対応

ダークモード用CSSの後に `.light` プレフィックスで上書き:
- ボーダー: `rgba(0, 0, 0, 0.06-0.08)`
- 背景: `rgba(248, 250, 252, 0.9)` 系
- シャドウ: `rgba(0, 0, 0, 0.04-0.06)`
- insetハイライト: `rgba(255, 255, 255, 0.5-0.8)`

## 避けるべきパターン(アンチパターン)

| パターン | 理由 | 代替 |
|----------|------|------|
| `border-left: 3px solid` 見出し | 2018年代の印象 | gradient bottom-border |
| `font-style: italic` 引用 | 古い印象 | `font-style: normal` + カード化 |
| `list-style-type: disc` | 地味 | カスタム `::before` グラデーションドット |
| `border-collapse: collapse` テーブル | 角丸が効かない | `border-separate` + `overflow: hidden` |
| `border-radius: 8-12px` | 2020年代前半 | 16-20px |
| 単色カード背景(`#1e293b`) | フラットで生気がない | グラデーション背景 |
| 単層シャドウ(`0 1px 4px`) | 深度が足りない | 2-3層 + insetハイライト |
| hover transform on mobile | 意味がない | 省略またはborder-color変化のみ |

## 参照ファイル

| ファイル | 内容 |
|---------|------|
| `src/app/globals.css` | 全CSSスタイル(記事コンテンツ、テーブル、モバイル対応) |
| `src/components/ArticleContent.tsx` | テーブル分類ロジック + data-label付与 |
| `src/app/news/[slug]/page.tsx` | 記事ページテンプレート |
| `docs/business/BRAND-IDENTITY.md` | カラーパレット・タイポグラフィ定義 |
---
name: ai-search-readiness
description: Diagnose and improve AI-search discoverability for projects tracked in product-hub. Use when asked about GEO/AEO/LLMO optimization, AI citation strategy, zero-click search countermeasures, ChatGPT/Perplexity/Claude search visibility, or cross-project audits with prioritized implementation plans.
---

# AI Search Readiness

## Overview

Run a repeatable audit-and-improvement workflow for AI-search visibility across all active projects.
Use this skill to generate per-project diagnosis files, identify blockers, and execute prioritized fixes.

## Workflow

1. Refresh product-hub data.

```bash
pnpm scan:all
```

2. Generate AI-search audit files for active projects.

```bash
pnpm ai-search:audit
# or preview only
pnpm ai-search:audit:dry
```

3. Open the generated summary and pick 2-3 projects for immediate action.

- Summary: `docs/ai-search-audits/<date>/SUMMARY.md`
- Project audit: `docs/ai-search-audits/<date>/<project>.md`

4. For each selected project, run the deep checks from `references/checklist.md`.

5. Apply the P0/P1 fixes directly in the target project and record the changes in the audit file.

6. Re-run scan and update the dashboard data.

```bash
pnpm scan:all
```

## Deep-Dive Rules

- Load `references/official-specs.md` before making crawler/indexability claims.
- Treat crawler allow/deny settings as environment-specific: check `robots.txt`, meta robots, and WAF/CDN rules.
- Do not stop at diagnosis; include concrete implementation tasks with file-level targets.
- Prefer fixes that improve both classic search and AI-search:
  - crawl/index health
  - answer-friendly page structure
  - source transparency and freshness
  - measurement (`utm_source`, AI referral segmentation)

## Output Contract

When this skill is used, produce:

1. A ranked list of affected projects (P0/P1/P2)
2. Concrete change list per project with file paths
3. KPI plan with baseline and target values

## Resources

### scripts/

- `scripts/bootstrap-audit.sh`
  - Generate audit templates for all active projects from dashboard JSON.
  - Create `SUMMARY.md` and project-level backlog files.

### references/

- `references/official-specs.md`
  - Official docs to verify crawler/indexability behavior.
- `references/checklist.md`
  - AI-search readiness checklist and scoring rubric.
# idea-register — 事業アイデア登録スキル

事業アイデアを Product Hub ダッシュボードの ideas.json に登録する。

## トリガー

- `アイデアを登録`
- `idea register`
- `ビジネスアイデアを追加`
- `新しいアイデア`

## ワークフロー

### 1. ユーザーからヒアリング

以下の情報をユーザーに確認する(AskUserQuestion を使用):

- **タイトル** (必須): アイデアの簡潔な名前
- **説明** (必須): 何をするのか、どんな価値があるのか
- **種別** (必須): 新規サービス (`new-service`) / 既存サービス拡張 (`extension`)
- **カテゴリ** (必須): saas / content / tool / app / service / other
- **優先度**: high / medium / low(デフォルト: medium)
- **タグ**: カンマ区切り(例: ai, automation, b2b)
- **メモ**: 補足情報(空でも可)

### 2. ideas.json に追記

```bash
# ファイルパス
IDEA_FILE="/Users/satokeita/Dev/product-hub/packages/dashboard/public/data/ideas.json"
```

1. `Read` ツールで `$IDEA_FILE` を読み込む
2. 新しいエントリを作成:

```json
{
  "id": "idea-YYYYMMDD-HHmmss",
  "title": "<ユーザー入力>",
  "description": "<ユーザー入力>",
  "type": "<ユーザー選択: new-service | extension>",
  "category": "<ユーザー選択>",
  "status": "new",
  "tags": ["<ユーザー入力>"],
  "priority": "<ユーザー選択>",
  "notes": "<ユーザー入力>",
  "createdAt": "<ISO 8601>",
  "updatedAt": "<ISO 8601>"
}
```

3. `ideas` 配列の末尾に追加
4. `totalIdeas` をインクリメント
5. `generatedAt` を現在時刻に更新
6. `Write` ツールでファイルを書き戻す

### 3. 確認メッセージ

登録完了後、以下を表示:
- 登録したアイデアのタイトル
- ダッシュボードURL: https://dashboard-jade-iota-81.vercel.app/ideas

## データモデル

### ステータス

| 値 | 意味 |
|----|------|
| `new` | 新規登録、未評価 |
| `evaluating` | 評価・検証中 |
| `validated` | 検証済み、実行可能と判断 |
| `building` | 実装・構築中 |
| `shelved` | 一時保留 |

### 種別

| 値 | 意味 |
|----|------|
| `new-service` | ゼロから立ち上げる新規サービス |
| `extension` | 既存サービス・プロダクトへの機能追加・拡張 |

### カテゴリ

| 値 | 意味 |
|----|------|
| `saas` | SaaS プロダクト |
| `content` | コンテンツビジネス |
| `tool` | 開発ツール・ユーティリティ |
| `app` | モバイル/デスクトップアプリ |
| `service` | サービス・コンサルティング |
| `other` | その他 |

### 優先度

| 値 | 意味 |
|----|------|
| `high` | 今すぐ検討・着手すべき |
| `medium` | 近いうちに検討したい |
| `low` | いつか検討する |

## ステータス更新

既存アイデアのステータスを変更する場合も、このスキルで対応可能:

1. `Read` で ideas.json を読み込む
2. 該当アイデアを ID またはタイトルで特定
3. `status` と `updatedAt` を更新
4. `Write` で書き戻す
---
name: bluesky-publisher
description: 記事公開後のBluesky告知・単独投稿
metadata: {"openclaw": {"emoji": "🦋"}}
---

# bluesky-publisher — Bluesky投稿

記事公開後のBluesky告知、または単独投稿をするスキル。

## いつ使うか

- 「Blueskyで告知して」「Blueskyに投稿して」
- 「この記事をBlueskyでシェアして」

## アカウント情報

- Handle: @ktlabworks.bsky.social
- App Password: TOOLS.mdを参照

## 投稿方法

### Bluesky API (AT Protocol)

```bash
# セッション作成
curl -X POST https://bsky.social/xrpc/com.atproto.server.createSession \
  -H "Content-Type: application/json" \
  -d '{"identifier": "ktlabworks.bsky.social", "password": "APP_PASSWORD"}'
```

レスポンスから `accessJwt` と `did` を取得。

### 投稿

```bash
curl -X POST https://bsky.social/xrpc/com.atproto.repo.createRecord \
  -H "Authorization: Bearer {accessJwt}" \
  -H "Content-Type: application/json" \
  -d '{
    "repo": "{did}",
    "collection": "app.bsky.feed.post",
    "record": {
      "$type": "app.bsky.feed.post",
      "text": "投稿内容",
      "createdAt": "2026-02-14T08:00:00.000Z"
    }
  }'
```

## 記事告知テンプレート

```
📝 記事を書きました

「{タイトル}」

{1行要約}

{URL}
```

## リンクカード付き投稿

リンクカードを表示するにはfacetsとembedを設定:

```json
{
  "text": "記事を書きました\n\nhttps://example.com/article",
  "facets": [{
    "index": {"byteStart": 20, "byteEnd": 50},
    "features": [{"$type": "app.bsky.richtext.facet#link", "uri": "https://example.com/article"}]
  }],
  "embed": {
    "$type": "app.bsky.embed.external",
    "external": {
      "uri": "https://example.com/article",
      "title": "記事タイトル",
      "description": "記事の説明"
    }
  }
}
```

## 投稿記録

```bash
# 対象記事の投稿記録を確認
cat /Users/satokeita/dev/content-studio/published/slug-name/note.json 2>/dev/null || \
cat /Users/satokeita/dev/content-studio/published/slug-name/zenn.json 2>/dev/null

# Bluesky告知記録を保存
cat > /Users/satokeita/dev/content-studio/published/slug-name/bluesky.json << 'EOF'
{
  "platform": "bluesky",
  "content": "投稿内容",
  "url": "https://bsky.app/profile/ktlabworks.bsky.social/post/XXXXX",
  "announced_at": "2026-02-16"
}
EOF
```

## 注意事項

- 投稿前にけいたの承認を得る
- Blueskyは300文字制限
- ハッシュタグはBlueskyでは機能が限定的
---
name: content-manager
description: Content Studio全体の管理・一覧表示・統計
metadata: {"openclaw": {"emoji": "📊"}}
---

# content-manager — コンテンツ管理

Content Studio 全体の管理、一覧表示、統計を行うスキル。

## いつ使うか

- 「記事の一覧を見せて」「ネタ一覧」
- 「記事の進捗状況」「コンテンツ統計」
- 「Content Studioの状況」

## データ保存先

- **アイデア**: `/Users/satokeita/dev/content-studio/ideas/*.md`
- **ドラフト**: `/Users/satokeita/dev/content-studio/drafts/*.md`
- **投稿記録**: `/Users/satokeita/dev/content-studio/published/{slug}/*.json`

## 便利なコマンド

### アイデア一覧

```bash
# ファイル一覧
ls /Users/satokeita/dev/content-studio/ideas/*.md

# フロントマター付きで確認(タイトル・ステータス・タグ・優先度)
for f in /Users/satokeita/dev/content-studio/ideas/*.md; do
  echo "=== $(basename "$f") ==="
  head -10 "$f"
  echo ""
done
```

### ドラフト一覧

```bash
# ファイル一覧
ls /Users/satokeita/dev/content-studio/drafts/*.md

# フロントマター付きで確認(タイトル・プラットフォーム・ステータス)
for f in /Users/satokeita/dev/content-studio/drafts/*.md; do
  echo "=== $(basename "$f") ==="
  head -10 "$f"
  echo ""
done
```

### 記事全体フロー(アイデア → ドラフト → 投稿の横断確認)

```bash
echo "=== アイデア ===" && ls /Users/satokeita/dev/content-studio/ideas/*.md 2>/dev/null
echo ""
echo "=== ドラフト ===" && ls /Users/satokeita/dev/content-studio/drafts/*.md 2>/dev/null
echo ""
echo "=== 投稿済み ===" && ls /Users/satokeita/dev/content-studio/published/ 2>/dev/null
```

### 投稿履歴

```bash
# 投稿記録を確認(各スラッグごとのJSONファイル)
for d in /Users/satokeita/dev/content-studio/published/*/; do
  echo "=== $(basename "$d") ==="
  for f in "$d"*.json; do
    [ -f "$f" ] && echo "  $(basename "$f"):" && cat "$f"
  done
  echo ""
done
```

### SNS告知履歴

```bash
# X/Bluesky告知記録を確認
for d in /Users/satokeita/dev/content-studio/published/*/; do
  for f in "$d"x.json "$d"bluesky.json; do
    [ -f "$f" ] && echo "$(basename "$(dirname "$f")")/$(basename "$f"):" && cat "$f"
  done
done
```

## 統計

### ステータス別カウント

```bash
echo "=== アイデア ===" && \
for status in new in_progress drafted archived; do
  count=$(grep -l "status: $status" /Users/satokeita/dev/content-studio/ideas/*.md 2>/dev/null | wc -l | tr -d ' ')
  echo "  $status: $count"
done && \
echo "" && echo "=== ドラフト ===" && \
for status in writing review ready published; do
  count=$(grep -l "status: $status" /Users/satokeita/dev/content-studio/drafts/*.md 2>/dev/null | wc -l | tr -d ' ')
  echo "  $status: $count"
done
```

### プラットフォーム別投稿数

```bash
echo "=== プラットフォーム別 ==="
for platform in note zenn; do
  count=$(find /Users/satokeita/dev/content-studio/published -name "${platform}.json" 2>/dev/null | wc -l | tr -d ' ')
  echo "  $platform: $count"
done
```

## ステータス更新

### アイデアのステータス変更

```bash
# ideas/001-slug.md のステータスを in_progress に変更
sed -i '' 's/^status: new/status: in_progress/' \
  /Users/satokeita/dev/content-studio/ideas/001-slug.md
```

### ドラフトのステータス変更

```bash
# drafts/slug.md のステータスを review に変更
sed -i '' 's/^status: writing/status: review/' \
  /Users/satokeita/dev/content-studio/drafts/slug.md
```

## ワークフローサマリー

```
Ideas (new) → Ideas (in_progress) → Drafts (writing) → Drafts (review)
           → Drafts (ready) → Publications → Announcements
```
---
name: content-studio-draft
description: Content Studioのアイデアからドラフト記事を作成する
metadata: {"version":"1.3.0","author":"keita","tags":["content-studio","draft","writing"]}
---

# Draft Writer Skill

## 概要

Content Studioに登録されたアイデアから、プラットフォームに応じた「読まれる記事」のドラフトを作成する。

## 🎯 ターゲット読者を最初に設定する

記事を書く前に必ず決める:
- **誰に向けて書くか**(エンジニア?初心者?マネージャー?)
- **読者の課題は何か**(何を解決したいと思ってこの記事を開くか)
- **読んだ後どうなってほしいか**

---

## 🔵 Zenn向け記事のスタイル(platform: zenn)

Zenn記事は**技術リファレンス**として読まれる。検索流入の読者が「問題→解決策」を素早く把握できることを最優先する。

### 基本原則

1. **簡潔に書く** — 同じことを違う言い方で繰り返さない
2. **結論先行** — 「何が問題で何が解決策か」を各セクションの冒頭に置く
3. **感情表現は最小限** — 「予想外でした」「焦りました」のようなつなぎ文は入れない
4. **導入は短く** — 1〜2文で背景を説明して、すぐに本題に入る
5. **コードブロックで語る** — 文章で説明するより、実際のコマンド・エラーメッセージ・設定ファイルを見せる

### 避けるべきパターン(実際の投稿時に削除されたもの)

| ❌ ドラフトで書きがち | ✅ Zennでは |
|---|---|
| 「結果は予想外でした。」 | 削除(読者は結果を見に来ている) |
| 「ここまでは順調でした。問題はこの後です。」 | 削除(ドラマチックなつなぎ不要) |
| 「無反応でした。5体のエージェント、すべて無反応です。」 | 「無反応だった。」で十分 |
| 「一見合理的に見えますが、これは避けるべきです。」 | 理由をリストで端的に示す |
| 長い導入(3段落以上) | 1〜2文で十分 |
| 反省点セクション | 各「学び」に統合するか省略 |
| 全体タイムラインの再掲 | 本文の流れで十分伝わる |

### 構造テンプレート(Zenn向け)

```markdown
# [タイトル(短く、具体的に)]

[1〜2文の背景説明。すぐに本題へ]

---

## 前提

[環境・対象の説明。テーブルやコードブロックで簡潔に]

## [手順/実行内容](手順が3つ以上ならh3で分割)

### 1. ステップ名
[コード + 簡潔な説明]

### 2. ステップ名
[コード + 簡潔な説明]

## ハマりポイント1: [端的な見出し]

[エラーメッセージやコードをまず見せる]
[原因の説明]
[解決策のコード]

**学び:** [1行で]

## まとめ

[箇条書きで要点のみ]
```

### 手順系コンテンツのルール

- 手順が3ステップ以上ある場合は**h3サブセクションに分割**する(1つの大きなコードブロックにまとめない)
- 各ステップにはコードブロック + 1行の説明を付ける

### テーブル・コードブロックの扱い

- 情報の比較にはテーブルを積極的に使う(Zennはテーブルの表示が綺麗)
- コードブロックには必ず言語指定する(`bash`, `json`, `javascript` 等)
- エラーメッセージやログは独立したコードブロックで示す

---

## 🟠 note向け記事のスタイル(platform: note)

note記事はZennより柔らかいトーンが許容されるが、**感情表現やエピソード語りは控えめ**にする。事実と具体情報で記事を構成し、感情は添える程度。

### 基本原則

1. **事実ベースで書く** — 感情ではなく、何をして何が起きたかを淡々と述べる
2. **一人称で語る** — 「〜しました」「〜でした」で自分の体験として書く(AIっぽい三人称・受動態を避ける)
3. **感情は添える程度** — 1セクションに1箇所あれば十分。連続させない
4. **導入は短く** — フックは1〜2文。長い前置きは不要
5. **数字で語る** — 「5体」「半日」「17件中17件」のように具体的に

### 文体

- **敬語ベース**(です・ます調)
- 丁寧すぎない(「〜でございます」は使わない)
- 語りかけ(「〜ではないでしょうか」)は控えめに

### 感情表現のルール

**使ってよいが、多用しない:**
- 「意外とハマりました」「助かりました」程度の軽い表現

**避ける:**
- ドラマチックなつなぎ文(「結果は予想外でした。」「問題はこの後です。」)
- 同じ感情の繰り返し・強調(「無反応でした。すべて無反応です。」)
- 感情の列挙(「焦りました」「心が折れかけました」「嬉しかったです」を連続させない)
- 過激・低俗な表現(「マジで」「ヤバい」「地獄」「草」等)

### 避けるべき表現(共通)

| ❌ NGパターン | ✅ 言い換え |
|---|---|
| 本記事では〜について解説します | (削除して本題に入る) |
| 〜することが推奨されます | 〜するとよいです |
| 以下の点に注意が必要です | (リストで直接示す) |
| 効率的に〜を実現できます | 楽になります |
| 〜を網羅的に解説 | 詳しく書きます |

### 構造テンプレート(note向け)

```markdown
# [タイトル(具体的に)]

[1〜2文の背景。すぐに本題へ]

## [問題・きっかけ]
[事実を具体的に述べる]

## [やったこと]
[時系列で淡々と。コードや設定があれば示す]

## [結果・学び]
[わかったことを簡潔に]

## まとめ
[箇条書きで要点]
```

---

## 使い方

```bash
# アイデアファイルを読み込む
cat /Users/satokeita/dev/content-studio/ideas/<NNN>-<slug>.md

# ドラフトを作成して保存
cat > /Users/satokeita/dev/content-studio/drafts/<slug>.md << 'EOF'
---
title: "タイトル"
description: "説明"
tags: [AI, 開発]
platform: note
status: writing
idea_id: "001-slug"
---

本文...
EOF
```

## ドラフトのフロントマター形式

```yaml
---
title: "..."
description: "..."
tags: [...]
platform: zenn | note
status: writing | review | ready | published
idea_id: "001-slug"  # リンク元のアイデアファイル
---
```

## データ保存先

- **ディレクトリ**: `/Users/satokeita/dev/content-studio/drafts/`
- **形式**: Markdownファイル(YAMLフロントマター付き)
- **ステータス**: `writing` → `review` → `ready`
---
name: idea-collector
description: Content Studioに記事ネタ・アイデアを登録する
metadata: {"openclaw": {"emoji": "💡"}}
---

# idea-collector — ネタ収集・登録

Content Studio にアイデア・記事ネタを登録するスキル。

## いつ使うか

- 「記事ネタを追加して」「アイデアを登録して」
- 「これ記事にできそう」「ネタとして保存して」
- OCRログやセッションログからネタを抽出したとき

## データ保存先

- **ディレクトリ**: `/Users/satokeita/dev/content-studio/ideas/`
- **形式**: Markdownファイル(YAMLフロントマター付き)
- **命名規則**: `{NNN}-{slug}.md`(NNN = ゼロ埋め連番)

## フロントマター形式

```yaml
---
title: "記事タイトル"
description: "説明"
source: manual          # OCR, session, web, manual
tags: [AI, 開発]
status: new             # new, in_progress, drafted, archived
priority: 1             # 高いほど優先
draft_file: ""          # ドラフト作成後にリンク
created_at: "2026-02-16"
---

本文(補足メモなど自由記述)
```

## 操作例

### ネタを追加

```bash
# 次の連番を取得
NEXT=$(printf "%03d" $(($(ls /Users/satokeita/dev/content-studio/ideas/*.md 2>/dev/null | wc -l | tr -d ' ') + 1)))

# アイデアファイルを作成
cat > /Users/satokeita/dev/content-studio/ideas/${NEXT}-slug-name.md << 'EOF'
---
title: "タイトル"
description: "説明"
source: manual
tags: [AI, 開発]
status: new
priority: 1
draft_file: ""
created_at: "2026-02-16"
---

補足メモ
EOF
```

### ネタ一覧

```bash
# ファイル一覧
ls /Users/satokeita/dev/content-studio/ideas/*.md

# フロントマター付きで確認
for f in /Users/satokeita/dev/content-studio/ideas/*.md; do
  echo "=== $(basename "$f") ==="
  head -10 "$f"
  echo ""
done
```

### ステータス更新

```bash
# ideas/001-slug.md のステータスを in_progress に変更
sed -i '' 's/^status: new/status: in_progress/' \
  /Users/satokeita/dev/content-studio/ideas/001-slug.md
```

## ワークフロー

1. ユーザーからネタを受け取る
2. タイトル・説明・タグを整理
3. Markdownファイルを作成して保存
4. 登録完了を報告

## 自動インポート(lifelog-analyzer連携)

日報用のログ(OCR、セッション、Git、Chrome履歴)から抽出したネタを自動登録:

```bash
# 昨日の分析結果をインポート
node ~/.openclaw/skills/idea-collector/auto-import.js

# 特定日を指定
node ~/.openclaw/skills/idea-collector/auto-import.js 2026-02-16
```

### 前提条件

先に `lifelog-analyzer` を実行して分析ファイルを生成:

```bash
node ~/.openclaw/skills/lifelog-analyzer/analyze.js 2026-02-16
```

### 自動化(cronジョブ)

毎朝自動でインポートする場合:

```
# 6:30 に昨日のログを分析 → Content Studioにインポート
schedule: { kind: "cron", expr: "30 6 * * *", tz: "Asia/Tokyo" }
payload: {
  kind: "agentTurn",
  message: "lifelog-analyzerで昨日のログを分析し、idea-collectorでContent Studioにインポートしてください"
}
```

### カテゴリ → タグ変換

| lifelog-analyzer | idea-collector tags |
|------------------|---------------------|
| dev_tips | 開発, Tips |
| tool_discovery | ツール, AI |
| life_insight | ライフ, 気づき |
| ai_usage | AI, 活用 |
| learning | 学習, インプット |

## 自動ネタ収集のヒント

- OCRログから興味深いキーワードを検出
- セッションログから「これは記事にできそう」の発言を抽出
- はてブバズアラートから関連ネタを派生
---
name: lifelog-collector
description: 6つのログソースからLifelogを自動収集し、15分単位のタイムラインMarkdownを生成する
metadata: {"version":"1.0.0","author":"keita","tags":["content-studio","lifelog","automation","collector"]}
---

# Lifelog Collector

毎日のAIツール利用ログ・開発活動を自動収集し、`lifelog/YYYY-MM-DD.md` に15分スロットのタイムラインMarkdownを出力するスクリプト。

## ログソース

| ソース | アイコン | パス | 収集内容 |
|---|---|---|---|
| Claude Code | 🤖 | `~/.claude/projects/*/[uuid].jsonl` | セッション開始時刻・最初のプロンプト・プロジェクト名 |
| Codex | 📟 | `~/.codex/sessions/YYYY/MM/DD/*.jsonl` | セッションメタ・cwd・モデル情報 |
| OpenClaw | 🐾 | `~/.openclaw/agents/*/sessions/*.jsonl` | セッション・エージェント名・Slackメッセージ |
| Git | 📝 | `~/Dev/*/.git` | コミット(git log --since/--until) |
| AI日報 | 📓 | `~/Dev/life-project-management/07_AI日報記録/` | 日報サマリー(セクション一覧) |
| zsh_history | 💻 | `~/.zsh_history` | 意味のあるコマンド(git commit, npm build等) |

## 実行方法

```bash
# 特定の日の収集
npx tsx scripts/collect-lifelog.ts 2026-02-18

# 当日(デフォルト)
npx tsx scripts/collect-lifelog.ts
```

## 収集範囲

前日18:00〜当日18:00の24時間。これにより「1日の終わりの振り返り」を含めた自然な区切りで収集される。

## 出力形式

```markdown
---
date: "YYYY-MM-DD"
entries_count: N
sources: [claude-code, codex, openclaw, git, daily-notes, zsh]
---

<!-- idle: 18:00-21:00 (12 slots, 180min) -->

## 09:00 | 🤖 claude-code | セッションタイトル
<!-- id: entry-YYYYMMDD-HHMM-xx -->
<!-- tags: source, project, category -->
<!-- articulated: false -->

詳細テキスト

---
```

## アーキテクチャ

```
ログソース → collectors/*.ts → RawActivity[] → time-slots.ts → lifelog/YYYY-MM-DD.md
```

- 各コレクタは `Collector` インターフェース `(targetDate, startHour, endHour) => Promise<RawActivity[]>` に準拠
- `Promise.allSettled` で並列実行(1ソースの失敗が全体に波及しない)
- 15分スロット96個に集約。同一スロットはAIツール優先
- 連続アイドル3スロット以上は `<!-- idle: ... -->` コメントで圧縮

## 自動実行

LaunchAgentで毎日18:00に自動実行:

```bash
# 登録
cp launchagents/com.content-studio.lifelog-collector.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.content-studio.lifelog-collector.plist

# 手動テスト
launchctl start com.content-studio.lifelog-collector

# ログ確認
cat /tmp/lifelog-collector.log
```
---
name: note-publisher
description: Content Studioのドラフトをnoteに投稿する
metadata: {"openclaw": {"emoji": "📓"}}
---

# note-publisher — note投稿

Content Studio のドラフトをnoteに投稿するスキル。

## いつ使うか

- 「noteに投稿して」「noteにアップして」
- 「この記事をnoteに公開して」

## 前提条件

note APIは公式には提供されていないため、ブラウザ操作で投稿する。

## ワークフロー

### 1. 投稿準備確認

```bash
# ready状態のドラフトを検索(platform が note または both)
grep -l 'status: ready' /Users/satokeita/dev/content-studio/drafts/*.md 2>/dev/null | while read f; do
  if grep -q 'platform: note\|platform: both' "$f"; then
    echo "=== $(basename "$f") ==="
    head -10 "$f"
    echo ""
  fi
done
```

### 2. ドラフト内容取得

```bash
cat /Users/satokeita/dev/content-studio/drafts/YYYY-MM-DD-slug.md
```

### 3. ブラウザでnote投稿

Browser Relay (Chrome拡張) を使用:

```
browser action=open profile=chrome targetUrl=https://note.com/kt_labs/n/new
```

1. タイトル入力
2. 本文をMarkdownからnote形式に変換して貼り付け
3. 公開設定
4. 投稿

### 4. 投稿記録

```bash
# 投稿記録ディレクトリを作成
mkdir -p /Users/satokeita/dev/content-studio/published/slug-name

# 投稿記録を保存
cat > /Users/satokeita/dev/content-studio/published/slug-name/note.json << 'EOF'
{
  "platform": "note",
  "url": "https://note.com/kt_labs/n/nXXXXX",
  "published_at": "2026-02-16"
}
EOF

# ドラフトのステータスを published に更新
sed -i '' 's/^status: ready/status: published/' \
  /Users/satokeita/dev/content-studio/drafts/slug-name.md
```

## note記事フォーマット変換

Markdownからnote向けに変換が必要な要素:
- 見出し: `#` → note見出しブロック
- コードブロック: そのままコピー可
- 画像: note画像ブロックに変換

## けいたのnoteアカウント

- URL: https://note.com/kt_labs
- 投稿前にけいたの最終確認を取ること

## 注意事項

- 投稿前に必ずけいたのレビュー・承認を得る
- 下書き保存 → けいた確認 → 公開の流れ
---
name: x-publisher
description: 記事公開後のX(Twitter)告知・単独ツイート投稿
metadata: {"openclaw": {"emoji": "🐦"}}
---

# x-publisher — X(Twitter)投稿

記事公開後のX告知、または単独ツイートを投稿するスキル。

## いつ使うか

- 「Xで告知して」「Twitterに投稿して」
- 「この記事をXでシェアして」
- 「ツイートして」

## 投稿方法

Browser Relay (Chrome拡張) を使用してX.comで投稿する。

### ブラウザ操作

```
browser action=open profile=chrome targetUrl=https://x.com/compose/tweet
```

1. ツイート内容を入力
2. 投稿ボタンをクリック

## 記事告知テンプレート

### note記事告知
```
📝 noteに記事を書きました

「{タイトル}」

{1行要約}

{URL}

#AI #個人開発 #{タグ}
```

### Zenn記事告知
```
🔧 Zennに技術記事を投稿しました

「{タイトル}」

{学びのポイント}

{URL}

#エンジニア #Zenn #{タグ}
```

## 投稿記録

```bash
# 対象記事の投稿記録を確認
cat /Users/satokeita/dev/content-studio/published/slug-name/note.json 2>/dev/null || \
cat /Users/satokeita/dev/content-studio/published/slug-name/zenn.json 2>/dev/null

# X告知記録を保存
cat > /Users/satokeita/dev/content-studio/published/slug-name/x.json << 'EOF'
{
  "platform": "x",
  "content": "ツイート内容",
  "url": "https://x.com/kt_labs/status/XXXXX",
  "announced_at": "2026-02-16"
}
EOF
```

## けいたのXアカウント

- Handle: @kt_labs (要確認)
- 投稿前にけいたの最終確認を取ること

## 投稿タイミングのヒント

- 平日: 7-9時、12-13時、18-21時
- 休日: 9-11時、20-22時
- 技術系は平日日中が反応良い傾向

## 注意事項

- 投稿前に必ずけいたの承認を得る
- 過度なハッシュタグは避ける(3-5個程度)
- リンクプレビューが出ることを確認
---
name: zenn-publisher
description: Content StudioのドラフトをZennに投稿する
metadata: {"openclaw": {"emoji": "📘"}}
---

# zenn-publisher — Zenn投稿

Content Studio のドラフトをZennに投稿するスキル。

## いつ使うか

- 「Zennに投稿して」「Zennにアップして」
- 「この技術記事をZennに公開して」

## Zenn CLI(推奨)

Zennはzenn-cliでGitHub連携による投稿が可能。

### セットアップ確認

```bash
# Zenn CLIインストール確認
which zenn || npm install -g zenn-cli

# Zennリポジトリ確認(なければ作成)
ls ~/dev/zenn-content || (cd ~/dev && npx zenn init)
```

## ワークフロー

### 1. ready状態のドラフト確認

```bash
# ready状態のドラフトを検索(platform が zenn または both)
grep -l 'status: ready' /Users/satokeita/dev/content-studio/drafts/*.md 2>/dev/null | while read f; do
  if grep -q 'platform: zenn\|platform: both' "$f"; then
    echo "=== $(basename "$f") ==="
    head -10 "$f"
    echo ""
  fi
done
```

### 2. Zenn形式で記事作成

```bash
cd ~/dev/zenn-content
npx zenn new:article --slug "article-slug" --title "タイトル" --type "tech"
```

### 3. 記事内容をコピー

Content Studioのドラフト → Zenn記事ファイルに内容をコピー

Zenn記事フォーマット:
```markdown
---
title: "記事タイトル"
emoji: "🚀"
type: "tech" # tech: 技術記事 / idea: アイデア
topics: ["AI", "Claude", "OpenClaw"]
published: false
---

本文...
```

### 4. プレビュー確認

```bash
cd ~/dev/zenn-content
npx zenn preview
# http://localhost:8000 でプレビュー
```

### 5. 公開

```bash
# frontmatterのpublished: trueに変更
# GitHubにpush
cd ~/dev/zenn-content
git add .
git commit -m "Add article: タイトル"
git push origin main
```

### 6. 投稿記録

```bash
# 投稿記録ディレクトリを作成
mkdir -p /Users/satokeita/dev/content-studio/published/slug-name

# 投稿記録を保存
cat > /Users/satokeita/dev/content-studio/published/slug-name/zenn.json << 'EOF'
{
  "platform": "zenn",
  "url": "https://zenn.dev/kt_labs/articles/slug",
  "published_at": "2026-02-16"
}
EOF

# ドラフトのステータスを published に更新
sed -i '' 's/^status: ready/status: published/' \
  /Users/satokeita/dev/content-studio/drafts/slug-name.md
```

## Zenn記事のベストプラクティス

- 絵文字は記事内容を端的に表すものを選ぶ
- topicsは3〜5個が理想
- TL;DRを冒頭に置く
- コードブロックは言語指定する

## 注意事項

- 投稿前に必ずけいたのレビュー・承認を得る
- published: false で下書き → けいた確認 → published: true
# Skill: frontend-design(UI/UX・実装方針)

## Purpose
本 Skill は、本サービスのフロントエンド実装で `anthropics/frontend-design` を適用することを前提に、実務上のチェックポイントと“参照先”を固定します。

## Applies To
- 画面追加/改修、UIコンポーネント追加/差し替え、スタイル調整

## Rules
1. **必須適用**: フロントエンド作業は `anthropics/frontend-design` を必ず適用する。  
   - 参照: `.codex/skills/frontend-design/SKILL.md`
2. **デザインシステム必読**: 実装前に `docs/DESIGN_SYSTEM.md` を読む。
3. **Figma参照実装を常に参照(重要)**: UI の追加/改修時は必ず `from_figma_make/components/design-system/*` を参照し、トークン・余白・タイポ・コンポーネント構造の一貫性を崩さない。
4. **再利用優先**: `src/components/ui/*`(shadcn/radix 派生)を優先して使う。
5. **一貫性**: 罫線はグレー系、背景は白/`gray-50`、アクセントは控えめ。
6. **CSS生成/優先順位に注意(重要)**:
   - 本リポジトリでは Tailwind 出力が“全ユーティリティ網羅”にならないことがあるため、**使ったクラスが実際に `src/index.css` / `src/styles/globals.css` に存在するか必ず確認**する。
   - `src/components/ui/*` の shadcn コンポーネントは **ベースクラスに `inline-flex` / 固定高さなど“構造を決めるクラス”**を含むことがある。`className` で `grid` 等を足しても、生成CSSの並びで負けて崩れる場合がある。
   - 構造が崩れる場合は、ユーティリティ追加で粘らず **スコープクラスを付けて(例: `ai-agent-group-tabs`)`[data-slot=...]` / `data-state` を使った局所CSS上書き**に切り替える(`src/styles/globals.css` に追記)。

## UI基準(要点)
- カード: `border border-gray-200 shadow-sm bg-white`
- サマリーカード: `rounded-lg border border-gray-200 bg-gray-50 px-4 py-3 shadow-sm`
- ヘッダー内の補助アクション: `Button` は `size="sm"` + `variant="secondary"`、アイコン付き、必要なら `rounded-lg border border-gray-200 bg-gray-50 p-2` のコンテナでまとめる
- タイポ:
  - 見出し: `text-2xl font-semibold`
  - セクション: `text-lg font-semibold`
  - 本文: `text-sm text-gray-700`

## Anti-patterns
- 既存のトーンから逸脱した強い色・濃い影・過剰な装飾。
- 生HTMLでボタン/入力を作り、`src/components/ui/*` を活用しない。
- 「崩れ」をユーティリティの継ぎ足しで誤魔化し続ける(特に Tabs / Dropdown / Dialog など Radix 系)。

## Debug Checklist(UIが崩れたとき)
1. 参照実装: `from_figma_make/components/design-system/*` の近いパターンを開く
2. CSS存在: 使ったクラスが `src/index.css` / `src/styles/globals.css` に存在するか確認(不足は `globals.css` に補完 or 既存クラスに置換)
3. 構造クラス: `src/components/ui/*` のベースクラス(display/height/padding)を確認
4. スコープ上書き: `data-slot` / `data-state` で局所的に上書き(影響範囲を限定)

## References
- `.codex/skills/frontend-design/SKILL.md`
- `docs/DESIGN_SYSTEM.md`
- `from_figma_make/components/design-system/`(参照実装)
- `docs/ADMIN_UI_USAGE.md`(管理画面系)
# Skill: pr-writing(PR作成ガイド)

## Purpose
PR の説明を一定品質に保ち、レビュー効率を上げます。

## Checklist
1. **背景**: なぜ必要か(1〜2文)
2. **変更内容**: 何を変えたか(箇条書き)
3. **影響範囲**: 影響する機能/画面/テーブル/API(破壊的変更があれば必ず)
4. **テスト計画と結果**: 実行コマンドと結果(`npm test` 等)
5. **スクリーンショット**: UI変更がある場合(可能なら Before/After)
6. **ロールバック**: 戻し方(必要なら)

## Tone
- 簡潔・事実ベース・手順は再現可能に。

## Templates
- `.ai/shared/templates/pr.md`

# Skill: quiz-authoring(クイズ作成・追加運用)

## Purpose
本 Skill は、クイズの作成・品質基準・追加手順を統合し、作業ミス(品質不足、誤ったマスター参照、運用漏れ)を防ぎます。

## Applies To
- 新規クイズ作成、既存クイズ修正、クイズ画像(explanation_images)追加
- DB 追加、Edge Function 反映、確認手順の作成

## Rules(必須)
1. **公式手順**: 追加・更新は `docs/QUIZ_DATA_WORKFLOW.md` に従う。
2. **品質基準**: `docs/QUIZ_QUALITY_STANDARDS.md` を満たす(特に「1問1概念」「解説 3文+ / 100字+」)。
3. **難易度**: 1–4 は `docs/QUIZ_DIFFICULTY_GUIDE.md` に従う。
4. **マスター追加禁止**: 「教科」「カテゴリ」「単元」は既存DBマスターに準拠し、勝手に追加しない。
5. **回答一意性**:
   - 自由入力(text)は正解を1つに絞る(採点可能な形にする)。
   - 複数要素を答えさせたい場合は選択式(multiple-choice)にする。
6. **社会の出題傾向**: 事件/政策の目的・影響などは選択式で出題するよう努める(`docs/QUIZ_DATA_WORKFLOW.md` 準拠)。

## 推奨アウトプット(人間/AI共通)
- **メタ情報**: 教科 / カテゴリ / 単元 / `unit_id` / `order` 方針 / 難易度配分
- **クイズ本体**(1問ずつ):
  - `question` / `answer` / `explanation` / `type` / `options`(必要なら)/ `difficulty`
- **登録手段**:
  - SQL(推奨): `INSERT INTO quizzes ...`
  - もしくは Edge Function の初期データ(`defaultQuizzes`)更新 + デプロイ(運用は `docs/SUPABASE_OPERATIONS.md` 参照)
- **確認手順**: SQL API / Edge Function 経由で取得して並び・内容・画像の確認
- **運用後処理**: `quiz_source/input` → `quiz_source/作成済` へ移動(`docs/QUIZ_DATA_WORKFLOW.md`)

## 解説(explanation)の必須チェックリスト
- [ ] 3段階構成(定義→背景/理由→影響/重要性)を意識している
- [ ] 3文以上、100文字以上
- [ ] 小学生が間違えやすい漢字は目立つように補足している

## explanation_images(画像)運用
- 形式: `[{ "url": "...", "alt": "...", "width": 640, "height": 360 }]`(配列)
- alt は必須。画像は200KB未満目安、学習に寄与するラベルを含める。
- 具体手順は `docs/QUIZ_DATA_WORKFLOW.md` を参照。

## Anti-patterns
- 正解が複数要素(列挙)で、自由入力にしてしまう。
- 解説が短すぎて「なぜ/だから何」が分からない。
- 単元/カテゴリを推測で新規作成してしまう。

## References
- `docs/QUIZ_DATA_WORKFLOW.md`
- `docs/QUIZ_QUALITY_STANDARDS.md`
- `docs/QUIZ_DIFFICULTY_GUIDE.md`
- `docs/SUPABASE_OPERATIONS.md`

# Skill: repo-conventions(本リポジトリ規約)

## Purpose
本 Skill は、このリポジトリで新規ファイル追加・改修を行う際の「置き場所」「依存」「禁止事項」「参照順」を明確にし、判断のブレを減らします。

## Applies To
- 新規機能追加、リファクタ、ファイル追加/移動
- UI 実装、API 連携、Supabase Edge Function 変更
- ドキュメント/運用整備(AI運用含む)

## Rules
1. **参照順**: `AI.md` → `.ai/shared/skills/*` → `docs/*` → コード。
2. **言語**: リポジトリ関連コミュニケーションは原則日本語。
3. **HTTP禁止事項**: フロントは `src/utils/api-client.ts` 経由(生 fetch 禁止)。
4. **生成ファイル禁止**: `src/utils/supabase/info.tsx` は手編集しない。
5. **UI方針**: `docs/DESIGN_SYSTEM.md` を必読。`src/components/ui/*` の再利用を優先。
6. **マスター追加禁止**: クイズの「教科/カテゴリ/単元」マスターは既存 DB に準拠し勝手に増やさない(追加は要相談)。

## Directory Placement(置き場所)
- **UI画面/部品**: `src/components/`(再利用UIは `src/components/ui/`)
- **スタイル/トークン**: `src/styles/`(独自 CSS を増やすならトークン→ユーティリティの順)
- **ユーティリティ**: `src/utils/`(API は `src/utils/api-client.ts` に集約)
- **Supabase Edge Function**: `supabase/functions/make-server-856c5cf0/index.ts`
- **クイズソース(教材Markdown)**: `quiz_source/`
- **運用スクリプト**: `scripts/`
- **E2E**: `e2e/`
- **AI運用(唯一の正)**: `AI.md` と `.ai/`(ツール固有は `.claude/` / `.codex/`)

## Allowed Variations
- 小さな UI ヘルパーはコンポーネント隣接配置でも可(過剰な utils 集約は避ける)。
- 既存の実装パターンに合わせて、テストは同ディレクトリ配置(例: `*.spec.tsx`)を優先。

## Tailwind v4 運用メモ(重要)
- 新しい Tailwind クラスを使う前に `src/index.css` に生成されているか確認する。
- 生成されていない場合は `src/styles/globals.css` にユーティリティとして補完する(トークン→ユーティリティ化を優先)。

## Anti-patterns
- UIから直接 `fetch()` する。
- `localStorage` からアクセストークンを直読みして API に付与する(Supabaseクライアント経由に寄せる)。
- `src/utils/supabase/info.tsx` を編集する。
- `docs/SupabaseSecret.md` など秘密情報を含むファイルの内容を別ファイルに複製する。
- 既存の `docs/*` を削除/上書きして内容を失う。

## References
- `AI.md`
- `docs/DESIGN_SYSTEM.md`
- `docs/SUPABASE_OPERATIONS.md`
- `docs/QUIZ_DATA_WORKFLOW.md`
- `docs/AI_KNOWLEDGE_MAP.md`

# Skill: security-secrets(秘密情報・安全運用)

## Purpose
秘密情報の漏洩と、不用意な破壊的操作を防ぎます。

## Rules
- `docs/SupabaseSecret.md` の内容(鍵/トークン)は、AI出力・ログ・新規ドキュメントへ転載しない。
- `.env` の値を出力しない(必要なら変数名で説明する)。
- 破壊的操作(大量削除・リセット・本番DB変更)は、手順と影響範囲を明示し、最小限にする。

# Skill: supabase-operations(Supabase運用)

## Purpose
Supabase(DB/Storage/Edge Function)の運用手順を誤らないための“参照先”と最低限の注意を固定します。

## Applies To
- SQL 実行、データ投入、Edge Function デプロイ、Storage への画像追加

## Rules
1. 詳細手順は `docs/SUPABASE_OPERATIONS.md` を参照する。
2. 秘密情報(Access Token / Secret key / anon key)は、**コード・ログ・新規ドキュメントに複製しない**。
3. Edge Function 名は `make-server-856c5cf0`(プロジェクトref: `gwaekeqhrihbhhiezupg`)。

## Deploy
```bash
supabase functions deploy make-server-856c5cf0 --project-ref gwaekeqhrihbhhiezupg
```

## References
- `docs/SUPABASE_OPERATIONS.md`
- `docs/SupabaseSecret.md`(取り扱い注意・手編集禁止)

# Skill: testing-policy(テスト方針)

## Purpose
本 Skill は、変更に対して「どのレベルのテストを追加/実行するべきか」を明確化します。

## Applies To
- バグ修正・新機能追加・リファクタ
- UIコンポーネント追加、APIクライアント修正、Edge Function 修正

## Test Types
- **Unit / Component(Vitest + Testing Library)**
  - 既存の `*.spec.ts(x)` 形式に合わせる。
  - 変更したロジック/コンポーネントを中心に最小追加。
- **E2E(Playwright)**
  - 主要フロー(ログイン→設定→解答→履歴/統計)のスモークが対象。
- **Storybook(test-runner)**
  - UI回帰が大きい場合に実行・更新を検討する。

## Required
- バグ修正: 再発防止テスト(最小ケース)を必ず追加。
- 公開ユーティリティ(`src/utils/*`)の変更: 期待値テストを追加。

## Optional
- UIの見た目中心の変更は、Storybook/E2E のいずれかで補完。

## Commands
```bash
npm test
npm run build
```

## Anti-patterns
- テストから本番 Supabase へ直接リクエストを投げる。
- 既存のパターンを無視してテストを別流儀で増やす。

# ChuzyuQuiz Vercelデプロイskill

ChuzyuQuiz歴史アプリのWeb版をVercelに安全にデプロイするためのワークフロー

## クイックスタート

```bash
# 1. デプロイ前チェック
python3 scripts/pre_deploy_check.py

# 2. デプロイ実行
git push origin main

# 3. デプロイ後確認(2分待機後)
python3 scripts/verify_deployment.py
```

## デプロイワークフロー

### Phase 1: 事前チェック
- 設定ファイルの検証(Supabase URL、環境変数)
- ビルドテスト実行
- プレースホルダー文字列の検出

### Phase 2: デプロイ実行
- Git push → Vercel自動デプロイ
- ビルドログ監視

### Phase 3: デプロイ後確認
- 2分待機(デプロイ完了まで)
- サイト接続確認
- 主要機能動作テスト
- パフォーマンス基本チェック

## トラブル対応経験を反映

### 緊急修正時のフロー
1. 問題の特定と修正
2. 設定ミス自動検出の実行
3. ローカルビルドテスト
4. デプロイ → 2分待機 → 動作確認

### よくある問題
- Supabase URLプレースホルダー残存
- 環境変数の設定ミス
- デプロイ直後のアクセス(完了前)

## 使用方法

このskillを使用する際は:
1. `scripts/pre_deploy_check.py`で事前確認
2. 問題がなければgit push
3. `scripts/verify_deployment.py`で事後確認

詳細な設定項目は`references/CONFIG_CHECKLIST.md`を参照。
---
name: codex-review
description: "OpenAI Codex CLI を使った実装レビュー。コミット前のコード変更をレビューし、品質問題・バグ・改善点を検出する。「レビュー」「コードレビュー」「実装チェック」のトリガーで発火。"
user-invocable: false
---

# Codex Review スキル

## 概要

OpenAI Codex CLI(`codex`コマンド)を使って、実装コードのレビューを自動実行する。
TDDフローの Green / Refactor 後、コミット前にレビューを挟む。

## コマンド

```bash
# 未コミットの変更をレビュー(ステージ済み + 未ステージ + 未追跡)
codex review --uncommitted

# 特定のブランチとの差分をレビュー
codex review --base main

# 特定のコミットをレビュー
codex review --commit <SHA>

# カスタムレビュー指示付き
codex review --uncommitted "セキュリティとパフォーマンスに注目してレビューしてください"

# バイパスモード(承認不要)で実行
codex --dangerously-bypass-approvals-and-sandbox review --uncommitted
```

## 環境

- **コマンド**: `codex`(`/opt/homebrew/bin/codex`)
- **バージョン**: v0.94.0
- **モデル**: gpt-5.2-codex high
- **エイリアス**: `cdx`(承認バイパス付き)

## TDDフローでの使い方

### 実装後(Green → レビュー)
```bash
cd /Users/satokeita/dev/history-quiz-app
codex review --uncommitted "specs/001-auth の受け入れ基準に対する実装をレビュー"
```

### リファクタ後(Refactor → レビュー)
```bash
codex review --uncommitted "リファクタリングの妥当性をレビュー。テストカバレッジの変化に注意"
```

## レビュー観点

Codex review に期待する検出項目:
- 型安全性の問題
- エラーハンドリングの漏れ
- セキュリティ上の懸念(XSS、インジェクション等)
- パフォーマンスの問題
- spec との乖離
- デッドコード、未使用インポート
- テストの不足や品質

## 出力の扱い

レビュー結果で指摘された問題は:
1. **Critical/High** → 修正してからコミット
2. **Medium** → 修正するか、理由をコメントに残す
3. **Low/Info** → 次回対応 or 無視
---
name: feedback-ops
description: "Supabase上のユーザーフィードバックを収集・トリアージし、優先度選定、根本原因分析、再発防止策の実装まで進める運用スキル。『feedbackが溜まっている』『対応優先度を決めたい』『類似調査とRCAをしたい』時に使う。"
---

# Feedback Ops

## 概要

このスキルは、`feedback`の実データ確認から、
「対応対象の選定 → 即時対応 → RCA(根本原因分析) → 再発防止(仕様・実装・検証)」までを一気通貫で進める。

## 使うタイミング

- `feedback` が溜まっていて優先度を決めたい
- 同種の不具合が再発しており、横断調査と対策が必要
- テスト投稿やノイズ投稿が運用キューを圧迫している
- 「直すだけ」でなく、仕様と運用の再発防止まで求められている

## 標準ワークフロー

### 1. データ収集(Supabase)

1. `web/.env` の `VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY` を使う  
2. 管理者アカウントでログインし、`/api/admin/feedback` を全件取得  
3. 必要なら `quiz_id` で `quizzes` を取得し、原文・正答・設問形式を確認

最短コマンド:
```bash
FEEDBACK_ADMIN_EMAIL=... FEEDBACK_ADMIN_PASSWORD=... \
  node .claude/skills/feedback-ops/scripts/triage_feedback.mjs
```

詳細は `references/triage-playbook.md` を参照。

### 1.1 類似調査で抽出した「リスク問題」を一括修正(必要時)

類似調査で「記述式なのに実質選択式」「用語だけの問題文」「複数要素回答」などがまとまって見つかった場合は、
管理APIを使って一括で修正する。

例: risk-22(用語だけの問題文 / 複数要素回答の記述式)を一括修正
```bash
FEEDBACK_ADMIN_EMAIL=... FEEDBACK_ADMIN_PASSWORD=... \
  node .claude/skills/feedback-ops/scripts/bulk_fix_risk_22_quizzes.mjs
```

修正後に再発確認(監査)
```bash
FEEDBACK_ADMIN_EMAIL=... FEEDBACK_ADMIN_PASSWORD=... \
  node .claude/skills/feedback-ops/scripts/audit_text_quiz_risks.mjs
```

### 2. トリアージ(優先度選定)

- `P1`: 学習品質や操作継続に直結(誤答誘発、進行不能、設問不成立)
- `P2`: 学習体験に影響(採点揺れ、導線不備、誤字脱字)
- `P3`: 提案・軽微改善

ノイズ(テスト投稿・内容不足)は `rejected` 候補として分離する。

### 3. 類似調査

該当フィードバック以外も含めて、以下を確認する:
- 同一 `quiz_id` の過去フィードバック
- 同タイプ問題の横断件数(例: `type=text` で複合回答を要求)
- 入力文パターン(`test`, `E2E`, `テスト`)

### 4. 即時対応

1. 問題を修正(管理API)
2. 対象FBを `resolved` + `resolution_note`
3. ノイズFBを `rejected` + `resolution_note`
4. 更新後に一覧を再取得し件数検証

### 5. 根本原因分析(RCA)

最小セット:
- 現象: 何が起きたか(日時・件数・影響)
- 原因: 入力品質不足 / 採点ロジック / 運用フロー不備
- 検知: なぜ事前に検知できなかったか
- 恒久対策: 仕様・実装・テスト・運用での防止策

### 6. 再発防止実装

SDDを守る:
1. `specs/` を先に更新  
2. 実装(APIバリデーション、判定ロジック、管理品質ゲート等)  
3. テスト追加・実行  
4. 対応結果と残リスクを報告

## 出力テンプレート(推奨)

最終報告は以下を含める:
1. 取得件数と内訳(`pending/in_progress/resolved/rejected`)
2. 対応対象IDと理由
3. 実施した修正(データ更新 + コード修正)
4. RCA(原因、検知漏れ、恒久対策)
5. 未対応バックログと次アクション

## リソース

- `scripts/triage_feedback.mjs`: Supabaseからフィードバックを取得し、優先度候補をJSONで出力
- `references/triage-playbook.md`: 具体的な判定基準と対応ルール
- `references/risk-22-rca.md`: risk-22 対応のRCAと再発防止メモ(テンプレとして流用可)
---
name: ios-appstore-ops
description: "Flutter iOS アプリの App Store Connect 申請運用。fastlane で beta/release を実行し、リジェクト後の再申請(状態確認、提出キャンセル、再提出、App Review返信)まで進める。iOS申請、TestFlight配布、App Store審査対応、reject対応の依頼で使う。"
---

# iOS App Store Ops

## Overview

Flutter iOS の配布と審査提出を、`fastlane ios beta` / `fastlane ios release` で再現可能に実行する。
リジェクト発生時は、App Store Connect の状態整理と再申請を同じ手順で進める。

## Core Workflow

### 1. Validate release prerequisites

1. `flutter_app/ios/fastlane/.env` の認証値を確認する。  
   必須: `APP_STORE_CONNECT_KEY_ID`, `APP_STORE_CONNECT_ISSUER_ID`, `APP_STORE_CONNECT_KEY_FILE`
2. `flutter_app/ios/fastlane/metadata/ja/support_url.txt` を確認する。  
   サポートページには問い合わせ先とアカウント削除導線を記載する。
3. `flutter_app/ios/fastlane/screenshots/ja` の iPhone/iPad スクリーンショットを確認する。
4. `store_assets/app-icon-main.png` を正本として扱う。  
   `release` / `beta` は `scripts/sync-ios-app-icons.sh` で自動反映される。

### 2. Upload candidate build (TestFlight)

1. Build number を指定して実行する。

```bash
cd flutter_app/ios
IOS_VERSION_NUMBER=1.0.0 IOS_BUILD_NUMBER=<build> fastlane ios beta
```

2. 成功ログを確認する。  
   `Successfully finished processing the build ...`

### 3. Submit for review

1. 再申請時は同一バージョン運用を優先する。

```bash
cd flutter_app/ios
IOS_VERSION_NUMBER=1.0.0 \
IOS_BUILD_NUMBER=<build> \
SKIP_APP_VERSION_UPDATE=true \
REJECT_IF_POSSIBLE=true \
fastlane ios release
```

2. 成功ログを確認する。  
   `Successfully submitted the app for review`(または同等メッセージ)

## Reject Re-Submission Playbook

`fastlane ios release` が App Store Connect 状態で失敗した場合、次の順で対処する。

1. `Cannot submit for review - A review submission is already in progress`
- App Store Connect で対象バージョンを開く。
- `提出をキャンセル` を実行する。
- `Prepare for Submission` に戻ったことを確認して `fastlane ios release` を再実行する。

2. `Cannot find edit app store version`
- 編集可能バージョンが存在しない状態。
- 審査中/提出中バージョンを取り下げる。
- 少し待ってから `fastlane ios release` を再実行する。

3. `The version number has been previously used`
- `SKIP_APP_VERSION_UPDATE=true` を付けて同一バージョン更新で再実行する。

4. App Review 返信が必要
- Resolution Center は手動返信を行う。
- サポートURL、アカウント削除導線、修正箇所を明記する。

テンプレートは `references/reject-reapply-playbook.md` を使う。

## Required Manual Actions

1. App Review メッセージへの返信(Resolution Center)
2. 提出中ステータスの取り下げ(必要時)
3. 最終の Submit ボタン操作(UIで再確認したい場合)

## References

- `references/release-checklist.md`
- `references/reject-reapply-playbook.md`
---
name: mobile-test
description: "Flutter モバイルアプリのE2Eテストを Maestro で実行し、動画エビデンスを取得する。テスト完了には動画取得が必須。ログインが必要なテストは必ずテストアカウントを使用し、スキップ禁止。トリガー:モバイルテスト、Flutterテスト、アプリテスト、E2Eテスト、maestroテスト、test the app、verify login works、テストを実行、動作確認"
---

# モバイルテスト

Flutter アプリ(flutter_app/)の E2E テストを Maestro で実行し、動画エビデンスを取得する。

## 必須制約

### 1. 動画取得は必須

**テスト完了の定義**: `.maestro/recordings/` に動画ファイル(.mp4)が生成されていること。

動画が取得されていない場合、テストは未完了とみなす。

### 2. ログイン必須テストのスキップ禁止

認証が必要なテストを「ログインできないから」等の理由でスキップしてはならない。
テストアカウントでログインを実行し、認証後の機能を必ずテストする。

テストアカウント情報: [references/test-account.md](references/test-account.md)

## テスト実行手順

### 手順 1: 環境確認

```bash
cd /Users/satokeita/Dev/history-quiz-app/flutter_app
flutter devices
```

### 手順 2: テスト実行と動画取得

```bash
cd /Users/satokeita/Dev/history-quiz-app
maestro record .maestro/flows/<flow_name>.yaml --output .maestro/recordings/<flow_name>.mp4
```

### 手順 3: テスト完了確認

```bash
ls -la /Users/satokeita/Dev/history-quiz-app/.maestro/recordings/
```

**.mp4 ファイルが存在しなければテスト未完了。**

## 新規フロー作成

フローテンプレート: [references/flow-templates.md](references/flow-templates.md)

## エラー検出のベストプラクティス

### 1. ランタイムエラーの検出

E2Eテストでは、画面表示の確認だけでなく、**エラーメッセージが表示されていないこと**を必ず確認する。

```yaml
# 良い例: エラーがないことを明示的に確認
- assertNotVisible:
    text: "type.*is not a subtype"
- assertNotVisible:
    text: "エラーが発生しました"

# 悪い例: 画面表示のみ確認
- assertVisible: "学習統計"  # エラー表示されていても通過してしまう
```

### 2. データ検証の実施

UI要素の存在確認だけでなく、表示されるデータの妥当性も確認する。

```yaml
# データが正しく表示されていることを確認
- assertVisible: "正答率"
- assertVisible: "問中"
```

## チェックリスト

- [ ] `.maestro/recordings/` に動画ファイル(.mp4)が存在する
- [ ] ログインが必要なテストはテストアカウントでログイン済み
- [ ] すべてのアサーションが成功している
- [ ] エラーメッセージが表示されていないことを確認している
- [ ] データが正しく表示されていることを確認している
---
name: project-config
description: "ChuzyuQuiz-歴史プロジェクトのサブエージェント向け補足設定。CLAUDE.md で定義されている基本情報(技術スタック、ディレクトリ構成、コマンド)を補完する。テスト環境、デプロイ先、テストアカウント等の運用情報。"
user-invocable: false
---

# ChuzyuQuiz-歴史 プロジェクト補足設定

> **注意**: 技術スタック、ディレクトリ構成、よく使うコマンドは `CLAUDE.md` を参照。
> このスキルはサブエージェントが追加で必要とする運用情報を提供する。

## テスト環境

| 種別 | ツール | 設定ファイル |
|------|--------|------------|
| Web Unit/Component | Vitest + @testing-library/react + jsdom | `web/vitest.config.ts` |
| Web E2E | agent-browser(Playwright MCP) | — |
| Mobile E2E | Maestro | `.maestro/flows/` |
| 静的解析(Web) | ESLint | `web/eslint.config.js` |
| 静的解析(Flutter) | `flutter analyze` | `flutter_app/analysis_options.yaml` |

## テストアカウント

- メールアドレス: `k.sato.8710@gmail.com`
- パスワード: `makeSense`

## デプロイ先

- **Web**: Vercel(予定)
- **Mobile**: Google Play Store
- **Backend**: Supabase(Edge Functions)
- **DB**: Supabase PostgreSQL

## Supabase プロジェクト

- Flutter設定: `flutter_app/lib/core/constants/config.dart`
- Web設定: `web/.env`(`VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY`)

## 開発方針

- **SDD(Spec-Driven Development)**: 仕様 → テスト → 実装の順(詳細は `sdd-testing` スキル)
- **TDD**: Web側はテストファースト(詳細は `tdd-workflow` スキル)
- **日本語**: UI・コンテンツ・コミットメッセージすべて日本語OK
---
name: quiz-ops
description: "中学受験向け日本史クイズの運用専用スキル。時代×難易度(Lv1-Lv4)の実数再集計、目標差分算出、Lv3/Lv4優先バックログ生成、重複/解説薄い/Lv誤判定の品質監査を行うときに使う。"
user-invocable: false
---

# Quiz Ops

## 目的

クイズ運用を「配分」と「品質」の両面で継続改善する。

- 配分: era×Lv の実数を目標に合わせる
- 品質: 重複・解説不足・難易度ミスを継続検出する
- 品質: 選択式の正答・選択肢の完全一致を維持する

## 使うタイミング

- 問題数の現状把握や差分分析を依頼されたとき
- どの時代・難易度から追加すべきか決めるとき
- クイズ品質監査(重複/解説/Lv妥当性)を実施するとき
- 月次の定期監査を回すとき

## 正本と参照先

- 難易度定義: `docs/QUIZ_DIFFICULTY_STANDARD.md`
- 目標配分: `docs/QUIZ_TARGET_DISTRIBUTION.md`
- Lv2作問基準: `docs/QUIZ_AUTHORING_LV2_CHECKLIST.md`
- Lv3/Lv4作問基準: `docs/QUIZ_AUTHORING_LV34_TEMPLATES.md`

## 実行手順(標準)

1. 監査を実行する  
`node scripts/quiz_ops_audit.mjs`

2. 結果を確認する
- `reference/quiz-ops/current-matrix.json`
- `reference/quiz-ops/gap-report.md`
- `reference/quiz-ops/addition-backlog.md`
- `reference/quiz-ops/quality-findings.md`

3. 追加計画を作る
- Lv4不足を最優先
- 次にLv3不足
- その後Lv2の網羅穴埋め

4. 作問時に基準を固定適用
- Lv2: チェックリスト準拠
- Lv3/Lv4: 思考系テンプレート準拠

## 優先順位ルール

1. `Lv4 gap` が大きい時代
2. `Lv3 gap` が大きい時代
3. `Lv2 gap`(教科書網羅の欠落)
4. 同点なら時代総量の大きい時代を先行(江戸、昭和、平成・令和など)

## 品質監査ルール

- 重複: 設問正規化テキスト一致を重複候補とする
- 解説不足: 文字数しきい値未満 + 文脈不足パターンを候補化
- Lv誤判定: 設問パターン(単純再生/比較/資料/因果)と難易度の不整合を候補化
- 選択式整合性: `type=multiple_choice` は `answer` が `options` のいずれかと文字列完全一致していること(全角/半角差分も不一致)

## 注意

- このスキルの監査は読み取り専用。DBを直接変更しない。
- 目標値変更時は先に `docs/QUIZ_TARGET_DISTRIBUTION.md` を更新してから再監査する。
---
name: sdd-testing
description: "SDD(Spec-Driven Development)テスト戦略。specs/ のユーザーストーリー・受け入れ基準・API契約からテストを体系的に導出する方法論。テスト順序、トレーサビリティ、PRゲートを定義。"
user-invocable: false
---

# SDD テスト戦略

## 核心: specs/ がすべてのテストの源泉

```
specs/<feature>/spec.md        → ユーザーストーリー + 受け入れ基準
specs/<feature>/contracts/*.md → API契約(型定義、リクエスト/レスポンス)
specs/<feature>/data-model.md  → DBスキーマ
```

**テストは spec に書いてあることだけを検証する。spec にないテストは原則書かない。**

## テスト導出マッピング

| spec の要素 | 導出するテスト | テスト種別 |
|------------|--------------|----------|
| 受け入れ基準テーブルの各行 | UIの振る舞いテスト | Unit/Component |
| API契約のリクエスト型 | バリデーションテスト | Unit |
| API契約のレスポンス型 | APIクライアントテスト | Unit |
| API契約のエラーレスポンス | エラーハンドリングテスト | Unit |
| Given/When/Then シナリオ | E2Eテスト(最重要のみ) | E2E |
| data-model.md | RLS/DBテスト | Integration |

## テスト順序(Contract-First)

1. **Contract Tests**: API契約通りにリクエスト/レスポンスが動くか
2. **Unit Tests**: 受け入れ基準テーブルの各行をテスト
3. **Component Tests**: UIコンポーネントの振る舞い
4. **E2E**: 最重要フローのみ(認証、クイズ完了、管理画面CRUD)

## トレーサビリティ

すべてのテストに spec 参照を付ける:

```typescript
// spec: 001-auth §US-1.1 #2 — 既存メールでの登録エラー
it('既存メールでの登録でエラーを表示する', async () => { ... });

// contract: 002-quiz/contracts/quiz-api §GET /api/quizzes 200
it('カテゴリIDでクイズ一覧を取得できる', async () => { ... });
```

## PRゲート チェックリスト

1. [ ] 対象機能の `specs/<feature>/spec.md` が存在する
2. [ ] 受け入れ基準テーブルの全行に対応するテストがある
3. [ ] `contracts/` のAPI契約に対応するテストがある
4. [ ] テスト名にspec参照(`spec: xxx §US-x.x #n`)が付いている
5. [ ] E2Eは最重要フローのみ(増やしすぎない)
6. [ ] 仕様変更がある場合は先に spec.md を更新している

## specがない機能の扱い

1. **まず spec を書く**: `specs/<feature-id>/spec.md` を作成
2. API があれば `contracts/` にAPI契約を定義
3. DB変更があれば `data-model.md` を作成
4. **それからテスト → 実装**

**仕様なしの実装は禁止。**
---
name: tdd-workflow
description: "Spec-Driven TDD ワークフロー。specs/ のユーザーストーリー・受け入れ基準・API契約からテストを導出し、Red-Green-Refactor で開発する。全開発作業の起点。"
user-invocable: false
---

# Spec-Driven TDD ワークフロー

## 原則

**すべての開発は specs/ から始まる。** コードを書く前に、必ず対応するspecを確認する。
**E2Eは毎回通す。** 実装後もリファクタ後も、E2Eまで含めて全テストパスを確認する。

## specs/ の構成

```
specs/
├── USER_STORIES.md              ← 全機能のユーザーストーリー一覧
├── 000-baseline/spec.md         ← ベースライン(Given/When/Then)
├── 001-auth/
│   ├── spec.md                  ← US-1.1〜1.5 + 受け入れ基準テーブル
│   ├── contracts/auth-api.md    ← API契約(リクエスト/レスポンス型定義)
│   └── data-model.md            ← DBスキーマ
├── 002-quiz/                    ← US-2.1〜 + quiz-api, rating-api 契約
├── 003-stats/                   ← US-3.x + stats-api 契約
├── 004-feedback/                ← US-4.x + feedback-api 契約
├── 005-ai-explanation/          ← US-5.x + ai-api 契約
└── 006-admin/                   ← US-6.x + admin-api 契約
```

## 開発フロー

```
Step 1: Spec確認
  └→ specs/<feature>/spec.md の受け入れ基準を読む
  └→ specs/<feature>/contracts/ のAPI契約を読む

Step 2: テスト導出(Red 🔴)
  └→ 受け入れ基準の各行 → Unit/Componentテストに変換
  └→ API契約 → Contract Testに変換
  └→ クリティカルパス → E2Eテストに変換
  └→ テスト実行 → 全て失敗することを確認

Step 3: 実装(Green 🟢)
  └→ テストを通す最小限のコードを書く
  └→ Unit テスト実行 → 全パス確認
  └→ E2E テスト実行 → 全パス確認 ← 必須!
  └→ Unit + E2E 両方パスして初めて Green

Step 4: リファクタ(Refactor 🔵)
  └→ テストが通ったままコードを改善
  └→ Unit テスト実行 → 全パス確認
  └→ E2E テスト実行 → 全パス確認 ← 必須!
  └→ Unit + E2E 両方パスして初めて完了

Step 5: Codex レビュー(Review 👁️)
  └→ codex review --uncommitted でコード変更をレビュー
  └→ Critical/High の指摘 → 修正してから次へ
  └→ Medium 以下 → 判断してコミット or 修正

Step 6: コミット
  └→ spec参照付きでコミット
```

## テスト実行の原則

**「テストパス」= Unit + E2E の両方がパス。**

E2Eを後回しにすると手戻りが発生する。実装のたびにE2Eまで通すことで、
統合レベルの問題を早期発見する。

```bash
# Unit テスト
cd web && npx vitest run

# E2E テスト(agent-browser で実行)
# → qa-engineer エージェントに委譲、またはオーケストレーターが直接実行
```

## テスト導出の具体例

### spec.md の受け入れ基準テーブルから:

```markdown
# specs/001-auth/spec.md §US-1.1
| # | 前提条件 | 操作 | 期待結果 |
| 2 | 既存のメールで登録試行 | サインアップ | エラー表示 |
```

→ Unit テスト:
```typescript
// spec: 001-auth §US-1.1 #2
it('既存メールでの登録試行でエラーを表示する', async () => { ... });
```

→ E2E テスト:
```
1. /auth にアクセス
2. 既存メールを入力してサインアップ
3. エラーメッセージが表示されることを確認
```

### contracts/ のAPI契約から:

```markdown
# specs/001-auth/contracts/auth-api.md
POST /api/login → 200: { access_token, user } | 400: { error }
```

→ Contract Test:
```typescript
// contract: 001-auth/contracts/auth-api §POST /api/login
it('ログイン成功時にaccess_tokenとuserを返す', async () => { ... });
```

## エージェント連携

```
オーケストレーター(メインのClaude Code)
  │
  ├→ Step 1: 自分で specs/ を読む
  │
  ├→ Step 2: test-writer-web に委譲
  │    「specs/001-auth の Unit + E2E テストを書いて」
  │
  ├→ Step 3: web-frontend-dev に委譲
  │    「テストを通す実装を書いて(Unit + E2E 両方パスさせて)」
  │    → 実装後に qa-engineer で E2E 実行
  │
  ├→ Step 4: リファクタ後に再度 E2E 実行
  │    → qa-engineer で E2E 再確認
  │
  └→ Step 5: コミット
```

## コミット戦略

```
test: [spec-ref] テスト追加(例: test: 001-auth §US-1.1 signup validation tests)
feat: [spec-ref] 実装(例: feat: 001-auth §US-1.1 signup form validation)
refactor: [対象] リファクタリング
```

テストと実装は **別コミット** にする(テストファーストの証跡)。

## 新機能追加時

仕様が specs/ にない場合:
1. **まず spec を書く**(spec.md + contracts/ + data-model.md)
2. テストを書く(Unit + E2E)
3. 実装する(Unit + E2E 両方パス)

**仕様なしの実装は禁止**(CLAUDE.md 準拠)。
---
name: visual-qa
description: "E2Eテスト実行時にビジュアル品質を自動チェック。レイアウト崩れ、テキスト折り返し異常、オーバーフロー、極端な空白を検出し、問題があれば即修正する。"
user-invocable: false
---

# ビジュアル品質自動チェック(Visual QA)

## 概要

E2E テスト中にページ遷移ごとにビジュアル品質をチェックし、レイアウト崩れを **検知→即修正→確認→コミット** する。
「報告して聞く」は禁止。問題を見つけたら即座に修正する。

## チェック項目(5つ)

| # | チェック名 | 条件 | 重要度 |
|---|-----------|------|--------|
| 1 | 要素幅チェック | メインコンテンツ内の要素が幅 < 100px かつ高さ > 50px | critical |
| 2 | テキスト縦長比チェック | h1/h2/h3/p の height/width 比 ≥ 3(テキスト5文字以上) | critical |
| 3 | ネスト container 検出 | `container` クラスが祖先→子孫で二重適用 | critical |
| 4 | オーバーフロー検出 | scrollWidth > clientWidth の要素 | warning |
| 5 | 空白比率チェック | ページの contentRect が viewport の 20% 未満 | warning |

## 実行方法

### チェックスクリプト

`web/e2e/visual-qa-checks.ts` に定義された関数群を使う。

```typescript
import { getAllChecks } from './visual-qa-checks';

// agent-browser の evaluate アクションで実行
const issues = await page.evaluate(getAllChecks());
```

### E2E テスト中の実行タイミング

1. 各ページ遷移後(navigate 完了後)
2. モーダル/ダイアログ表示後
3. 動的コンテンツのロード完了後

### 実行手順

```
1. ページ遷移を実行
2. ページのロード完了を待つ
3. visual-qa チェック(getAllChecks)を evaluate で実行
4. 結果を確認 — issues が空なら OK
5. issues がある場合 → 問題検出時のフローへ
```

## 問題検出時のフロー

> **重要: 問題を見つけたら即座に修正する。ユーザーに聞かない!**

```
検知 → 即修正 → 確認 → コミット
```

### 具体的な手順

1. **スクリーンショット保存** — エビデンスとして問題の状態をキャプチャ
2. **問題の特定** — issue の type, severity, element, description を確認
3. **即座に修正** — 下記「よくある原因と修正パターン」を参照して修正
4. **再チェック** — 修正後に同じチェックを再実行して問題が解消されたことを確認
5. **テスト再実行** — 既存テスト(51件)が全て通ることを確認
6. **コミット&報告** — 修正内容をコミットし、何を直したかを報告

### 修正できない場合

- 3回修正を試みても解消しない場合のみ、問題の詳細とともに報告する
- その場合も「何を試したか」を必ず含める

## よくある原因と修正パターン

### パターン 1: Tailwind v4 の container 二重ネスト

**症状**: 要素が極端に狭くなる(幅 32px 等)、テキストが縦書きになる

**原因**: Layout の `<main>` と ページコンポーネントの `<div>` の両方に `container` クラスが付いている。Tailwind v4 では `container` が `max-width` を設定するため、ネストすると内側が潰れる。

**修正**: ページコンポーネント側の `container` クラスを削除する。

```tsx
// ❌ Before — container が二重
<div className="container mx-auto max-w-xl p-6">

// ✅ After — ページ側は container を外す
<div className="mx-auto max-w-xl p-6">
```

### パターン 2: max-w-* が container breakpoint に解決される

**症状**: 想定より狭い/広いレイアウトになる

**原因**: Tailwind v4 では `max-w-xl` 等が container query のブレークポイントサイズに解決される場合がある。

**修正**: 明示的な値を使う。

```tsx
// ❌ Before
<div className="max-w-xl">

// ✅ After — 明示的な rem 値
<div className="max-w-[36rem]">
```

### パターン 3: flexbox/grid の shrink

**症状**: flex コンテナ内の要素が潰れる

**原因**: デフォルトの `flex-shrink: 1` で子要素が縮小される。

**修正**: `min-w-0` または `flex-shrink-0` を追加。

```tsx
// ❌ Before
<div className="flex gap-4">
  <div>潰れるコンテンツ</div>
</div>

// ✅ After
<div className="flex gap-4">
  <div className="min-w-0 flex-shrink-0">潰れないコンテンツ</div>
</div>
```

### パターン 4: 空白比率が高い

**症状**: ページにコンテンツがほとんど表示されない

**原因**: 条件分岐でコンテンツが非表示、ローディング状態の停止、API エラー

**修正**: コンポーネントの状態管理を確認し、適切なフォールバック UI を表示する。

## 技術詳細

- **対象プロジェクト**: history-quiz-app(React 19 + TypeScript + Vite)
- **CSS フレームワーク**: Tailwind CSS v4(設定ファイルなし、CSS ベース)
- **テスト実行**: agent-browser(Playwright MCP)
- **チェックスクリプト**: `web/e2e/visual-qa-checks.ts`
---
name: web-e2e
description: "Webアプリの E2E テストを agent-browser で実行する。クリティカルパス(認証、クイズフロー、管理画面操作)の動作確認に使う。「E2Eテスト」「ブラウザテスト」「動作確認」「画面テスト」のトリガーで発火。"
user-invocable: false
---

# Web E2E テスト(agent-browser)

## 概要

`agent-browser`(Playwright MCP)を使って、React Webアプリの E2E テストを実行する。

**E2E テストの原則**: テストピラミッドに従い、E2E は**最重要フローのみ**に限定する。増やしすぎない。

## テスト対象(クリティカルパス)

E2E で検証すべきフローは以下に限定:

1. **認証フロー**: ログイン → セッション維持 → ログアウト
2. **クイズフロー**: カテゴリ選択 → クイズ開始 → 回答 → 結果表示
3. **管理画面操作**: `/admin/quizzes` CRUD、`/admin/feedback` 確認、`/admin/updates` 管理
4. **フィードバック送信**: bug / content_error / suggestion / other の全タイプ
5. **統計表示**: 苦手分野の表示(正答率 < 60%、最低3問回答)

## 実行手順

### 1. 開発サーバー起動

```bash
cd web && npm run dev
# http://localhost:5173 で起動
```

### 2. agent-browser でテスト実行

agent-browser を使って以下の手順でテスト:

```
1. Navigate to http://localhost:5173
2. Snapshot で現在の状態を確認
3. 操作を実行(クリック、入力等)
4. 期待する状態をアサーション(Snapshot で確認)
5. Screenshot でエビデンス取得
```

### 3. ビジュアル品質チェック(各ページ遷移後に実行)

ページ遷移後、アサーション前に必ず visual-qa チェックを実行する:

```
1. ページ遷移を実行
2. ロード完了を待つ
3. visual-qa チェックを evaluate で実行(web/e2e/visual-qa-checks.ts の getAllChecks())
4. issues が空 → OK、テスト続行
5. issues がある → visual-qa スキルの「問題検出時のフロー」に従い即修正
```

### 4. テストアカウント

- メールアドレス: `k.sato.8710@gmail.com`
- パスワード: `makeSense`

## テストシナリオ記述

各テストは `specs/` の受け入れシナリオに対応させる:

```markdown
## テスト: 認証フロー(spec: specs/001-auth/spec.md §US-1.1)

1. /auth にアクセス
2. メールアドレスとパスワードを入力
3. ログインボタンをクリック
4. ホーム画面に遷移することを確認
5. ログアウトボタンが表示されることを確認
```

## 注意事項

- E2E は**本数を絞る**。Unit/Component テストで十分なものは E2E にしない
- **スクリーンショットをエビデンスとして取得**する
- テスト結果は `specs/` のシナリオとの**トレーサビリティ**を維持
- Supabase のデータに依存するテストは、テストアカウントのデータが前提

## エビデンス

テスト実行時に以下を記録する:

- **スクリーンショット**: 各ページ遷移後のキャプチャ
- **ビジュアルQAチェック結果**: 各ページの visual-qa チェック結果(issues の有無、検出された問題、修正内容)
- **テスト結果サマリー**: 全テストの pass/fail と所要時間
---
name: web-testing
description: "Web(React/TypeScript)のユニット/コンポーネントテスト作成・実行。Vitest + Testing Library のセットアップ、テストパターン、モック戦略を提供。テストケースは specs/ の受け入れ基準・API契約から導出する。"
user-invocable: false
---

# Web テストスキル

## テスト環境

- **ランナー**: Vitest
- **UIテスト**: @testing-library/react + @testing-library/jest-dom
- **環境**: jsdom
- **設定**: `web/vitest.config.ts`

## テストファイル配置

```
web/src/__tests__/
├── utils/              # ユーティリティのテスト
│   ├── api-client.test.ts
│   └── token-manager.test.ts
├── components/         # コンポーネントのテスト
│   ├── quiz/
│   ├── auth/
│   └── ui/
├── contexts/           # Contextのテスト
│   └── AuthContext.test.tsx
└── pages/              # ページのテスト
    └── admin/
```

## Spec → テスト導出

**すべてのテストは specs/ から導出する。**

### 受け入れ基準テーブル → テストケース

spec.md の各行がテストケースになる:

```typescript
// spec: 001-auth §US-1.1 #1 — 正常登録
it('メール・パスワード・表示名で新規登録できる', async () => { ... });

// spec: 001-auth §US-1.1 #2 — 既存メール
it('既存メールでの登録でエラーを表示する', async () => { ... });

// spec: 001-auth §US-1.1 #3 — パスワード短すぎ
it('6文字未満のパスワードでエラーを表示する', async () => { ... });
```

### API契約 → テストケース

contracts/ の型定義がテストの期待値になる:

```typescript
// contract: 001-auth/contracts/auth-api §POST /api/login 200
it('ログイン成功時に access_token と user を返す', async () => {
  mockFetch.mockResolvedValueOnce({
    ok: true,
    json: async () => ({
      access_token: 'token-xxx',
      user: { id: 'uuid', email: 'test@example.com', display_name: 'テスト' }
    }),
  });
  const result = await apiClient.login('test@example.com', 'password');
  expect(result.access_token).toBeDefined();
  expect(result.user.email).toBe('test@example.com');
});
```

## テスト実行コマンド

```bash
cd web
npx vitest run                    # 全テスト実行
npx vitest run --reporter=verbose # 詳細出力
npx vitest run src/__tests__/utils/  # ディレクトリ指定
npx vitest --coverage             # カバレッジ
```

## テスト命名規則

```typescript
// 必ず spec 参照をコメントで記載
// spec: <feature-id> §<user-story> #<criteria-number>
// contract: <feature-id>/contracts/<api-file> §<method> <path> <status>
```

## モック戦略

| 対象 | 方法 |
|------|------|
| API呼び出し | `global.fetch` をモック |
| Supabase Auth | `@supabase/supabase-js` をモック |
| Router | `react-router-dom` の `MemoryRouter` でラップ |
| Context | テスト用Provider作成 or モック |
| localStorage | `vi.stubGlobal` |

## テストの品質基準

- **1テスト = 1つの受け入れ基準の行**(1:1対応を目指す)
- **spec にないテストは原則書かない**
- **Arrange-Act-Assert** パターンを厳守
- **エッジケースは spec で定義されたもの**を優先

詳細パターンは [references/testing-patterns.md](references/testing-patterns.md) を参照。
---
name: review-codex
description: Review code changes using Codex CLI. Use this skill when the user wants to review implemented code, uncommitted changes, or specific commits using the codex review command. Triggers on requests like "review my changes with codex", "codex review", or "review this commit".
---

# Review Codex

Run `codex review` to analyze code changes and provide feedback.

## Usage

### Review Uncommitted Changes (Default)

```bash
codex review --uncommitted
```

Reviews all staged, unstaged, and untracked changes in the current directory.

### Review Against Base Branch

```bash
codex review --base main
```

Reviews changes compared to the specified base branch.

### Review Specific Commit

```bash
codex review --commit <SHA>
```

Reviews changes introduced by a specific commit.

### With Custom Instructions

```bash
codex review --uncommitted "Focus on security vulnerabilities"
```

Add a prompt to provide specific review instructions.

## Options

| Option | Description |
|--------|-------------|
| `--uncommitted` | Review staged, unstaged, and untracked changes |
| `--base <BRANCH>` | Review changes against the given base branch |
| `--commit <SHA>` | Review changes introduced by a specific commit |
| `--title <TITLE>` | Optional title to display in review summary |
| `-m, --model <MODEL>` | Specify model to use |

## Workflow

1. Determine what to review:
   - No args provided → use `--uncommitted` (most common)
   - PR context → use `--base <target-branch>`
   - Specific commit → use `--commit <sha>`

2. Run `codex review` with appropriate options

3. Present the review results to the user
Back to Dashboard