- name
- nopal
- description
- Codex용 Google Workspace 오케스트레이션 스킬. "nopal", "/nopal", "gws", "gmail", "calendar", "drive", "sheets", "docs", "slides", "chat", "tasks", "meet", "메일 보내줘", "일정 확인", "회의 준비", "스프레드시트 만들어", "문서/시트/드라이브 작업", "send email", "check calendar", "prepare meeting", "create spreadsheet" 같은 요청에 사용됩니다.
# nopal for Codex
Read these first:
- `$PLUGIN_ROOT/skills/nopal/references/gws-shared.md`
Load as needed (필요한 서비스만):
- `$PLUGIN_ROOT/skills/nopal/references/gws-gmail.md`
- `$PLUGIN_ROOT/skills/nopal/references/gws-calendar.md`
- `$PLUGIN_ROOT/skills/nopal/references/gws-drive.md`
- `$PLUGIN_ROOT/skills/nopal/references/gws-docs.md`
- `$PLUGIN_ROOT/skills/nopal/references/gws-sheets.md`
- `$PLUGIN_ROOT/skills/nopal/references/gws-slides.md`
- `$PLUGIN_ROOT/skills/nopal/references/gws-chat.md`
- `$PLUGIN_ROOT/skills/nopal/references/gws-tasks.md`
- `$PLUGIN_ROOT/skills/nopal/references/gws-meet.md`
- `$PLUGIN_ROOT/skills/nopal/references/recipes.md`
- `$PLUGIN_ROOT/skills/nopal/references/workflows.md`
Use this skill when the user wants Google Workspace work orchestrated from natural language.
Questioning policy: `$PLUGIN_ROOT/shared/questioning-policy.md` §A + §1 + §2c.
- Codex CLI has no structured question card UI. When a decision is needed, output numbered-options-in-chat per §A.
- Infer what you can; ask only what is genuinely unknown (§1). If the request is already concrete, skip clarification and proceed (§2c).
## 규칙
- 모든 질문은 §A 번호 블록으로 채팅에 출력한다. 존재하지 않는 카드 UI를 가정하지 않는다.
- gws CLI를 통해서만 Google Workspace와 상호작용한다. 직접 HTTP 호출 금지.
- 읽기 전용 단순 조회(일정 확인, 메일 확인 등)는 확인 없이 바로 실행한다. 쓰기/변경 작업만 사용자 확인을 받는다.
---
## 지원 서비스 (9개)
| 서비스 | 헬퍼 명령어 | 주요 용도 |
|--------|------------|----------|
| Gmail | `+send`, `+triage`, `+watch` | 이메일 보내기/읽기/관리 |
| Calendar | `+insert`, `+agenda` | 일정/이벤트 관리 |
| Drive | `+upload` | 파일/폴더/공유 관리 |
| Sheets | `+read`, `+append` | 스프레드시트 읽기/쓰기 |
| Docs | `+write` | 문서 읽기/쓰기 |
| Slides | (직접 API) | 프레젠테이션 생성/편집 |
| Chat | `+send` | 채팅 스페이스/메시지 |
| Tasks | (직접 API) | 할일 목록/태스크 관리 |
| Meet | (직접 API) | 회의 링크 생성/참가자/녹화/스크립트 |
---
## Workflow
### Step 0: 환경 확인 (자동)
gws CLI 설치 여부와 인증 상태를 자동으로 확인한다. 사용자에게 묻지 않는다.
**0-1. gws CLI 설치 확인**
`command -v gws` 실행.
- 미설치: `npm install -g @googleworkspace/cli` 자동 설치. 완료 후 `gws --version` 확인.
- 설치 실패 시: `$PLUGIN_ROOT/skills/nopal-setup/SKILL.md` 내용을 기반으로 수동 안내 후 중단.
- 설치된 경우: 0-2로 진행.
**0-2. 인증 상태 확인**
`gws auth status` 실행.
- 인증 안 된 경우: `gws auth setup`은 인터랙티브 TUI이므로 셸 도구로 실행할 수 없다. `$PLUGIN_ROOT/skills/nopal-setup/SKILL.md` 기반으로 설정 안내(5단계 setup → login → credentials export)를 채팅에 출력하고 중단. 사용자가 설정 완료 후 재실행하면 0-2부터 재확인 후 Step 1로 진행.
- 인증 완료: Step 1로 진행.
---
### Step 1: 요청 파싱
**요청이 주어진 경우** — 사용자의 자연어 요청을 그대로 오케스트레이션 입력으로 사용하고 Step 2로 진행.
**요청이 없는 경우** — §A 번호 블록으로 채팅에 출력하고 답변을 기다린다:
```
무엇을 도와드릴까요?
1. 자유 요청 (추천) — 하고 싶은 작업을 자유롭게 말씀해주세요. 예: '내일 오후 2시에 팀 회의 잡고 참석자에게 메일 보내줘'
2. 오늘 일정 확인 — Google Calendar 오늘 일정 조회
3. 이메일 확인 — Gmail 최근 읽지 않은 이메일 확인
4. 사용법 안내 — Nopal이 할 수 있는 일과 예시
```
- 1 또는 자유 입력 → 입력 텍스트를 요청으로 사용, Step 2로 진행
- 2 → "오늘 일정을 확인해줘"로 설정, Step 2로 진행
- 3 → "읽지 않은 이메일을 확인해줘"로 설정, Step 2로 진행
- 4 → 아래 안내를 채팅에 출력하고 종료:
```
Nopal은 Google Workspace 9개 서비스를 자연어로 자동 조합합니다.
지원 서비스: Gmail, Calendar, Drive, Sheets, Docs, Slides, Chat, Tasks, Meet
사용 예시:
내일 오전 10시에 팀 회의 잡아줘
지난주 매출 스프레드시트에서 합계 구해줘
회의록을 Google Docs로 만들고 참석자에게 공유해줘
읽지 않은 이메일 중 중요한 것만 요약해줘
여러 서비스를 조합하는 복잡한 요청도 가능합니다:
내일 회의 참석자 목록을 스프레드시트로 만들고 각자에게 메일로 안건 보내줘
```
---
### Step 2: 의도 파악
사용자의 자연어 요청을 분석하여 다음을 결정한다:
**2-1. 필요한 서비스 식별**
요청에서 키워드와 의도를 추출하여 9개 서비스 중 어떤 것이 필요한지 판별한다.
| 키워드/의도 | 매핑 서비스 |
|------------|-----------|
| 메일, 이메일, 보내, 수신, 답장 | Gmail |
| 일정, 회의, 미팅, 약속, 캘린더, 스케줄 | Calendar |
| 파일, 폴더, 업로드, 다운로드, 공유, 드라이브 | Drive |
| 스프레드시트, 엑셀, 표, 데이터, 시트, 합계, 매출 | Sheets |
| 문서, 글, 작성, 편집, 보고서, 회의록 | Docs |
| 발표, 슬라이드, 프레젠테이션, PPT | Slides |
| 채팅, 메시지, 알림 | Chat |
| 할일, 태스크, 체크리스트, 투두 | Tasks |
| 화상회의, 미트, 회의 링크, 녹화, 참가자, 스크립트 | Meet |
하나의 요청에 여러 서비스가 관여할 수 있다.
예: "회의 참석자에게 메일 보내줘" → Calendar + Gmail
**2-2. 실행 유형 판별**
| 유형 | 설명 | 예시 |
|------|------|------|
| 단순 조회 | 정보만 읽기 | "오늘 일정 알려줘" |
| 단순 실행 | 한 서비스 동작 | "메일 보내줘" |
| 복합 조합 | 여러 서비스 체이닝 | "회의록 작성 후 참석자에게 공유" |
---
### Step 3: 인터뷰 (부족한 정보 수집)
**원칙: 질문은 최소화한다. 필요한 것만 묻는다.**
**3-1. 정보 갭 분석 (내부 처리)**
요청 실행에 필요한 파라미터를 나열하고, 이미 주어진 것과 부족한 것을 구분한다.
예시 — "내일 오후 2시에 팀 회의 잡아줘":
- 날짜: 내일 (주어짐)
- 시간: 오후 2시 (주어짐)
- 제목: 팀 회의 (주어짐)
- 참석자: ? (부족)
- 시간 길이: ? (부족, 기본값 1시간 사용 가능)
- 장소/링크: ? (부족)
**3-2. 기존 데이터 조회 후 옵션 제시**
가능하면 Google Workspace에서 데이터를 먼저 조회하여 선택지에 반영한다.
예시 — "어떤 회의를 준비할까요?" 대신:
1. `gws calendar +agenda --days 3 --format json` 실행
2. 결과에서 회의 목록 추출
3. §A 번호 블록으로 회의 목록을 선택지로 제시
```
어떤 회의를 준비할까요?
1. 내일 10:00 — 주간 스탠드업 (참석자 5명, Google Meet)
2. 내일 14:00 — 프로젝트 리뷰 (참석자 3명, 회의실 B)
3. 모레 09:00 — 전체 회의 (참석자 12명, 대회의실)
4. 직접 입력해주세요
```
**3-3. 질문 방식 (§A 번호 블록)**
부족한 파라미터가 있을 때만 질문한다. 질문은 `$PLUGIN_ROOT/shared/questioning-policy.md` §A의 번호형 선택지 블록을 채팅에 출력하고 사용자의 다음 답변을 읽는다.
규칙:
- 존재하지 않는 객관식 카드 UI를 가정하지 않는다. 반드시 §A 번호 블록을 채팅에 출력한다.
- 질문은 한 번에 묶어서 한다 (라운드트립 최소화).
- 기본값으로 해결 가능한 파라미터는 질문하지 않고 기본값을 사용한다.
- 회의 시간: 기본 1시간
- 이메일 형식: 기본 일반 텍스트
- 파일 공유 권한: 기본 "보기 가능"
- 모호한 요청의 경우에만 명확화 질문을 한다.
**인터뷰 패턴 예시:**
```
요청: "회의 준비해줘"
→ [Calendar 조회 후] 번호 블록으로 회의 목록 제시
→ "자료도 공유할까요? 1. 네 2. 아니오"
→ "참석자에게 메일도 보낼까요? 1. 네 2. 아니오"
요청: "보고서 보내줘"
→ [Drive 조회 후] 번호 블록으로 최근 파일 목록 제시
→ "누구에게 보낼까요? (이메일 주소를 적어주세요)"
요청: "이번 주 할일 정리해줘"
→ [Tasks 조회 후] 바로 정리 (추가 질문 불필요)
```
---
### Step 4: 계획 수립
**4-1. 레퍼런스 로딩**
필요한 서비스의 reference 파일만 선택적으로 읽는다.
```
$PLUGIN_ROOT/skills/nopal/references/gws-shared.md (항상 읽기)
$PLUGIN_ROOT/skills/nopal/references/gws-{서비스명}.md (필요한 서비스만)
```
예: Gmail + Calendar 조합이면:
```
$PLUGIN_ROOT/skills/nopal/references/gws-shared.md
$PLUGIN_ROOT/skills/nopal/references/gws-gmail.md
$PLUGIN_ROOT/skills/nopal/references/gws-calendar.md
```
reference 파일이 없으면 이 SKILL.md의 명령어 가이드와 헬퍼 목록을 기반으로 동작한다.
**4-2. 프리셋 패턴 확인**
references/ 폴더에 `workflows.md`, `recipes.md`가 있으면 참조하여 검증된 패턴을 우선 사용한다.
없어도 동적으로 새 조합을 생성할 수 있다. 프리셋에 없다고 거부하지 않는다.
**4-3. ExecutionPlan 동적 생성**
실행할 gws 명령어를 순서대로 나열한다. 각 단계는 다음 정보를 포함:
| 필드 | 설명 |
|------|------|
| order | 실행 순서 (1, 2, 3, ...) |
| service | 사용하는 서비스 (Gmail, Calendar, ...) |
| command | 실제 gws 명령어 |
| depends_on | 이전 단계의 결과가 필요한 경우 해당 order 번호 |
| description | 이 단계가 하는 일 (한글, 사람이 읽기 쉽게) |
예시 ExecutionPlan:
```
| # | 서비스 | 작업 | 의존 |
|---|--------|------|------|
| 1 | Calendar | 내일 일정 조회 | - |
| 2 | Docs | 회의록 문서 생성 | - |
| 3 | Drive | 회의록 참석자에게 공유 | 1, 2 |
| 4 | Gmail | 참석자에게 회의록 링크 메일 발송 | 1, 2, 3 |
```
**4-4. 사용자 확인 (조건부)**
**읽기 전용 단순 조회는 확인 없이 바로 실행한다.**
| 실행 유형 | 확인 | 이유 |
|-----------|------|------|
| 단순 조회 (read-only) | **생략 → 바로 Step 5** | 부작용 없음. 속도 우선 |
| 단순 실행 (write 1개) | 확인 필요 | 데이터 변경 |
| 복합 조합 (2+ 서비스) | 확인 필요 | 여러 서비스 변경 |
**단순 조회 판별 기준:**
- 서비스 1개만 사용
- 명령어가 `list`, `get`, `+triage`, `+agenda` 등 읽기 전용
- `create`, `send`, `insert`, `update`, `delete`, `trash`, `modify`, `patch` 등 쓰기 동작이 없음
단순 조회가 아닌 경우, 계획을 마크다운 테이블로 보여주고 확인을 받는다.
§A 번호 블록으로 확인을 받는다:
```
이렇게 실행할까요?
[계획 테이블]
1. 네, 실행해주세요 (추천) — 위 계획대로 순서대로 실행합니다.
2. 수정할 부분이 있어요 — 변경하고 싶은 단계를 알려주세요.
3. 취소 — 실행하지 않고 종료합니다.
```
- 1 → Step 5로 진행
- 2 → 사용자 피드백 반영 후 계획 재수립
- 3 → 종료
---
### Step 5: 실행
사용자가 확인한 ExecutionPlan을 순서대로 셸에서 실행한다.
**5-1. 명령어 실행 규칙**
| 규칙 | 설명 |
|------|------|
| 헬퍼 우선 | 헬퍼 명령어(`+send`, `+agenda` 등)가 있는 서비스는 헬퍼를 우선 사용 |
| JSON 출력 | 모든 명령어에 `--format json` 플래그 사용 |
| 결과 파싱 | 각 단계 실행 후 JSON 결과에서 다음 단계에 필요한 ID/값 추출 |
| 에러 격리 | 한 단계가 실패해도 나머지 단계는 계속 진행 |
**5-2. 서비스별 명령어 가이드**
#### Gmail
**이메일 발송 — 한글 인코딩 필수 규칙:**
`gws gmail +send`는 한글 제목을 RFC 2047 인코딩하지 않아 수신 시 깨진다.
**한글이 포함된 메일은 반드시 아래 raw API 방식을 사용한다.**
```bash
# 이메일 보내기 (한글 지원 — raw API)
# 1. RFC 2822 메시지를 만들어 base64url로 인코딩
RAW=$(node -e "
const to='user@example.com';
const subject='한글 제목';
const body='한글 본문 내용';
const mime=[
'MIME-Version: 1.0',
'Content-Type: text/plain; charset=utf-8',
'Content-Transfer-Encoding: base64',
'To: '+to,
'Subject: =?UTF-8?B?'+Buffer.from(subject).toString('base64')+'?=',
'',
Buffer.from(body).toString('base64')
].join('\r\n');
process.stdout.write(Buffer.from(mime).toString('base64url'));
")
gws gmail users messages send --params '{"userId":"me"}' --json "{\"raw\":\"$RAW\"}"
# CC/BCC 포함 시 mime 배열에 추가:
# 'Cc: cc@example.com',
# 'Bcc: bcc@example.com',
# 이메일 목록 조회 (헬퍼 — 추천)
# "안 읽은 메일" → 기본 쿼리(is:unread) 사용
gws gmail +triage --format json
# "최근 메일", "지금 온 메일" → 읽음 상관없이 최근 메일 전체
gws gmail +triage --max 10 --query 'newer_than:1d' --format json
# 특정 조건 검색
gws gmail +triage --max 10 --query 'from:boss' --format json
# 주의: "메일 확인해줘", "지금 온 메일" 등 일반적 요청은 is:unread가 아닌
# newer_than:1d 또는 조건 없이 최근 메일을 보여준다. "안 읽은 메일"이라고
# 명시한 경우에만 is:unread를 사용한다.
# 이메일 목록 조회 (API — 세밀한 검색 시)
# 주의: 반드시 "users messages"로 호출. "messages"만 쓰면 에러남
gws gmail users messages list --params '{"userId":"me","maxResults":10}' --format json
# 이메일 상세 읽기
gws gmail users messages get --params '{"userId":"me","id":"MESSAGE_ID"}' --format json
# 이메일 휴지통 이동 (gws 0.6.1+ 에서 411 버그 수정됨)
gws gmail users messages trash --params '{"userId":"me","id":"MESSAGE_ID"}'
```
#### Calendar
```bash
# 일정 조회 (헬퍼)
gws calendar +agenda --days 7 --format json
# 일정 생성 (헬퍼)
# --summary (NOT --title), --start, --end 필수. --location, --description, --attendee 선택
gws calendar +insert --summary "회의 제목" --start "2026-03-06T14:00:00+09:00" --end "2026-03-06T15:00:00+09:00"
عرض على GitHub