Client Hospitality AI Platform
Guests can get property information, check availability and report maintenance problems through an AI assistant. It answers routine questions, guides booking requests and turns reported problems into tracked work for staff, taking over repetitive information lookup and issue recording while keeping permissions and approvals with the business.
The client’s platform handled two connected jobs: routine guest support and staff coordination. A guest could ask for Wi-Fi instructions, look for a suitable property or report a leaking shower. The assistant used the property and reservation records to answer, or created a maintenance issue with a recorded next step for the operations team.
The client needed support for both prospective and staying guests, alongside an assistant for its operations team. The system connected those conversations to the existing reservation, property and maintenance records. Staff could review what the assistant had done and investigate failed requests through a control portal.
The core delivery was one shared runtime for two audiences, with configurable skills, explicit booking and issue flows, durable run state and an operator workflow connecting traces to evaluation.
The problem: helpful language was only the first step
A guest asking for the Wi-Fi instructions needs accurate information for the correct stay. A guest reporting a leaking shower needs an issue recorded, a responsible person or escalation path, and an honest account of what happens next.
Those requests can look similar in a chat interface while requiring very different operational behavior. A polite response that promises a repair without creating the corresponding work makes the second situation worse.
The host copilot brought a different authority boundary. Staff needed access to operational information and actions that should not be exposed to a guest. The operator maintaining the assistants needed another set of controls: inspect a run, change configuration, test behavior and understand cost.
| User | Needed outcome | Evidence the product had to use |
|---|---|---|
| Prospective guest | Suitable properties for explicit dates and occupancy | Search criteria and current calendar results |
| Guest with an active stay | Relevant property or reservation information | Authorized stay and property context |
| Guest reporting an issue | A recorded issue and accurate next-step status | Task, assignee, appointment and escalation outcomes |
| Host or operations team | A scoped operational view and appropriate actions | Current backend records and allowed capabilities |
| Operator maintaining the AI | An inspectable explanation and a controlled improvement path | Configuration, prompt assembly, tool results, traces and evaluations |
Our process: work backward from the operational result
1. Translate workflows into concrete scenarios
The requirements were organized around a starting state, a user request, allowed actions and a completion condition. That made the expected behavior specific enough to implement and evaluate.
For example, a maintenance scenario had to resolve the guest’s stay, check for an existing issue, record or update the right work and report the actual dispatch status. “Be helpful” could guide tone, but it could not express those completion conditions.
I connected these client workflows to the runtime’s boundaries: who the actor was, what context the assistant needed, which tools it could use and what evidence would justify its final response.
2. Keep the hospitality backend authoritative
The existing backend already owned reservations, listings, tasks, messaging and payments. The agent service therefore integrated through internal APIs rather than recreating those business entities inside an AI framework.
The Python service owned agent execution, configuration and agent-specific state. The domain backend remained the system of record. This gave the integration a clear division: the harness could reason about an operation and retain its reference, while the backend determined the business record’s actual state.
3. Build the shared runtime and capability catalog
We developed a common execution path for the concierge and host copilot, with different personas and authority. Prompts, skills, tools, model settings and agent definitions became configurable resources. Each turn resolved the relevant capabilities and assembled the context required to use them.
4. Move mandatory operational steps into explicit flows
Booking and issue handling needed more structure than an open-ended model plan. We put the mandatory checks and state transitions into domain-specific flows, while the model interpreted the conversation and explained the returned outcome.
5. Build the operating surface alongside the assistant
The control portal brought configuration, playgrounds, run traces, evaluation and spend together. It gave the client’s team a way to see what reached the model, investigate a failure and compare a proposed change against a baseline.
Architecture: a harness around the model loop
The custom Python and FastAPI runtime sat between incoming conversations, model providers and the hospitality backend. PostgreSQL stored durable agent state and configuration. The Next.js portal exposed the operational controls.
Patterns from OpenClaw informed the harness and lifecycle boundary, while Hermes provided a reference for the surrounding agent components. Our implementation used request-local attempts and a typed event stream suited to a service shared across tenants.
The reason for a custom harness was the responsibility around the model: admission, routing, scoped context, tool policy, deadlines, approval state, result persistence and event recording. A successful model response was only one stage in that lifecycle.
| Boundary | Responsibility |
|---|---|
| Ingress and orchestration | Resolve identity, admit an event, route it and own the run lifecycle |
| Context and capabilities | Assemble persona, current facts, knowledge, history and allowed tools |
| Model execution | Run a bounded tool-calling loop through provider adapters or the gateway |
| Domain tools | Read or change business state through the hospitality backend |
| Durable state and events | Preserve conversation continuity, execution outcomes and operational evidence |
| Operator portal | Inspect configuration, reproduce behavior, evaluate changes and track spend |
One runtime, two authority models
The guest concierge and host copilot shared routing, context assembly, model execution and event recording. Their personas and allowed actions differed.
The implementation supplied account and tenant scope from trusted runtime context, stripped protected scope keys from model arguments and checked tool allowlists at execution. Guest flows also used the resolved stay set and focus. Backend account-scoped access remained the final authority on the domain record.
This prevented permission from becoming only a sentence in the prompt. The assistant could interpret a guest’s request without receiving the ability to select a different tenant or grant itself a new capability.
The runtime also included confirmation behavior and a durable approval path. An action waiting for approval was represented as a distinct outcome. Conversational confirmation and an authorized approval remained different concepts; the detailed series develops the stronger action-binding and resumption checks those workflows require.
Capabilities were composed for each turn
The capability catalog included versioned prompts, skills, tool definitions, model settings and agent configurations. A request selected relevant skills, context and tools rather than exposing every operation on every turn.
Composition deduplicated shared instructions and tool sets, while authority limited the effective capability set. Prompt assembly combined stable persona fragments with fresh property knowledge, live facts, host rules and conversation state.
The operator playground displayed the assembled input and exposed tools. That made an apparently simple question—“why did this prompt change have no effect?”—answerable. The team could inspect whether the skill was selected, the fragment was included and the tool survived policy filtering.
It also avoided creating a new autonomous agent for every intent. Booking, issue reporting and reservation questions could be capabilities of the same concierge when they shared audience, authority and conversation continuity.
Booking: preserve the conversation, recheck the facts
The booking flow separated property discovery from calendar verification. A property matching a description was a candidate; availability required a current calendar result for the requested dates and occupancy.
Conversation state preserved earlier options and their ordinals. That mattered when a guest referred to “the second one” or returned to a previous search after changing dates. The selection had to resolve against the options actually shown, with their associated context.
Before returning a checkout link, the flow rechecked availability. The response could then describe a checkout opportunity accurately. A checkout link remained distinct from a confirmed reservation, whose state belonged to the booking backend.
The division of work was deliberate: the model handled flexible language and comparison; the application owned remembered options, fresh checks and the meaning of the resulting booking state.
Maintenance: a task is not the same as a dispatched repair
Issue handling connected a guest complaint to a scoped stay, duplicate checks, staff availability, task ownership and escalation. The returned result distinguished a proposed task, an assigned person, a booked slot and notification evidence.
An illustrative request makes the difference clear: a guest says, “The shower is leaking. Can someone come this afternoon?” A useful response depends on what the operation actually returned. A task with an assignee but no appointment does not justify promising an arrival time. An escalation record does not establish that a staff notification was delivered.
The implementation’s explicit flow reduced dependence on the model remembering every mandatory step. It also made backend semantics part of the product contract: an accepted request, suggested action and completed mutation could not all be treated as the same success.
Longer operations could be handed to asynchronous workflows. Their acceptance was separate from eventual completion, so the conversation and follow-up path needed a correlated workflow identity and an accurate status.
Reliability involved identities, state and side effects
The runtime organized execution around tenant, session, run and attempt identities. A tenant defined account scope; a session grouped conversation continuity; a run represented admitted work; an attempt represented an execution envelope.
Inbound idempotency sat ahead of classification and paid model work. Durable run and conversation state supported inspection and continuity, and lifecycle outcomes distinguished completion, failure, timeout and waiting for approval. Stage timings helped separate routing and context costs from the model loop itself.
A durable outbox supported retryable projections such as backend audit delivery. This addressed a different risk from duplicate inbound messages. A retryable audit record did not, by itself, guarantee exactly-once business mutations.
Those distinctions shaped the reliability work: admitting an event once, preventing duplicate domain actions and delivering audit evidence were separate boundaries. The technical series develops crash recovery and stronger release checks around them, including the points where a backend receipt must remain authoritative.
The control portal made the system operable
The Next.js portal included prompts, tools, skills, agents and models; a multi-turn playground; tool-contract and deployability views; run traces; evaluation datasets and runs; offline reports; observability; and spend.
Its value was the connected investigation path. An operator could inspect a conversation, examine route and prompt assembly, inspect tool results and identify the configuration responsible for the behavior. A persisted run could then become an evaluation case.
That brought the product’s improvement loop into the same operating surface as the assistant. A bad response did not have to remain an anecdote or an isolated log entry.
Evaluation checked behavior and business evidence
Evaluation combined deterministic assertions, configurable model judges, human verdicts and baseline comparisons. The two kinds of checks served different purposes.
A deterministic check could establish whether a tool was called, whether a returned record existed or whether a forbidden action occurred. A judge or human reviewer could assess clarity, appropriateness and whether the response accurately described the evidence.
The distinction was especially valuable for false completion. A response could sound successful while the backend contained only a proposal or an unresolved task. Evaluating the final sentence alone would miss the failure.
The platform tracked agent cost and judge cost separately. That made evaluation visible as an operating expense and helped connect quality changes with their latency and cost consequences.
My contribution
My role was architect and developer, spanning the runtime, domain integration and operator experience.
- Workflow translation: turned hospitality requests into execution boundaries, required evidence and implementable booking and issue flows.
- Custom harness: worked on the shared runtime, request-local execution, capability composition and lifecycle behavior for the two assistants.
- Domain tools and state: connected conversation context to the existing backend’s reservations, properties, tasks and operational outcomes.
- Operator controls: developed the control portal and its connection to prompt assembly, tools, traces, evaluation and spend.
- Quality and iteration: connected observed behavior to repeatable scenarios and baseline comparisons so changes could be investigated and evaluated.
The work required moving between customer workflows, backend semantics and model behavior. The most important decisions often sat at their intersection: what the assistant could claim, which state was authoritative and how an operator could tell what happened.
Outcomes
The delivered capabilities included a shared runtime for two assistants, dynamic capability composition, explicit booking and maintenance flows, durable execution records, and a control portal connecting configuration to evaluation and cost.
Those are the concrete product outcomes. Operational savings and automation rates would need a separate, consistently defined before-and-after dataset; no such percentage is claimed here.
The broader result was an agent product with an operating model around it. Guest requests could be connected to backend evidence, and the client’s team had a way to inspect, test and change the behavior responsible for those results.
Explore the engineering in depth
Technical Stack
| Layer | Technology |
|---|---|
| Runtime | Python, FastAPI, Pydantic, Asyncio |
| State | PostgreSQL, SQLAlchemy, Alembic, Versioned configuration |
| Models | Provider adapters, LiteLLM gateway, Bounded tool-calling loop |
| Operations | Rails APIs, Booking and issue flows, Trigger.dev workflows |
| Control | Next.js, React, TypeScript, TanStack Query |
| Quality | Scenario evals, LLM judges, Human calibration, Runtime event traces |
How engagements like this are scoped and delivered: How I Work.