An AI agent that had never seen our tooling just planned a real trip on live inventory: round-trip flights from Washington Dulles to Barcelona, seven nights in a hotel, one traveler with a passport and frequent-flyer numbers, itemized at $3,931.21 and verified bookable with a dry run. Twenty-six commands, just under seven minutes, starting from "what is this CLI?" An agent that already knew the tool did the same job in two minutes and forty-one seconds.
A quote is not a demo. Behind that number is everything a real booking needs: seats on a real airplane, a room held for real dates, a traveler whose passport and loyalty numbers are already where the airline and hotel expect them. Carrying all of that end to end, with any agent you care to run, is what we spent the year building.
This post is the story of how we got here. Fittingly for a CLI, it runs like a session.
$ voyagier login
Earlier this year I caught the agent bug. For months I had been running an AI agent for my own work, a walrus named Wally who has become something of a Voyagier mascot. Wally does not just answer questions. He operates: reads systems, runs tools, comes back with results. Once you have watched an agent work like that, you look at every piece of software differently. You stop asking "what does the interface look like?" and start asking "what would my agent need to plug into this?"

This is Wally, who we interact with via terminal/SSH and Slack.
The software in this case is a travel platform. Voyagier's advisors plan trips in our web app: live inventory, traveler manifests, flights and hotels that lock and book. I wanted Wally to do what I do in that app. Build a customer trip on real inventory, and plan it agentically, end to end.

We went looking to see if this already existed: a tool an agent could drive from search all the way to a booked trip, flights and hotels together, travelers and payment included. The closest things we found could search, or could book a single flight. Nothing carried a whole trip. It didn't exist. So I started building it on top of the modern booking infrastructure our engineers have been working on for the past year.
Early attempts, chatbots bolted onto the product and MCP servers wired to raw APIs, fell short the same way: the agent could talk about the trip, but the surface was either too thin to act or too raw to act safely. What an agent needed was an instrument, purpose-built to be held by an agent, with the safety rails in the tool itself rather than in a prompt. That instrument became a command-line interface to our booking engine, the same engine our human advisors use. It is @voyagier/cli on npm. For months, its entire user base was our own agents.
$ voyagier plan-trip
Why a CLI, and why does the "for agents" part matter to me personally? Two reasons.
First, I believe open-source AI is the future, and the agent ecosystem is moving too fast to bet on one assistant, one framework, or one vendor. The bet I am comfortable making: you should be able to bring whatever agent you want to our platform. Your agent, your model, our inventory and booking engine. A CLI is the most durable way to enable that, because every agent framework in existence can run a shell command. For everything else, the same CLI runs as an MCP server.
Second, the work itself. We started this company because we are good at booking complex travel. A complicated trip means holding dozens of constraints in working memory at once: fare rules, passport expiries, split rooms, a hotel that is perfect except for the three nights it is not available. Our booking team does this well, and it is the most cognitively expensive thing we do. It also does not scale by willpower, and accuracy is hardest to maintain exactly when the constraint count peaks. Synthesis across many constraints at once is the thing LLMs are turning out to be very good at. So the division of labor we built into the tool: the agent holds the constraints, the human keeps the judgment, the client relationship, and the veto. Our own team is the first beneficiary. More trips per advisor, fewer 11pm detail checks, and the mistakes caught by a machine that never gets tired of cross-checking.
$ voyagier search flights --json
Dogfooding a tool on your own agents is humbling in a way no design review is. Every session produced a friction log, and the friction was never where we expected. Three lessons that shaped the tool:
Agents drown in exactly the output that looks thorough. Early versions returned super data dense payloads that I thought would be useful. I am talking megabytes of flight data in JSON. It burned out the model we were using at the time (GPT-OSS 20B) basically instantly. The fix was not better docs, it was a compact envelope. Here is the Barcelona search from this week's run:
{
"selectionId": "a30b0a9b…",
"returnSelectionId": "1cfbd8c1…",
"isRoundTrip": true,
"optionCount": 200,
"topOptions": [
{ "index": 1, "optionId": "312038b0…", "summary": "IAD→BCN · UA · $884.73 · PT7H45M" },
{ "index": 2, "optionId": "574ed6ee…", "summary": "IAD→BCN · UA · $888.03 · PT10H15M" }
],
"note": "Showing top 10 of 200 options — re-run with --full for the complete dump, or refine with --sort/--max-stops."
}200 options exist. The agent sees ten summaries, the ids it needs, and a documented path to the rest.
Errors an agent can branch on beat errors a human can read. Every failure returns the same JSON shape against a stable table of codes, so an agent that reads PRICE_CHANGED or AUTH_FAILED can decide its next move without parsing prose. Unstructured errors were where runs went off the rails; structured ones fixed more agent behavior than anything else we shipped.
Agents do not need more data. They need to know what is left. Trip planning has state: travelers, searches, selections, fare picks. On our platform that state lives in the trip's blueprint, the structure that knows what a bookable version of this trip requires. Instead of making the agent reconstruct that state, every mutation reads the blueprint and returns the current blockers with copy-pasteable fixes. In an early test session, when our agent added a traveler without a gender (required by airlines at ticketing), the next select told it exactly this:
{
"kind": "TRAVELLER_DATA",
"message": "Blog Tester is missing gender (required for checkout)",
"nextStep": "voyagier travellers update 0a81cb64… --gender <M|F|X>"
}Agents follow this loop well. Humans, it turns out, like it too. That became a theme: almost everything we built for agents made the tool better for people.
$ voyagier agent-docs
By June we thought the surface was solid, so we ran the experiment that mattered: a completely fresh agent session. No source code, no docs beyond what the tool prints, no memory of ever seeing it. One instruction: plan and price a real trip.
That first cold run completed the loop, then did something more valuable than succeeding. It complained, precisely. A search output that flooded its context. A blocker that pointed at nothing. A status command and a booking check that disagreed about readiness. That friction log became the fix list we worked through, almost line for line. A cold agent is the harshest usability reviewer you will ever recruit, because it cannot fill gaps with charitable assumptions, and it files its complaints in writing.
This week we re-ran the experiment against the published package and raised the bar: a real international trip. Round trip Washington Dulles to Barcelona, seven nights in a hotel, one traveler carrying a passport, two frequent-flyer memberships, and a Marriott Bonvoy number, all attached in a single command. The cold agent went from zero knowledge to a verified $3,931.21 quote in twenty-six commands and just under seven minutes: United nonstop economy at $884.73, and, unprompted, Le Méridien Barcelona, which it picked in part because a Marriott property meant the traveler's Bonvoy number would apply. The blueprint did the guiding. At every step the plan knew what was still missing, and every response pointed at the next unmet requirement, down to the copy-pasteable command. Because the traveler was complete from the start, the checkout blockers that catch humans never fired at all.
Then we timed what repeat use looks like: same trip shape, fresh plan, but an agent that had already read the docs. Seventeen commands, 161 seconds. Under three minutes for flights plus a hotel on live inventory, and most of the residue is supplier API latency, not agent hesitation.
Here is the condensed cold session, real ids and all:

Its verdict, verbatim:
"The
select --waitsnapshot with runnable nextSteps is the best part of the UX — I mostly just executed what the tool told me to run next. Total: 26 commands, ~7 minutes, zero dead ends that the docs didn't already have an answer for."
It still found friction (a warning line that corrupts JSON pipes, mirrored room selections that made it guess), and that is now on the fix list. The loop continues. That is the point.
$ voyagier book --dry-run
The hard design problem was checkout. A tool that can spend someone's money needs to fail safely by default, and in travel, "the price changed mid-conversation" is the ordinary case. Fares reprice constantly.
Our answer is a price-gated checkout. Mechanically it is simple, a compare-and-set on the total, and the simplicity is the feature:
$ voyagier book d860398a --dry-run --json
{ "chargeableSubtotal": 3931.21, "blockers": [], "message": "Would create Stripe Checkout Session",
"nextStep": "voyagier book d860398a --expect-total 3931.21" }
$ voyagier book d860398a --expect-total 3931.21
A real booking refuses to run without a price expectation. If the fare repriced between the dry run and the commit, the command fails closed with PRICE_CHANGED and nothing is charged. The agent surfaces the new price to a human, or re-verifies and tries again. Either way it cannot pay a price it never stated.
Two related decisions came from the same thinking. Commands that reach a real person, like emailing a client a payment link, require an explicit confirmation flag: the agent states its intent twice before a human gets an email. And actions are addressed by id, never by display text. Hotel names and fare descriptions come from our contracted suppliers, which makes them a plausible vehicle for prompt injection, so the integration docs mark supplier text as untrusted and tell agents to act on ids. We would rather document the attack surface than hope nobody notices it.
We do not claim agent checkout is risk-free. We claim the failure modes are boring, which is the realistic goal.
$ voyagier mcp
Opening the tool to any agent was mostly a matter of writing down what our own agents already knew. If you are pointing an agent at Voyagier, this is the map:
- Docs:
voyagier agent-docsprints the full integration contract: JSON shapes, error codes, known quirks. A cold agent reads it at the start of a session instead of relying on whatever its operator pasted into a prompt. The cold run above credits this one command for most of its speed. - No install:
npx @voyagier/cliruns anywhere, including CI jobs and sandboxes. - MCP:
voyagier mcpserves the same surface, same commands, same error codes over stdio. It iscom.voyagier/clion the official MCP registry. - Oversight: every plan an agent builds is a normal trip plan at voyagier.com, the same advisor view where this story started. A human can look over the agent's shoulder at any point. That is a design decision, not an apology.
That last point reflects a belief: travel is heading toward a multi-surface world. Agent-only, web app, agent-plus-advisor, or a phone call, these are not competing products. They are views of the same trip, backed by the same engine, and you can switch between them mid-plan. Nothing requires it, but we encourage CLI users to open their plan in the web app at least once. We spent years making it beautiful.
The agent does not start from a blank slate, either. Trip Importer brings your past trips onto the platform, and Blueprint distills your habits into Traveler DNA, the profile that informs every choice the engine surfaces, from flight times to neighborhoods. Because every surface runs on the same engine, an agent planning your next trip inherits everything the platform learned from your last ones. The CLI gives an agent hands. The rest of the platform gives it memory.

$ voyagier --help
Access is by invitation right now. Agents transact on real inventory with real money, so we onboard deliberately rather than opening a signup form. Everything short of book spends nothing: search, plan, quote, and dry-run are free to explore.
- Request access: voyagier.com/agents
- Install:
npm i -g @voyagier/cli(ornpx @voyagier/cli) - Point your agent at:
voyagier agent-docs - Agent-readable summary: voyagier.com/llms.txt
- MCP:
npx -y @voyagier/cli mcp, or findcom.voyagier/cliin the MCP registry - OpenClaw users:
clawhub install voyagier-cli










