Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ Claude Code, Codex, OpenCode, OpenClaw/ClawHub 등 각종 코딩 에이전트
| 카카오톡 Mac CLI | macOS에서 카카오톡 대화 조회, 검색, 메시지 전송 | 불필요 | [카카오톡 Mac CLI 가이드](docs/features/kakaotalk-mac.md) |
| 서울 지하철 도착정보 조회 | 서울 지하철 역 기준 실시간 도착 예정 열차 확인 | 불필요 | [서울 지하철 도착정보 가이드](docs/features/seoul-subway-arrival.md) |
| 지하철 분실물 조회 | 지하철 역/물품명 기준 공식 LOST112 분실물 검색 조건과 유실물센터 진입점 안내 | 불필요 | [지하철 분실물 조회 가이드](docs/features/subway-lost-property.md) |
| 긱뉴스 조회 | GeekNews 공개 RSS/Atom 피드 기반 최신 글 목록, 검색, 상세 확인 | 불필요 | [긱뉴스 조회 가이드](docs/features/geeknews-search.md) |
| 한국 날씨 조회 | 기상청 단기예보 기반 한국 날씨 조회 | 불필요 | [한국 날씨 조회 가이드](docs/features/korea-weather.md) |
| 사용자 위치 미세먼지 조회 | 현재 위치 또는 지역 기준 PM10/PM2.5 미세먼지 조회 | 불필요 | [사용자 위치 미세먼지 조회 가이드](docs/features/fine-dust-location.md) |
| 한강 수위 정보 조회 | 한강 관측소 기준 현재 수위·유량·기준수위 확인 | 불필요 | [한강 수위 정보 가이드](docs/features/han-river-water-level.md) |
| 한국 법령 검색 | 한국 법령/조문/판례/유권해석 검색 | 불필요 | [한국 법령 검색 가이드](docs/features/korean-law-search.md) |
| 한국 부동산 실거래가 조회 | 아파트/오피스텔/빌라/단독주택 실거래가·전월세·지역코드 조회 | 불필요 | [한국 부동산 실거래가 조회 가이드](docs/features/real-estate-search.md) |
| 생활쓰레기 배출정보 조회 | 시군구 기준 생활쓰레기·음식물·재활용 배출요일·시간·장소·관리부서 확인 | 불필요 | [생활쓰레기 배출정보 조회 가이드](docs/features/household-waste-info.md) |
| 학교 급식 식단 조회 | 교육청·학교명으로 NEIS 학교 검색·급식 식단 조회 | 불필요 | [학교 급식 식단 조회 가이드](docs/features/k-schoollunch-menu.md) |
| 의약품 안전 체크 | 식약처 e약은요·안전상비의약품 정보를 인터뷰-first 흐름으로 조회 | 필요 | [의약품 안전 체크 가이드](docs/features/mfds-drug-safety.md) |
| 식품 안전 체크 | 식약처 부적합 식품·식품안전나라 회수 정보를 인터뷰-first 흐름으로 조회 | 필요 | [식품 안전 체크 가이드](docs/features/mfds-food-safety.md) |
| 한국 주식 정보 조회 | KRX 상장 종목 검색, 기본정보, 일별 시세 조회 | 불필요 | [한국 주식 정보 조회 가이드](docs/features/korean-stock-search.md) |
Expand Down Expand Up @@ -92,12 +94,14 @@ Claude Code, Codex, OpenCode, OpenClaw/ClawHub 등 각종 코딩 에이전트
- [카카오톡 Mac CLI](docs/features/kakaotalk-mac.md)
- [서울 지하철 도착정보 조회](docs/features/seoul-subway-arrival.md)
- [지하철 분실물 조회 가이드](docs/features/subway-lost-property.md)
- [긱뉴스 조회 가이드](docs/features/geeknews-search.md)
- [한국 날씨 조회 가이드](docs/features/korea-weather.md)
- [사용자 위치 미세먼지 조회](docs/features/fine-dust-location.md)
- [한강 수위 정보 가이드](docs/features/han-river-water-level.md)
- [한국 법령 검색 가이드](docs/features/korean-law-search.md)
- [한국 부동산 실거래가 조회 가이드](docs/features/real-estate-search.md)
- [생활쓰레기 배출정보 조회 가이드](docs/features/household-waste-info.md)
- [학교 급식 식단 조회 가이드](docs/features/k-schoollunch-menu.md)
- [의약품 안전 체크 가이드](docs/features/mfds-drug-safety.md)
- [식품 안전 체크 가이드](docs/features/mfds-food-safety.md)
- [한국 주식 정보 조회 가이드](docs/features/korean-stock-search.md)
Expand Down
216 changes: 216 additions & 0 deletions docs/adding-a-skill.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# 새 스킬 추가 가이드

