visa-itinerary-gen

一键生成领馆级签证行程计划书 — Generate consulate-grade visa itinerary from natural language. Real flyai data, zero hallucination. PDF + booking links with Fliggy.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "visa-itinerary-gen" with this command: npx skills add zephryve/visa-itinerary-gen

visa-itinerary-gen — Visa Itinerary Generator

一句话说明: 输入"4个人4月27号从杭州去意大利和法国,5月4号回",一键生成领馆级签证行程计划书(PDF)+ 飞猪预订链接。省 ¥30-110 代做费,省 3-5 小时手工排版。

Generate a consulate-grade visa itinerary document with one command. Real data from flyai, zero hallucination.

Execution Contract — Read This First

You are a strict executor of this skill, not a co-designer. Follow every step in the exact order written. Do NOT:

  • Skip steps you consider unnecessary. Every step exists for a reason. If it says "run this command", run it. If it says "review this output", review it.
  • Reinterpret instructions. "Pick the top-rated hotel" means pick the top-rated hotel. Do not substitute a cheaper hotel for budget reasons, do not pick a "better value" alternative, do not apply your own judgment to override an explicit rule.
  • Optimize on behalf of the user. This skill already handles edge cases (budget exceeded, data missing, etc.) in specific steps. If a situation is not covered by the instructions, ask the user — do not invent a workaround.
  • Combine or reorder steps. Step numbers are execution order. Do not merge Step 3+4+5 into a single batch, do not skip Step 2 because "the date is obvious", do not skip Step 8 because "the output looks fine".

When in doubt, follow the literal instruction. When instructions conflict with your judgment, the instruction wins.

Step 0: Dependency Check — MANDATORY, DO NOT SKIP

When this skill is activated, first run these checks before doing anything else. This step catches environment problems early — skipping it leads to silent failures mid-execution that are harder to debug.

# 1. Check node (required by flyai-cli)
which node > /dev/null 2>&1 || echo "MISSING: node"

# 2. Check flyai-cli binary
which flyai > /dev/null 2>&1 || echo "MISSING: flyai-cli"

# 3. Check python3
which python3 > /dev/null 2>&1 || echo "MISSING: python3"

# 4. Check playwright (for PDF generation)
python3 -c "import playwright" 2>/dev/null || echo "MISSING: playwright"

If anything is missing, ask the user for permission before installing. Do NOT install silently — always confirm first.

  • node missing → tell user: install Node.js from https://nodejs.org/ (cannot be auto-installed)
  • flyai-cli missing → ask user: "flyai-cli is not installed. It's a free CLI tool (no API key needed) for searching flights, hotels, and attractions on Fliggy. Shall I install it? (npm i -g @fly-ai/flyai-cli)" → if user agrees, run the install command
  • python3 missing → tell user: install Python 3 from https://python.org/ (cannot be auto-installed)
  • playwright missing → ask user: "playwright is not installed. It's needed for PDF generation. Shall I install it? (pip3 install playwright && python3 -m playwright install chromium)" → if user agrees, run the install commands

After all dependencies are present, verify flyai actually works:

flyai fliggy-fast-search --query "test" > /dev/null 2>&1 && echo "flyai OK" || echo "flyai ERROR"

If flyai returns an error, warn the user but do not stop — it may still work for specific queries.

Only proceed to Step 1 when all dependencies are confirmed present.

When to Use This Skill

Activate when the user wants to:

  • Generate a travel itinerary for any visa application (Schengen, Japan, South Korea, Southeast Asia, etc.)
  • Create a travel plan document for consulate/embassy submission
  • Prepare visa application documents (specifically the itinerary)

Input

The user provides a natural language description of their trip. Extract these parameters:

ParameterRequiredExample
destinationYes"Italy and France"
datesYes"Apr 27 - May 4"
travelersYes (default: 1)4
departure_cityYes"Hangzhou"
budgetNo"60,000 CNY"

Example: "4个人4月27号从杭州去意大利和法国,5月4号回,预算6万"

Execution Steps

Step 1: Parse Input & Validate

Extract destination cities, travel dates, number of travelers, departure city, and budget from the user's input.

Mandatory validation — do NOT proceed to Step 2 until all required fields are confirmed:

