A personal, chat-first short-term-rental operations app. The owner doesn't manage the portfolio through forms — they talk to a management agent that executes every change as an audited tool call, while the app's pages stay read-only views of state. Around that agent: a conversational concierge for guests, a prescribed checklist-based workflow that cleaning/maintenance contractors must complete and report on before approval, and reporting.
stayops contractor checklist on mobile — requirement-gated steps with photo evidence and a submit gate
The contractor's prescribed checklist on a phone — requirement-gated steps with photo evidence, and a submit gate that won't pass the job until it's complete.
Built for personal use (managing a handful of the author's own properties) and shared publicly in case it's useful to others running their own rentals. Single operator — not a multi-tenant product, no vendor marketplace, and no payment processing: bookings originate on the platforms (Airbnb, Furnished Finder) and sync in.
Status — owner surface live (M1). Contracts, backend services, all three surfaces, and the design system are built and verified. As of M1, the owner surface runs live end-to-end: real Clerk auth + route protection, live SSE agent transport, owner pages reading the live database, live two-way calendar sync, and a live-model merge gate. The guest and contractor surfaces still run against fixtures + a mock model pending their integration milestones (M2/M3), with reporting and polish in M4/M5 — see
docs/PLAN.md. 257 tests;next buildgreen.
Three token- or Clerk-gated surfaces, all rendered from the same A2UI component vocabulary:
- Owner (Clerk-gated) — a triage-first dashboard (what needs you / today / this month / recent activity), read-only Properties · Calendar · Jobs · Messages pages, and a summonable agent sheet. Every mutation goes through the agent; pages carry a "read-only · changes via agent" lock chip.
- Guest (tokenized link, no account) — a concierge landing + reservation details with a 24-hour access-info gate, house rules, and a message thread with the owner.
- Contractor (tokenized link, no account) — a work hub landing, the prescribed checklist (requirement-gated steps, photo evidence), and a message thread.
Under the surfaces:
- A2UI — a typed protocol streaming server-authored envelopes that render a frozen 12-component catalog inline in the chat and as the page surfaces. Props are Zod-validated at the dispatch boundary; an unknown or malformed component degrades to a safe fallback rather than crashing the stream.
- Two-way iCal sync — platform feeds are the dates authority (UID-keyed upserts,
last_hashshort-circuit, idempotent re-runs); a per-unit tokenized export feed publishes manual bookings/leases/blocks back out. Turnover work orders auto-create on checkout and auto-cancel when unstarted. - Server-enforced trust invariants — a submit gate that refuses a work order while any required photo/note/stock is missing; synced bookings immutable in dates/status (open only to annotation); and a confirm handshake that must precede destructive/financial agent actions. Every executed tool writes an audit row.
- Human messaging — real threads with author-only edit, soft-delete (tombstone, never erased), read state, and a cache-keyed AI thread summary whose claims tap through to their source messages.
- Eval harness — a golden owner-scenario suite whose
--dry-runvalidates the confirm-gating invariant class in CI without model calls.
See docs/FEATURES.md for the feature-by-feature map and .claude/verification-status.json for per-iteration verification.
Next.js 16 (App Router) + React 19 + TypeScript · Tailwind 4 + shadcn/ui · A2UI-rendered chat UI · Vercel AI SDK + AI Gateway · Drizzle ORM + Neon Postgres · Clerk auth · Vercel Blob (photo evidence) · two-way iCal sync + Gmail enrichment · deployed on Vercel. Full rationale in docs/PLAN.md.
Runs locally against a Neon Postgres branch with a seeded demo world. No live keys are required for the dev walkthrough — Clerk passes through when its keys are absent, and the agent/summary run on fixtures + a mock model.
npm install cp .env.example .env.local # set DATABASE_URL (a Neon connection string); the rest are optional for dev npm run db:push # apply the Drizzle schema to your DB npx tsx scripts/seed.ts # seed the realistic demo world (idempotent) npm run dev # http://localhost:3000
Dev-only harnesses: /dev/fixtures (every A2UI component from its fixture) and /dev/theme (the design tokens) — both excluded from production builds.
Other scripts: npm test (vitest) · npm run lint · npm run build · npm run evals -- --dry-run (model-free scenario/confirm-gating check) · npm run db:studio.
The owner surface's live wiring — SSE agent transport, real Clerk sessions, a live model through the AI Gateway, and owner pages reading the live DB — shipped in M1 (needs Clerk + AI_GATEWAY_API_KEY; see .env.example). The remaining integration work — the guest & contractor live surfaces (M2/M3, incl. Vercel Blob for contractor photo uploads), Gmail OAuth for booking-email enrichment (M1.1), and reporting + polish (M4/M5) — is tracked in docs/PLAN.md. All live features require account-level credentials.
app/—(app)owner surface (Clerk-gated),(public)guest/contractor surfaces (token-gated),api/routes.components/a2ui/— the renderer, the 12-component catalog implementations, and the surface chrome.lib/—db/schema(Drizzle),services(domain logic),ingest(calendar sync + email enrichment),agent(pipe + per-surface toolsets),a2ui(protocol + catalog + fixtures).docs/—PLAN.md(architecture + build order),FEATURES.md(feature index), the three surface specs, andfeatures/*/(per-iteration plans + acceptance criteria).evals/— the owner-scenario eval harness.
MIT — see LICENSE.