Skip to content
GoatWhistlePublic

About

Trip planner that starts from a sentence, not filters. Describe the trip you want and Elsewhere turns it into an editable Travel DNA, assembles up to three genuinely different futures from real data (best match, cheaper, different landscape), lets you simulate changes, forecasts the risks relevant to you and builds a priced trip plan with observed

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Elsewhere: describe the trip you want, see where it could take you

A trip planner for people who know how they want to rest but not yet where. Write the trip in one sentence, get up to three genuinely different futures, and see what each one costs you.

Run locally Documentation OpenAPI contract

first run: no keys, no LLM corpus: 408 properties
destinations: 7 decisions: 32 recorded license: MIT

API: Rails 8.1 and Ruby 3.3 storage: PostgreSQL and PostGIS
jobs: Sidekiq and Redis web: React 19 and TypeScript LLM: any OpenAI-compatible

Why it exists How it works Run locally Data Structure Limitations

Why it exists

Travel search starts from filters: a city, dates, a price range, a star rating. People do not think that way. They think "a week by a warm sea for two, under 180,000 rubles, no crowds, good food, lots of walking". Turning that into filters is the hard part, and booking sites leave it to the user.

Elsewhere starts from the sentence. It turns the request into explicit preferences, assembles whole trips from real data, and shows the trade-off behind every option instead of a ranked list of near duplicates. It plans; it never books or takes payment.

How it works

Dream form with the trip described in one sentence Three futures with match score and itemised cost
1. Dream. One sentence plus the facts a search cannot guess: origin, dates, nights, travellers. 2. Futures. Best match, a cheaper one and a different landscape, each priced component by component.
Forecast of risks relevant to this traveller Trip plan with flights in trip order
3. Forecast. Only the risks that matter to this traveller, each with a measurement and a fix. 4. Trip plan. Flights, stay, transfers and the total, with observed and modeled numbers marked.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#fffdf8","primaryTextColor":"#1d2925","primaryBorderColor":"#174c3b","secondaryColor":"#ebe7dc","tertiaryColor":"#f3f0e8","lineColor":"#65706b","textColor":"#1d2925","noteBkgColor":"#ebe7dc","noteTextColor":"#3d4a45","actorBkg":"#fffdf8","actorBorder":"#174c3b","fontFamily":"Inter"}}}%%
flowchart LR
  D[Dream text] --> P[Dream parser]
  P --> DNA[Travel DNA]
  DNA --> F[Futures A, B, C]
  S[(Supply: catalogue, fares, climate, OSM)] --> F
  F --> Sim[Simulator]
  Sim --> F
  F --> Fc[Forecast]
  Fc --> Plan[Trip plan]
Loading
  • Travel DNA. The parser turns the sentence into weighted preferences and hard constraints. Every dimension can be edited; each save creates a new version, and the user always has the last word.
  • Futures. Up to three whole trips by archetype: the best match, one that is really cheaper, and one with a different type of geography. If an archetype cannot clear its threshold, the set is smaller and the response says why. Near duplicates never fill the gap.
  • Experience Match. The score decomposes into per-preference contributions, so "88%" can be read line by line. Unknown values stay unknown instead of counting as neutral.
  • Simulator. "Make it cheaper", "quieter", or a slider move. The original future is kept, a new version is created, and the delta in price and match is shown.
  • Forecast. Risk rules fire only on a measurement or a labelled proxy: night noise from the distance to a primary road, a cold sea from marine data. Each risk carries severity, confidence and mitigations derived from the risk itself.
  • The LLM's role is narrow. It reads and phrases text. Prices, scores and distances are computed in code. When the model is down or slow, a deterministic path answers and marks the result as degraded.

Run locally

You need Git, Node.js 20+, and either Ruby 3.3+ or Docker.

git clone https://github.com/GoatWhistle/elsewhere.git
cd elsewhere
bin/setup

bin/setup creates .env from .env.example, installs gems and prepares the database. Without a suitable Ruby it builds the Docker image and runs PostgreSQL with PostGIS and Redis in Compose.

Start the API with local Ruby:

bin/rails server

Or, when setup chose Docker:

docker compose up app

Then start the web app in another terminal:

npm install --prefix web
npm run dev --prefix web

The web app opens at http://localhost:5173, the API at http://localhost:3000. The default SUPPLY_MODE=fixture works without API keys or a model. In development the web app can also run on MSW mocks without the backend; set VITE_API_MODE=real to call the API.

Variable Purpose
SUPPLY_MODE fixture for the offline corpus, live for real providers
IGNAV_API_KEY, ORS_API_KEY Flight fares and routing in live mode
LLM_BASE_URL, LLM_MODEL Any OpenAI-compatible endpoint, for example Ollama with qwen3:8b
LLM_TIMEOUT_SECONDS Model timeout; a local 8B model needs about 30 s per dream

bin/check runs Packwerk boundaries, RSpec, the TypeScript check and ESLint in one go. npm test --prefix web runs the web tests.

Where the data comes from

Data Source Used for
Properties Catalogue harvested once and stored locally Real attributes and a base price level
Coast, roads, POI, airports OpenStreetMap in PostGIS Distances and surroundings
Climate and weather Open-Meteo Climate normals, sea temperature, forecast
Flight fares Ignav Live fares in live mode, recorded responses in fixture
Room rate for exact dates Calibrated model Observed base level with modeled seasonality
Reviews Not connected No review-based conclusions are drawn

The bundled corpus holds 408 properties across seven destinations: Anapa, Sochi, Kaliningrad, Kazan, Saint Petersburg, Caucasian Mineral Waters and Sheregesh.

Structure

packs/
  shared/      value objects and the AI task runner
  supply/      catalogue, fares, climate, geography and the rate model
  planning/    Travel DNA, constraints, assembly, match and the simulator
  foresight/   evidence, risk rules and mitigations
app/           HTTP controllers and background jobs
web/           React interface with a typed client and MSW mocks
spec/          backend unit, contract and end-to-end specs
docs/          product, architecture, research and the decision log

Logic lives in Packwerk packs, not in controllers. Dependencies point one way: shared ← supply ← planning ← foresight, and only supply talks to the network. The HTTP API follows docs/04_api/openapi.yaml, checked by a contract spec. The documentation is in Russian.

Limitations

  • A planner, not a booking service: no offers, orders or payments.
  • Room rates for specific dates include modeled seasonality and are labelled as modeled.
  • Reviews are not connected, so review-based risks such as food quality stay out of the forecast.
  • live mode depends on provider keys and their availability.
  • The web interface is in Russian only.


Team GoatWhistle, 2026. Licensed under MIT.

About

Trip planner that starts from a sentence, not filters. Describe the trip you want and Elsewhere turns it into an editable Travel DNA, assembles up to three genuinely different futures from real data (best match, cheaper, different landscape), lets you simulate changes, forecasts the risks relevant to you and builds a priced trip plan with observed

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages