--- 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 # 8 hours 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))