Open-source project
calderbuild/MeetSpot avatar
calderbuild/MeetSpot

MeetSpot ranks venues by the least satisfied person in the group

End the "Where should we meet?" debate by instantly finding a spot that’s fair, convenient, and loved by everyone. An intelligent meeting point recommendation system.

539 stars59 forksPythonMIT

At a glance

What is it?
MeetSpot is a FastAPI application that computes a geographic midpoint for a group and then ranks nearby venues by how each participant would feel about them, using a maximin over per-person taste scores rather than a group average, and it can reject a candidate centre when one person's real commute breaks a limit. It is MIT licensed and runs on Render.
Who is it for?
Adopt MeetSpot if you are building a group meeting planner and the interesting problem is fairness rather than ranking, since ranking by the worst-off person rather than the average is the idea that distinguishes it. Do not adopt it as a production service without reading the configuration surface, because it depends on several paid map and taste APIs and a hosted deployment.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 12 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A midpoint, then a ranking that protects the worst off

MeetSpot is described as an autonomous agent that decides the fairest meeting point for everyone, and the contrast with a normal location tool is the point.

Most location tools return results near you. MeetSpot calculates the geographic center of all participants and returns AI-ranked venues that minimize everyone's travel time. The comparison table in the documentation puts it as four differences: search near your location against calculate a fair center for all, keyword-based ranking against AI-powered multi-factor scoring, static results against adaptive dual-mode routing, and no reasoning against explainable AI with chain-of-thought.

The recent work sections show what that means in practice. The 2026-10 entry adds group taste fairness, where each person lists what they like, the same venues are scored once per person, and the venues are ranked by the least-satisfied person. The 2026-09 entry adds real commute-time fairness, where candidate centers are checked against real travel times and rejected if anyone goes over their limit.

The framing in the readme is that picking a place for a group usually means somebody gets dragged somewhere they would never choose. MeetSpot already finds a fair location, and since 2026-09-30 it also tries to find a fair place, using each person's own taste.

How the taste ranking actually works

The mechanism is a maximin, and it is the single most interesting idea in the project.

Each person lists a few things they love, artists, movies, shows, brands, books. MeetSpot resolves them to Qloo entities, has Qloo score the same set of nearby venues once per person, and ranks venues by the least-satisfied person, described as a maximin over each person's percentile, rather than by the group average.

The consequence is straightforward. A venue that two people love and the third would hate is left out, and the page says who would have been unhappy and why.

The pipeline the documentation sketches is: addresses and tastes per person, then a search that resolves each taste to an entity, in parallel with a fair center and real commute check, then a heatmap per person whose cell-wise minimum picks between commute-fair centers and shades the map, then Qloo insights giving 30 candidate venues near the center, then insights per person on those same 30 with explainability, and finally a percentile per person so the ranking is by the worst-off person, with a separate path that finds shared taste tags for the group.

The table of which Qloo capability does what explains the design. The search endpoint turns a list of names into entities and shows each person what their taste was recognised as. Insights with a location filter and venue tag produce the candidates. The results entities and interests entities filters score the same candidates once per person, so people can be compared. The explainability feature is where the phrase person 1 matches via Barbie comes from, and the documentation stresses that the reason comes from Qloo's data, not from a language model.

The agent, and what the explainability claim rests on

The agent itself is named in the documentation. MeetSpotAgent is a ReAct agent over DeepSeek, and the group taste work gave it a new tool, group_taste_rank.

Given a group with tastes, it geocodes everyone, computes the fair center, calls the tool, and explains its pick person by person using only what the tools returned. The results page also has an Ask the agent card, which runs it on the same group and shows each tool call it made.

That last detail is the one that makes the explainability claim checkable. Showing the tool calls is a different thing from printing a paragraph of reasoning, because the tool calls are the argument. If the ranking is done by a maximin over per-person percentiles computed by Qloo, then the agent's job is to narrate that computation rather than to invent a justification, and the visible tool trace lets a reader confirm which is happening.

The documentation is also careful about the scope of the change. The Qloo client, the per-person maximin ranking and taste heatmap in the recommender, the agent tool and English agent mode, the per-person taste inputs, the taste card, the fit bars and the left-out venues on the results page, and the Ask the agent card all landed after 2026-09-30. Requests without tastes behave exactly as before, which is a good sign for a change that touches the core of the product.

Commute fairness, and a geometric midpoint that is not fair

The second fairness layer attacks a weakness the first one leaves open, and the explanation is crisp.

A geometric midpoint can still be unfair, because one person may have a direct train while another needs two transfers.

On the international path, each participant can set a max commute in minutes. MeetSpot then takes several candidate centers, asks Google Routes for each person's real travel time to each one, and keeps the candidate that breaks no one's limit. If every candidate breaks some limit, it picks the one with the smallest total overage, and treats an unreachable leg as the worst case. The results page shows which candidates were accepted or rejected and why.

So there are two candidate generators and two filters. The center is fair in distance and the commute check is fair in travel, and a candidate has to pass both. The fallback behaviour is the sensible part: when nothing is fully acceptable, the minimum total overage is a graceful degradation rather than a failure, and treating an unreachable leg as the worst case stops an island of a venue from looking good because the map returned a straight line.

The China path with Amap and requests without commute limits behave exactly as before, which keeps the two markets from diverging in behaviour for no reason.

The configuration surface, and what it needs to run

The application is a Python project with a small package manifest and a long environment file, and the environment file is where the real requirements are.

The manifest is minimal. The package is meetspot at version 1.0.0, the main entry is web_server.py, the dev and start scripts both run python web_server.py, and the engine requirement is Python 3.11. The web server is FastAPI, and the dependencies are pinned exactly: fastapi 0.136.1, uvicorn 0.47.0, pydantic 2.13.4, httpx, aiohttp, aiofiles, jinja2, loguru, slowapi for rate limiting, sqlalchemy with greenlet, aiosqlite and asyncpg for the database, python-jose for tokens, and the openai and tenacity packages for the model calls.

The environment file shows what has to be configured. Amap credentials are required, with a security JS code, and the Google Maps Platform key is optional and used for the international scenarios. Qloo keys are optional and are for the group taste ranking on the English and Google path. There is a port setting defaulting to 8000, a PostgreSQL database URL for a hosted deployment, a pgbouncer transaction-mode flag, and a comma-separated CORS origins list.

The keys themselves look like this in the environment file:

bash
# Optional: Port configuration (defaults to 8000)
PORT=8000
# Optional: Log level
LOG_LEVEL=info
# Optional: LLM API (OpenAI-compatible endpoints, e.g. DeepSeek)
# LLM_MODEL=deepseek-flash

The model configuration accepts an OpenAI-compatible endpoint with a base URL and a model name, and the example points at DeepSeek with a flash model. There is also a legacy OpenAI configuration, a log level, and a payment integration with an application id, a secret and a checkout URL, plus a free daily request limit per IP, a credit price in cents and the number of credits per purchase. The free daily limit defaults to 2, which the comment says is for the competition demo.

A desktop app, a hosted deployment, and a long file list

The recent work includes a macOS application with a RevenueCat paywall, an Electron desktop build with a server-verified entitlement running against the RevenueCat Test Store, added in October 2026 alongside the taste work.

The repository layout shows how much is in the project. There is an api directory, an app directory with the tools, a config directory, a data directory, a desktop directory, a docs directory, a locales directory for internationalisation, a public directory with the static assets, templates for the server-rendered pages, tests, tools, a Dockerfile, a render.yaml for the Render deployment, an environment.yml for conda, and a lighthouserc.json for the frontend performance checks. There is also a postmortem directory, which is a slightly unusual thing to see in a repository and suggests the project writes up its own incidents.

The container image is a reasonable production shape. It starts from python 3.12-slim, sets the working directory and the Python path, installs git and curl, installs the pinned requirements, copies the application, creates a non-root user and gives it ownership of the directory, exposes port 8000, and defines a health check that curls the health endpoint every 30 seconds with a 5 second start period and 3 retries.

The public demo runs on Render at a meetspot subdomain, and there is a New York demo group available through the finder page. The licence is MIT, the last push was on 2026-10-12, and the repository publishes no GitHub releases.

Editorial conclusion

Adopt MeetSpot if you are building a group meeting planner and the interesting problem is fairness rather than ranking, since ranking by the worst-off person rather than the average is the idea that distinguishes it. Do not adopt it as a production service without reading the configuration surface, because it depends on several paid map and taste APIs and a hosted deployment. Before you run it, check three things: which map provider you will use, since the China path and the international path behave differently, that you have Qloo credentials for the group taste ranking, and that you are comfortable with the free daily limit, which the configuration sets low for the competition demo.

Frequently asked questions

What does MeetSpot do differently from a normal maps search?

It calculates the geographic center of all participants rather than searching near one location, and it ranks venues by the least-satisfied person using a maximin over each person's taste percentile instead of the group average, so a venue that two people love and the third would hate is left out.

How does MeetSpot check commute fairness?

On the international path each participant can set a max commute in minutes, and MeetSpot asks Google Routes for each person's real travel time to each candidate center, keeping the one that breaks no one's limit. If every candidate breaks a limit it picks the smallest total overage and treats an unreachable leg as the worst case.

Which APIs does MeetSpot need to run?

Amap credentials are required, with a Google Maps Platform key for the international scenarios, and Qloo keys for the group taste ranking. The model call goes through an OpenAI-compatible endpoint configured with a base URL and a model name, with the example pointing at DeepSeek, and a PostgreSQL URL is used for a hosted deployment.

What is the MeetSpot agent and how does it explain its answer?

MeetSpotAgent is a ReAct agent over DeepSeek with a group_taste_rank tool. It geocodes the group, computes the fair center, calls the tool and explains the pick person by person using only what the tools returned, and the results page shows each tool call it made.

How is MeetSpot deployed?

The Dockerfile builds from python 3.12-slim, installs the pinned requirements, creates a non-root user, exposes port 8000 and adds a health check that curls the health endpoint. The live demo runs on Render, and the repository also ships a macOS Electron desktop build with a server-verified entitlement.

Official sources

  1. calderbuild/MeetSpot on GitHub
  2. Issues
  3. License: MIT
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/calderbuild-meetspot.svg)](https://hysenlabs.com/projects/calderbuild-meetspot)

Was this useful?