FieldRequiredHow to resolve if missing
Destination (目的地)YesAsk user
Departure city (出发城市)YesAsk user
Departure date (出发日期)YesAsk user
Trip duration (行程区间)Yes — need either return date OR number of daysAsk user: "请问返回日期或出行天数?"
Travelers (出行人数)No — default 1Use default
Budget (预算)NoSkip

If the user provides "玩7天" or "一共8天", calculate the return date from departure date + days. If only a return date is given, calculate trip days from the two dates. Either form is acceptable — the goal is to determine the full date range.

Stop and ask the user if any of the 4 required fields cannot be determined from their input. Do not guess or assume.

Once all fields are confirmed, plan a realistic day-by-day city routing. For multi-country trips, determine the city sequence. Example for Italy + France:

  • Milan → Venice → Florence → Rome → Nice → Paris

Step 2: Get Current Date — MANDATORY, DO NOT SKIP

date +%Y-%m-%d

You MUST run this command and use the output as the reference date. Do NOT assume today's date from your training data or system prompt — those can be wrong. This is the only reliable source of truth for date calculations. Use it to resolve relative dates ("next month", "this Friday", etc.).

Step 3: Call flyai — Flights

Retry rule (applies to all flyai calls in Step 3, 4, and 5): If a flyai command returns empty results (null or empty itemList) or errors out, wait 3 seconds and retry once. If still failed, handle per the Error Handling table and continue to the next step.

Search for all flight segments. Flight search works with both Chinese and English city names, but prefer Chinese for consistency.

International departure:

flyai search-flight --origin "{出发城市}" --destination "{第一个目的城市}" --dep-date "{start_date}" --sort-type 3

Inter-city flights (if applicable):

flyai search-flight --origin "{城市A}" --destination "{城市B}" --dep-date "{date}" --sort-type 3

Return flight:

flyai search-flight --origin "{最后一个城市}" --destination "{出发城市}" --dep-date "{end_date}" --sort-type 3

From each result, extract: marketingTransportName, marketingTransportNo, depDateTime, arrDateTime, depStationName, arrStationName, adultPrice, jumpUrl.

If no flight found for a segment: note it as "Train" or "To be confirmed" — do NOT hallucinate a flight number.

Step 4: Call flyai — Hotels

For each city in the itinerary, search hotels. You MUST include dates for overseas cities — without dates, overseas cities return wrong results from unrelated cities (not empty, but wrong data — more dangerous).

CRITICAL: Always use Chinese city names for hotel search. English names cause flyai to fuzzy-match wrong cities (e.g., "Tokyo" → Cape Town, "Nice" → Dubai, "Osaka" → null). This is not a fallback — Chinese is the only reliable option for overseas cities.

flyai search-hotels --dest-name "{城市中文名}" --check-in-date "{checkin}" --check-out-date "{checkout}" --sort rate_desc

From each result, extract: name, address, price, score, detailUrl.

Verify the hotel is actually in the target city. Check the address field — if it contains a different country or city, discard that result.

Pick the top-rated hotel for each city — this is a hard rule, not a suggestion. Do NOT substitute a cheaper or "better value" hotel to fit the user's budget. Budget handling is done separately in the booking links output (see Error Handling: "Budget exceeded"). Your job here is to pick the highest-rated valid hotel, period. If no valid results, mark "Hotel to be confirmed" in the itinerary.

Step 5: Call flyai — Attractions

For each city, search top attractions. You MUST use Chinese city names — English names return empty results.

Universal rule: Regardless of user input language, translate ALL city names to Chinese before calling any flyai command (hotels, attractions, flights with non-Chinese city names). Do not rely on a fixed mapping table — the agent is responsible for accurate translation.

flyai search-poi --city-name "{城市中文名}"

From results, extract: name, address, freePoiStatus, ticketInfo.price, jumpUrl.

Select 2-4 attractions per city to fill the daily itinerary. Distribute realistically — no more than 3 major attractions per day.

Step 6: Internal Logic

Only execute this step for multi-country Schengen trips. For single-country trips or non-Schengen destinations (e.g., Japan, South Korea, Southeast Asia), skip this step entirely.

Schengen 90/180 Day Check:

  • Count total days inside Schengen zone
  • If > 90 days, add a warning at the top of the document

Main Application Country:

  • Count days spent in each country
  • The country with the most days = main application country
  • If tied, the first country visited is the main application country

Step 7: Generate Output

You MUST produce TWO outputs:

Output 1: Travel Plan Table (Markdown → PDF)

Generate a full English single-page travel plan table. This is the visa itinerary — keep it clean and simple, no extra sections.

# Travel Plan

| Country | Day | Date | City | Touring Spots | Accommodation | Transportation |
|---------|-----|------|------|---------------|---------------|----------------|
| CHINA | 1 | {YYYY/MM/DD} ({Day}) | {origin}→{first_city} | — | {hotel_name} ({full_address}) | Flight {airline} {flight_no}: {origin}→{dest} {dep_time} |
| {COUNTRY} | 2 | {YYYY/MM/DD} ({Day}) | {city} | {Spot 1}, {Spot 2}, {Spot 3} | {hotel_name} | Public transport and walking |
| ... | ... | ... | ... | ... | ... | ... |
| CHINA | {n} | {YYYY/MM/DD} ({Day}) | {last_city}→{origin} | — | — | Flight {airline} {flight_no}: {dep_city}→{origin} {dep_time} |

Critical rules:

  • ALL text in English
  • Every day must have specific touring spots — never write "Free day" or "Rest"
  • Touring Spots: just list attraction names, no descriptions (e.g. "Duomo di Milano, Galleria V.E. II, The Last Supper")
  • Accommodation: first time a hotel appears → full name + address; subsequent nights at same hotel → name only
  • Transportation: flight rows → "Flight {airline} {flight_no}: {route} {time}"; train rows → "Train {city_a}→{city_b}"; sightseeing days → "Public transport and walking"
  • Keep it concise — the whole table should fit on a single A4 page
  • No Declaration, no Financial Summary, no Notes for Visa Officer — just the itinerary table. Real visa itineraries that get approved are plain tables. Adding extra sections deviates from standard consulate submission format.

Generate PDF from the table

Save the Markdown table to travel_plan.md in the working directory, then render it to PDF:

python3 <skill_dir>/scripts/render_pdf.py --md travel_plan.md --output My_Travel_Plan.pdf

For example, if this skill is installed at ~/.claude/skills/visa-itinerary-gen/, the command would be:

python3 ~/.claude/skills/visa-itinerary-gen/scripts/render_pdf.py --md travel_plan.md --output My_Travel_Plan.pdf

The script converts Markdown to a styled A4 PDF internally (Times New Roman, black & white, single-page table layout). Deliver both files to the user:

  • travel_plan.md — editable source, user can modify and re-render
  • My_Travel_Plan.pdf — print-ready for consulate submission

Output 2: Booking Links Data (JSON → HTML)

Write a data.json file to the working directory containing all flyai data for booking links. Then run the render script to produce the HTML files.

JSON schema — every field is required unless marked optional:

{
  "title": {
    "destination_cn": "意大利 & 法国",
    "destination_en": "Italy & France",
    "dates": "2026-04-27 ~ 2026-05-04"
  },
  "flights": [
    {
      "route_cn": "杭州 → 米兰",
      "route_en": "Hangzhou → Milan",
      "airline_cn": "南航 CZ8790 → 阿提哈德 EY889+EY081",
      "airline_en": "China Southern CZ8790 → Etihad EY889+EY081",
      "price": 4580,
      "url": "https://a.feizhu.com/..."
    }
  ],
  "hotels": [
    {
      "city_cn": "米兰",
      "city_en": "Milan",
      "name_cn": "米兰大教堂广场酒店",
      "name_en": "Hotel Piazza Duomo Milano",
      "price": 1280,
      "star": "高档型",
      "recommendation_cn": "近米兰大教堂",
      "recommendation_en": "Near Duomo di Milano",
      "url": "https://a.feizhu.com/..."
    }
  ],
  "attractions": [
    {
      "city_cn": "米兰",
      "city_en": "Milan",
      "name_cn": "米兰大教堂",
      "name_en": "Duomo di Milano",
      "category_cn": "宗教场所 · 米兰地标",
      "category_en": "Landmark · Milan's iconic cathedral",
      "url": "https://a.feizhu.com/..."
    }
  ]
}

