Travel assistant for NanoClaw: byAir flight notifications (delay, gate, connection risk, inbound aircraft delay, time-to-leave, arrival logistics), traffic-aware drive planning for in-person meetings (auto drive blocks + leave-by traffic rechecks), travel-booking gap checks, and nightly TripIt sync. Per-chat overlay plugin.
—
—
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
This skill is an action router — pick the step that matches the situation and execute only that step. Do not run other steps; do not parallelize.
The precheck (reconcile_sweep.py) plans and applies every Drive: block change — airport, meeting, and lodging drives — every ~30 minutes, diffing against the calendar and touching only its own blocks. It leaves legacy drive-planner / flight-assist blocks alone (you clean those up). Its contract — inputs, apply counts, the fail-closed no-wake payload on error, and the wake gating — lives in reconcile_sweep.py (module docstring, build_sweep_payload) and calendar_apply.apply_plan. Do not restate its logic here.
Run this after a cadence sweep that woke you (wake_agent: true). The precheck has already rendered the operator notice deterministically (render_notification in reconcile_sweep.py — the one-line templates and enumeration live there). Send data.message verbatim via mcp__nanoclaw__send_message, then finish.
Relay the string as-is: do not rewrite, summarize, add to it, or reference anything from a prior wake — each notice stands alone, composed only from this sweep's payload. If data.message is absent or empty, proceed silently and finish. Finish here.
Run this when the operator replies to a drive notification to skip one — "skip", "skip 1", "skip 2 and 3", "skip the Massage drive". Map each local index to the meeting NAME from the message you sent (index 1 = the first meeting listed); a bare "skip" refers to the single meeting just offered. Never surface an internal id — the operator only ever named the drive by its position or name. For each named meeting, invoke:
python3 /home/node/.claude/skills/tessl__drive-engine/skip_drive.py '{"summary": "<meeting name>"}'The script deletes that meeting's drive blocks and records a skip so no future sweep recreates them. It always prints a JSON result on stdout; read it (do not treat a non-zero exit as "no result"):
{"skipped": true, "meeting": ...} (exit 0) — confirm what you skipped.{"skipped": false, "unmatched": ...} (exit 0) — the name wasn't found; say so.{"skipped": false, "ambiguous": ..., "candidates": [...]} (exit 0) — several same-named meetings; ask the operator which when they mean, then re-invoke.{"skipped": false, "error": ...} (exit 1) — an operational failure (an unauthenticated gateway, transport error); tell the operator the skip couldn't be recorded and to retry. Exit 2 is a usage/JSON error in how it was invoked — fix the call.Reply in one message. Finish here.
Run this when the operator answers a drive-or-fly question the sweep asked about a trip with no flight booked — "drive", "fly", "we're driving", "I'll fly that one". Map the answer to the trip NAME from the message you sent; a bare "drive" or "fly" refers to the single trip just asked about. Never surface an internal key — the operator only ever saw the trip name. Invoke:
python3 /home/node/.claude/skills/tessl__drive-engine/answer_drive_or_fly.py '{"trip": "<trip name>", "answer": "drive"}'answer is drive or fly, nothing else. The script records the answer so it outranks the drive time from then on and the question is not repeated. It always prints a JSON result on stdout; read it (do not treat a non-zero exit as "no result"):
{"recorded": true, "trip": ..., "answer": ...} (exit 0) — confirm what you recorded. On drive, the next sweep adds the drives; on fly, the booking check reports the missing flight.{"recorded": false, "unmatched": ...} (exit 0) — the trip name wasn't found; say so.{"recorded": false, "ambiguous": ..., "candidates": [...]} (exit 0) — several same-named trips; ask the operator which when they mean, then re-invoke.{"recorded": false, "error": ...} (exit 1) — an operational failure; tell the operator the answer couldn't be recorded and to retry. Exit 2 is a usage error in how it was invoked — fix the call.Reply in one message. Finish here.
Run this when a block looks like an engine bug — a drive for a meeting you are travelling away from, a wrong-timezone block, a missing drive for a real trip. Send one message via mcp__nanoclaw__send_message naming the block's summary and leg identity (e.g. meeting_outbound mtg123 or airport_departure BNA-STN-...) and what looks wrong, so it can be fixed in code. Never edit the calendar by hand to compensate. Finish here.
.tessl-plugin
skills
check-travel-bookings
drive-engine
expertflyer
flight-assist
references
nightly-travel-sync
sync-tripit