| --- |
| title: Borderless |
| emoji: π |
| colorFrom: yellow |
| colorTo: purple |
| sdk: gradio |
| sdk_version: 6.16.0 |
| app_file: app.py |
| pinned: false |
| license: apache-2.0 |
| hardware: cpu |
| short_description: Agentic immigration research for global movers |
| tags: |
| - agents |
| - gradio |
| - immigration |
| - travel |
| - research |
| - tool-use |
| - qwen |
| - langgraph |
| - maplibre |
| - geospatial |
| models: |
| - Qwen/Qwen3.6-27B |
| datasets: [] |
| hf_oauth: true |
| hf_oauth_scopes: |
| - inference-api |
| hf_oauth_expiration_minutes: 480 |
| disable_embedding: false |
| startup_duration_timeout: 10m |
| --- |
| |
| # Borderless |
|
|
| **An agentic immigration research tool β describe your background in plain English, explore where you could go.** |
|
|
| Live demo: **[build-small-hackathon/borderless](https://huggingface.co/spaces/build-small-hackathon/borderless)** |
|
|
| Built for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon) β small models (β€32B), big adventure. |
|
|
| ## What it does |
|
|
| Immigration research is fragmented across government sites, forums, and spreadsheets. Borderless puts it in one conversational flow: |
|
|
| 1. **Describe yourself** β citizenship, education, work history, budget, timeline, and goals via a guided intake form or free-form chat. |
| 2. **Get a research plan** β the agent parses your profile, picks realistic destination countries, and breaks the work into focused to-dos. |
| 3. **Watch parallel research** β subagents investigate each to-do at the same time, searching official sources and scraping government pages. |
| 4. **Explore on a 3D globe** β recommended countries appear on an interactive MapLibre globe with pathway labels. |
| 5. **Read a consolidated answer** β visa pathways, documents, timelines, costs, risks, and cited official sources in one structured report. |
|
|
| No forms to decode. No keyword guessing. Just a research session that meets you where you are. |
|
|
| ## How it works |
|
|
| Borderless uses a **[LangGraph](https://docs.langchain.com/oss/python/langgraph/overview)** workflow powered by **[Qwen/Qwen3.6-27B](https://huggingface.co/Qwen/Qwen3.6-27B)** via the Hugging Face Inference API: |
|
|
| ``` |
| User profile β Planner β parallel Researchers (one per to-do) β Consolidator β final answer |
| ``` |
|
|
| | Stage | What happens | |
| |-------|----------------| |
| | **Planner** | Reads the profile, selects 3β4 destination countries, emits a research plan, and marks countries on the globe. | |
| | **Researchers** | Run in parallel via LangGraph `Send`. Each subagent searches official immigration sources, scrapes government pages, and writes a findings report for its to-do. | |
| | **Consolidator** | Merges all findings into a single structured answer with pathways, documents, risks, timelines, and official source links. | |
|
|
| Progress streams live in the chat: thinking steps, the research plan, tool calls (with expandable arguments and results), per-to-do findings, globe updates, and the final answer. |
|
|
| ### Research tools |
|
|
| | Tool | What it fetches | |
| |------|-----------------| |
| | `get_country_profile` | Country metadata and official immigration domain hints | |
| | `search_immigration_info` | Web search with source-quality labels for official immigration pages (Exa) | |
| | `scrape_web_page` | Markdown content from a specific official government or embassy URL (Firecrawl) | |
| | `crawl_web_site` | Multiple pages from an official immigration website section (Firecrawl) | |
| | `update_globe` | Marks, highlights, and flies to countries on the MapLibre globe | |
|
|
| Sign in with your Hugging Face account for inference, or set `HF_TOKEN` as a Space secret for server-side API access. |
|
|
| ## Features |
|
|
| - **Guided intake** β form fields and demo personas turn a profile into a complete research prompt |
| - **LangGraph parallel research** β planner plus parallel subagents, not a single monolithic agent loop |
| - **Live streaming UI** β thinking, tool calls, findings, and the final answer appear as the workflow runs |
| - **Tool-driven 3D globe** β MapLibre GL globe with markers, pathway labels, and fly-to camera moves |
| - **Source quality** β search results flag likely official government and embassy sources |
| - **Structured recommendations** β shortlist, pathways, documents, risks, timelines, next steps, and official sources |
| - **Chat history** β sessions persist in the browser |
|
|
| ## Example prompts |
|
|
| - *"I'm a software engineer from India with 8 years of experience and a master's degree. Where could I realistically relocate for skilled work within 12β18 months?"* |
| - *"I hold a Hong Kong passport and want to study in Europe on a modest budget. What are my visa options?"* |
| - *"Compare skilled worker pathways to Canada, Germany, and Ireland for a solo applicant with USD 20k savings."* |
|
|
| ## Tech stack |
|
|
| - **[Gradio Server](https://gradio.app)** β custom HTML/JS UI, OAuth, and streaming API endpoints |
| - **[LangGraph](https://docs.langchain.com/oss/python/langgraph/overview)** β planner / parallel researcher / consolidator workflow |
| - **[Qwen3.6-27B](https://huggingface.co/Qwen/Qwen3.6-27B)** β planning and synthesis via Hugging Face Inference API (`huggingface_hub.InferenceClient`) |
| - **[MapLibre GL JS](https://maplibre.org/)** β interactive 3D globe |
| - **[Exa](https://exa.ai)** β neural web search for discovering immigration sources |
| - **[Firecrawl](https://firecrawl.dev)** β scrape and crawl official web pages |
|
|
| ## Project structure |
|
|
| ``` |
| app.py # Gradio Server entry point and API routes |
| assets/ |
| index.html # Custom UI shell |
| app.js # Intake form, chat, history, streaming client |
| gradio_api.js # Gradio SSE streaming helper |
| globe.js / globe.css # MapLibre globe rendering |
| server.css # App styling |
| ui/ |
| server_api.py # Chat API adapter and intake helpers |
| globe_commands.py # Globe marker/highlight/fly-to state |
| country_coords.py # Country coordinate lookup |
| intake/ # Profile form, personas, prompt builders |
| agent/ |
| graph/ # LangGraph workflow (planner, researchers, consolidator) |
| respond.py # Legacy single-agent loop (fallback mode) |
| tools.py # Tool dispatch |
| completion.py # Hugging Face Inference API client |
| streaming.py # Chunked answer streaming |
| tool_schemas/ # Function-calling schemas |
| apis/ |
| exa.py # Exa web search |
| firecrawl.py # Firecrawl scrape/crawl |
| rest_countries.py # Country metadata (with static fallback) |
| country_profile.py # Country profile tool |
| data/ |
| countries_fallback.yaml # Static country coordinates when REST Countries is unavailable |
| intake/ # Form choices and demo personas |
| ``` |
|
|
| ## Hackathon fit |
|
|
| | Constraint | Borderless | |
| |------------|------------| |
| | Model β€ 32B | Qwen3.6-27B (27B) | |
| | Gradio on HF Spaces | Yes β [live Space](https://huggingface.co/spaces/build-small-hackathon/borderless) | |
| | Agentic | LangGraph multi-agent research with visible tool traces | |
| | Sharing is Caring | JSONL tool traces can be sanitized and published β see `TRACE_SHARING.md` | |
| | Field Notes | See `FIELD_NOTES.md` | |
|
|
| **Track:** Backyard AI β immigration research is a real, specific problem faced by millions of people weighing where they can live, work, and study. |
|
|
| ## Run locally |
|
|
| ```bash |
| pip install -r requirements.txt |
| cp .env.example .env # then fill in API keys |
| python app.py |
| ``` |
|
|
| Set `HF_TOKEN` in `.env` (or sign in through OAuth on the Space). The default model is `Qwen/Qwen3.6-27B:featherless-ai` on the Hugging Face Inference API. |
|
|
| For web research tools, set API keys from [dashboard.exa.ai](https://dashboard.exa.ai/api-keys) and [firecrawl.dev](https://firecrawl.dev): |
|
|
| | Variable | Purpose | |
| |----------|---------| |
| | `HF_TOKEN` | Hugging Face Inference API access (Space secret and/or user OAuth) | |
| | `EXA_API_KEY` | `search_immigration_info` | |
| | `FIRECRAWL_API_KEY` | `scrape_web_page`, `crawl_web_site` | |
| | `BORDERLESS_MODEL_ID` | Model override (default `Qwen/Qwen3.6-27B:featherless-ai`) | |
| | `BORDERLESS_INFERENCE_MODE` | `hub` (default, InferenceClient) or `router` (OpenAI-compatible router) or `local` (MiniCPM on ZeroGPU) | |
| | `BORDERLESS_AGENT_MODE` | `graph` (default) or `legacy` for the single-agent loop | |
| | `BORDERLESS_TRACE_DIR` | JSONL trace output directory | |
| | `BORDERLESS_DISABLE_TRACE_LOGS` | Set to `1` to disable local trace logs | |
|
|
| On Hugging Face Spaces, add API keys as **Space secrets** (Settings β Secrets). Without keys, web tools return a clear error and the agent continues with partial results. |
|
|
| ### Startup logs (normal on Spaces) |
|
|
| | Log | Meaning | |
| |-----|---------| |
| | `GRADIO_HOT_RELOAD: ... Using 'demo'` | Harmless β Gradio found the app entrypoint. | |
| | `Invalid file descriptor: -1` in `BaseEventLoop.__del__` | Harmless asyncio cleanup noise during Gradio SSR hot reload. | |
| | `HF_TOKEN is set ... independently from the token you've just configured` | Informational β Space secret and OAuth login both provide tokens. | |
|
|
| ## License |
|
|
| Apache-2.0 (model: [Qwen/Qwen3.6-27B](https://huggingface.co/Qwen/Qwen3.6-27B)) |
|
|