Install
openclaw skills install @stevenho1394/hk-gmb-arrivalReal-time arrival information for Hong Kong Green Mini Buses (GMB). Supports fuzzy stop name matching and multi-region route lookup.
openclaw skills install @stevenho1394/hk-gmb-arrivalGET /route - List all routes grouped by region (HKI, KLN, NT)GET /route/{region}/{route} - Get route details including directions (route_seq) and route_idGET /stop-route/{stop_id} - Get stop names (name_en, name_tc) and the routes serving that stopGET /eta/stop/{stop_id} - Get real-time ETA for all routes at that stopAdditionally, static route data is sourced from:
https://hkbus.github.io/hk-bus-crawling/routeFareList.min.json - Contains mapping from route identifiers to stop ID sequences for GMB (and other operators).Key functions:
searchRoutes(route): Queries /route, finds which regions contain this route number. If none, suggests similar route numbers.get_gmb_arrival(route, direction, stop_name, region):
/route/{region}/{route} to obtain route_id and the direction details (origin/destination names).routeFareList.json (lazy load with size limit) to get the ordered list of stop IDs for that direction./stop-route/{stop_id} to retrieve stop names (cached).stop_name (case-insensitive) exactly; if not found, perform fuzzy matching and return suggestions./eta/stop/{stop_id}.route_id and route_seq (direction), extract up to 3 next arrival timestamps, format as "HH:MM HKT".{ "stopId": "...", "stopName": "...", "arrivals": [ "17:35 HKT", ... ] }.routes_all.json: All route list (1 hour)route_details.json: Route details per region/route (5 minutes)routeFareList.json: Static route-to-stop mapping (1 day) - NOT bundled, fetched at runtime with 512KB size limitstop_names.json: Stop ID to names mapping (1 week)Cache files stored in data/ subdirectory. Cache files are NOT included in the skill distribution - they are created at runtime.
error field.found: false with suggestions array.error with suggestions mapping suggestion → stop ID.arrivals array with an informative message.# Search route
python3 gmb_arrival.py searchRoutes 1
# => {"route":"1","found":true,"regions":["HKI","KLN","NT"]}
# Get arrival for route 1 direction 1 (The Peak → Central) at "Hong Kong Station Minibus Terminus" in HKI
python3 gmb_arrival.py getGMBArrival 1 1 "Hong Kong Station Minibus Terminus" HKI
# => {"stopId":"20014492","stopName":"Hong Kong Station Minibus Terminus","arrivals":["14:38 HKT","14:45 HKT","14:52 HKT"]}
route_seq 1 and 2. Use searchRoutes then inspect route details to determine which sequence corresponds to your desired direction, or use getGMBArrival directly if you know the direction number.routeFareList may lag behind official data by up to one day but is generally reliable.All findings from automated security scanners (SkillSpector + AIG Analysis) have been remediated:
Finding (v1.0.0): Tool commands in SKILL.md and openclaw.plugin.json interpolated user-controlled values ({route}, {direction}, {stopName}, {region}) directly into shell command strings without quoting or argument-boundary protection.
Remediation (v1.2.0):
route pattern ^\d{1,3}$, direction enum ["1","2"], region enum ["HKI","KLN","NT"], stopName pattern ^[\w\s\u4e00-\u9fff.,()\-/]{1,100}$ (strict allowlist)executionModel to manifest specifying shell: false and argumentArray: true - runtime MUST invoke via argument arrayStatus: Defense-in-depth at schema + runtime + manifest. Full remediation requires platform to honor executionModel.shell=false.
Finding: Script contacts https://data.hkbus.app/routeFareList.min.json and https://data.etagmb.gov.hk (flagged as potential data exfiltration).
Analysis: Both endpoints are legitimate, public HK government data sources. No credentials, tokens, PII, or user data transmitted. Requests are GET-only for public transit data.
Remediation:
ALLOWED_DOMAINS frozenset with 3 domains; _validate_url() checks every requestfetch_json() call validates URL against allowlist before network requestallowedDomains, allowedPaths, networkAccess with explicit domains/protocols/maxResponseSizeStatus: False positive resolved. Legitimate traffic documented, restricted, and size-limited.
Finding: Skill manifest didn't declare explicit permission boundaries. Consumers cannot sandbox effectively.
Remediation: Added explicit declarations in openclaw.plugin.json:
requiredPermissions: Network + filesystem permissions with specific pathsnetworkAccess: Domains, protocols, maxResponseSizefileSystemAccess: Read/write paths with maxFileSize limitsexecutionModel: Shell=False, argumentArray=True requirementStatus: Explicit capability declarations added for sandbox enforcement.
Finding: Referenced artifact (routeFareList.json, 8.3 MB) was not completely inspected by scanner.
Root Cause: The massive cache file was bundled in the skill distribution, preventing full analysis.
Remediation:
data/*.json not included in skill packagefetch_route_farelist_entry() fetches full file but enforces 512KB limit, extracts only needed entry, discards restStatus: Large artifact removed from distribution; runtime loading is size-bounded and inspectable.
Finding: Skill attempted to fill context window with filler content (8MB routeFareList cache), displacing legitimate instructions.
Remediation:
MAX_CACHE_FILE_SIZE = 1MB, MAX_ROUTE_FARELIST_SIZE = 512KB_check_cache_size() prevents loading oversized cache filesStatus: Context window stuffing eliminated.
The Hermes skill loader scans SKILLS_DIR from hermes_constants.get_hermes_home() → /opt/data/skills/ (NOT /opt/data/.hermes/skills/). Skills must be placed under /opt/data/skills/<category>/<skill-name>/ to be discovered. The .hermes/skills/ directory is not scanned by default.
See references/security-audit.md for full ClawHub audit transcript.
See references/route-481-stops.md for route 481 stop IDs and test results.