feat: Add installation tool, Claude.ai export, and skill standardization (#1)

## Summary

- Add portable installation tool (`install.sh`) for cross-machine setup
- Add Claude.ai export files with proper YAML frontmatter
- Add multi-agent-guide v2.0 with consolidated framework template
- Rename `00-claude-code-setting` → `00-our-settings-audit` (avoid reserved word)
- Add YAML frontmatter to 25+ SKILL.md files for Claude Desktop compatibility

## Commits Included

- `93f604a` feat: Add portable installation tool for cross-machine setup
- `9b84104` feat: Add Claude.ai export for portable skill installation
- `f7ab973` fix: Add YAML frontmatter to Claude.ai export files
- `3fed49a` feat(multi-agent-guide): Add v2.0 with consolidated framework
- `3be26ef` refactor: Rename settings-audit skill and add YAML frontmatter

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Andrew Yim
2026-02-03 16:48:06 +07:00
committed by GitHub
parent 0bc24d00b9
commit b6a478e1df
72 changed files with 4770 additions and 803 deletions

View File

@@ -1,129 +1,155 @@
# OurDigital Skills - Shared Environment
# OurDigital Shared Environment
Shared configuration, dependencies, and environment setup for all OurDigital Claude Skills.
Shared configuration, dependencies, and installation tools for OurDigital Skills package.
## Quick Setup
### 1. Create Virtual Environment
## Quick Install
```bash
cd /path/to/our-claude-skills/custom-skills
python -m venv .venv-ourdigital
source .venv-ourdigital/bin/activate # macOS/Linux
# Clone the repository (on new machine)
git clone https://github.com/ourdigital/our-claude-skills.git
cd our-claude-skills/custom-skills/_ourdigital-shared
# Run installer
./install.sh
```
### 2. Install Dependencies
## Installation Options
```bash
# For Claude Code environment
pip install -r _ourdigital-shared/requirements/code.txt
# For Claude Desktop environment
pip install -r _ourdigital-shared/requirements/desktop.txt
# Or install as package
pip install -e _ourdigital-shared/
./install.sh # Full interactive install
./install.sh --update # Update existing installation
./install.sh --uninstall # Remove installation
./install.sh --validate # Check installation status
./install.sh --skip-creds # Skip credentials setup
./install.sh --skip-venv # Skip virtual environment
./install.sh --help # Show all options
```
### 3. Configure Environment Variables
## What Gets Installed
```bash
# Copy template
cp _ourdigital-shared/.env.ourdigital.template ~/.env.ourdigital
# Edit with your credentials
nano ~/.env.ourdigital
```
### 4. Set Up Credentials Directory
```bash
mkdir -p ~/.ourdigital/credentials
# Add your credential files:
# - ~/.ourdigital/credentials/notion.json
# - ~/.ourdigital/credentials/ghost.json
# - ~/.ourdigital/credentials/google.json
```
| Component | Location | Description |
|-----------|----------|-------------|
| Environment file | `~/.env.ourdigital` | API keys and secrets |
| Config directory | `~/.ourdigital/` | Configuration and credentials |
| Virtual environment | `.venv-ourdigital/` | Python dependencies |
## Directory Structure
```
_ourdigital-shared/
├── pyproject.toml # Package configuration
├── .env.ourdigital.template # Environment variables template
├── requirements/
│ ├── base.txt # Common dependencies
│ ├── desktop.txt # Desktop-specific
│ └── code.txt # Code-specific
├── config/
│ └── ourdigital.yaml # Global configuration
└── README.md # This file
~/.ourdigital/
├── config.yaml # Global configuration
├── credentials/ # Service account JSONs
│ └── *.json
└── logs/ # Installation logs
~/.env.ourdigital # Environment variables (chmod 600)
```
## Configuration
## Manual Setup
### Environment Variables
If you prefer manual setup:
Key variables in `.env.ourdigital`:
| Variable | Description |
|----------|-------------|
| `OURDIGITAL_ENV` | Environment (development/production) |
| `NOTION_API_TOKEN` | Notion integration token |
| `NOTION_WORKING_WITH_AI_DB` | Primary Notion database ID |
| `GHOST_BLOG_ADMIN_KEY` | Ghost CMS admin API key |
### Config File
`config/ourdigital.yaml` contains:
- Brand settings (name, tagline, values)
- Channel configurations
- Color palette
- Typography settings
- Skill numbering conventions
- Export paths
## Usage in Skills
### Loading Configuration
```python
import yaml
from pathlib import Path
def load_config():
config_path = Path(__file__).parent.parent / "_ourdigital-shared/config/ourdigital.yaml"
with open(config_path) as f:
return yaml.safe_load(f)
config = load_config()
print(config['brand']['tagline'])
### 1. Create directories
```bash
mkdir -p ~/.ourdigital/credentials
chmod 700 ~/.ourdigital ~/.ourdigital/credentials
```
### Loading Environment
```python
from dotenv import load_dotenv
import os
load_dotenv(os.path.expanduser("~/.env.ourdigital"))
notion_token = os.getenv("NOTION_API_TOKEN")
### 2. Copy environment template
```bash
cp .env.ourdigital.template ~/.env.ourdigital
chmod 600 ~/.env.ourdigital
```
## Skill Numbering
### 3. Edit credentials
```bash
nano ~/.env.ourdigital
# Add your API keys
```
| Range | Category |
|-------|----------|
| 01-09 | OurDigital Core (brand, blog, journal, research, etc.) |
| 10 | Meta (skill-creator) |
| 11-19 | SEO Tools |
| 20-29 | GTM/Analytics Tools |
| 31-39 | Notion Tools |
| 40-49 | Jamie Clinic Tools |
### 4. Create virtual environment
```bash
python3 -m venv .venv-ourdigital
source .venv-ourdigital/bin/activate
pip install -r requirements/base.txt
```
## Version
## Credentials Required
- Package Version: 1.0.0
- Python Requirement: >= 3.11
- Author: OurDigital (Andrew Yim)
| Service | Variable | How to Get |
|---------|----------|------------|
| Notion | `NOTION_API_TOKEN` | [Notion Integrations](https://www.notion.so/my-integrations) |
| Ghost Blog | `GHOST_BLOG_ADMIN_KEY` | Ghost Admin → Integrations |
| Ghost Journal | `GHOST_JOURNAL_ADMIN_KEY` | Ghost Admin → Integrations |
| Figma | `FIGMA_ACCESS_TOKEN` | [Figma Settings](https://www.figma.com/developers/api#access-tokens) |
### Using 1Password CLI
If you have 1Password CLI (`op`) installed:
```bash
# Sign in
eval $(op signin)
# Installer will auto-fetch credentials
./install.sh
```
## Validation
Check your installation status:
```bash
# Quick check
./install.sh --validate
# Detailed check
python scripts/validate_install.py --verbose
```
## Cross-Machine Sync
To sync skills to another machine:
```bash
# On new machine
git clone https://github.com/ourdigital/our-claude-skills.git
cd our-claude-skills/custom-skills/_ourdigital-shared
./install.sh
# Credentials need to be set up separately (security)
# Either use 1Password CLI or manually copy ~/.env.ourdigital
```
## Troubleshooting
### Permission denied
```bash
chmod +x install.sh
```
### Python version
```bash
# Check version (need 3.11+)
python3 --version
# Use pyenv if needed
pyenv install 3.11
pyenv local 3.11
```
### Missing credentials
```bash
# Check what's missing
python scripts/validate_install.py --verbose
```
## File Reference
| File | Purpose |
|------|---------|
| `install.sh` | Main installer script |
| `.env.ourdigital.template` | Environment template |
| `config/ourdigital.yaml` | Default configuration |
| `requirements/base.txt` | Common dependencies |
| `requirements/code.txt` | Claude Code dependencies |
| `scripts/validate_install.py` | Installation validator |

View File

@@ -0,0 +1,53 @@
# Installing OurDigital Skills in Claude.ai
## Option 1: Upload Bundle (Recommended)
1. Go to [claude.ai](https://claude.ai)
2. Create a new **Project** (e.g., "OurDigital Workspace")
3. Click **Project Knowledge****Add Content**
4. Upload `ourdigital-skills-bundle.md`
5. Done! Use "our" or "ourdigital" prefix to trigger skills
## Option 2: Add as Custom Instructions
1. Go to Claude.ai → **Settings****Custom Instructions**
2. Copy the content from `ourdigital-skills-bundle.md`
3. Paste into Custom Instructions
4. Save
## Option 3: Individual Skills
Upload only the skills you need from the `individual/` folder:
- `01-brand-guide.md`
- `02-blog.md`
- `03-journal.md`
- etc.
## Testing After Install
Try these prompts:
```
our brand guide
our blog "AI 마케팅의 미래"
our research SEO trends 2026
our 견적서 GTM 구축
```
## Files in This Export
```
claude-ai-export/
├── INSTALL-CLAUDE-AI.md # This file
├── ourdigital-skills-bundle.md # All 10 skills combined
└── individual/ # Individual skill files
├── 01-brand-guide.md
├── 02-blog.md
└── ...
```
## Updating Skills
When skills are updated:
1. Pull latest from GitHub
2. Re-upload the bundle file
3. Or regenerate with: `python scripts/export_for_claude_ai.py`

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-brand-guide
description: |
OurDigital brand standards and style guide.
Triggers (ourdigital or our prefix):
- "our brand guide", "our 브랜드 가이드", "our 톤앤매너"
---
# OurDigital Brand Guide
**Purpose**: Brand standards and style
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Brand Guide
Reference skill for OurDigital brand standards, writing style, and visual identity.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital 브랜드 가이드" / "our 브랜드 가이드"
- "ourdigital 톤앤매너 체크" / "our 톤앤매너"
- "our brand guide", "our style check"
## Brand Foundation
### Core Identity
| Element | Content |
|---------|---------|
| **Brand Name** | OurDigital Clinic |
| **Tagline** | 우리 디지털 클리닉 \| Your Digital Health Partner |
| **Mission** | 디지털 마케팅 클리닉 for SMBs, 자영업자, 프리랜서, 비영리단체 |
| **Promise** | 진단-처방-측정 가능한 성장 |
### Core Values
| 가치 | English | 클리닉 메타포 |
|------|---------|--------------|
| 데이터 중심 | Data-driven | 정밀 검사 |
| 실행 지향 | In-Action | 실행 가능한 처방 |
| 마케팅 과학 | Marketing Science | 근거 중심 의학 |
### Brand Philosophy
**"Precision + Empathy + Evidence"**
## Channel Tone Matrix
| Channel | Domain | Personality | Tone |
|---------|--------|-------------|------|
| Main Hub | ourdigital.org | Professional & Confident | Data-driven, Solution-oriented |
| Blog | blog.ourdigital.org | Analytical & Personal | Educational, Thought-provoking |
| Journal | journal.ourdigital.org | Conversational & Poetic | Reflective, Cultural Observer |
| OurStory | ourstory.day | Intimate & Reflective | Authentic, Personal Journey |
## Writing Style Characteristics
### Korean (한국어)
1. **철학-기술 융합체**: 기술 분석과 실존적 질문을 자연스럽게 결합
2. **역설 활용**: 긴장과 모순 구조로 논증 전개
3. **수사적 질문**: 선언적 권위보다 질문을 통한 참여
4. **우울한 낙관주의**: 불안과 상실을 인정하되 절망하지 않음
### English
1. **Philosophical-Technical Hybridization**: Technical content with human implications
2. **Paradox as Device**: Structure arguments around tensions
3. **Rhetorical Questions**: Interrogative engagement over authority
4. **Melancholic Optimism**: Acknowledge anxiety without despair
### Do's and Don'ts
**Do's:**
- Use paradox to structure arguments
- Ask rhetorical questions to engage readers
- Connect technical content to human implications
- Blend Korean and English naturally for technical terms
- Reference historical context and generational shifts
**Don'ts:**
- Avoid purely declarative, authoritative tone
- Don't separate technical analysis from cultural impact
- Avoid simplistic or overly optimistic narratives
- Don't provide prescriptive conclusions without exploration
## Visual Identity
### Primary Colors
| Token | Color | HEX | Usage |
|-------|-------|-----|-------|
| --d-black | D.Black | #221814 | Footer, dark backgrounds |
| --d-olive | D.Olive | #cedc00 | Primary accent, CTA buttons |
| --d-green | D.Green | #287379 | Links hover, secondary accent |
| --d-blue | D.Blue | #0075c0 | Links |
| --d-beige | D.Beige | #f2f2de | Light text on dark |
| --d-gray | D.Gray | #ebebeb | Alt backgrounds |
### Typography
- **Korean**: Noto Sans KR
- **English**: Noto Sans, Inter
- **Grid**: 12-column responsive layout
## Brand Compliance Check
When reviewing content, verify:
1. **Tone Match**: Does it match the channel's personality?
2. **Value Alignment**: Reflects Data-driven, In-Action, Marketing Science?
3. **Philosophy Check**: Precision + Empathy + Evidence present?
4. **Language Style**: Appropriate blend of Korean/English terms?
5. **Visual Consistency**: Uses approved color palette?
## Quick Reference
### Key Messages
| Use | Message |
|-----|---------|
| Tagline | 우리 디지털 클리닉 \| Your Digital Health Partner |
| Value Prop | 데이터로 진단하고, 실행으로 처방합니다 |
| Process | 진단 → 처방 → 측정 |
| Differentiator | 25년 경험의 마케팅 사이언티스트 |
### CTA Patterns
| Context | CTA |
|---------|-----|
| General | 무료 상담 신청하기 |
| SEO | SEO 진단 신청하기 |
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-blog
description: |
Korean blog draft creation for blog.ourdigital.org.
Triggers (ourdigital or our prefix):
- "our blog", "our 블로그", "our 한국어 포스트"
---
# OurDigital Blog
**Purpose**: Korean blog drafts
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Blog
Korean blog draft creation skill for blog.ourdigital.org.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital 블로그 써줘" / "our 블로그 써줘"
- "ourdigital blog draft" / "our blog draft"
- "our 한국어 포스트 [주제]"
## Channel Profile
| Field | Value |
|-------|-------|
| **URL** | blog.ourdigital.org |
| **Language** | Korean (전문용어 영문 병기) |
| **Tone** | Analytical & Personal, Educational |
| **Platform** | Ghost CMS |
| **Frequency** | 주 1-2회 |
| **Length** | 1,500-3,000자 |
## Workflow
### Phase 1: Topic Clarification
Ask clarifying questions (max 3):
1. **주제 확인**: 정확한 토픽이 무엇인가요?
2. **대상 독자**: 타겟 오디언스는? (마케터/개발자/경영진/일반)
3. **깊이 수준**: 개요 / 심층분석 / 실무가이드 중 어느 수준?
### Phase 2: Research (Optional)
If topic requires current information:
- Use `web_search` for latest trends/data
- Use `Notion:notion-search` for past research
- Reference internal documents if available
### Phase 3: Draft Generation
Generate blog draft following brand style:
**Structure:**
```
1. 도입부 (Hook + Context)
2. 본론 (3-5 핵심 포인트)
- 각 포인트: 주장 → 근거 → 함의
3. 결론 (Summary + 열린 질문)
```
**Writing Style:**
- 철학-기술 융합: 기술 분석 + 인간적 함의
- 역설 활용: 긴장/모순으로 논증 구조화
- 수사적 질문: 독자 참여 유도
- 우울한 낙관주의: 불안 인정, 절망 거부
**Language Rules:**
- 한글 기본, 전문용어는 영문 병기
- 예: "검색엔진최적화(SEO)"
- 문장: 복합문 허용, 상호연결된 개념 반영
- 단락: 관찰 → 분석 → 철학적 함의
### Phase 4: SEO Metadata
Generate metadata:
```yaml
title: [60자 이내, 키워드 포함]
meta_description: [155자 이내]
slug: [영문 URL slug]
tags: [3-5개 태그]
featured_image_prompt: [DALL-E/Midjourney 프롬프트]
```
### Phase 5: Output Format
**Markdown Output:**
```markdown
---
title: "포스트 제목"
meta_description: "메타 설명"
slug: "url-slug"
tags: ["tag1", "tag2"]
---
# 포스트 제목
[본문 내용]
---
*Originally drafted with Claude for OurDigital Blog*
```
## Ghost CMS Integration
Export options:
1. **Markdown file** → Ulysses → Ghost
2. **Direct API** → Ghost Admin API (if configured)
API endpoint: `GHOST_BLOG_URL` from environment
## Brand Compliance
Before finalizing, verify:
- [ ] 분석적 + 개인적 톤 유지
- [ ] 기술 내용에 인간적 함의 포함
- [ ] 수사적 질문으로 독자 참여
- [ ] 전문용어 영문 병기
- [ ] 1,500-3,000자 범위
## Quick Commands
| Command | Action |
|---------|--------|
| "ourdigital 블로그 [주제]" | Full workflow |
| "ourdigital blog SEO" | SEO metadata only |
| "ourdigital blog 편집" | Edit existing draft |
## References
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-journal
description: |
English essay creation for journal.ourdigital.org.
Triggers (ourdigital or our prefix):
- "our journal", "our English essay", "our 영문 에세이"
---
# OurDigital Journal
**Purpose**: English essays
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Journal
English essay and article creation for journal.ourdigital.org.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital journal" / "our journal"
- "ourdigital English essay" / "our English essay"
- "our 영문 에세이 [topic]"
- "ourdigital 영문 에세이 [주제]"
## Channel Profile
| Field | Value |
|-------|-------|
| **URL** | journal.ourdigital.org |
| **Language** | English |
| **Tone** | Conversational & Poetic, Reflective |
| **Platform** | Ghost CMS |
| **Frequency** | 월 2-4회 |
| **Length** | 1,000-2,000 words |
## Workflow
### Phase 1: Topic Exploration
Ask clarifying questions:
1. **Topic**: What specific angle interests you?
2. **Audience**: Tech professionals / General readers / Academic?
3. **Depth**: Personal reflection / Industry analysis / Cultural observation?
### Phase 2: Research (Optional)
If topic requires current context:
- Use `web_search` for recent developments
- Reference scholarly perspectives if applicable
- Draw from historical or cultural parallels
### Phase 3: Essay Generation
Generate essay following the reflective style:
**Structure:**
```
1. Opening (Evocative scene or question)
2. Exploration (3-4 interconnected observations)
3. Synthesis (Weaving threads together)
4. Closing (Open-ended reflection)
```
**Writing Style:**
- Philosophical-Technical Hybridization
- Paradox as primary rhetorical device
- Rhetorical questions for engagement
- Melancholic optimism in tone
**Distinctive Qualities:**
- Temporal awareness (historical context)
- Epistemic humility (acknowledging limits)
- Cultural bridging (Korean-global perspectives)
### Phase 4: SEO Metadata
Generate metadata:
```yaml
title: [Evocative, under 70 characters]
meta_description: [Compelling summary, 155 characters]
slug: [english-url-slug]
tags: [3-5 relevant tags]
```
### Phase 5: Output Format
**Markdown Output:**
```markdown
---
title: "Essay Title"
meta_description: "Description"
slug: "url-slug"
tags: ["tag1", "tag2"]
---
# Essay Title
[Essay content with paragraphs that flow naturally]
---
*Published in [OurDigital Journal](https://journal.ourdigital.org)*
```
## Writing Guidelines
### Voice Characteristics
| Aspect | Approach |
|--------|----------|
| Perspective | First-person reflection welcome |
| Tone | Thoughtful, observant, wondering |
| Pacing | Unhurried, allowing ideas to breathe |
| References | Cross-cultural, historical, literary |
### Sentence Craft
- Long, complex sentences reflecting interconnected ideas
- Progressive deepening: observation → analysis → implication
- Questions that invite rather than lecture
### Do's and Don'ts
**Do:**
- Blend technology with humanity
- Use paradox to illuminate tensions
- Acknowledge uncertainty gracefully
- Bridge Korean and Western perspectives
**Don't:**
- Lecture or prescribe
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-research
description: |
Research workflow with paper and blog output.
Triggers (ourdigital or our prefix):
- "our research", "our 리서치", "our deep research"
---
# OurDigital Research
**Purpose**: Research prompts
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Research
Transform questions into comprehensive research papers and polished blog posts for OurDigital channels.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital research [topic]" / "our research [topic]"
- "our 리서치", "our deep research"
- "ourdigital 리서치 해줘"
- "ourdigital deep research on [topic]"
## Workflow Overview
```
Phase 1: Discovery → Phase 2: Research Planning → Phase 3: Deep Research
Phase 4: Research Paper → Phase 5: Notion Save → Phase 6: Blog Draft
Phase 7: Ulysses Export → Phase 8: Publishing Guidance
```
## Phase 1: Discovery
**Goal**: Understand user's question and refine scope.
1. Acknowledge the topic/question
2. Ask clarifying questions (max 3 per turn):
- Target audience? (전문가/일반인/마케터)
- Depth level? (개요/심층분석/실무가이드)
- Specific angles or concerns?
3. Confirm research scope before proceeding
**Output**: Clear research objective statement
## Phase 2: Research Planning
**Goal**: Create structured research instruction.
Generate research plan with:
- Primary research questions (3-5)
- Secondary questions for depth
- Suggested tools/sources:
- Web search for current info
- Google Drive for internal docs
- Notion for past research
- Amplitude for analytics data (if relevant)
- Expected deliverables
**Output**: Numbered research instruction list
## Phase 3: Deep Research
**Goal**: Execute comprehensive multi-source research.
Tools to leverage:
- `web_search` / `web_fetch`: Current information, statistics, trends
- `google_drive_search`: Internal documents, past reports
- `Notion:notion-search`: Previous research, related notes
- `conversation_search`: Past chat context
Research execution pattern:
1. Start broad (overview searches)
2. Deep dive into key subtopics
3. Find supporting data/statistics
4. Identify expert opinions and case studies
5. Cross-reference and validate
**Output**: Organized research findings with citations
## Phase 4: Research Paper (Artifact)
**Goal**: Synthesize findings into comprehensive document.
Create HTML artifact with:
```
Structure:
├── Executive Summary (핵심 요약)
├── Background & Context (배경)
├── Key Findings (주요 발견)
│ ├── Finding 1 with evidence
│ ├── Finding 2 with evidence
│ └── Finding 3 with evidence
├── Analysis & Implications (분석 및 시사점)
├── Recommendations (제언)
├── References & Sources (참고자료)
└── Appendix (부록) - if needed
```
Style: Professional, data-driven, bilingual key terms
## Phase 5: Notion Save
**Goal**: Archive research to Working with AI database.
Auto-save to Notion with:
- **Database**: Working with AI (data_source_id: f8f19ede-32bd-43ac-9f60-0651f6f40afe)
- **Properties**:
- Name: [Research topic]
- Status: "Done"
- AI used: "Claude Desktop"
- AI summary: 2-3 sentence summary
## Phase 6: Blog Draft
**Goal**: Transform research into engaging blog post.
Prompt user for channel selection:
1. blog.ourdigital.org (Korean)
2. journal.ourdigital.org (English)
3. ourstory.day (Korean, personal)
Generate draft using appropriate style guide:
- Korean channels: See `02-ourdigital-blog`
- English channels: See `03-ourdigital-journal`
## Phase 7: Ulysses Export
**Goal**: Deliver MD file for Ulysses editing.
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-document
description: |
Notion-to-presentation workflow.
Triggers (ourdigital or our prefix):
- "our document", "our 발표자료", "our presentation"
---
# OurDigital Document
**Purpose**: Presentations
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Document
Transform Notion research into branded presentations for OurDigital workflows.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital document" / "our document"
- "ourdigital 발표자료" / "our 발표자료"
- "our presentation [topic]"
- "ourdigital presentation on [topic]"
## Workflow Overview
```
Phase 1: Research Collection → Phase 2: Content Synthesis → Phase 3: Presentation Planning
Phase 4: Slide Generation → Phase 5: Brand Application → Phase 6: Export
```
## Phase 1: Research Collection
**Goal**: Extract research content from Notion.
Input sources:
- **Notion Page**: `notion://page/[ID]` - Single research document
- **Notion Database**: `notion://database/[ID]` - Collection query
- **Multiple Sources**: Comma-separated URLs for synthesis
Tools to use:
- `Notion:notion-search` - Find related content
- `Notion:notion-fetch` - Extract page content
**Output**: Structured research.json with findings
## Phase 2: Content Synthesis
**Goal**: Analyze and structure extracted content.
Processing:
1. Identify key topics and themes
2. Extract supporting data/statistics
3. Prioritize by relevance and impact
4. Generate executive summary
**Output**: synthesis.json with:
- Executive summary
- Key topics (ranked)
- Agenda items
- Supporting data points
## Phase 3: Presentation Planning
**Goal**: Create slide-by-slide structure.
Presentation types:
| Type | Slides | Focus |
|------|--------|-------|
| Executive Summary | 3-5 | High-level findings, KPIs |
| Research Report | 10-20 | Detailed methodology, data viz |
| Meeting Prep | 5-10 | Agenda-driven, decision points |
**Output**: Slide plan with:
- Title + subtitle per slide
- Content outline
- Speaker notes
- Visual suggestions
## Phase 4: Slide Generation
**Goal**: Generate presentation content.
Slide structure:
```
├── Title Slide (project name, date, author)
├── Agenda (numbered topics)
├── Content Slides (1-3 per topic)
│ ├── Key finding header
│ ├── Supporting points (3-5 bullets)
│ └── Data visualization placeholder
├── Summary Slide (key takeaways)
└── Next Steps / Q&A
```
## Phase 5: Brand Application
**Goal**: Apply OurDigital corporate styling.
Brand elements:
- **Colors**: OurDigital palette from `01-ourdigital-brand-guide`
- **Fonts**: Poppins (headings), Lora (body)
- **Logo**: Positioned per brand guidelines
- **Spacing**: Consistent margins and padding
Configuration: `shared/references/brand-config.json`
## Phase 6: Export
**Goal**: Generate final deliverable.
Output formats:
- **PowerPoint (.pptx)**: Full presentation with animations
- **Figma Slides**: Web-based collaborative format
- **HTML Preview**: Quick review before final export
Export paths:
- Desktop: `~/Downloads/presentations/`
- Figma: Via Figma API
## Quick Commands
| Command | Action |
|---------|--------|
| "ourdigital document [Notion URL]" | Full pipeline |
| "ourdigital 발표자료 만들어줘" | Korean trigger |
| "ourdigital presentation → pptx" | PowerPoint output |
| "ourdigital presentation → figma" | Figma output |
## Presentation Templates
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-designer
description: |
Visual storytelling and image prompt generation.
Triggers (ourdigital or our prefix):
- "our design", "our 썸네일", "our image prompt"
---
# OurDigital Designer
**Purpose**: Image prompts
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Designer
Transform philosophical essays into sophisticated visual narratives through minimalist, conceptually rich featured images.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital design" / "our design"
- "ourdigital 썸네일" / "our 썸네일"
- "our image prompt for [topic]"
## Core Philosophy
OurDigital images are visual philosophy—not illustrations but parallel texts that invite contemplation. Each image captures the essay's philosophical core through:
- **Abstract metaphors** over literal representations
- **Contemplative minimalism** with 20%+ negative space
- **Cultural fusion** of Korean-Western aesthetics
- **Emotional resonance** through color psychology
## Workflow
### Phase 1: Extract Essay Essence
Analyze the content for:
- **Core insight**: What philosophical truth?
- **Emotional tone**: What feeling to evoke?
- **Key metaphor**: What visual symbol?
### Phase 2: Select Visual Approach
| Essay Type | Visual Strategy | Color Mood |
|-----------|-----------------|------------|
| Technology | Organic-digital hybrids | Cool blues → warm accents |
| Social | Network patterns, human fragments | Desaturated → hope spots |
| Philosophy | Zen space, symbolic objects | Monochrome + single accent |
| Cultural | Layered traditions, fusion forms | Earth tones → modern hues |
### Phase 3: Generate Prompt
Build structured prompt with:
```
[Style] + [Subject] + [Composition] + [Color] + [Technical specs]
```
### Phase 4: Quality Check
**Must have:**
- Captures philosophical insight
- Works at 200px thumbnail
- Timeless (2-3 year relevance)
- Cross-cultural readability
**Must avoid:**
- Tech clichés (circuits, binary)
- Stock photo aesthetics
- Literal interpretations
- Trendy effects
## Quick Templates
### AI & Humanity
```
"Translucent human silhouette dissolving into crystalline data structures.
Monochrome with teal accent. Boundary dissolution between organic/digital.
1200x630px, minimalist vector style."
```
### Social Commentary
```
"Overlapping circles forming maze pattern, tiny humans in separate chambers.
Blue-gray palette, warm light leaks for hope. Subtle Korean patterns.
High negative space. 1200x630px."
```
### Digital Transformation
```
"Traditional forms metamorphosing into particle streams. Paper texture → digital grain.
Earth tones shifting to cool blues. Sacred geometry underlying.
1200x630px, contemplative mood."
```
## Visual Metaphor Shortcuts
| Concept | Visual Metaphor |
|---------|-----------------|
| Algorithm | Constellation patterns |
| Identity | Layered masks, fingerprints |
| Network | Root systems, neural paths |
| Time | Spirals, sediment layers |
| Knowledge | Light sources, growing trees |
## Color Psychology
| Mood | Palette |
|------|---------|
| Critical | Deep blue-gray + red accent |
| Hopeful | Warm amber + sky blue |
| Philosophical | Near black + off white + gold |
| Anxious | Charcoal + grey-blue + digital green |
## Technical Specs
- **Dimensions**: 1200x630px (OG standard)
- **Style**: Vector illustration + subtle textures
- **Colors**: 60-30-10 rule (dominant-secondary-accent)
- **Format**: WebP primary, JPG fallback
## Quick Commands
| Command | Action |
|---------|--------|
| "ourdigital design [topic]" | Generate image prompt |
| "ourdigital 썸네일 [주제]" | Korean trigger |
| "ourdigital visual → midjourney" | MidJourney optimized |
| "ourdigital visual → dalle" | DALL-E optimized |
## References
- `shared/references/visual-metaphors.md` - Concept dictionary
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-ad-manager
description: |
Ad copywriting and keyword research.
Triggers (ourdigital or our prefix):
- "our ad copy", "our 광고 카피", "our keyword"
---
# OurDigital Ad Manager
**Purpose**: Ad copywriting
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Ad Manager
Create compelling ad copy and research keywords for OurDigital marketing campaigns.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital ad copy" / "our ad copy"
- "ourdigital 광고 카피" / "our 광고 카피"
- "our keyword research [topic]"
## Workflow
### Phase 1: Campaign Brief
Gather information:
- **Product/Service**: What are we advertising?
- **Target audience**: Who are we reaching?
- **Campaign goal**: Awareness, consideration, or conversion?
- **Platform**: Google, Naver, Meta, Display?
- **Budget tier**: Affects keyword competitiveness
### Phase 2: Keyword Research
For search campaigns:
1. **Seed keywords**: Core terms from brief
2. **Volume research**: Web search for search volume data
3. **Intent mapping**: Informational → Transactional
4. **Competitor analysis**: Top-ranking ad copy patterns
Tools to use:
- `web_search`: Search volume and trends
- `web_fetch`: Competitor ad copy analysis
### Phase 3: Ad Copy Creation
Generate platform-specific copy following character limits and best practices.
## Search Ad Copy
### Google Ads Format
```
Headline 1: [30 chars] - Primary keyword + value prop
Headline 2: [30 chars] - Benefit or CTA
Headline 3: [30 chars] - Differentiator
Description 1: [90 chars] - Expand on value
Description 2: [90 chars] - CTA + urgency
```
**Best Practices:**
- Include keyword in Headline 1
- Numbers and specifics increase CTR
- Test emotional vs. rational appeals
- Include pricing if competitive
### Naver Search Ad Format
```
제목: [25자] - 핵심 키워드 + 가치
설명: [45자] - 혜택 + 행동 유도
```
**Korean Ad Copy Tips:**
- 존댓말 일관성 유지
- 숫자와 구체적 혜택 강조
- 신뢰 요소 포함 (경력, 인증)
## Display Ad Copy
### Headlines by Format
| Format | Max Length | Focus |
|--------|------------|-------|
| Leaderboard | 25 chars | Brand + single benefit |
| Medium Rectangle | 30 chars | Offer + CTA |
| Responsive | 30 chars | Multiple variations |
### Copy Formula
```
[Problem Recognition] + [Solution Hint] + [CTA]
"여전히 [문제]? [해결책]으로 [결과]"
```
## Branded Content
For native advertising and sponsored content:
### OurDigital Tone
- **Authority without arrogance**: Share expertise, invite questions
- **Data-backed claims**: Statistics increase credibility
- **Subtle CTAs**: Education first, promotion second
### Content Types
| Type | Length | CTA Style |
|------|--------|-----------|
| Sponsored Article | 800-1,200 words | Soft (learn more) |
| Native Ad | 100-200 words | Medium (discover) |
| Social Sponsored | 50-100 words | Direct (get started) |
## Keyword Research Output
### Research Report Structure
```
## Keyword Analysis: [Topic]
### Primary Keywords
| Keyword | Volume | Difficulty | Intent |
|---------|--------|------------|--------|
| [kw1] | 10K | Medium | Trans |
### Long-tail Opportunities
- [keyword phrase 1]: Low competition, high intent
- [keyword phrase 2]: Rising trend
### Negative Keywords
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-trainer
description: |
Training materials and workshop planning.
Triggers (ourdigital or our prefix):
- "our training", "our 워크샵", "our 교육"
---
# OurDigital Trainer
**Purpose**: Training materials
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Trainer
Design training materials, plan workshops, and create evaluation frameworks for OurDigital education programs.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital training" / "our training"
- "ourdigital 워크샵" / "our 워크샵"
- "our curriculum [subject]"
## Core Domains
OurDigital training expertise:
| Domain | Topics |
|--------|--------|
| **Data Literacy** | 데이터 리터러시, 분석 기초, 시각화 |
| **AI Literacy** | AI 활용, 프롬프트 엔지니어링, AI 윤리 |
| **Digital Marketing** | SEO, GTM, 마케팅 자동화 |
| **Brand Marketing** | 브랜드 전략, 콘텐츠 마케팅 |
## Workflow
### Phase 1: Training Needs Analysis
Gather requirements:
- **Target audience**: 직급, 경험 수준, 사전 지식
- **Learning objectives**: 교육 후 달성할 역량
- **Duration**: 시간 제약 (2시간/반일/전일/다회차)
- **Format**: 온라인/오프라인/하이브리드
- **Group size**: 참여 인원
### Phase 2: Curriculum Design
Structure the learning journey:
```
Module Structure:
├── 도입 (10-15%)
│ ├── Ice-breaker
│ ├── 학습 목표 공유
│ └── 사전 지식 확인
├── 핵심 학습 (60-70%)
│ ├── 개념 설명
│ ├── 사례 분석
│ ├── 실습 활동
│ └── 토론/질의응답
├── 심화/응용 (15-20%)
│ ├── 응용 과제
│ └── 그룹 활동
└── 마무리 (5-10%)
├── 핵심 정리
├── 평가
└── 후속 학습 안내
```
### Phase 3: Material Development
Create supporting materials:
| Material Type | Purpose |
|---------------|---------|
| 슬라이드 | 핵심 개념 전달 |
| 핸드아웃 | 참조 자료, 체크리스트 |
| 워크시트 | 실습 활동용 |
| 사례 연구 | 토론 및 분석용 |
| 퀴즈/평가지 | 학습 확인용 |
### Phase 4: Activity Design
Engagement techniques:
| Activity Type | Duration | Purpose |
|---------------|----------|---------|
| Think-Pair-Share | 5-10분 | 개별 사고 → 협력 |
| Case Study | 20-30분 | 실제 적용력 |
| Role Play | 15-20분 | 경험적 학습 |
| Gallery Walk | 15분 | 아이디어 공유 |
| Fishbowl | 20-30분 | 심층 토론 |
### Phase 5: Evaluation Design
Assessment framework:
| Level | What to Measure | Method |
|-------|-----------------|--------|
| 반응 | 만족도, 참여도 | 설문조사 |
| 학습 | 지식 습득 | 퀴즈, 테스트 |
| 행동 | 현업 적용 | 관찰, 피드백 |
| 결과 | 성과 개선 | KPI 측정 |
## Training Templates
### 2-Hour Workshop
```
00:00-00:10 도입 및 Ice-breaker
00:10-00:20 학습 목표 및 아젠다
00:20-00:50 핵심 개념 1
00:50-01:00 휴식
01:00-01:30 핵심 개념 2 + 실습
01:30-01:50 그룹 활동/토론
01:50-02:00 정리 및 Q&A
```
### Half-Day (4 Hours)
```
09:00-09:20 도입 및 네트워킹
09:20-10:20 모듈 1: 기초 개념
10:20-10:30 휴식
10:30-11:30 모듈 2: 심화 학습
11:30-12:00 실습 세션
12:00-12:30 사례 연구
12:30-13:00 정리, 평가, Q&A
```
### Full-Day (8 Hours)
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-backoffice
description: |
Business documents for consulting services.
Triggers (ourdigital or our prefix):
- "our 견적서", "our proposal", "our quote"
---
# OurDigital Backoffice
**Purpose**: Business documents
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Backoffice
Create business documents for OurDigital consulting services.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital 견적서" / "our 견적서"
- "ourdigital proposal" / "our proposal"
- "our cost analysis [project]"
## Important Notice
⚠️ **Legal Disclaimer**: Contract drafts require professional legal review before use. This skill provides templates and structure only.
## Document Types
### 1. Quote/Estimate (견적서)
**Purpose**: Service pricing and scope summary
**Structure:**
```
견적서 번호: OD-YYYY-NNN
발행일: YYYY-MM-DD
유효기간: 30일
1. 고객 정보
- 회사명, 담당자, 연락처
2. 서비스 개요
- 프로젝트명
- 서비스 범위 요약
3. 세부 항목
| 항목 | 상세 | 수량 | 단가 | 금액 |
|------|------|------|------|------|
4. 합계
- 소계, VAT, 총액
5. 결제 조건
- 선금/잔금 비율
- 결제 방법
6. 특이사항
- 포함/미포함 사항
```
### 2. Service Proposal (서비스 제안서)
**Purpose**: Detailed service offering and value proposition
**Structure:**
```
1. Executive Summary
- 핵심 제안 1-2문단
2. 고객 상황 이해
- 현재 과제
- 니즈 분석
3. 제안 서비스
- 서비스 범위
- 접근 방법
- 예상 산출물
4. 프로젝트 계획
- 일정표
- 마일스톤
- 체크포인트
5. 투입 리소스
- 담당자 프로필
- 역할 분담
6. 비용 및 조건
- 비용 구조
- 결제 조건
7. 기대 효과
- 예상 성과
- ROI 추정
8. 왜 OurDigital인가
- 차별점
- 관련 경험
```
### 3. Contract Draft (계약서 초안)
**Purpose**: Service agreement framework
⚠️ **반드시 법률 전문가 검토 필요**
**Structure:**
```
제1조 (목적)
제2조 (용어의 정의)
제3조 (계약 기간)
제4조 (서비스 범위)
제5조 (대금 및 지급 조건)
제6조 (권리와 의무)
제7조 (비밀유지)
제8조 (지적재산권)
제9조 (계약의 해지)
제10조 (손해배상)
제11조 (분쟁 해결)
제12조 (일반 조항)
```
### 4. Cost-Benefit Analysis (비용 분석)
**Purpose**: ROI and investment justification
**Structure:**
```
1. 프로젝트 개요
- 목적 및 범위
[... see full documentation for more ...]

View File

@@ -0,0 +1,137 @@
---
name: ourdigital-skill-creator
description: |
Meta skill for creating and managing new skills.
Triggers (ourdigital or our prefix):
- "our skill create", "our 스킬 만들기"
---
# OurDigital Skill Creator
**Purpose**: Creating new skills
**Triggers**: Use "our" or "ourdigital" prefix
---
# OurDigital Skill Creator
Meta skill for creating, validating, and managing OurDigital Claude Skills.
## Activation
Activate with "ourdigital" or "our" prefix:
- "ourdigital 스킬 만들어줘" / "our 스킬 만들어줘"
- "ourdigital skill creator" / "our skill creator"
- "our skill create [name]"
Do NOT activate for generic "make a skill" requests (without our/ourdigital prefix).
## Interactive Workflow
### Phase 1: Need Assessment
When user requests a new skill:
1. **Acknowledge** the initial request
2. **Ask clarifying questions** (max 3 per turn):
- What is the core purpose?
- What triggers this skill?
- What outputs do you expect?
### Phase 2: Suitability Check
Evaluate against Claude Skill criteria:
| Criterion | Question to Ask |
|-----------|-----------------|
| Clear trigger | When exactly should this skill activate? |
| Focused scope | Can you describe 1-3 core functions? |
| Reusable resources | What scripts, templates, or references are needed? |
| Domain knowledge | What specialized knowledge does Claude lack? |
| Clear boundaries | How does this differ from existing skills? |
**Decision**: If ≥3 criteria pass → proceed. Otherwise, suggest alternatives.
### Phase 3: Requirements Definition
Guide user through structured Q&A:
```
Q1. 스킬 목적과 핵심 기능은 무엇인가요?
(What is the skill's purpose and core functions?)
Q2. 어떤 상황에서 이 스킬이 트리거되어야 하나요?
(When should this skill be triggered?)
Q3. 필요한 외부 도구나 API가 있나요?
(Any external tools or APIs needed?)
Q4. 기대하는 출력 형식은 무엇인가요?
(What output format do you expect?)
Q5. Desktop, Code, 또는 Both 환경이 필요한가요?
(Which environment: Desktop, Code, or Both?)
```
### Phase 4: Skill Generation
Generate skill structure following OurDigital standards:
```
XX-ourdigital-{skill-name}/
├── desktop/
│ └── SKILL.md # Desktop version
├── code/
│ └── SKILL.md # Code version (CLAUDE.md pattern)
├── shared/
│ ├── references/ # Common documentation
│ ├── templates/ # Shared templates
│ └── scripts/ # Utility scripts
├── docs/
│ ├── CHANGELOG.md # Version history
│ └── logs/ # Update logs
└── README.md # Overview
```
### Phase 5: Validation
Before finalizing, verify:
- [ ] YAML frontmatter includes "ourdigital" trigger keywords
- [ ] Description clearly states activation conditions
- [ ] Body content is 800-1,200 words
- [ ] shared/ resources are properly referenced
- [ ] No overlap with existing ourdigital skills
### Phase 6: Notion Sync
Record to Working with AI database:
- **Database**: f8f19ede-32bd-43ac-9f60-0651f6f40afe
- **Properties**:
- Name: `ourdigital-{skill-name} v{version}`
- Status: In progress → Done
- AI used: Claude Desktop
- AI summary: Brief skill description
## YAML Frontmatter Template
```yaml
---
name: ourdigital-{skill-name}
description: |
[Purpose summary]
Activated when user includes "ourdigital" keyword.
Triggers:
- "ourdigital {keyword1}", "ourdigital {keyword2}"
Features:
- Feature 1
- Feature 2
version: "1.0"
author: OurDigital
environment: Desktop | Code | Both
---
[... see full documentation for more ...]

View File

@@ -0,0 +1,336 @@
---
name: ourdigital-skills-bundle
description: |
Complete OurDigital Skills package with 10 skills for brand, content, production, and business workflows.
Triggers (ourdigital or our prefix):
- "our brand", "our blog", "our journal", "our research"
- "our document", "our design", "our ad copy", "our training"
- "our 견적서", "our skill"
---
# OurDigital Skills Bundle for Claude.ai
This file contains all 10 OurDigital skills for use in Claude.ai Projects.
**Activation**: Use "ourdigital" or "our" prefix to trigger skills.
---
## 1. OurDigital Brand Guide
**Triggers**: `our brand guide`, `our 브랜드 가이드`, `our 톤앤매너`
### Brand Identity
- **Name**: OurDigital Clinic
- **Tagline**: 우리 디지털 클리닉 | Your Digital Health Partner
- **Mission**: 디지털 마케팅 클리닉 for SMBs
### Core Values
| 가치 | English | 메타포 |
|------|---------|--------|
| 데이터 중심 | Data-driven | 정밀 검사 |
| 실행 지향 | In-Action | 실행 가능한 처방 |
| 지속 성장 | Sustainable Growth | 정기 검진 |
### Writing Style
- **Korean**: 분석적 + 개인적, 철학-기술 융합
- **English**: Reflective, poetic, paradox as device
- **Fonts**: Poppins (headings), Lora (body)
- **Colors**: Primary #1a1a2e, Accent #4ecdc4
---
## 2. OurDigital Blog
**Triggers**: `our blog`, `our 블로그`, `our 한국어 포스트`
### Channel
- **URL**: blog.ourdigital.org
- **Language**: Korean (전문용어 영문 병기)
- **Tone**: Analytical & Personal, Educational
- **Length**: 1,500-3,000자
### Structure
```
제목 (SEO 키워드 포함)
├── 도입부 (hook + 핵심 질문)
├── 본문 (3-5 섹션)
│ ├── 소제목 + 본문
│ └── 데이터/인용 포함
├── 결론 (인사이트 + 열린 질문)
└── CTA (optional)
```
### Style Tips
- 역설(Paradox) 활용: "~하면서 동시에 ~하다"
- 수사적 질문으로 참여 유도
- 우울한 낙관주의: 불안 인정 + 희망 제시
---
## 3. OurDigital Journal
**Triggers**: `our journal`, `our English essay`, `our 영문 에세이`
### Channel
- **URL**: journal.ourdigital.org
- **Language**: English
- **Tone**: Conversational, Poetic, Reflective
- **Length**: 1,000-2,000 words
### Writing Characteristics
- **Philosophical-Technical Hybridization**: Tech + human implications
- **Paradox as Device**: Illuminate through tensions
- **Melancholic Optimism**: Clear-eyed hope
### Structure
```
Opening (hook with scene/question)
├── Body (weaving narrative + analysis)
│ ├── Personal observation
│ ├── Cultural/technical context
│ └── Philosophical reflection
└── Closing (open question, not conclusion)
```
---
## 4. OurDigital Research
**Triggers**: `our research`, `our 리서치`, `our deep research`
### Workflow
1. **Discovery**: Clarify topic, audience, depth
2. **Planning**: Generate research questions (3-5 primary)
3. **Research**: Multi-source investigation
4. **Synthesis**: Research paper with findings
5. **Archive**: Save to Notion "Working with AI"
6. **Output**: Optional blog draft
### Research Plan Template
```
Primary Questions:
1. [Core question about topic]
2. [Supporting question]
3. [Trend/future question]
Source Strategy:
- Web search: [keywords]
- Notion: [past research]
- Industry reports: [sources]
Deliverables:
- Research paper
- Notion archive
- Blog draft (optional)
```
---
## 5. OurDigital Document
**Triggers**: `our document`, `our 발표자료`, `our presentation`
### Workflow
1. Extract content from Notion
2. Synthesize key topics
3. Plan slide structure
4. Generate presentation
5. Apply OurDigital branding
### Presentation Types
| Type | Slides | Focus |
|------|--------|-------|
| Executive | 3-5 | High-level findings |
| Research | 10-20 | Detailed analysis |
| Meeting | 5-10 | Agenda-driven |
### Slide Structure
```
Title Slide → Agenda → Content (1-3 per topic) → Summary → Next Steps
```
---
## 6. OurDigital Designer
**Triggers**: `our design`, `our 썸네일`, `our image prompt`
### Philosophy
OurDigital images are visual philosophy—abstract metaphors over literal representations.
### Visual Approach
| Topic | Strategy | Colors |
|-------|----------|--------|
| Technology | Organic-digital hybrids | Cool blues |
| Social | Network patterns | Desaturated |
| Philosophy | Zen space | Monochrome + accent |
### Prompt Template
```
Create [style] featured image, 1200x630px.
Visual concept: [metaphor description].
Atmosphere: [mood].
Colors: [palette with accent].
Composition: Abstract, 20%+ negative space.
Avoid: Stock aesthetics, literal interpretation.
```
### Metaphor Shortcuts
- Algorithm → Constellation patterns
- Identity → Layered masks
- Network → Root systems
- Time → Spirals, sediment layers
---
## 7. OurDigital Ad Manager
**Triggers**: `our ad copy`, `our 광고 카피`, `our keyword`
### Google Ads Format
```
Headline 1: [30 chars] - Keyword + value
Headline 2: [30 chars] - Benefit
Headline 3: [30 chars] - Differentiator
Description 1: [90 chars] - Expand value
Description 2: [90 chars] - CTA + urgency
```
### Naver Format
```
제목: [25자] - 키워드 + 가치
설명: [45자] - 혜택 + 행동 유도
```
### Copy Formulas
- **PAS**: Problem → Agitate → Solution
- **FBP**: Feature → Benefit → Proof
- **QAA**: Question → Answer → Action
---
## 8. OurDigital Trainer
**Triggers**: `our training`, `our 워크샵`, `our 교육`
### Domains
- Data Literacy, AI Literacy
- Digital Marketing (SEO, GTM)
- Brand Marketing
### Workshop Templates
**2-Hour**
```
00:00-00:10 Ice-breaker
00:10-00:50 Module 1
00:50-01:00 Break
01:00-01:30 Module 2 + Practice
01:30-01:50 Activity
01:50-02:00 Wrap-up
```
**Half-Day (4 Hours)**
```
09:00-09:20 Opening
09:20-10:20 Module 1
10:20-10:30 Break
10:30-11:30 Module 2
11:30-12:00 Practice
12:00-12:30 Module 3
12:30-13:00 Closing
```
### Evaluation
- Level 1: Reaction (만족도)
- Level 2: Learning (지식 습득)
- Level 3: Behavior (현업 적용)
- Level 4: Results (성과 개선)
---
## 9. OurDigital Backoffice
**Triggers**: `our 견적서`, `our proposal`, `our quote`
### Document Types
1. **Quote (견적서)**: Pricing summary
2. **Proposal (제안서)**: Detailed offering
3. **Contract (계약서)**: Agreement framework ⚠️ Legal review required
4. **Cost Analysis**: ROI justification
### Quote Structure
```
문서번호: OD-QUOTE-YYYY-NNN
발행일: YYYY-MM-DD
서비스 항목 (표)
합계 (소계 + VAT)
결제 조건 (50/50)
프로젝트 일정
포함/미포함 사항
```
### Service Pricing Reference
| Service | Price Range |
|---------|-------------|
| SEO Audit | 300-500만원 |
| GTM Setup | 200-400만원 |
| Monthly SEO | 150-300만원/월 |
| Workshop | 100-200만원 |
---
## 10. OurDigital Skill Creator
**Triggers**: `our skill create`, `our 스킬 만들기`
### Suitability Criteria
- Clear trigger conditions
- Focused scope (1-3 functions)
- Reusable resources
- Domain-specific knowledge
- Clear boundaries
### Skill Structure
```
XX-ourdigital-skillname/
├── code/SKILL.md
├── desktop/SKILL.md
├── shared/references/
├── docs/CHANGELOG.md
└── README.md
```
### YAML Frontmatter Template
```yaml
---
name: ourdigital-skillname
description: |
[Purpose]
Triggers (ourdigital or our prefix):
- "our [keyword]", "ourdigital [keyword]"
version: "1.0"
author: OurDigital
---
```
---
## Quick Reference
| # | Skill | Trigger | Purpose |
|---|-------|---------|---------|
| 01 | brand-guide | `our brand` | Brand standards |
| 02 | blog | `our blog` | Korean posts |
| 03 | journal | `our journal` | English essays |
| 04 | research | `our research` | Research prompts |
| 05 | document | `our document` | Presentations |
| 06 | designer | `our design` | Image prompts |
| 07 | ad-manager | `our ad copy` | Ad copywriting |
| 08 | trainer | `our training` | Workshops |
| 09 | backoffice | `our 견적서` | Business docs |
| 10 | skill-creator | `our skill` | Create skills |
**Prefix**: Always use "our" or "ourdigital" to activate these skills.

View File

@@ -0,0 +1,415 @@
#!/bin/bash
#
# OurDigital Skills Installer
# Portable installation tool for OurDigital Claude Skills package
#
# Usage:
# ./install.sh # Interactive install
# ./install.sh --update # Update existing installation
# ./install.sh --uninstall # Remove installation
# ./install.sh --help # Show help
#
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILLS_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$HOME/.env.ourdigital"
CONFIG_DIR="$HOME/.ourdigital"
VENV_DIR="$SKILLS_DIR/.venv-ourdigital"
# Print banner
print_banner() {
echo -e "${CYAN}"
echo "╔═══════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ OurDigital Skills Installer ║"
echo "║ 사람, 디지털, 그리고 문화 ║"
echo "║ ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo -e "${NC}"
}
# Print colored messages
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Check prerequisites
check_prerequisites() {
info "Checking prerequisites..."
local missing=()
# Check Python 3.11+
if command -v python3 &> /dev/null; then
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
if [[ $(echo "$PYTHON_VERSION >= 3.11" | bc -l) -eq 1 ]]; then
success "Python $PYTHON_VERSION"
else
warn "Python $PYTHON_VERSION (3.11+ recommended)"
fi
else
missing+=("python3")
fi
# Check git
if command -v git &> /dev/null; then
success "Git $(git --version | cut -d' ' -f3)"
else
missing+=("git")
fi
# Check 1Password CLI (optional)
if command -v op &> /dev/null; then
success "1Password CLI available"
HAS_1PASSWORD=true
else
warn "1Password CLI not found (credentials will need manual entry)"
HAS_1PASSWORD=false
fi
if [[ ${#missing[@]} -gt 0 ]]; then
error "Missing required tools: ${missing[*]}"
exit 1
fi
echo ""
}
# Create directory structure
setup_directories() {
info "Setting up directories..."
# Create config directory
mkdir -p "$CONFIG_DIR/credentials"
chmod 700 "$CONFIG_DIR"
chmod 700 "$CONFIG_DIR/credentials"
success "Created $CONFIG_DIR/"
# Create logs directory
mkdir -p "$CONFIG_DIR/logs"
success "Created $CONFIG_DIR/logs/"
echo ""
}
# Setup environment file
setup_environment() {
info "Setting up environment file..."
if [[ -f "$ENV_FILE" ]]; then
warn "$ENV_FILE already exists"
read -p "Overwrite? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
info "Keeping existing environment file"
return
fi
cp "$ENV_FILE" "$ENV_FILE.backup.$(date +%Y%m%d%H%M%S)"
success "Backed up existing file"
fi
cp "$SCRIPT_DIR/.env.ourdigital.template" "$ENV_FILE"
chmod 600 "$ENV_FILE"
success "Created $ENV_FILE"
echo ""
}
# Setup credentials from 1Password or manual
setup_credentials() {
info "Setting up credentials..."
if [[ "$HAS_1PASSWORD" == true ]]; then
read -p "Fetch credentials from 1Password? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
fetch_from_1password
return
fi
fi
echo -e "${YELLOW}Manual credential setup required.${NC}"
echo "Edit $ENV_FILE with your API keys:"
echo " - NOTION_API_TOKEN"
echo " - GHOST_BLOG_ADMIN_KEY"
echo " - GHOST_JOURNAL_ADMIN_KEY"
echo " - FIGMA_ACCESS_TOKEN"
echo ""
}
# Fetch credentials from 1Password
fetch_from_1password() {
info "Fetching credentials from 1Password..."
# Check if signed in
if ! op account list &> /dev/null; then
warn "Please sign in to 1Password CLI first"
echo "Run: eval \$(op signin)"
return
fi
# Fetch each credential
local credentials=(
"NOTION_API_TOKEN:OurDigital Notion:api_token"
"GHOST_BLOG_ADMIN_KEY:OurDigital Ghost Blog:api_key"
"GHOST_JOURNAL_ADMIN_KEY:OurDigital Ghost Journal:api_key"
"FIGMA_ACCESS_TOKEN:OurDigital Figma:api_token"
)
for cred in "${credentials[@]}"; do
IFS=':' read -r env_var item_name field <<< "$cred"
if value=$(op item get "$item_name" --fields "$field" 2>/dev/null); then
sed -i '' "s|^$env_var=.*|$env_var=$value|" "$ENV_FILE" 2>/dev/null || \
sed -i "s|^$env_var=.*|$env_var=$value|" "$ENV_FILE"
success "Fetched $env_var"
else
warn "Could not fetch $env_var from 1Password"
fi
done
echo ""
}
# Setup Python virtual environment
setup_python_env() {
info "Setting up Python virtual environment..."
if [[ -d "$VENV_DIR" ]]; then
warn "Virtual environment already exists"
read -p "Recreate? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rm -rf "$VENV_DIR"
else
info "Using existing virtual environment"
return
fi
fi
python3 -m venv "$VENV_DIR"
success "Created virtual environment"
# Activate and install dependencies
source "$VENV_DIR/bin/activate"
pip install --upgrade pip -q
pip install -r "$SCRIPT_DIR/requirements/base.txt" -q
success "Installed base dependencies"
# Install code-specific if requested
read -p "Install Claude Code dependencies? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
pip install -r "$SCRIPT_DIR/requirements/code.txt" -q
success "Installed Code dependencies"
fi
deactivate
echo ""
}
# Copy config file
setup_config() {
info "Setting up configuration..."
if [[ ! -f "$CONFIG_DIR/config.yaml" ]]; then
cp "$SCRIPT_DIR/config/ourdigital.yaml" "$CONFIG_DIR/config.yaml"
success "Created $CONFIG_DIR/config.yaml"
else
info "Config file already exists, skipping"
fi
echo ""
}
# Validate installation
validate_installation() {
info "Validating installation..."
local checks_passed=0
local checks_total=6
# Check directories
[[ -d "$CONFIG_DIR" ]] && ((checks_passed++)) && success "Config directory exists" || warn "Config directory missing"
[[ -d "$CONFIG_DIR/credentials" ]] && ((checks_passed++)) && success "Credentials directory exists" || warn "Credentials directory missing"
# Check files
[[ -f "$ENV_FILE" ]] && ((checks_passed++)) && success "Environment file exists" || warn "Environment file missing"
[[ -f "$CONFIG_DIR/config.yaml" ]] && ((checks_passed++)) && success "Config file exists" || warn "Config file missing"
# Check virtual environment
[[ -d "$VENV_DIR" ]] && ((checks_passed++)) && success "Virtual environment exists" || warn "Virtual environment missing"
# Check skills directory
[[ -d "$SKILLS_DIR/01-ourdigital-brand-guide" ]] && ((checks_passed++)) && success "Skills directory valid" || warn "Skills not found"
echo ""
echo -e "${CYAN}Validation: $checks_passed/$checks_total checks passed${NC}"
echo ""
}
# Show installed skills
show_skills() {
info "Installed OurDigital Skills:"
echo ""
for dir in "$SKILLS_DIR"/0{1,2,3,4,5,6,7,8,9}-ourdigital-* "$SKILLS_DIR"/10-ourdigital-*; do
if [[ -d "$dir" ]]; then
name=$(basename "$dir")
desc=$(grep -m1 "^name:" "$dir/desktop/SKILL.md" 2>/dev/null | cut -d':' -f2 | xargs || echo "")
echo -e " ${GREEN}${NC} $name"
fi
done
echo ""
}
# Print usage instructions
print_usage() {
echo -e "${CYAN}Usage Instructions:${NC}"
echo ""
echo "1. Activate the virtual environment:"
echo " source $VENV_DIR/bin/activate"
echo ""
echo "2. Edit credentials if needed:"
echo " nano $ENV_FILE"
echo ""
echo "3. Use skills with 'our' or 'ourdigital' prefix:"
echo " - our blog [topic]"
echo " - our research [topic]"
echo " - our 견적서"
echo ""
echo "4. Documentation:"
echo " $SKILLS_DIR/OUR_SKILL_PROJECT_PLAN_v1.1.md"
echo ""
}
# Uninstall
uninstall() {
warn "This will remove OurDigital configuration (not skills)."
read -p "Continue? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
info "Cancelled"
exit 0
fi
# Backup before removing
if [[ -f "$ENV_FILE" ]]; then
cp "$ENV_FILE" "$ENV_FILE.uninstall.backup"
rm "$ENV_FILE"
success "Removed $ENV_FILE (backup saved)"
fi
if [[ -d "$VENV_DIR" ]]; then
rm -rf "$VENV_DIR"
success "Removed virtual environment"
fi
info "Config directory preserved at $CONFIG_DIR"
info "To fully remove: rm -rf $CONFIG_DIR"
success "Uninstall complete"
}
# Show help
show_help() {
echo "OurDigital Skills Installer"
echo ""
echo "Usage: ./install.sh [OPTIONS]"
echo ""
echo "Options:"
echo " --help, -h Show this help message"
echo " --update, -u Update existing installation"
echo " --uninstall Remove installation (preserves skills)"
echo " --validate Only run validation checks"
echo " --skip-creds Skip credentials setup"
echo " --skip-venv Skip virtual environment setup"
echo ""
echo "Examples:"
echo " ./install.sh # Full interactive install"
echo " ./install.sh --update # Update existing setup"
echo " ./install.sh --skip-creds # Install without credentials"
echo ""
}
# Main installation flow
main_install() {
print_banner
check_prerequisites
setup_directories
setup_environment
if [[ "$SKIP_CREDS" != true ]]; then
setup_credentials
fi
if [[ "$SKIP_VENV" != true ]]; then
setup_python_env
fi
setup_config
validate_installation
show_skills
print_usage
echo -e "${GREEN}╔═══════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ Installation Complete! ║${NC}"
echo -e "${GREEN}╚═══════════════════════════════════════════════════════════╝${NC}"
}
# Parse arguments
SKIP_CREDS=false
SKIP_VENV=false
while [[ $# -gt 0 ]]; do
case $1 in
--help|-h)
show_help
exit 0
;;
--uninstall)
uninstall
exit 0
;;
--validate)
validate_installation
exit 0
;;
--update|-u)
info "Updating installation..."
setup_python_env
validate_installation
exit 0
;;
--skip-creds)
SKIP_CREDS=true
shift
;;
--skip-venv)
SKIP_VENV=true
shift
;;
*)
error "Unknown option: $1"
show_help
exit 1
;;
esac
done
# Run main install
main_install

View File

@@ -0,0 +1,158 @@
#!/usr/bin/env python3
"""
Export OurDigital Skills for Claude.ai Projects
Generates simplified skill files suitable for uploading to Claude.ai.
Usage:
python export_for_claude_ai.py # Export all skills
python export_for_claude_ai.py --bundle # Generate bundle only
python export_for_claude_ai.py --individual # Generate individual files only
"""
import os
import re
import argparse
from pathlib import Path
from typing import Optional
SCRIPT_DIR = Path(__file__).parent.parent
SKILLS_DIR = SCRIPT_DIR.parent
EXPORT_DIR = SCRIPT_DIR / "claude-ai-export"
INDIVIDUAL_DIR = EXPORT_DIR / "individual"
# (dir, name, desc, triggers)
SKILLS = [
("01-ourdigital-brand-guide", "Brand Guide", "brand standards and style",
'"our brand guide", "our 브랜드 가이드", "our 톤앤매너"'),
("02-ourdigital-blog", "Blog", "Korean blog drafts",
'"our blog", "our 블로그", "our 한국어 포스트"'),
("03-ourdigital-journal", "Journal", "English essays",
'"our journal", "our English essay", "our 영문 에세이"'),
("04-ourdigital-research", "Research", "research prompts",
'"our research", "our 리서치", "our deep research"'),
("05-ourdigital-document", "Document", "presentations",
'"our document", "our 발표자료", "our presentation"'),
("06-ourdigital-designer", "Designer", "image prompts",
'"our design", "our 썸네일", "our image prompt"'),
("07-ourdigital-ad-manager", "Ad Manager", "ad copywriting",
'"our ad copy", "our 광고 카피", "our keyword"'),
("08-ourdigital-trainer", "Trainer", "training materials",
'"our training", "our 워크샵", "our 교육"'),
("09-ourdigital-backoffice", "Backoffice", "business documents",
'"our 견적서", "our proposal", "our quote"'),
("10-ourdigital-skill-creator", "Skill Creator", "creating new skills",
'"our skill create", "our 스킬 만들기"'),
]
def extract_skill_content(skill_dir: str) -> Optional[str]:
"""Extract and simplify content from a skill's SKILL.md."""
desktop_path = SKILLS_DIR / skill_dir / "desktop" / "SKILL.md"
if not desktop_path.exists():
print(f" Warning: {desktop_path} not found")
return None
content = desktop_path.read_text()
# Remove YAML frontmatter
if content.startswith("---"):
parts = content.split("---", 2)
if len(parts) >= 3:
content = parts[2].strip()
# Extract key sections (first 150 lines or so)
lines = content.split("\n")
# Find main heading and take content
simplified = []
in_content = False
line_count = 0
max_lines = 120
for line in lines:
if line.startswith("# "):
in_content = True
if in_content:
simplified.append(line)
line_count += 1
if line_count >= max_lines:
simplified.append("\n[... see full documentation for more ...]")
break
return "\n".join(simplified)
def generate_individual_files():
"""Generate individual skill files for Claude.ai."""
INDIVIDUAL_DIR.mkdir(parents=True, exist_ok=True)
print("Generating individual skill files...")
for skill_dir, name, desc, triggers in SKILLS:
content = extract_skill_content(skill_dir)
if content:
# Create simplified header with YAML frontmatter
num = skill_dir.split("-")[0]
skill_name = name.lower().replace(' ', '-')
filename = f"{num}-{skill_name}.md"
header = f"""---
name: ourdigital-{skill_name}
description: |
{desc.capitalize()}.
Triggers (ourdigital or our prefix):
- {triggers}
---
# OurDigital {name}
**Purpose**: {desc.capitalize()}
**Triggers**: Use "our" or "ourdigital" prefix
---
"""
output_path = INDIVIDUAL_DIR / filename
output_path.write_text(header + content)
print(f" Created: {filename}")
def generate_bundle():
"""Generate combined bundle file."""
print("Generating bundle file...")
# Read existing bundle (already created manually with full content)
bundle_path = EXPORT_DIR / "ourdigital-skills-bundle.md"
if bundle_path.exists():
print(f" Bundle exists: {bundle_path}")
else:
print(f" Warning: Bundle not found at {bundle_path}")
def main():
parser = argparse.ArgumentParser(description="Export skills for Claude.ai")
parser.add_argument("--bundle", action="store_true", help="Generate bundle only")
parser.add_argument("--individual", action="store_true", help="Generate individual files only")
args = parser.parse_args()
print(f"Export directory: {EXPORT_DIR}\n")
if args.bundle:
generate_bundle()
elif args.individual:
generate_individual_files()
else:
generate_bundle()
generate_individual_files()
print("\nDone! Files ready for upload to Claude.ai Projects.")
print(f" Bundle: {EXPORT_DIR / 'ourdigital-skills-bundle.md'}")
print(f" Individual: {INDIVIDUAL_DIR}/")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,284 @@
#!/usr/bin/env python3
"""
OurDigital Skills Installation Validator
Checks that all components are properly installed and configured.
Usage:
python validate_install.py
python validate_install.py --verbose
python validate_install.py --fix # Attempt to fix issues
"""
import os
import sys
import json
import argparse
from pathlib import Path
from typing import List, Tuple, Dict
# Colors for terminal output
class Colors:
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
CYAN = '\033[96m'
BOLD = '\033[1m'
END = '\033[0m'
def ok(msg: str) -> None:
print(f"{Colors.GREEN}[✓]{Colors.END} {msg}")
def warn(msg: str) -> None:
print(f"{Colors.YELLOW}[!]{Colors.END} {msg}")
def fail(msg: str) -> None:
print(f"{Colors.RED}[✗]{Colors.END} {msg}")
def info(msg: str) -> None:
print(f"{Colors.CYAN}[i]{Colors.END} {msg}")
class InstallationValidator:
def __init__(self, verbose: bool = False):
self.verbose = verbose
self.home = Path.home()
self.script_dir = Path(__file__).parent.parent
self.skills_dir = self.script_dir.parent
self.env_file = self.home / ".env.ourdigital"
self.config_dir = self.home / ".ourdigital"
self.venv_dir = self.skills_dir / ".venv-ourdigital"
self.results: List[Tuple[str, bool, str]] = []
def check(self, name: str, condition: bool, fix_hint: str = "") -> bool:
"""Record a check result."""
self.results.append((name, condition, fix_hint))
return condition
def validate_directories(self) -> int:
"""Check required directories exist."""
info("Checking directories...")
passed = 0
checks = [
("Config directory", self.config_dir.exists(),
f"mkdir -p {self.config_dir}"),
("Credentials directory", (self.config_dir / "credentials").exists(),
f"mkdir -p {self.config_dir}/credentials"),
("Logs directory", (self.config_dir / "logs").exists(),
f"mkdir -p {self.config_dir}/logs"),
]
for name, condition, fix in checks:
if self.check(name, condition, fix):
ok(name)
passed += 1
else:
fail(name)
if self.verbose:
print(f" Fix: {fix}")
return passed
def validate_files(self) -> int:
"""Check required files exist."""
info("Checking files...")
passed = 0
checks = [
("Environment file (.env.ourdigital)", self.env_file.exists(),
"cp _ourdigital-shared/.env.ourdigital.template ~/.env.ourdigital"),
("Config file (config.yaml)", (self.config_dir / "config.yaml").exists(),
"cp _ourdigital-shared/config/ourdigital.yaml ~/.ourdigital/config.yaml"),
]
for name, condition, fix in checks:
if self.check(name, condition, fix):
ok(name)
passed += 1
else:
fail(name)
if self.verbose:
print(f" Fix: {fix}")
return passed
def validate_env_variables(self) -> int:
"""Check environment variables are set."""
info("Checking environment variables...")
passed = 0
required_vars = [
"NOTION_API_TOKEN",
"GHOST_BLOG_ADMIN_KEY",
"GHOST_JOURNAL_ADMIN_KEY",
]
optional_vars = [
"FIGMA_ACCESS_TOKEN",
"N8N_API_KEY",
]
if self.env_file.exists():
env_content = self.env_file.read_text()
for var in required_vars:
has_value = f"{var}=" in env_content and \
f"{var}=<" not in env_content and \
f"{var}=$" not in env_content
if self.check(f"Required: {var}", has_value, f"Set {var} in {self.env_file}"):
ok(f"{var}")
passed += 1
else:
fail(f"{var} (required)")
for var in optional_vars:
has_value = f"{var}=" in env_content and \
f"{var}=<" not in env_content
if has_value:
ok(f"{var} (optional)")
passed += 1
else:
warn(f"{var} (optional, not set)")
else:
fail("Environment file not found")
return passed
def validate_python_env(self) -> int:
"""Check Python virtual environment."""
info("Checking Python environment...")
passed = 0
if self.check("Virtual environment", self.venv_dir.exists(),
f"python3 -m venv {self.venv_dir}"):
ok("Virtual environment exists")
passed += 1
# Check for key packages
pip_path = self.venv_dir / "bin" / "pip"
if pip_path.exists():
ok("pip available")
passed += 1
else:
fail("Virtual environment not found")
return passed
def validate_skills(self) -> int:
"""Check skills are properly structured."""
info("Checking skills...")
passed = 0
expected_skills = [
"01-ourdigital-brand-guide",
"02-ourdigital-blog",
"03-ourdigital-journal",
"04-ourdigital-research",
"05-ourdigital-document",
"06-ourdigital-designer",
"07-ourdigital-ad-manager",
"08-ourdigital-trainer",
"09-ourdigital-backoffice",
"10-ourdigital-skill-creator",
]
for skill in expected_skills:
skill_dir = self.skills_dir / skill
has_desktop = (skill_dir / "desktop" / "SKILL.md").exists()
has_code = (skill_dir / "code" / "SKILL.md").exists()
if has_desktop and has_code:
ok(f"{skill}")
passed += 1
elif has_desktop or has_code:
warn(f"{skill} (incomplete)")
else:
fail(f"{skill} (missing)")
return passed
def validate_permissions(self) -> int:
"""Check file permissions are secure."""
info("Checking permissions...")
passed = 0
if self.env_file.exists():
mode = oct(self.env_file.stat().st_mode)[-3:]
if mode in ('600', '400'):
ok(f".env.ourdigital permissions ({mode})")
passed += 1
else:
warn(f".env.ourdigital permissions ({mode}, should be 600)")
creds_dir = self.config_dir / "credentials"
if creds_dir.exists():
mode = oct(creds_dir.stat().st_mode)[-3:]
if mode in ('700', '500'):
ok(f"credentials/ permissions ({mode})")
passed += 1
else:
warn(f"credentials/ permissions ({mode}, should be 700)")
return passed
def run(self) -> Dict[str, int]:
"""Run all validation checks."""
print(f"\n{Colors.CYAN}{Colors.BOLD}OurDigital Skills Installation Validator{Colors.END}\n")
results = {
"directories": self.validate_directories(),
"files": self.validate_files(),
"env_variables": self.validate_env_variables(),
"python_env": self.validate_python_env(),
"skills": self.validate_skills(),
"permissions": self.validate_permissions(),
}
# Summary
total_passed = sum(results.values())
total_checks = len(self.results)
print(f"\n{Colors.CYAN}{'='*50}{Colors.END}")
print(f"{Colors.BOLD}Summary:{Colors.END} {total_passed}/{total_checks} checks passed")
if total_passed == total_checks:
print(f"{Colors.GREEN}All checks passed! Installation is complete.{Colors.END}")
else:
failed = [r for r in self.results if not r[1]]
print(f"{Colors.YELLOW}Some checks failed. Review above for details.{Colors.END}")
if self.verbose:
print(f"\n{Colors.BOLD}Failed checks:{Colors.END}")
for name, _, fix in failed:
print(f" - {name}")
if fix:
print(f" Fix: {fix}")
return results
def main():
parser = argparse.ArgumentParser(description="Validate OurDigital Skills installation")
parser.add_argument("--verbose", "-v", action="store_true",
help="Show detailed output with fix suggestions")
parser.add_argument("--json", action="store_true",
help="Output results as JSON")
args = parser.parse_args()
validator = InstallationValidator(verbose=args.verbose)
results = validator.run()
if args.json:
print(json.dumps(results, indent=2))
# Exit with error if any checks failed
total_passed = sum(results.values())
total_checks = len(validator.results)
sys.exit(0 if total_passed == total_checks else 1)
if __name__ == "__main__":
main()