Data filling rules:

Flights — format airline_cn and airline_en fields:

  • airline_cn uses marketingTransportName as-is from flyai (e.g. "南航", "阿提哈德"). airline_en uses the airline's official English name (e.g. "China Southern", "Etihad").
  • Flight numbers are mandatory. Never omit the flight number or write only the airline name.
  • Direct flight: {airline} {flight_no} — e.g. 海南航空 HU7937
  • Same-airline connecting flights: combine flight numbers with + — e.g. 阿提哈德 EY156+EY888
  • Multi-airline connecting flights: separate airlines with — e.g. 南航 CZ8790 → 阿提哈德 EY889+EY081
  • No transfer descriptions. Do not write "经多哈中转", "via Abu Dhabi" etc.
  • price: per-person price as a number (not string), from flyai result
  • url: Fliggy jumpUrl from flyai. If no link available, set to empty string ""

Hotels:

  • Pick the top-rated hotel for each city — hard rule. Do NOT substitute a cheaper hotel.
  • name_en: use the hotel's own English name, not a translation of the Chinese transliteration
  • price: per-night price from flyai price field as a number. Do not calculate total cost or multiply by nights/guests
  • star: tier label from flyai (e.g. "豪华型", "高档型", "舒适型")
  • recommendation_cn/en: interestsPoi or notable features (e.g. "近圣马可广场" / "Near St. Mark's Square")

Attractions:

  • name_en: use the internationally recognized English name (e.g. "布拉格城堡" → "Prague Castle")
  • category_cn/en: from flyai category. Discard obviously wrong labels (e.g. "山湖田园" for a city observation deck)

After writing data.json, render the HTML files:

python3 <skill_dir>/scripts/render_booking.py --data data.json --output-dir .

For example, if this skill is installed at ~/.claude/skills/visa-itinerary-gen/, the command would be:

python3 ~/.claude/skills/visa-itinerary-gen/scripts/render_booking.py --data data.json --output-dir .

The script produces two files:

  • booking_links_cn.html — Chinese version
  • booking_links_en.html — English version

Budget Check (only when budget is specified)

After generating both outputs, calculate the estimated total: sum all flight prices × number of travelers, plus all hotel prices × number of nights per hotel. If the total exceeds the user's stated budget:

  1. Identify the most expensive hotel (highest per-night price)
  2. From the Step 4 flyai results for that city, pick the next-best hotel one tier down (e.g., 豪华型 → 高档型 → 舒适型). If the original results have no lower-tier options, re-run flyai search-hotels for that city without the --sort parameter and pick the top-rated hotel from the lower tier.
  3. Recalculate total. Still over budget? Repeat for the next most expensive hotel.
  4. Update both Output 1 (travel_plan.md + re-render PDF) and Output 2 (data.json + re-run render_booking.py) with the new hotel selections.
  5. If all hotels are already at 舒适型 and total still exceeds budget, keep the current selection and add a note: set a budget_warning field in data.json's title object (e.g. "budget_warning": "Estimated total exceeds stated budget").

If no budget is specified, skip this check entirely.

Step 8: Delivery Review — MANDATORY, DO NOT SKIP

Before delivering to the user, review each output as if you were the person who will submit it to a consulate. This step catches data errors that ruin the document's credibility. Do NOT skip it because "the output looks fine" — that is exactly when errors slip through.

The goal is to deliver something that can be used directly — not a draft that needs manual checking.

Review Output 1 (Travel Plan PDF) — the visa officer will read this:

  • Language check: scan the entire travel_plan.md for any non-ASCII characters (Chinese, Japanese, Arabic, etc.). The travel plan must be pure English + numbers + standard punctuation. If any non-ASCII text is found (most commonly: Chinese airline names copied from flyai, Chinese hotel names, or Chinese city names), translate it to the correct English equivalent and re-render the PDF. This is a hard gate — do not proceed to delivery until the table is 100% English.
  • Every hotel address is in the correct city (not a different country or region)
  • Every flight row has a specific flight number + departure time (not just the airline name)
  • Each day's touring spots are only in that day's city (no mixing cities on transfer days)
  • Transfer day timing is realistic (early morning flight = no sightseeing that day)
  • Every piece of data (flight numbers, hotel names, touring spot names) must trace back to a flyai call. If a touring spot was not returned by flyai, it must be removed — use "Local exploration / neighborhood walk" instead. This skill's promise is zero hallucination from real data.

