korean-transit-route

$npx mdskill add NomaDamas/k-skill/korean-transit-route

Provides Korean public transit directions using subway, bus, and walking routes.

  • Solves the problem of finding door-to-door transit routes in Korea.
  • Uses ODsay LIVE API for routing and Kakao geocoding for address lookup.
  • Analyzes user input to extract origin and destination, then computes optimal transit paths.
  • Returns detailed transit steps, transfers, and estimated travel times.

SKILL.md

.github/skills/korean-transit-routeView on GitHub ↗
---
name: korean-transit-route
description: Korean door-to-door public transit routing (subway + bus + walking) via ODsay LIVE API with Kakao geocoding for address-to-address queries. Use when the user asks for 지하철/버스/대중교통 길찾기, 환승 경로, 소요시간, or transit directions between two places in Korea.
license: MIT
metadata:
  category: transit
  locale: ko-KR
  phase: v1
---

# korean-transit-route

한국 대중교통(지하철+버스+도보) 도어투도어 길찾기 스킬. ODsay LIVE API + Kakao Local geocoding.

## When to use

- "강남에서 잠실 지하철로 어떻게 가?"
- "서울역 → 인천공항 대중교통 경로"
- "환승 가장 적은 경로", "최소 시간 경로"

## Credentials

- 환경변수 `ODSAY_API_KEY` 가 있으면 사용. 없으면 `~/.config/k-skill/secrets.env` 에서 로드.
- ODsay Server 키는 호출 IP 화이트리스트 등록 필수. 발급은 https://lab.odsay.com
- Kakao Local geocoding은 기본 hosted `k-skill-proxy` 경유로 호출하므로 사용자 쪽 `KAKAO_REST_API_KEY` 는 불필요하다. self-host proxy 운영자만 `KAKAO_REST_API_KEY` 를 서버에 설정한다.

## Inputs

자연어 입력에서 출발/도착을 추출. 좌표가 없으면 **반드시 geocoding 먼저** (ODsay는 좌표만 받음).

### Geocoding (필수 선행 단계)

기본 hosted proxy를 사용한다. Proxy가 Kakao Local REST API 키를 서버에서만 주입하고, caller `apiKey` 는 무시한다.

1. `https://k-skill-proxy.nomadamas.org/v1/kakao-local/geocode?q=<주소/장소명>`
2. proxy 내부 fallback: Kakao Local `address.json` → 결과 없으면 `keyword.json`

응답 `documents[0].x`(경도), `.y`(위도) 사용.

```python
import os, urllib.parse, urllib.request, json
PROXY=os.environ.get('KSKILL_PROXY_BASE_URL','https://k-skill-proxy.nomadamas.org').rstrip('/')
def geocode(q):
    url=PROXY+'/v1/kakao-local/geocode?q='+urllib.parse.quote(q)
    with urllib.request.urlopen(url,timeout=10) as resp:
        d=json.loads(resp.read())
    if d.get('documents'):
        doc=d['documents'][0]
        return float(doc['x']), float(doc['y']), doc.get('place_name') or doc.get('address_name')
    return None
```

지하철역명만 정확히 알 때는 ODsay `searchStation` 도 OK 하지만, 도어투도어 결과를 원하면 **실제 출발지/도착지 좌표**를 써야 첫/끝 도보 구간이 계산됨.

## Core call

```bash
set -a; . ~/.config/k-skill/secrets.env; set +a
KEY=$(python3 -c "import os,urllib.parse;print(urllib.parse.quote(os.environ['ODSAY_API_KEY'],safe=''))")
curl -s "https://api.odsay.com/v1/api/searchPubTransPathT?apiKey=${KEY}&SX=${SX}&SY=${SY}&EX=${EX}&EY=${EY}&OPT=0&SearchPathType=${TYPE}"
```

Parameters:
- `SX,SY` 출발 경도/위도, `EX,EY` 도착 경도/위도 (WGS84)
- `OPT`: `0` 추천순(기본), `4` 최소시간, `5` 최소환승
- `SearchPathType`: `0` 지하철+버스, `1` 지하철만, `2` 버스만

## Response shape

`result.path[]` 배열, 각 path:
- `pathType`: 1=지하철, 2=버스, 3=지하철+버스
- `info.totalTime`(분), `info.payment`(원), `info.subwayTransitCount`, `info.busTransitCount`, `info.totalWalk`(m), `info.firstStartStation`, `info.lastEndStation`
- `subPath[]`: 구간별. `trafficType` 1=지하철 2=버스 3=도보. 지하철이면 `lane[0].name`, `startName`, `endName`, `passStopList.stations[]`(경유역)

## Recommended output (door-to-door)

`subPath` 의 각 구간을 `trafficType` 별로 표시. 첫/끝 도보 구간은 출발지·도착지에서 역까지 실제 도보를 의미하므로 **반드시 포함**.

