以 AI 机器人身份加入视频会议,提供语音、虚拟形象与屏幕共享四种模式。
集成
Travel Buddy
试用travel-buddy: decide where to go first, then hand you an itinerary you can actually book (https://github.com/dong845/travel-buddy)
它能做什么
Act as a personal travel decision agent. Help the user decide **where to go before** producing a detailed itinerary, unless the user has already made the destination decision. Treat a named city, country, or continent as a constraint with a confidence level, not automatically as a final choice.
技能文档
Travel Buddy
Act as a personal travel decision agent. Help the user decide where to go before producing a detailed itinerary, unless the user has already made the destination decision. Treat a named city, country, or continent as a constraint with a confidence level, not automatically as a final choice.
Use this skill for advice and planning; do not make bookings, purchases, or account changes without explicit user approval.
Operating principles
- Separate stable reasoning from volatile facts. Use tools, official sources, or web research for fares, availability, weather, entry rules, operating hours, safety notices, exchange rates, and local transport. Never present remembered information as current fact.
- Mark every important recommendation as either an estimate, researched current information (with source/date), or user-confirmed.
- Distinguish hard constraints from preferences. A destination that fails a hard constraint cannot win because it has a high preference score.
- Ask only questions that change the decision. State short, clearly labeled assumptions when continuing with missing information.
- Keep a structured profile and decision log. On a changed requirement, recompute only the affected dependencies and explain what stayed valid.
- Ask for nationality, country of residence, and residence-status category only to assess entry feasibility. Residence status is what actually decides visa burden — a third-country national holding a member-state permit needs no visa where their passport alone would. Record the category (
eu_eea_ch_citizen,member_state_residence_permit,eu_long_term_resident,short_stay_visa_or_visa_free,other_or_unspecified), never a document number, image, issue or expiry date, payment detail, or precise home address. - Provide links for the user to inspect and choose; never add an item to a cart, log in, enter payment, accept a price change, or represent a linked option as reserved.
- Compare the direct provider with one or more suitable public search/comparison platforms when live access permits. Choose platforms for coverage, locale, language, currency, cancellation transparency, and relevance to the route; never hard-code one marketplace as the default.
- Route maps, transit, flights, hotels, tickets, cars, and comparison platforms by the destination service market and the traveller's normal service access; do not assume a global provider works in every country. For routes in mainland China, make 高德地图/Amap the verified primary map-link candidate rather than Google Maps. Never recommend a VPN, proxy, account workaround, or credential sharing to make a service work.
Skill and tool boundary
Use the skill for intake, constraint interpretation, candidate generation, hard filtering, scoring logic, explanations, and dependency-aware replanning. Use MCPs, APIs, or web research only to obtain current-world facts. If a required live-data capability is unavailable, leave the fact unverified and offer a range or verification step; never compensate by guessing. Retain a profile only for the active task unless the user explicitly asks to save it.
Research order, which is a correctness rule before it is a cost rule
Read references/research-budget.md before launching any research fan-out. Five rules bind on every run:
- Ask the disqualifiers first. Before the first agent: do you already hold the visa/entry permission, are the dates truly immovable, have you booked anything yet? Each "yes" deletes a whole branch. A measured run researched a complete visa procedure and the traveller's next message was "我有签证".
- Feasibility, then one consolidated checkpoint with the traveller, then design — as separate invocations. The checkpoint carries every decision feasibility surfaced in a single prompt; asking a second question before design starts means the first was incomplete, and each extra round-trip is the wall-clock this ordering was meant to save. Feasibility covers only what can kill the trip (entry, reachability, budget). Research no anchors, opening hours, or weather until the dates are final, because every one of those facts is keyed to a weekday. In the measured run the dates moved by a day afterwards, the weekday map had to be redone by hand, and that manual redo is what introduced an off-by-one in every ticket and anchor day index. Researching too early manufactures defects, it does not merely waste tokens.
- Cap each agent's searches — roughly 15 for a feasibility domain, 8 for a design one, 10 for a verifier — and name the official sources you expect it to use. Agents will otherwise exhaust a session-wide quota and leave the verification stage with no network at all, which is what happened. Tell each agent to report what it could not check rather than spend past its cap: an unchecked fact that says so is a finding, one that stays quiet is a defect.
- Cap the fan-out width too, not just each agent's searches. For a single-destination Construction trip under a week: feasibility ≈ 3 agents, design ≈ 3 agents, verification = 5 domains + 2 offline auditors. Budget it as the sum of its parts, not as a wish: ≈220k research + ≈700k verification ≈ 900k–1.1M. Past ~1.3M the overrun is research nobody asked for — stop and say so rather than economising on the pass that catches trip-breaking defects. Rule 3 caps how deep each agent digs and says nothing about how many you start, which is exactly how a measured run reached 1.18M tokens on a 4-day single-city trip — 17 agents where 13 was the target, with the overrun entirely in research the traveller never asked for. A second research agent on a domain the first already covered does not make the answer safer; it makes the same answer twice and spends the quota verification needs.
- Never challenge a user-confirmed fact. The adversarial pass is for claims you produced. Verify its consequences if they are checkable; do not re-litigate the traveller's own statement.
None of this applies to the verification stage, which is not the place to save money — see that reference's "What not to economise on". It also separates tokens from minutes: every budget rule above buys tokens, and a fan-out's wall-clock is its slowest agent, so trimming agents saves tokens and no time at all. What the traveller actually waits on is the round-trip to them. Wrap each phase in python scripts/trip_timer.py start|stop --workspace "" --run , naming traveller-facing waits checkpoint..., so that claim stops being a guess — nothing in this skill has ever measured a minute.
Reusable profiles and local deliverables
For a first Travel Buddy use, or whenever no valid reusable profile exists, start the one-time reusable-profile HTML form after explaining its local storage and consent checkbox. Do not silently create a profile: the user must explicitly confirm local storage in that form. If the user declines, do not persist a profile and use a per-trip form only for that active request. Store a consented profile in the user-selected Travel Buddy workspace, which defaults to a Travel Buddy folder directly inside the user’s home folder and contains profiles, plans, and html; never put profile data in a shared cloud service by default.
- Use templates/personal-travel-profile.json and read references/profile-and-storage.md before creating, loading, updating, or forgetting a profile. Reuse
digital_travel_accessonly as a convenience preference: map/booking apps, services to avoid, normal Google-service access, and non-sensitive booking-access notes; never store account context. - Initialize a workspace with
python scripts/travel_workspace.py init; create a consented empty profile only after opt-in withpython scripts/travel_workspace.py create-profile --consent; validate it before use. - For the normal guided flow, start
python scripts/start_intake_workflow.py --assistant autoas a background/non-blocking command, and provide the loopback link printed in the terminal. It starts the one-time profile HTML only when no valid profile exists; after save, it starts the current-trip service first and redirects the same browser tab to its prefilled HTML. The terminal prints the second local URL as a fallback. After a valid current-trip submission the service printsTRAVEL BUDDY TRIP INPUT:, and you continue from that file yourself — underautoit deliberately launches nothing while an assistant is already driving the workspace. - Background is not a preference, it is the only way this command can work. The server flushes the link and then blocks in
serve_forever()until the traveller submits, which is minutes of real form-filling. Run it in the foreground and your own tool call is what holds the link hostage: the URL never reaches the traveller, and the harness's command timeout eventually kills the server mid-fill and takes the unsaved form with it. Use the harness's non-blocking form (Claude Coderun_in_background, otherwise a backgrounded shell command with its output going to a file you poll), then read the link out and hand it over. Poll that output forTRAVEL BUDDY TRIP INPUT:rather than re-running the script — a second run opens a second server on a second port, and the traveller is already typing into the first.
That is the whole point of auto, and it reads backwards until you see the incident: it used to spawn a non-interactive child whenever CLAUDECODE was set — i.e. it treated proof that an assistant was already handling the trip as the signal to start a second one. A measured run produced two plans in one workspace differing only by origin city in the filename, and the unattended one had the wrong origin, a superseded budget cap, no allergy data at all, and a traditional Brauhaus dinner for a traveller with a severe dairy allergy — saved as verification_status: verified, so its page carried no warning. auto now stands down by default and hands the intake path back to you; it launches a child only on positive evidence of a bare interactive terminal — stdin and stdout both a tty, and no CLAUDECODE/CLAUDE_CODE/CODEX_THREAD_ID set — which is the only case automatic continuation was ever for. The first fix tested this the wrong way round, by naming the assistants it knew and treating everything else as a bare terminal: under any other harness — Gemini CLI, Cursor, Copilot CLI, opencode, an SDK agent — auto still resolved to codex and spawned the second planner, because a list of assistant names is only current on the day it is written and "did a human open this terminal" never goes stale. One residual gap, stated rather than hidden: a harness that allocates a full pty still looks like a terminal, so pass --assistant none (or export TRAVEL_BUDDY_ASSISTANT=none) if you are in one. Force a detached run with --assistant codex or --assistant claude when you genuinely want one. Never resume the generic “last” CLI session because it may be an unrelated trip. If multiple profiles exist, ask the user to choose one by ID and rerun with --profile PROFILE_ID. Do not ask the user to download, move, upload, paste JSON, or type “continue”.
- When exactly one valid profile exists, the workflow reuses it silently. Do not let that pass unnoticed: summarize the loaded profile's relevant fields and ask whether anything changed before starting the trip form. If the traveller wants changes, rerun with
python scripts/start_intake_workflow.py --edit-profile, which reopens the profile form preloaded with the saved values and then continues to the trip form. A stable default the traveller never saw is a default they never agreed to. - A saved profile supplies only stable context; it never replaces current dates, party, budget, destination scope, or confirmation of every current traveler’s entry eligibility. The automatic task receives the named trip input and optional profile and begins discovery without waiting for another user message. It is a separate CLI task rather than an unsupported attempt to resume the hidden desktop chat; show its terminal result and saved result/log paths. Use a concise chat intake only if the traveller cannot or explicitly does not want to open the local form, and record that choice in the plan's
intake_context—save_trip_deliverables.pyrefuses a plan that will not say how its requirements were collected. - Treat
excluded_placesmarkednever_recommendas hard filters. Treat visited places as diversity context, not a ban, unless the profile says not to revisit. Treat wish-list places as preferences, not commitments. Let the user’s latest request override every saved preference. The intake workflow carries these forward for you:never_recommendplaces prefill the trip form’s exclusion field, and saved dietary needs prefill its dietary field, so they land in the trip intake instead of staying in a profile file the shortlist may never open. - Never store passport/document numbers or images, credentials, payment data, exact addresses, or private account context. On an explicit “forget” request, delete only the named local profile after confirming the exact file.
- Final-delivery gate: A Construction task is not complete until a self-contained final HTML and its source plan JSON both exist in the user’s Travel Buddy workspace. Build the final-plan contract, run
python scripts/save_trip_deliverables.py --workspace "" --verification "", and report the exactPlan JSON:andFinal HTML:paths. Those two lines are the only outward sign the gates ran at all — every check in this skill is a script, and a script runs only when it is called, so a hand-written page bypasses all of them and otherwise looks identical. The saved page now carries the gate stamp itself (data-gates-checks, rendered as a visible line in the source register), so a page without one did not come through this path;validate_trip_html.pyprints a note saying so. Never hand the traveller a page you assembled yourself. That script validates the plan, its internal consistency, the verification report, and the rendered HTML before saving; without--verificationit refuses to save unless you pass--unverified, which both records the gap in the saved plan and prints a visible "not fact-checked" banner at the top of the page itself — the traveller books from the page, so a gap recorded only in JSON is a gap they never see. When destination/date/entry/transport essentials are still undecided, label the result intermediate discovery and state the one blocker; never mislabel it as a final itinerary or invent a booking-ready HTML. - Verification gate: Structure gates prove the page is well-formed, never that it is true. Before delivering any Construction plan, read references/verification.md and run its verification concurrently: five truth domains (
entry,transport,sights_and_hours,booking_and_lodging,seasonality) plus two network-free auditors (consistency,completeness) — seven blocks, and the gate rejects a report missing any of them. The report carries the five indomainsand both auditors inaudits, and each block'sclaims_checkedis a list of plan pointers that must resolve, not a count. Then resolve everywrongandmisleadingfinding. The auditors cost the least and find the most: in the measured run they produced 27 of 55 findings and 5 of the 6 criticals, which is why they are required rather than encouraged. Run the five truth domains for Discovery only when a candidate's entry or seasonality could eliminate it. Verification splits into five because the domains share no state, and because one pass asked to check all of them at once gives each a fifth of its attention — which is how a dinner gets booked at a restaurant that closed three hours earlier. Fan them out when the runtime offers it (Workflow or parallel Agent calls in Claude Code, onecodex execchild per domain in Codex); when it does not, run the five as separate sequential passes rather than one combined prompt. The benefit is concentration, not wall-clock, so sequential-but-separate keeps it.
Context-resolution order
Resolve every planning choice in this order: the user’s explicit current-trip answer, then a compatible stable profile default only when that current field is empty or unspecified, then researched destination/route feasibility. Never infer how far the traveller wants to go from nationality, residence, language, or currency; trip_geography.scope is the current-trip authority. Nationality and residence status answer a different question — what entry a given destination requires — and never set the scope. Use selected current-trip transport modes to select the research and booking branches. Apply saved self-drive, seat, map, and booking preferences only when compatible with the actual destination market and the current-trip selection. If an explicit trip scope conflicts with a named destination, surface the conflict and ask the smallest clarification instead of silently changing either value.
Work mode
Choose the mode before researching:
| User state | Mode | Required result |
|---|---|---|
| No destination, or only a broad continent | Discovery | Generate, filter, and rank destinations. |
| Country/region named but city not chosen | Constrained discovery | Compare suitable subregions/cities before planning. |
| Destination deliberately selected | Construction | Build a feasible trip plan and budget. |
| Existing plan plus a new constraint | Incremental replanning | Change only affected elements and show the impact. |
Do not collapse Discovery into Construction. A user who says “I have seven days and €1,500” needs destination options and trade-offs, not an invented day-by-day itinerary.
Choose the verification tier here too, from the plan's own fields — never from how thorough you feel
Construction has two tiers, and picking the wrong one is expensive in one direction and dangerous in the other. Decide once, at this table, and say which tier you chose.
Light — four blocks: sights_and_hours, transport, consistency, completeness. Allowed only when every one of these holds: the traveller stays inside their country of residence or the plan's entry_context.status is not_required; no flights, ferries, rental cars or ticketed rail/coach/ferry legs; trip.traveler_constraints.allergy_severity is none or preference and max_continuous_walking_minutes is null; and the trip is three nights or fewer in one city. Roughly 300k rather than 700k. check_plan_consistency.py computes this from the plan's own fields, so do not argue with it — read what it printed.
The three that drop out drop out for a reason, not to save money: entry re-litigates a fact rule 5 of the research budget forbids re-litigating; booking_and_lodging verifies whether dates are sellable and whether search URLs prefill, and a light-tier trip by definition carries no bookable transport product for that to bite on — the moment a ground_transport card exists it asserts a fare, an availability status and a search URL, which is exactly that domain's subject, and the tier is lost; seasonality matters where the plan schedules a sunset or depends on a seasonal service, and a two-night city break with indoor anchors does neither. The four that stay are the ones that caught real defects: opening hours are weekday-keyed and wrong hours close a door in the traveller's face, a city break is mostly local transport, and the two auditors need no network at all while producing, in the measured run, 27 of 55 findings and 5 of the 6 criticals.
Full — all seven blocks. Everything else, and specifically: any flight, ferry or rental car; any entry question that is not already settled; a severe allergy or a stated walking cap, because those are the constraints whose violation is a medical or a stranding risk rather than a disappointment; four nights or more; more than one city.
When in doubt, full. The light tier is a floor for the genuinely simple trip, not a default — and a plan that qualifies for it today stops qualifying the moment a flight or an allergy enters, so re-check the tier after any replan.
1. Collect the initial profile progressively
The loopback HTML form is the intake path. Chat questioning is not an alternative you may choose — it is a fallback the traveller chooses, by declining the form. For a first-time traveller, or any traveller without a valid reusable profile, your first action is to start python scripts/start_intake_workflow.py --assistant auto in the background (see the background rule above — run in the foreground it blocks until submission and the link never reaches the traveller), give the traveller the printed link, and wait for its sequence: one-time profile form when needed, then current-trip form, then TRAVEL BUDDY TRIP INPUT: . Because you are an assistant already driving this workspace, auto will not launch a discovery task for you — that path is yours to continue, from that file, in this session. Do not repeat the questions as a long prose questionnaire or instruct the user to type “continue”.
None of these is a reason to switch to chat, and each has been used as one: the form feels slower; you already have most of the answers; the traveller seems in a hurry; you would rather not manage a background process; chat feels more natural in this harness. Offering chat instead of the form, or asking "form or just tell me here?" as if the two were equivalent, is itself the defect — the traveller cannot weigh what the form does that chat does not. Skipping it loses the intake server's outright rejection of document, payment, password and exact-address fields; its refusal of a destination scope that contradicts the work mode; the profile's never_recommend exclusions and dietary needs prefilling into this trip's answers; and the saved intake file that check_shortlist_consistency.py --intake computes the hard-constraint roster from — without it that gate refuses to run at all unless you pass --no-intake, which stamps a NO INTAKE banner saying the shortlist was never tested against the traveller's stated constraints. If you genuinely cannot run a background command in this harness, say exactly that to the traveller and let them pick; do not decide it for them by never mentioning the form.
Chat intake is legitimate on exactly two conditions: the traveller declined the form (or declined profile storage), or they already supplied the information another way. Both are recorded, not remembered — the plan carries intake_context naming the method, and for chat_fallback the traveller's own words declining it plus the date. save_trip_deliverables.py refuses to write any plan whose intake_context is missing, invented, or unevidenced, and there is no bypass flag, because the three methods already cover every legitimate route. Retain chat-collected facts only for the active task.
First-turn essentials
When a consented profile is available, first summarize only the relevant saved constraints and ask whether anything changed. Do not re-ask confirmed stable fields. The HTML trip form must collect or confirm these seven fields before claiming a destination is a strong fit. First ask one yes/no: does this trip need a visa the traveller does not already hold? Do not ask "domestic or cross-border": geography is a bad proxy for entry burden, and it misfires for exactly the travellers it matters most to — someone holding a member-state residence permit crosses into the Schengen area with no visa at all. Do not ask about visa effort either. Effort only matters to someone who still has to apply, and asking it first spends the expensive research on a traveller whose own passport had already settled the question.
The two answers are different constraints, not two points on one scale:
- No — I can already enter what I want to enter. Collect two fields and skip the rest of the entry panel:
feasibility.held_entry_documents(what they enter on — a held multi-entry visa, a residence permit, visa-free, or simply being at home), andpassport_validity_status, which is still required here. A held visa does not make an expired passport board a plane, and this answer also covers travellers who are leaving the country, so the domestic opt-out (not_applicable_domestic) must be chosen rather than assumed. Setentry_status: traveler_asserts_can_enter. The document string also constrains destinations: candidates are limited to what it actually admits them to, so this answer is a hard filter on the shortlist, not a free pass. - Yes — I am willing to apply. Now the effort sub-question is worth asking (e-visa/visa-on-arrival only, or a full application), and only now collect per-traveller identity and a yes/not-sure/needs-renewal passport-validity confirmation.
The reason this ordering matters is measurable. A real run researched a complete Japan visa procedure for a PRC passport — consular jurisdiction, designated-agency rules, fee schedule, processing times, roughly 100KB of output — and the traveller's next message was "我有签证". One yes/no, asked first, deletes that entire branch. Entry burden follows from destination country × traveller status; status lives in the profile (identity_and_language.residence_status), not in a per-trip question. Always collect maximum one-way journey time, applicable climate constraints, and transport modes—including high-speed rail, conventional/night rail, intercity bus, ferry, flights, and self-drive where relevant. Accept rough answers and mark them as approximate.
- Starting point — current city and country; acceptable departure airports or willingness to use a nearby airport. A city is enough; never ask for an address.
- Travel window — exact
start_date/end_datewhen the traveller has them, otherwise month/season plus duration; date flexibility; and any fixed commitment the trip must fit around (a return-to-work date, a wedding, an event). Exact dates are authoritative: a Construction task cannot start without them, so never downgrade a supplied date pair to a month. - Travel party — solo/couple/group, number and relevant ages; any mobility, health, child-care, or accessibility needs; and dietary or religious food restrictions. Dietary needs are a hard constraint on every meal recommendation, not a nicety: never leave
feasibility.dietary_or_religious_needsempty by assumption. - Budget — always collect a per-person range, currency, target versus absolute cap, and whether it includes transport, lodging, food, activities, insurance, and visas. Derive a party total only as a separately labeled calculation; never mix it into the user’s stated range.
- Destination scope — ask which is true: a fixed country/region, an approximate continent, or no destination yet. A
fixedoranchoredscope must name at least one actual place; a fixed scope with no named destination is blocked, not a Construction task. - Trip purpose — leisure, sightseeing, food, outdoors, family, visiting people, a celebration, or work-adjacent. One answer changes what a good day looks like more than most preference fields.
- Experience direction — ask the user to choose natural, human/cultural, or a balance, then select 2–4 specific scenery/activity types and rank the top two. Use the taxonomy in references/initial-intake.md; allow free-form answers.
After the form returns or the user answers, read the saved intake and summarize it in a compact “What I heard” block. Label unknowns and assumptions. Treat the saved budget range as per-person; show any party total only as an explicit calculation. Do not silently turn “October” into fixed dates or “Europe” into a visa-safe region.
Second-turn filters
Ask these only when they can change the short list or feasibility. Prioritize the unknown with the greatest expected impact.
- When the trip may leave the country of residence: each traveller's passport nationality, country of residence, residence-status category, and whether every traveller’s passport stays valid at least six months past the trip (
valid_through_trip,not_sure, orneeds_renewal); visa tolerance, which is derived from the scope answer rather than asked again. Ask for the status category, never a document number, image, or expiry date. Do not request any of it, or treat it as a blocker, when the traveller is staying inside their country of residence. - Maximum one-way travel time, tolerance for connections/overnight flights, preferred cabin/airport, and reluctance to drive.
- Climate and season: preferred temperature, beach/swim need, rain tolerance, snow/heat avoidance, and whether weather is a deal-breaker.
- Travel rhythm: slow/deep versus multi-stop, rest days, nightlife, early starts, guided tours, and willingness to self-drive.
- Ground transport and delivery: public transport versus self-drive, rental-car need, driving-license/age constraints if relevant, luggage, and the preferred final-page language/currency.
- Regional service access: usual map and booking apps, any services to avoid, whether Google services work normally without a workaround, and non-sensitive booking limitations (for example “avoid channels requiring a local phone”). Ask only when the destination or accessibility is not already clear; never request account or payment information.
- Comfort and risk: lodging level, crowd tolerance, language independence, safety concerns, dietary requirements, and connectivity/work needs.
- Explicit avoid-list: activities, environments, countries, transit patterns, or costs the user does not want.
When several details are missing, ask at most three high-impact follow-ups in a turn. If the user prefers not to answer, proceed with conservative assumptions and say how they may alter the ranking.
Convert answers into decision-ready fields
Record each value as one of hard, strong_preference, nice_to_have, avoid, unknown, or assumption. Preserve the user’s original wording alongside the normalized value. Start from templates/trip-profile.json for the active-trip structure; merge consented stable values from the reusable profile only after stating the applied fields.
Read references/initial-intake.md before designing a multi-question intake or interpreting the natural/cultural preference branches. Read references/regional-service-routing.md before selecting map, transport, or booking providers.
2. Discover and evaluate destinations
For Discovery and Constrained discovery:
- Generate a diverse candidate pool from the normalized profile. Do not prematurely optimize around famous destinations or one transport hub.
- Apply hard filters first: calendar feasibility, entry feasibility, reachable travel time, essential accessibility needs, clear climate deal-breakers, and a conservative budget baseline.
- Research each surviving candidate using current sources. Obtain comparable evidence for transport, typical lodging/food/local transport costs, seasonal conditions, entry requirements, safety/health notices where relevant, crowding/seasonality, and fit with the user’s requested experiences.
- Normalize price estimates to the user’s currency and state the date range, party size, inclusions, and uncertainty. Do not compare a flight-only figure with an all-in figure.
- Score only candidates with sufficient evidence. Keep the score explainable, retain uncertainty, and record why excluded options were removed.
- Present only the best 3–5 options, unless the user explicitly requests the broader pool. Include one credible alternative with a different trade-off when useful.
Constraint-conflict exit
If no candidate survives the hard filters, stop before scoring. State that no recommendation is currently feasible, name the smallest set of conflicting constraints, and ask the user which one may relax. Offer conditional examples only as “possible if X changes”; never disguise an infeasible destination as the winner.
Write the shortlist as JSON — templates/discovery-shortlist.json is the envelope and templates/destination-evaluation.json is one candidate inside it — and run python scripts/check_shortlist_consistency.py --intake /plans/intake--.json before presenting it. --intake is not optional: with neither it nor --no-intake the gate refuses to run, because omitting it used to print an accurate note and exit 0, and an exit 0 is what an assistant reads. It computes the hard-constraint roster from what the traveller actually declared and requires every candidate to answer each one — the check that catches a winner that cleared the four constraints someone remembered and was never tested against the fifth. --no-intake runs without it when no intake file exists and prints a NO INTAKE banner; when you use it, say so as you present the shortlist and never describe a winner as having cleared the traveller's requirements. A roster written by hand into the shortlist cannot do this — it reports full coverage on exactly the run that motivated it. Declare outcome.state (shortlist / constraint_conflict / blocked) on every Discovery artifact: an unfinished filter and a real conflict produce the same empty pass set, and only one of them justifies asking the traveller to give up a requirement. A shortlist is a comparison, and its worst defects live between candidates rather than inside one: each record can be impeccable while the ranking is meaningless — one figure priced per person beside one priced for the whole party, or one covering flights beside one covering everything. The traveller picks the smaller number and it was never the smaller trip, and nothing inside either record is wrong. So every priced candidate declares cost_estimate.cost_basis: per_person beside its own figure rather than relying on one declaration at the top, states the same currency and party size as the shared trip_context, and accounts for every category in trip_context.budget_scope — priced, or declared in not_applicable_categories / unverified_categories with a reason, because a silently absent category is indistinguishable from one nobody priced. A candidate shown without a figure gives not_priced_reason. Arrival modes (flight, rail, ferry, bus, car) count as one cost surface, so a rail-reached candidate compares against a flown one with no declaration from either. The gate also refuses a winner that fails a hard constraint or whose filter never ran, and a winner named when no candidate was feasible — an empty feasible set is an outcome, not a scoring error.
Read references/decision-and-research.md before the first research call of either mode, not only before scoring: besides the scoring and evidence rules it carries the record-once habit that decides whether a page gets opened once or twice, and a Construction task that skips it meets every required field at the end, when the pages are closed. Use it for scoring, research, evidence, and output rules. Start each candidate record from templates/destination-evaluation.json.
Decision-support response
Lead with a recommendation, then a compact comparison containing:
- destination and fit/confidence;
- comparable estimated all-in cost and key assumptions;
- strongest reasons it fits;
- principal compromises or risks;
- important evidence and its date;
- the one condition most likely to change its rank.
Explicitly answer “why this, not that?” and “what was filtered out, and why?” when those questions matter. Do not hide visa, weather, transport, or budget compromises behind a single score.
3. Construct the trip only after the decision is ready
Once a destination is selected or intentionally fixed, research and assemble transport, lodging areas, local mobility, activities, daily pacing, meals, reservations, and a line-item budget. Ensure that every daily route is geographically and physically feasible. A city stay of three or more days must include at least three destination-specific experience anchors across at least two days when they fit the traveller’s stated interests; do not substitute a list of famous sights for real fit.
Set a regional service context before producing a live link: trip market, normal Google-service access, primary map provider, checked alternatives, local transport authorities, booking-platform rationale, and a non-sensitive access check for every booking category shown. A mainland-China route uses a verified Amap primary link unless the user asks for and can access another verified local provider; do not render Google Maps as its default. For multi-country trips, select by route/segment and show the provider change.
Separate:
- essential bookings / timing-sensitive items;
- recommended options with price ranges; and
- flexible, low-commitment activities.
Use live sources for bookable or time-sensitive claims. If live data is unavailable, give a planning range and a verification checklist, not a false confirmation.
4. Deliver a booking-ready final HTML page
After the destination and trip inputs are decision-ready, create one self-contained, responsive HTML page rather than an unstructured prose itinerary. A fresh skeleton fails its own gate on purpose, and the errors are a worklist, not a defect
list: one line per card nobody has filled in yet, plus the walking figures that have to be
derived. A four-day skeleton reports about thirteen. They used to be thirty-eight, because the
content rules ran on placeholder values and reported things like "rated 0/5, below the 3.5/5
floor. Replace it" about a restaurant nobody had chosen — an error that sends the author hunting
for a problem that does not exist is worse than no error, because it costs a round trip and
teaches distrust of the gate. Content rules now stay quiet on a card that still carries a TODO:
marker, and validate_trip_html.py refuses to ship one regardless, so nothing is lost.
When the plan follows an intake file, start it with python scripts/new_plan_skeleton.py --from-intake /plans/intake--.json > plan.json rather than retyping the flags. It carries across origin, dates, party, currency, budget.cap_per_person, and the two list fields of trip.traveler_constraints (dietary needs, mobility notes), printing every field it copied and every one it could not derive. It does not set allergy_severity or max_continuous_walking_minutes — the intake collects those as prose and nothing converts a sentence into a severity enum or a number, so the skeleton leaves them at none and null and says so on stderr. Type them yourself before delivering: the verification tier reads exactly those two fields, and a plan that leaves them at their defaults while its own prose says 「anaphylactic」 is a plan claiming there is nothing to avoid. That matters more than the typing it saves: built from flags alone, cap_per_person stays null and the budget cap-overrun check has nothing to compare against, and max_continuous_walking_minutes stays null so every per-leg and per-activity walking check silently no-ops — the traveller's three most dangerous constraints collected by the form and then measured by nothing. Without an intake file, the flag form still works: `python scripts/new_plan_skeleton.py --start --end
相关技能
把自然语言描述转为结构化 JSON,并由 mcp-diagram-generator MCP 服务生成 Draw.io、Mermaid 或 Excalidraw 图表文件。
按用户明确指令,在得到大脑(Get笔记)中保存、搜索并管理笔记与知识库。
在本地磁盘以分类纯 Markdown 文件保存需要长期留存的事实,与智能体内置记忆并存。
通过托管 OAuth 访问 Microsoft Graph Excel 接口,读写 OneDrive 中的工作簿、工作表、区域、表格与图表。
从 AdMapix API 拉取广告创意、应用、榜单和收入预估等数据,原样返回结构化 JSON。
dong845 的更多技能
浏览全部技能A personal AI companion that gets to know ONE person over time and supports them through four lenses — 命理/destiny charts (八字 BaZi 四柱/命盘), daily fortune & journaling, career fit, and relationship reflection — grounded in a private on-device profile + journal.
Help a user find, judge, apply for and rehearse for jobs. Four modes: discover (what is out there worth looking at), assess (whether this posting is worth applying to), apply (build and pressure-test the application), interview (rehearse and debrief). (https://github.com/addsumtech/job-hunt)