새 스킬을 k-skill에 추가하는 방법과 스킬이 동작하는 구조를 설명한다.

---

## 스킬이란

스킬은 AI 에이전트(Claude Code 등)가 특정 작업을 수행하는 방법을 정의한 문서+코드 묶음이다. 에이전트는 `SKILL.md`를 읽고 거기 적힌 워크플로우를 따라 실행한다.

스킬에는 네 가지 구현 유형이 있다.

| 유형 | 설명 | 예시 |
|------|------|------|
| **SKILL.md 전용** | 문서만으로 동작 (에이전트가 bash/python 직접 실행) | `kakaotalk-mac`, `srt-booking` |
| **npm 패키지** | `packages/` 아래 Node.js 라이브러리로 구현 | `k-lotto`, `blue-ribbon-nearby` |
| **프록시 경유** | `k-skill-proxy`가 upstream API 키를 보관하고 HTTP로 중계 | `seoul-subway-arrival`, `fine-dust-location` |
| **Python 스크립트** | `scripts/`의 Python 파일 직접 실행 | `korean-spell-check`, `sillok-search` |

---

## 스킬의 구조

모든 스킬은 **저장소 루트에 디렉토리 하나**를 갖는다.

```
k-skill/
├── my-new-skill/ ← 스킬 디렉토리 (이름 = 스킬 이름)
│ ├── SKILL.md ← 필수. 에이전트가 읽는 핵심 파일
│ └── (지원 파일들) ← 선택. 스크립트, 데이터 등
├── packages/ ← npm 패키지 유형일 때만
│ └── my-new-skill/
│ ├── package.json
│ ├── src/
│ └── test/
└── scripts/ ← Python 스크립트 유형일 때만
└── my_new_skill.py
```

---

## SKILL.md 형식

`SKILL.md`는 YAML frontmatter + Markdown 본문으로 구성된다.

```markdown
---
name: my-new-skill
description: 한 문장으로 이 스킬이 무엇을 하는지 설명한다. 에이전트 UI에 표시된다.
license: MIT
metadata:
category: utility
locale: ko-KR
phase: v1
---

# My New Skill

## What this skill does

이 스킬이 무엇을 하는지 한두 문단으로 설명한다.

## When to use

- "사용자가 이런 말을 할 때"
- "또는 이런 상황일 때"

## Prerequisites

- Node.js 18+ (필요하면)
- 패키지 설치 명령

## Workflow

### 1. 첫 번째 단계

설명과 실행할 코드를 적는다.

```bash
# 실행할 명령어
```

### 2. 두 번째 단계

...

## Done when

- 이런 조건이 만족되면 완료다

## Failure modes

- 예상 가능한 실패 상황

## Notes

- 특이사항, 보안 정책 등
```

### frontmatter 필드

| 필드 | 필수 | 설명 |
|------|------|------|
| `name` | ✅ | **디렉토리 이름과 정확히 일치**해야 한다 |
| `description` | ✅ | 에이전트 UI 표시용 한 줄 설명 |
| `license` | ✅ | 항상 `MIT` |
| `metadata.category` | ✅ | `utility` / `transit` / `travel` / `messaging` / `legal` / `setup` 등 |
| `metadata.locale` | ✅ | `ko-KR` |
| `metadata.phase` | ✅ | `v1` (안정) / `v1.5` (기능 추가 중) |

