40° 48′ 32″ N  ·  73° 57′ 41″ W / bbox [-73.985,40.795,-73.945,40.825] / corpus 13,350 places / CCR 75.5% / v0.1 · shipped May 2026
Columbia EECS E6895 · Final Project · 2026

An illuminated atlas
of the city,
narrated by an agent.

Palimpsest plans a short walking tour anywhere on Manhattan and narrates it from free public-domain sources — every claim grounded in a retrieved document under a strict five-field citation contract, verified before the response leaves the server.

13,350 places · Manhattan-wide hybrid retrieval + reranker pgvector · PostGIS · pg_trgm OpenRouter · bring your own key
§01 · the problem

Why
this matters.

A large language model will tell you Riverside Church is a thirteenth-century gothic cathedral with absolute confidence. It isn't. Hallucinations about places — names, dates, who built what — are a citation problem, not a model-scale problem.

“LLMs are confident liars about places.”

The fix is not a bigger model. The fix is a retrieval contract that refuses to render a sentence the model can't ground in a real document from a real source — and a UI that shows the user exactly which document.

Palimpsest treats narration the way an academic treats a footnote: every assertion is anchored to a doc_id, a canonical source_url, the source feed, a character span inside the document, and the agent turn that retrieved it. The verifier rejects any sentence missing a field; the frontend renders the surviving citations as chips you can click.

unconstrained · gpt-style

Riverside Church, completed in 1192, was funded by Andrew Carnegie and houses the oldest bell carillon in North America. Martin Luther King Jr. delivered his “Beyond Vietnam” speech here in 1965.

palimpsest · verified

Riverside Church, completed in 1930wiki·p3, was funded by John D. Rockefeller Jr.wiki·p4 and houses the Laura Spelman Rockefeller Memorial Carillonwiki·p7. King delivered “Beyond Vietnam” here in 1967wiki·p11.

§02 · the product

An agent
that walks
the page.

Tell it where you want to go. It plans a route inside the bbox, queries each stop against the corpus, narrates the walk, and lets you click any sentence back to the source paragraph it came from.
a walk near Columbia streaming
Morningside Pk. N
Morningside Heights · Upper West Side 1 : 14 400
Riverside Church
Low Library
Cathedral of St. John
Morningside Park
§03 · how it works

Five pieces,
each minimal.

A retrieval-augmented agent on top of a pgvector + PostGIS corpus. The web shell streams server-sent events; the verifier holds the line on every sentence. No tricks, no magic — just a small, honest pipeline.
narration + citations stream back over SSE
Browser
React · MapLibre
TypeScript · Vite
Agent
Claude · FastAPI
SSE streaming
Tools
search_places
plan_walk · OSRM
Corpus
pgvector · PostGIS
13,350 places
Verifier
5-field citation
contract check
01

Browser

3D map on the left, chat pane on the right. React + Vite + TypeScript + MapLibre GL.

apps/web
02

Agent

FastAPI service runs an LLM in a bounded 6-turn tool-use loop and streams events back as SSE.

apps/agent
03

Tools

Two typed tools: search_places for hybrid retrieval, plan_walk for OSRM-backed routing.

apps/agent/tools
04

Corpus

13,350 places — 12,858 OSM features + 492 Wikipedia/Wikidata entries — embedded with bge-small, indexed by pgvector + PostGIS + pg_trgm.

data/corpus
05

Verifier

Rejects any sentence whose citations don't all clear the 5-field contract against the retrieval ledger. Runs before the response leaves the server.

apps/agent/verify
§04 · results

By the
numbers.

Palimpsest ships Manhattan-wide, with hybrid retrieval, an optional cross-encoder reranker, BYOK auth, and a food-discovery side flow. Evaluated on Manhattan-100, an LLM-judged benchmark of 95 graded questions.
13,350
places indexed
12,858 OpenStreetMap features + 492 Wikipedia / Wikidata entries, embedded and queryable out of the box.
75.5%
citation-correct rate
Hybrid retrieval + bge-reranker on Manhattan-100. Vanilla LLM with no retrieval scores 6.8%.
100%
embedding coverage
Every corpus row has a vector. No nulls, no fallbacks, no excuses.
§05 · the contract

Five fields,
or it doesn't
render.

The verifier is the smallest interesting piece of the system. It checks every sentence the model generates against a strict five-field schema — if any field is missing, the sentence is dropped before the user sees it.

The schema.

A citation must resolve to a real document the agent actually retrieved in this conversation — the verifier checks every emitted citation against the per-request retrieval ledger before the response is streamed. No string-matching, no “trust me”.

  • doc_id— stable identifier inside the source feed
  • source_url— canonical URL of the source document
  • source_type— the feed it came from (wikipedia / wikidata / osm)
  • span— character offsets [start, end] inside the document
  • retrieval_turn— which agent turn put this doc on the ledger
{
  "sentence": "Riverside Church was completed in 1930.",
  "citations": [
    {
      "doc_id":         "wp:Riverside_Church",
      "source_url":     "https://en.wikipedia.org/wiki/Riverside_Church",
      "source_type":    "wikipedia",
      "span":           [412, 486],
      "retrieval_turn": 2
    }
  ],
  "verified": true   // passes ledger check
}
§06 · sources

Public
domain,
cited back.

Every claim in the narration resolves to one of these feeds. All are public-domain or openly-licensed, ingested in full, embedded, and queryable through the same retrieval contract.

Wikipedia

Long-form narrative, dates, names. Pulled article-by-article for places inside the Manhattan footprint and chunked for retrieval.

shipped · part of 492 entries

Wikidata

Structured properties — architects, completion year, heritage status — joined onto the Wikipedia chunks via QID.

shipped · part of 492 entries

OpenStreetMap

Geometry, addresses, building footprints. POI tags drive the “type of place” field; geometry feeds OSRM for the walk leg.

shipped · 12,858 features
§07 · the stack

What's
under the
hood.

No frameworks-on-frameworks. Each layer is one well-understood tool, picked because it does its job and gets out of the way.
Frontend
·React 18 ·Vite ·TypeScript ·MapLibre GL ·TailwindCSS ·EventSource
Agent & API
·FastAPI ·Python 3.12 ·Pydantic v2 ·OpenRouter · BYOK ·Server-Sent Events ·uvicorn
Retrieval
·Postgres 16 ·pgvector ·PostGIS ·pg_trgm ·bge-small-en-v1.5 ·bge-reranker-base ·RRF fusion ·OSRM (foot) ·Redis
Infra
·Docker Compose ·ghcr.io images ·GitHub Actions ·pytest · ruff
§08 · the team

Built
by three.

Graduate students in the Department of Computer Science at Columbia, shipped over a semester. Course: EECS E6895, Advanced Big Data & AI.
CY

Chenhao Yang

retrieval & corpus

Built the ingest pipeline, the embedding store, and the spatial index. Wrote the verifier.

Columbia · M.S. CS
KJ

Kaining Jia

agent & API

Designed the tool-use loop, the SSE stream, and the typed Pydantic contract for every tool call.

Columbia · M.S. CS
TD

Thomas Duan

frontend & cartography

Made the map breathe — engine wrapper, marker style, flyTo choreography, and the chat shell.

Columbia · M.S. CS

Walk the page
with us.

The live demo is online — bring your own OpenRouter key and ask it for a walk. The codebase is public, the documents are public, the corpus is in the published Docker images. Clone, run, file issues.