
Subway Lost Property
Plan and run Korean subway lost-property searches against Lost112 and Seoul Metro official sources with structured payloads and curl examples.
Overview
subway-lost-property is an agent skill for the Idea phase that plans Lost112 and Seoul Metro lost-property searches with payloads, sources, and curl-ready examples.
Install
npx skills add https://github.com/nomadamas/k-skill --skill subway-lost-propertyWhat is this skill?
- Builds SearchPlan JSON with query, POST payload, suggested keywords, and official source URLs
- Targets lost112.go.kr find list API with referer and user-agent curl pattern (60s max time)
- Includes Seoul Metro lost center reference URL in official_sources
- CLI argparse-driven Python 3 script with frozen dataclasses for query and plan
- Emits guidance and cautions alongside curl_example for manual verification
- CURL max time 60 seconds for Lost112 requests
- Default output file lost112-search-result.html
Adoption & trust: 1.8k installs on skills.sh; 5.4k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You lost something on the Seoul subway and do not know which official portal fields, dates, or keywords to use.
Who is it for?
People in Korea automating initial lost-item lookups on subway lines with station and date filters.
Skip if: Global lost-property systems, non-subway claims, or builders expecting a maintained third-party API SLA.
When should I use this skill?
You need to query or plan a Lost112 / Seoul Metro subway lost-property search with station, dates, and item keywords.
What do I get? / Deliverables
You get a SearchPlan document with payloads, official links, keyword suggestions, and a curl example to run or hand to your agent for the lookup step.
- SearchPlan JSON (payload, sources, guidance, curl_example)
- Optional saved HTML search result file
Recommended Skills
Journey fit
This is a narrow discovery/research utility for a specific civic workflow rather than a product-build step across the journey. Discover fits looking up official channels, dates, stations, and keywords before visiting lost-and-found centers.
How it compares
A localized CLI research helper—not a customer-support SaaS integration or MCP server for ticketing.
Common Questions / FAQ
Who is subway-lost-property for?
Solo users or builders in Korea who want agent-assisted, scriptable prep for Lost112 and Seoul Metro lost-property searches.
When should I use subway-lost-property?
At Idea/discover when you need official URLs, form payloads, and search keywords right after an item is lost on the metro—before visiting a center in person.
Is subway-lost-property safe to install?
It performs network calls to government sites; check the Security Audits panel on this page, review the script locally, and do not treat HTML dumps as authoritative without verifying on official portals.
SKILL.md
READMESKILL.md - Subway Lost Property
#!/usr/bin/env python3 from __future__ import annotations import argparse import json import shlex import subprocess from dataclasses import asdict, dataclass from datetime import date, timedelta from typing import Callable LOST112_LIST_URL = "https://www.lost112.go.kr/find/findList.do" LOST112_REFERER_URL = "https://www.lost112.go.kr/" LOST112_OUTPUT_FILE = "lost112-search-result.html" LOST112_CURL_MAX_TIME = 60 SEOUL_METRO_LOST_CENTER_URL = "https://www.seoulmetro.co.kr/kr/page.do?menuIdx=541" CURL_USER_AGENT = "Mozilla/5.0" Runner = Callable[..., subprocess.CompletedProcess[str]] @dataclass(frozen=True) class SearchQuery: station: str item: str | None = None line: str | None = None start_date: date | None = None end_date: date | None = None @dataclass(frozen=True) class SearchPlan: query: SearchQuery payload: dict[str, str] suggested_keywords: list[str] official_sources: list[dict[str, str]] guidance: list[str] cautions: list[str] curl_example: str def to_dict(self) -> dict[str, object]: return { "query": { **asdict(self.query), "start_date": self.query.start_date.isoformat() if self.query.start_date else None, "end_date": self.query.end_date.isoformat() if self.query.end_date else None, }, "payload": self.payload, "suggested_keywords": self.suggested_keywords, "official_sources": self.official_sources, "guidance": self.guidance, "cautions": self.cautions, "curl_example": self.curl_example, } def normalize_station(station: str) -> str: normalized = " ".join(station.split()) if not normalized: raise ValueError("station is required") return normalized def expand_station_keywords(station: str) -> list[str]: normalized = normalize_station(station) keywords = [normalized] if normalized.endswith("역") and len(normalized) > 1: keywords.append(normalized[:-1]) return list(dict.fromkeys(keyword for keyword in keywords if keyword)) def build_search_payload(query: SearchQuery) -> dict[str, str]: station = normalize_station(query.station) if not query.start_date or not query.end_date: raise ValueError("start_date and end_date are required") payload = { "pageIndex": "1", "START_YMD": query.start_date.strftime("%Y%m%d"), "END_YMD": query.end_date.strftime("%Y%m%d"), "PRDT_NM": (query.item or "").strip(), "DEP_PLACE": station, "SITE": "V", "PLACE_SE_CD": "", "FD_LCT_CD": "", "FD_SIGUNGU": "", "IN_NM": "", "ATC_ID": "", "F_ATC_ID": "", "PRDT_CL_CD01": "", "PRDT_CL_CD02": "", "PRDT_CL_NM": "", "MENU_NO": "", } return payload def _base_curl_command(url: str | None, max_time: int, *, follow_redirects: bool = True) -> list[str]: command = [ "curl", "-fsS", "--http1.1", "--tls-max", "1.2", "--retry", "1", "--max-time", str(max_time), "-A", CURL_USER_AGENT, ] if follow_redirects: command.insert(2, "-L") if url: command.append(url) return command def build_curl_command(payload: dict[str, str]) -> str: command = _base_curl_command("", LOST112_CURL_MAX_TIME, follow_redirects=False) command.extend(["--referer", LOST112_REFERER_URL]) for key, value in payload.items(): if value: command.extend(["--data-urlencode", f"{key}={value}"]) command.extend(["--output", LOST112_OUTPUT_FILE]) command.append(LOST112_LIST_URL) return " ".join(shlex.quote(part) for part in command) def probe_source(name: str, url: str, runner: Runner = subprocess.run) -> dict[str, str]: command = _base_curl_command(url, 15) try: completed = runner(command, capture_output=True,