---

## 유형별 구현 방법

### A. SKILL.md 전용 스킬

에이전트가 `SKILL.md` 안의 bash/python 코드를 직접 실행한다.

1. 디렉토리 생성: `mkdir my-new-skill`
2. `my-new-skill/SKILL.md` 작성
3. Workflow 섹션에 에이전트가 따를 단계별 명령어를 적는다

외부 라이브러리나 서버 없이 동작해야 한다.

### B. npm 패키지 스킬

`packages/my-new-skill/`에 Node.js 구현체를 만들고, 루트 디렉토리 `my-new-skill/SKILL.md`에서 `require('my-new-skill')`로 호출한다.

```
packages/my-new-skill/
├── package.json # name, version, main, exports 필수
├── README.md
├── src/
│ └── index.js
└── test/
└── index.test.js
```

`package.json`에 `"name": "my-new-skill"` 설정 후 루트 `package.json`의 `workspaces`에 등록한다.

npm에 배포하려면 `.changeset/` 파일을 추가한다 (`docs/releasing.md` 참고).

### C. 프록시 경유 스킬

upstream API 키를 사용자에게 노출하지 않으려면 `k-skill-proxy`를 경유한다.

1. `packages/k-skill-proxy/src/server.js`에 새 route 추가
2. `SKILL.md` Workflow에 `curl $KSKILL_PROXY_BASE_URL/v1/...` 형태로 호출 작성
3. upstream API 키는 서버의 `~/.config/k-skill/secrets.env`에만 보관

프록시 서버는 main 브랜치에 merge되어야 프로덕션에 반영된다 (`CLAUDE.md` 참고).

### D. Python 스크립트 스킬

`scripts/my_skill.py`를 만들고 `SKILL.md`에서 `python3 scripts/my_skill.py`로 호출한다.

---

## 스킬 등록 & 검증

스킬은 **별도 레지스트리 없이 디렉토리 스캔으로 자동 발견**된다.

추가 후 검증:

```bash
npm run ci
```

이 명령은 `scripts/validate-skills.sh`를 실행해 다음을 확인한다.

- 루트 하위 모든 디렉토리에 `SKILL.md`가 있는지
- frontmatter가 `---`로 시작하는지
- `name` 필드가 있는지
- `description` 필드가 있는지
- `name` 필드 값이 디렉토리 이름과 일치하는지

---

## 시크릿이 필요한 스킬

인증이 필요한 스킬은 아래 우선순위로 credential을 확보한다.

1. 이미 환경변수에 있으면 → 그대로 사용
2. 에이전트 vault(1Password, Bitwarden, macOS Keychain) → 주입
3. `~/.config/k-skill/secrets.env` → 파일에서 읽기
4. 아무것도 없으면 → 사용자에게 물어보고 3번에 저장

시크릿 변수 이름 규칙: `KSKILL_<서비스명>_<항목>` (예: `KSKILL_SRT_ID`)

절대 하지 말 것:
- 시크릿을 저장소에 커밋
- 프록시 upstream 키를 클라이언트에 노출
- 사용자 확인 없이 side-effect가 있는 작업 실행

---

## 체크리스트

새 스킬을 PR 올리기 전에 확인한다.

- [ ] `my-new-skill/SKILL.md` 작성 완료
- [ ] frontmatter `name`이 디렉토리 이름과 일치
- [ ] `npm run ci` 통과 (`./scripts/validate-skills.sh` 포함)
- [ ] npm 패키지라면 `packages/`에 구현체와 테스트 추가
- [ ] npm 패키지라면 `.changeset/*.md` 파일 추가 (반드시 **기능 PR에서**, Version Packages PR에서 추가하지 말 것)
- [ ] 프록시 경유라면 `k-skill-proxy/src/server.js`에 route 추가하고 main에 merge
- [ ] 시크릿이 있다면 `KSKILL_` 접두사 규칙 준수 및 `docs/setup.md` 업데이트
- [ ] `docs/features/my-new-skill.md` 작성 (선택, 상세 가이드)