```
🚇 범안로95번길 32 → SKT타워
경로 1: 54분 · 1,950원 · 환승 2회 · 도보 688m
  🚶 도보 1분
  🚌 19번 부천범박힐스테이트 → 역곡역 (9분)
  🚶 도보 2분
  🚇 1호선 역곡 → 종각 (15정거장, 35분)
  🚶 도보 7분
```

3개 이내 경로 비교 권장. `OPT=4`(최소시간) / `OPT=5`(최소환승) 옵션을 사용자가 선호 표시하면 그쪽으로 호출.

## Done when

- 출발지와 도착지가 geocoding 되었거나, 좌표/역명이 명확히 확인되었다.
- ODsay 응답에서 1개 이상 경로가 정리되었다.
- 각 경로의 총 소요시간, 요금, 환승 횟수, 총 도보 거리가 포함되었다.
- 첫/끝 도보 구간이 포함된 door-to-door 요약을 보여줬다.
- upstream API 키가 응답에 노출되지 않았다.

## Helpers

좌표 모르고 역명만 아는 경우 — `searchStation` 으로 변환:

```bash
curl -s "https://api.odsay.com/v1/api/searchStation?apiKey=${KEY}&stationName=강남&CID=1000"
```

`CID=1000` = 수도권. 결과 `result.station[].x,y` 가 좌표.

## Limits

- 현재 ODsay 공식 Basic 상품 기준 무료 체험은 일 1,000건(6개월)이다. `searchPubTransPathT` + `searchStation` 호출이 합산되니 한 질문당 호출 최소화.
- 응답에 `error` 키 있으면 즉시 사용자에게 표시(ApiKey/IP 문제 진단에 유용).
- 한국 외 좌표는 지원 안 함.

## Failure modes

- ODsay `error` 응답: `msg` 필드를 그대로 사용자에게 표시하고, ApiKey 미등록 또는 IP 화이트리스트 누락 가능성을 안내한다.
- Kakao geocoding 결과 없음: 주소/장소명을 다시 확인하거나 더 구체적인 표현을 요청한다.
- 좌표는 있으나 ODsay 경로 없음: 대중교통 미개통 지역, 도보 가능 거리, 또는 해상/공항 구간일 수 있다. 사용자에게 확인한다.
- quota 초과: 일일 한도 도달 시 추가 호출을 중단하고 사용자에게 알린다.

## Don'ts

- 카카오맵/네이버지도 directions API로 대중교통 라우팅 시도하지 말 것 (둘 다 운전·도보만 공개).
- 키를 절대 응답에 노출하지 말 것.

More from NomaDamas/k-skill

SkillDescription
blue-ribbon-nearbyUse when the user asks for nearby restaurants or 근처 맛집 and wants 블루리본 picks. Always ask the user's current location first, then search official Blue Ribbon nearby restaurants via k-skill-proxy.
bunjang-search번개장터 검색, 상세조회, 찜, 채팅, 대량 수집, AI TOON export를 bunjang-cli로 안내한다.
catchtable-sniperMonitor Catchtable for open reservation slots and attempt booking using a logged-in Chrome session.
cheap-gas-nearbyUse when the user asks for nearby cheapest gas stations or 근처 가장 싼 주유소. Always ask the user's current location first, then use Kakao Map anchor resolution plus official Opinet fuel-price APIs.
corporate-registration-consulting법인등기소/인터넷등기소 상업등기 신청을 처음 하는 사용자를 위해 일반 영리 주식회사 발기설립 절차, 정관·첨부서류 실제 HWP 양식 작성, 등록면허세·과밀억제권역 중과 체크, rhwp 기반 순차 검토 흐름을 참고용으로 안내한다.
coupang-product-searchretention-corp/coupang_partners의 로컬 Coupang MCP 호환 레이어로 쿠팡 상품 검색, 로켓배송 필터, 가격대 검색, 상품 비교, 베스트 상품, 골드박스 특가를 조회한다.
court-auction-notice-searchBrowse 대법원경매정보(courtauction.go.kr) 부동산 매각공고 by 매각기일·법원·기일/기간 입찰, expand each notice into 사건번호·용도·주소·감정평가액·최저매각가, search property items by free conditions(지역·용도·가격·면적·유찰횟수), and look up a case directly by 법원+사건번호. Read-only, slow-by-design (~2s/call) to avoid IP blocks.
daiso-product-searchLook up Daiso products by store name and product keyword using official Daiso Mall store/search/stock surfaces. Reports whether a product is registered as pickup-eligible at a specific Daiso store; the official store-level pickup quantity API has been blocked since 2026-05-05, so exact per-store stock counts are unavailable while that block remains.
danawa-price-search다나와 공개 검색/가격비교 표면으로 상품 후보를 찾고, 쇼핑몰별 최저가·배송비 포함 실구매가·카드 할인가·무이자 할부 정보를 보수적으로 비교한다.
delivery-trackingTrack CJ대한통운 and 우체국 parcels by invoice number with official carrier endpoints, and structure the workflow around a carrier adapter that can grow to more couriers later.