Inspiration

I come at this from a few sides. I'm an alum of ACRE, Milwaukee's commercial real estate development program, so I've tried to put a deal together myself. I also serve as a City Plan Commissioner, which means I sit on the body that reviews what gets built. From both seats I kept seeing the same thing: the small developers who actually change a block, the folks doing eight to forty units, lose deals in predevelopment. That's the slow stretch before you've spent real money, where the answer to "can I even build this?" lives in a county GIS tab, a 90-page zoning PDF, and a spreadsheet held together with hope.

It's a big, underserved group. About 46% of the country's 49.5 million rental units sit in one-to-four-unit properties, and roughly 70% of those small properties are owned by individuals rather than institutions (2021 Rental Housing Finance Survey). Meanwhile the kind of building they make is disappearing: "missing middle" two-to-four-unit construction fell from about 11% of multifamily building in the 2000s to roughly 4% today (NAHB, 2025). The tool the big firms use, Argus, runs three to five thousand dollars a seat and assumes you have an analyst. Nobody doing a twelve-unit infill is buying that. So I built the tool I wished those developers had.

What it does

PencilOut is a predevelopment command center. Point it at a real Milwaukee parcel and it answers the four questions that decide a deal:

  • What can I build? Cited zoning and land-use answers, scoped to the parcel.
  • What deadlines can cost me money? A backward-planned checklist and countdowns from the contract's anchor dates.
  • Does it pencil? A source-backed proforma and an honest feasibility verdict.
  • How do I prove it? Every answer carries a citation, and one click turns the project into a shareable update.

The rule underneath all of it: every zoning claim is cited, or it gets flagged as unsupported. Ask about something the corpus doesn't cover and PencilOut tells you it can't answer instead of inventing a number. And when a deal doesn't work, it says so. On the demo parcel, a real City of Milwaukee RFP, the break-even rent comes out around $45 a foot, more than double the market, so the verdict is a plain "this doesn't pencil."

How we built it

The whole app runs on a single Amazon Aurora PostgreSQL Serverless v2 instance doing four jobs at once:

  • relational core for projects, parcels, documents, and anchor dates
  • pgvector for the cited zoning RAG (HNSW, Amazon Bedrock Titan v2 embeddings, 1024 dimensions)
  • PostGIS for ~160,000 Milwaukee parcel geometries
  • pg_trgm for fuzzy address and TAXKEY search, around 50ms at the 95th percentile

Tenant isolation is implemented in the database using Postgres row-level security, so an organization only ever sees its own deals. Amazon Bedrock (Titan v2 embeddings plus Claude Haiku synthesis) and Amazon S3 run the document pipeline: upload, extract, chunk, embed, index. The front end is Next.js 16 with HeroUI Pro, deployed on Vercel, with Clerk Organizations for auth and Drizzle for the schema and migrations.

Challenges we ran into

The isolation work had a trap. I wanted row-level security driven by SET LOCAL inside each transaction, but the Aurora Data API can't hold a session, so it can't keep that setting alive, and RLS would quietly do nothing. I switched to the postgres.js driver over a real connection so isolation is enforced in the database, not just in app code. That also ruled out Aurora DSQL, since pgvector and PostGIS only run on classic Aurora PostgreSQL.

The first deploy fooled me: the page loaded but the AI didn't, because I'd shipped without Bedrock and S3 credentials. The fix was a scoped IAM user wired into Vercel. Milwaukee's data had its own surprises too, like the two vacant lots in the demo assemblage reporting zero lot area in MPROP, so the buildable number has to come from somewhere else. And teaching the RAG to say "I don't know" took as much care as teaching it to answer.

Accomplishments that we're proud of

One database doing four jobs, with no bolt-on vector store, geo service, or search cluster. Citations that are enforced rather than decorative, where an answer without a source gets flagged. Tenant isolation that fails the entire test suite if a new table ships without RLS turned on. And a tool that's willing to tell you a deal is bad. The honest "doesn't pencil" verdict on a real RFP is the part I'm proudest of, because that's the moment that actually saves a small developer money. It runs on real Milwaukee data, and it's live.

What we learned

Postgres goes a lot further than I expected. Relational, vector, spatial, and fuzzy search in one instance held up fine, and keeping a zoning answer to a single query kept everything consistent. "The page loads" and "the feature works" turned out to be different claims, and I'll test for the second one from now on. The biggest product lesson is that honesty is a feature: a tool that flatters your spreadsheet is worse than one that tells you the truth.

What's next for PencilOut

Versioning and supersession on the municipal corpus, so an answer can never quietly lean on last year's zoning code. A citation that opens the source PDF to the exact page instead of just naming it. An RFP-response generator that turns the cited answers, pro forma, and design constraints into a submission-ready package, which is the deliverable the developer actually owes the city. And more cities beyond Milwaukee.

Built With

Share this project:

Updates