---

## 관련 문서

- [공통 설정 가이드](setup.md) — 시크릿 설정 방법
- [릴리스와 자동 배포](releasing.md) — npm 패키지 배포 흐름
- [보안/시크릿 정책](security-and-secrets.md) — 인증 정보 취급 원칙
68 changes: 68 additions & 0 deletions docs/features/geeknews-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# 긱뉴스 조회 가이드

## 이 기능으로 할 수 있는 일

- GeekNews 공개 RSS/Atom 피드에서 최신 글 목록 조회
- 제목/요약/작성자 기준 키워드 검색
- 특정 항목의 RSS 기반 요약/링크/작성자/게시 시각 확인

## 먼저 필요한 것

- [공통 설정 가이드](../setup.md) 완료
- `python3` 사용 가능 환경
- 인터넷 연결

## v1 범위

이 기능은 **RSS-first / 읽기 전용** 범위로 제공된다.

- 공개 피드(`https://feeds.feedburner.com/geeknews-feed`)만 사용한다.
- 최신 글/검색/상세 조회까지만 다룬다.
- 댓글, 투표, 로그인, 개인화 상태는 다루지 않는다.

## 기본 흐름

1. 최신 글을 훑을 때는 목록 조회부터 실행한다.
2. 원하는 주제가 있으면 제목/요약/작성자 기준 검색으로 좁힌다.
3. 특정 글을 확인할 때는 링크/id/토픽 번호 일부로 상세 조회한다.

## 예시

최신 글 목록:

```bash
python3 scripts/geeknews_search.py list --limit 5
```

검색:

```bash
python3 scripts/geeknews_search.py search --query Claude --limit 5
```

상세:

```bash
python3 scripts/geeknews_search.py detail --id 28439
```

오프라인 fixture 또는 저장된 feed로 검증할 때:

```bash
python3 scripts/geeknews_search.py list \
--feed-file scripts/fixtures/geeknews-feed.xml \
--limit 3
```

## 출력에서 확인할 점

- `source.feed_url` 이 GeekNews RSS feed를 가리키는지
- `items[].title`, `items[].link`, `items[].author_name`, `items[].summary` 가 함께 내려오는지
- 상세 조회에서 `item.content_html` 과 `item.summary` 가 모두 포함되는지
- 검색 결과가 제목/요약/작성자 기준으로 보수적으로 매칭되는지

## 주의할 점

- RSS 피드 기반이라 원문 전체/댓글/메타데이터는 제한적일 수 있다.
- FeedBurner 응답이 느리거나 실패하면 재시도하거나 직접 링크를 여는 fallback이 필요하다.
- 상세 조회는 feed에 포함된 `content` 범위까지만 보장한다.
6 changes: 3 additions & 3 deletions docs/features/household-waste-info.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@

```bash
curl -fsS --get 'https://k-skill-proxy.nomadamas.org/v1/household-waste/info' \
--data-urlencode 'cond[SGG_NM::LIKE]=강남구' \
--data-urlencode 'pageNo=1' \
--data-urlencode 'numOfRows=20' \
--data-urlencode 'cond[SGG_NM::LIKE]=강남구'
--data-urlencode 'numOfRows=100'
```