Review Output 2 (data.json) — the user will use this to book:

  • Every flight entry has both airline_cn and airline_en with flight numbers (not just airline name)
  • Every flight entry has a non-empty url (if flyai returned a jumpUrl)
  • Every hotel entry has a non-empty url
  • Every hotel entry has star and recommendation_cn/en populated
  • Every attraction entry has category_cn/en populated; discard obviously wrong labels
  • All _en fields contain correct English translations:
    • Airline names: use IATA official English name (e.g. "南航" → "China Southern Airlines", not "Southern Airlines")
    • Hotel names: use the hotel's own English name, not a translation of the Chinese transliteration
    • Attraction names: use the internationally recognized English name (e.g. "布拉格城堡" → "Prague Castle")
    • If unsure of the correct English name, keep the flyai Chinese name rather than guessing
  • render_booking.py execution: verify the script ran successfully (exit code 0) and both HTML files exist. If the script failed, fix the data.json issue and re-run.

When something fails review:

  • Fix it if you can (correct data.json fields and re-run render_booking.py)
  • If unfixable (flyai has no data), mark it clearly in the output and tell the user what needs their attention
  • Default is: user receives a ready-to-use document, not a TODO list

Error Handling

SituationAction
Flight not foundWrite "To be confirmed — please check alternative routes" in Destination column
Hotel not foundWrite "To be confirmed — please book a hotel with free cancellation" in Hotel column
Attraction data sparseUse fliggy-fast-search --query "{city} tourist attractions" as fallback
Schengen stay > 90 daysAdd prominent warning: "⚠ WARNING: Total Schengen stay exceeds 90 days"
flyai not installedPrint installation instructions and stop
Budget exceededMention in booking links output that estimated total exceeds stated budget

Important Notes

  • Never hallucinate data. Every flight number, hotel name, and address must come from flyai results. If flyai returns no data, mark it as "To be confirmed" — do NOT make up information. Visa officers can and will verify.
  • Always include booking links. In Output 2, every hotel and flight must have a Fliggy booking link from the flyai response.
  • Keep the travel plan clean. Output 1 is just a table — no extra sections, no branding. Follow standard consulate submission format.
  • Brand mention. Only in Output 2 (booking links), include "Based on fly.ai real-time results".

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

LovTrip AI Travel Planner

AI 行程规划 / AI Travel Itinerary Planner — 智能生成多日旅行行程,支持景点搜索、预算计算、酒店航班。当用户需要旅行规划、生成行程、搜索景点酒店航班时使用。

Registry SourceRecently Updated
3810Profile unavailable
General

Trip Planner 0→1

从 0 到 1 制作一份完整的自由行出行攻略,覆盖需求采集、多源资源调研(小红书 MCP + 地图 + Web 搜索)、方案决策、Markdown 行程书产出、交互式 Todo 网页(本地存储 + 可选云端同步)、一键部署到静态托管的端到端工作流。适用于东南亚海岛、日本、欧洲自驾、美洲公路旅行等任何自由行场景。触...

Registry SourceRecently Updated
620Profile unavailable
General

PandaMate China Travel Expert

中国入境旅游完整助手。当用户需要以下信息时触发:(1)入境中国签证、240小时过境免签、落地签等签证政策 (2)中国支付方式(支付宝/微信支付绑定境外银行卡、外币兑换) (3)中国交通(高铁、飞机、国内航班预订) (4)中国城市旅游攻略(北京、上海、广州、成都、杭州等) (5)中国海关入境申报、文化禁忌 (6)电...

Registry SourceRecently Updated
700Profile unavailable
General

Trip Planner Generator

Generates structured travel plans for trip websites. Invoke when user wants to create a travel itinerary, plan a trip, or needs help organizing travel details.

Registry SourceRecently Updated
1110Profile unavailable