Live demo: spatialdesk.vercel.app · Code: github.com/spenceryang/spatialdesk
Autonomous demo agent that finds newly purchased SF homes by AI-company employees, generates remodel proposals (3D massing, facade renders, scoped moves with cost/ROI), drafts buyer-specific outreach, and learns from response outcomes.
Built on Next.js App Router + the OpenAI Agents SDK, with a live Server-Sent Events trace so you can watch the agent reason and call tools in real time.
npm install
npm run devOpen http://localhost:3000.
API keys (OpenAI, Tavily, Resend, etc.) belong in .env.local — see .env.example.
There are two run modes, toggled by the pill in the header:
- Demo (default) — deterministic, no API calls, pre-baked fixtures. Repeatable on stage.
- Live — real Tavily search + OpenAI calls for the buyer enrichment, design theme, remodel scope, and outreach drafting. Requires
OPENAI_API_KEYandTAVILY_API_KEY. Asset-bound steps (3D massing, facade renders) still serve the pre-rendered images.
- Lead list (
/): pick the 170 St Germaine Ave hero lead. - Lead detail (
/leads/[id]) opens with five tabs: Property, Proposal, Outreach, Buyer, Learning. - Click Run Agent. The right-side trace pane streams reasoning, tool calls, and results live.
- Watch the agent enrich the buyer, parse the floor plan, score the lead, infer a design theme and remodel scope, generate 3D massing + facade renders, and draft three outreach variants.
- Open Learning and click Run Learning Agent to analyze
outcomes.jsonand propose updated scoring weights.
DEMO_SCRIPT.md has the full ~3:30 narrated walkthrough.
Stack
- Next.js 15 App Router + TypeScript
- OpenAI Agents SDK (
@openai/agents) - Tailwind + Three.js / react-three-fiber for the 3D viewer
- Zustand for client state, Zod for tool schemas
- JSON-on-disk for all persistence (
/data) - Server-Sent Events for live agent traces
Routes
app/page.tsx— lead listapp/leads/[id]/page.tsx— lead detail with tabsapp/api/agent/run— POST, runs the SpatialDesk agentapp/api/agent/learn— POST, runs the Learning agentapp/api/trace/[runId]— GET, SSE stream of trace events
Agents (/lib/agent)
- SpatialDesk — enrich buyer, parse floor plan, score lead, infer design theme + remodel scope, build 3D model, render facade, draft outreach.
Tools:
tavilySearch,parseFloorPlan,scoreLead,inferDesignTheme,inferRemodelScope,build3DModel,renderFacade,generateOutreach. - SpatialDeskLearning — analyze outcomes, surface reply drivers, propose scoring-weight updates.
Tools:
logOutcome,proposeWeightUpdate. trace-bus.ts— in-memory pub/sub that fans tool events out to SSE subscribers perrunId.
Data (/data)
leads.json,buyers.json— pipeline + buyer profilesoutcomes.json— outreach response logscoring-weights.json+scoring-history.json— current weights and version archivefloorplans/— structured room data per leadtraces/— persisted run event buffers
Components (/components)
AgentTracePane— SSE listener, renders reasoning + tool calls liveProposalTab,OutreachTab,LearningTab,BuyerTab,PropertyTabThreeDViewer,FloorPlanViewer,ScoringEvolution,PipelineAnimation
Demo assets
170 St Germaine Ave/— hero property photos (webp)FloorPlan/— pre-rendered floor plan imagepublic/— pre-baked massing + facade renders
One-off utilities under /scripts:
seed-leads.ts— seedleads.jsonwith demo dataparse-hero-floorplan.ts— parse the 170 St Germaine floor planpre-render-sketchup.ts— pre-render SketchUp models to images
The OpenAI client is real; the planning loop runs against gpt-5 if a key is configured. Tavily, SketchUp, Formas, TracePaper, and Resend tool calls return canned data from /lib/tools/demo-output.ts so the flow stays deterministic for demos. Wire them up by replacing the relevant tool implementation under /lib/tools.