현재 proxy가 패스스루하는 파라미터는 `pageNo`, `numOfRows`, `cond[SGG_NM::LIKE]` 뿐이며, `returnType`은 항상 `json`으로 강제된다. 원본 API의 `cond[DAT_CRTR_YMD::*]`, `cond[DAT_UPDT_PNT::*]` 같은 부가 필터는 현재 지원하지 않는다 — 일반 사용자 질의("강남구 쓰레기 배출 요일")는 시군구 검색만으로 충분하기 때문이다.
클라이언트는 **`cond[SGG_NM::LIKE]`** 와 **`pageNo` / `numOfRows`**(또는 `page_no` / `num_of_rows`)를 **함께** 넘긴다. `pageNo` / `numOfRows` 값은 **반드시 `1` / `100`** 이어야 하고, 그 외 값이나 숫자만으로 표현되지 않는 문자열이면 proxy가 **`400`** 을 반환하고 upstream을 호출하지 않는다. upstream에는 항상 `pageNo=1`, `numOfRows=100`만 전달된다. `returnType`은 항상 `json`으로 강제된다. 원본 API의 `cond[DAT_CRTR_YMD::*]`, `cond[DAT_UPDT_PNT::*]` 같은 부가 필터는 현재 지원하지 않는다 — 일반 사용자 질의("강남구 쓰레기 배출 요일")는 시군구 검색만으로 충분하기 때문이다.

## 조회 흐름 권장 순서

Expand Down
61 changes: 61 additions & 0 deletions docs/features/k-schoollunch-menu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# 학교 급식 식단 조회 가이드

## 이 기능으로 할 수 있는 일

- 시도교육청 이름(자연어) + 학교 이름으로 학교 코드 조회
- 특정 일자 급식 식단(조·중·석) 조회
- 나이스(NEIS) Open API 인증키는 프록시 서버(`KEDU_INFO_KEY`)에서만 관리

## 가장 중요한 규칙

1. 클라이언트는 **`KEDU_INFO_KEY`를 들고 있지 않는다.** `k-skill-proxy`만 upstream `KEY`를 붙인다.
2. 학교 식별은 **하드코딩 금지**. 반드시 **`/v1/neis/school-search` → `/v1/neis/school-meal`** 순서로 조합한다.

## 먼저 필요한 것

- 인터넷 연결
- 프록시 base URL (기본: `https://k-skill-proxy.nomadamas.org`)

## 기본 조회 흐름

### 1) 학교 검색

```bash
curl -fsS --get 'https://k-skill-proxy.nomadamas.org/v1/neis/school-search' \
--data-urlencode 'educationOffice=서울특별시교육청' \
--data-urlencode 'schoolName=미래초등학교'
```

응답에 `resolved_education_office`와 `schoolInfo` 블록이 붙는다. `row`에서 `ATPT_OFCDC_SC_CODE`, `SD_SCHUL_CODE`, `SCHUL_NM`, 주소 필드를 확인한다.

### 2) 급식 조회

```bash
curl -fsS --get 'https://k-skill-proxy.nomadamas.org/v1/neis/school-meal' \
--data-urlencode 'educationOfficeCode=B10' \
--data-urlencode 'schoolCode=7010123' \
--data-urlencode 'mealDate=20260410'
```

`educationOfficeCode` / `schoolCode`는 1단계 검색 결과에서 가져온다.

선택: `mealKindCode=1` (조식), `2` (중식), `3` (석식).

## 파라미터 요약

| 단계 | 주요 쿼리 |
| --- | --- |
| school-search | `educationOffice`, `schoolName` (별칭: `office`, `school`, …) |
| school-meal | `educationOfficeCode`, `schoolCode`, `mealDate` (`YYYYMMDD` 또는 `YYYY-MM-DD`) |

## 자주 보는 필드 (급식)

- `MLSV_YMD`: 급식일
- `MMEAL_SC_NM` / `MMEAL_SC_CODE`: 끼니 구분
- `DDISH_NM`: 메뉴(HTML `<br/>` 구분이 많음)
- `CAL_INFO`, `NTR_INFO`: 칼로리·영양 정보(있는 경우)

## 참고 링크

- 나이스 교육정보 개방 포털: `https://open.neis.go.kr/`
- 프록시 구현·엔드포인트 목록: [k-skill 프록시 서버 가이드](k-skill-proxy.md)
Loading
Loading