Fred • Engineering

From a chat message to an inbox of checked apartments

Overview

Fred is a tool-using AI agent with a web app around it. You chat with it in plain words, and it saves your search, starts crawlers on the listing sites, checks every building with the city and writes up the places that fit, while the app shows each step as it happens.

Why we built it. James and I built Fred at the AI Engineer NYC hackathon on October 11, 2026, because we’re hunting for an apartment ourselves and were tired of checking every site and alert email by hand. It had to be live by the end of the day, so we picked tools that ship fast, run without servers to look after, and let two people and their agents work at the same time without stepping on each other.

Role
I built the web app; James built the API, the agent and the crawlers
Stack
TypeScript · Next.js · Mastra · Claude · Hono · Zod · Cloudflare
Surface
Web app, chat and email alerts
Focus
Showing the agent’s work · nothing sent without you

Problem

Listings are scattered, incomplete and sometimes fake, and an agent has to act on them.

  • No listing site has an API

    StreetEasy, Zillow and the rest only show their listings on their own pages, so every source needs its own crawler.

  • Search results leave things out

    A listing card rarely says the fees, the pet policy or the laundry, which are the things renters ask about first.

  • The costly cases are the quiet ones

    A broker fee, a building with open violations or a scam deposit is exactly where a confident wrong answer hurts most.

  • Trust needs receipts

    To believe an agent, you need to see what it checked, where each number came from and what it doesn’t know.

How it works

Chat in, checked places out.

Four stages, with you in charge of anything that leaves the app.

  • 1. You say what you want

    Fred turns “1 bed under $4,500 in Greenpoint, dog OK” into a saved search: dealbreakers, nice-to-haves with a weight, and notes in its memory.

  • 2. Fred checks the sites

    It starts crawlers on StreetEasy, Zillow, RentHop, Zumper, Compass, Nooklyn, Craigslist and landlords’ own sites for that search. The same apartment on several sites becomes one place.

  • 3. It checks each place

    Code drops places that clearly miss a dealbreaker. Fred reads the full listing page when facts are missing, looks at the photos, and scores the building from NYC Open Data.

  • 4. It writes up the ones that fit

    Fred adds them to your inbox with why it picked each one, emails strong fits if you asked, and drafts messages to landlords that only send after you approve.

How it’s built

A tool-using agent behind one typed contract.

The loop

Fred is a Mastra agent on Claude Sonnet 5.5 at low effort, for speed. It works in a loop, calling tools and reading what they return, and it only writes its reply once the tools are done, so the places it talks about are ones it has actually looked up. The model is one setting, so the same agent runs on Gemini too, and 15 scripted conversations check what Fred did, not just what it said.

The hands

Every action is one of 25 typed tools with a Zod schema. The model never touches the database. It calls tools that read and write the same data the app shows, so whatever Fred changes, you see.

ToolsWhat Fred can doCount
SearchRead and change your search, search the listings, start the crawlers and check on them5
PlacesAdd places to your inbox, look through it, open a place and update it4
ResearchRead a listing’s full page, search the web for the landlord and the building, look at the photos3
Messages and toursDraft, send or cancel a message to a landlord, request a tour, list and update tours6
AlertsSet up email alerts, verify the address and send a test3
MemoryKeep notes about you, recall earlier chats and update your profile3
RepliesSuggest answers you can tap1

The wiring, and why

Everything runs on Cloudflare, so there was no server to set up or look after, and the app and the API share one domain.

PieceWhat we usedWhy
Web appNext.js and Tailwind on a Cloudflare Worker, through OpenNextThe same host as the API, so a service binding serves both on one domain
ChatVercel AI SDK (useChat), streamed over server-sent eventsEach tool call arrives as its own part, so the app can show Fred’s steps live
APIHono on a Worker, with Zod schemas for every routeOne contract generates the app’s types, so the two sides can’t drift apart
AgentMastra with Claude Sonnet 5.5A tool loop, memory and evals, with the model as one setting
DataCloudflare D1, R2 for photos, Workers AI for chat recallBuilt into the same Worker, with nothing extra to run
ListingsApify crawlers, started on demandNo listing site has an API, and on-demand runs search your areas, not all of NYC
BuildingsNYC Open Data, and NYPD complaint data for area safetyFree and public, with a record for every building
ResearchNimble for the web, Gemini for photosReading a full listing page or a landlord’s reviews when the card leaves it out
MapsMapLibre with OpenFreeMap tilesNo key or account, and the tiles have a dark style
ErrorsSentry in the Worker and the appSeeing what broke during a one-day build

Two people and a few agents

We each worked with a few Claude Code agents. They coordinated on a shared message board, where they posted contract changes, bugs and questions for each other, and the API contract lived in one place (packages/api) that both sides built from. CI checked the Worker, the app and the contract on every push, so a change on one side that broke the other failed the checks.

The part I’m proudest of

The app shows Fred’s work as it happens.

My side was the web app, and the hard part was making an agent’s work readable while it streams in.

  • Live steps from the stream

    Each tool call arrives as its own part. I turn it into plain words (“Searching Greenpoint”, then “Searched Greenpoint”), refresh the inbox when a tool that changes it finishes, and fold the steps into one line. Next’s compression was holding the whole stream until the end, so every step showed up at once; turning it off in Next, since Cloudflare compresses at the edge, fixed it.

  • A contract both sides build from

    The app’s types are generated from the Zod schemas, and CI fails if they’re stale. When I wanted a dealbreaker level, my agent asked James’s agent on the board, the contract changed first, and my Profile change shipped on top of it.

  • Every place has a URL

    The open listing, the view and the sort live in the URL, so a listing can be shared, a reload keeps your place and the back button closes the modal. The places on either side load in the background, so the arrows feel instant.

  • Maps and voice with no keys

    MapLibre and OpenFreeMap need no account. Next doesn’t bundle MapLibre’s web worker, so a build step copies it in, and a browser without WebGL2 gets a note instead of a broken page. The mic records in the browser, and Whisper turns it into text right there.

Challenges

What broke during the day, and what we did.

  • The newest Next broke every page

    Next 16.4 added a file the Cloudflare adapter doesn’t bundle, so every page returned a 500. I pinned 16.3.8 until the adapter catches up.

  • One site blocked every crawler

    Apartments.com’s bot protection stopped every approach we tried, so it isn’t a source.

  • Search cards leave out the facts

    Zillow’s results have no fees, pets or descriptions, so its crawler reads each listing page once and keeps it for 14 days, and Fred reads a page itself when it needs to know.

  • The crawlers ran the wrong search

    We found they’d been running a placeholder search instead of the one in the app. Now Fred starts them on demand, for your own search.

By the numbers

25
15
7
37

You can try all of it in the live demo, which signs you in as a fresh guest with an example search.

What I’d do next

  • Read the full listing page on every site, not only Zillow, so fewer facts say Unknown.
  • Run the evals in CI and block a deploy when one fails.
  • Send alerts by text as well as email.
  • Open it to renters beyond the two of us, with real accounts instead of two logins and a demo.