Civic Tech · Meet the Builders

From PR to Citizen to "There Must Be a Better Way": Building MerlionOS

🛠️ Google Tech Stack & Infrastructure
Google Gemini 2.5 Flash Gemini 3.1 Flash-Lite Google Search Grounding Google Cloud BigQuery Google Cloud Run

A few months ago, I became a Singapore citizen. On paper, it was a milestone; in practice, it was an administrative explosion. As a Permanent Resident, my civic digital footprint was fairly routine: filing taxes via IRAS, renewing my Re-entry Permit with ICA, occasionally checking my CPF balances, booking a polyclinic appointment through HealthHub, and using OneMap to check bus arrival times. But the citizenship journey changes everything.

Suddenly, the process is far more active. First, you check your application status and make appointments on the ICA portal for your new identity card and passport. Next, you complete the mandatory Singapore Citizen Journey onboarding. And then, a whole new world of civic admin opens up—tracking SkillsFuture credits, redeeming CDC vouchers on RedeemSG, and keeping up with HDB BTO launches.

When I sat down to list all the agency sites I needed to access to fulfill my new duties, stay informed, and handle daily life, the count came to 19 separate statutory board and national service portals. Juggling that many bookmarks and browser tabs every week—plus checking SMRT’s Twitter/X feed each morning to see if my MRT line was running smoothly—felt like an endless obstacle course.

I wanted a clean, searchable index that securely verified the links to those essential portals: ICA, ELD, IRAS, CPF, RedeemSG, SP Group, SkillsFuture, Workforce Singapore, MOM, MOH, HDB, MOE, LTA, NEA, Gov.sg, SG Journey, OneMap, HealthHub, and ActiveSG.

So I began by collecting the portals I needed to fulfill my Singaporean duties, stay informed, and enjoy the country’s privileges—all in one place.

The real story of MerlionOS isn't just the destination; it is the journey of how it got built, chunk by chunk, from a local script to a hardened agentic platform.

🎨 From External Links to a Local Dashboard

It started as a weekend hackathon project for the Hack2skill × Google Cloud GenAI Academy APAC Cohort 2. Rather than jumping straight into complex AI agent loops, I wanted to solve my own immediate frustration: building a clean, trustworthy index for the 19 essential Singapore government portals I found myself needing as a new citizen.

In my first iteration, I built a customizable drag-and-drop grid, fetching agency logos directly from official URLs to keep them authentic and up-to-date. But a directory of links only solved half my problem—what I really needed was personal situational awareness before stepping out the door. That realization drove me to build SG Hub, a real-time civic command center embedded right inside my dashboard.

I was tired of opening half a dozen separate apps and websites just to get through my routine. Before heading out or planning my day, I often found myself checking SMRT's Twitter/X feed just to see if my MRT line was delayed, looking up hyper-local rain alerts and regional PSI air quality readings, scrolling through 7 official government Telegram channels for public announcements, and monitoring 15 different community deal channels for local savings. On top of that, keeping track of upcoming HDB BTO launch tables meant manually refreshing the HDB newsroom. With SG Hub, I brought all of these scattered daily feeds together into a single, real-time civic command center right on my dashboard.

📊 Streaming Economic Insights with Google Cloud BigQuery

Beyond daily situational awareness, I wanted to understand broader macro trends affecting citizens and job seekers in Singapore. To track economic signals alongside civic services, I plugged into Google Cloud BigQuery to analyze public data.gov.sg datasets—streaming job market vacancy counts, year-over-year sector growth trends, and Ministry of Manpower (MOM) retrenchment statistics. By combining BigQuery's fast analytical queries with live API fallbacks, I could monitor top affected industries and workforce shifts directly inside MerlionOS.

💬 Breathing Life into the Chatbot

A directory of links is useful, but the ultimate vision was an assistant that could explain the rules and guide citizens through complex processes. I introduced a chat widget, but standard HTTP post-backs felt clunky. To make the interaction feel premium and responsive, I rebuilt the backend using FastAPI.

I powered the core engine with Google Gemini 2.5 Flash to leverage its parallel tool-calling capabilities. Now, when a user asks multi-step civic questions—such as "I just got my Singapore citizenship — what do I need to do first?", "What tech jobs are in demand right now, and what's the median salary?", or "When do I need to register to vote?"—the model can intelligently invoke the right agency search tools, job market scrapers, and portal guides concurrently.

To ensure the assistant stays reliable under heavy traffic and prevent service disruptions during peak usage, I built a resilient fallback router: if a 429 rate limit is hit, the engine silently falls back to Gemini 3.1 Flash-Lite with Google Search Grounding, maintaining 100% uptime without sacrificing accurate web-grounded responses.

🛡️ Hardening Security: Protecting Civic Trust

When building a tool that connects citizens to government portals, security and trust are paramount. A single malicious redirect or XSS vulnerability could ruin user confidence, so I built defense-in-depth security directly into the core architecture.

On the client side, I implemented strict XSS sanitization via a custom safeURL utility that filters out dangerous protocols (javascript:, data:, vbscript:) and escapes quotes to prevent HTML breakouts. On the backend, my BeautifulSoup scraper follows redirect chains but enforces domain verification—ensuring final landing pages strictly resolve to .gov.sg or trusted public domains like healthhub.sg, wsg.sg, and cdc.gov.sg. Finally, to safeguard user privacy, any URLs matching authentication keywords (singpass, login, auth, corppass) are strictly blocked from automated scraping.

🏆 Shortlisted in the Top 101

I submitted my initial prototype to the Hack2skill × Google Cloud GenAI Academy APAC Cohort 2 hackathon, and was thrilled when MerlionOS was shortlisted in the top 101 projects out of 1,500+ submissions.

Being shortlisted was the ultimate motivation boost. Receiving $100 in Google Cloud Platform (GCP) credits gave me the perfect opportunity to scale beyond a simple prototype and engineer MerlionOS into a comprehensive, high-fidelity platform.

🏗️ MerlionOS System Architecture
graph TD
    User["👤 Citizen User"] -->|Browser / Mobile| FE["💻 Web Frontend & Dashboard"]
    FE -->|Intent Search & Glossary| LocalStorage["💾 LocalStorage Preferences"]
    
    FE -->|FastAPI SSE / REST| API["🚀 FastAPI Backend (Google Cloud Run)"]
    
    subgraph "Google AI & Data Stack"
        API -->|Parallel Tool Calling| Gemini["🤖 Google Gemini 2.5 Flash"]
        Gemini -->|429 Rate Limit Fallback| FlashLite["⚡ Gemini 3.1 Flash-Lite + Search Grounding"]
        API -->|Economic Analytics| BQ["📊 Google Cloud BigQuery"]
    end
    
    subgraph "External Feeds & Security"
        API -->|x-api-key| DataGov["🌐 Data.gov.sg (NEA, LTA Datamall)"]
        API -->|safeURL & .gov.sg Domain Check| GovPortals["🏛️ 81 Statutory Portals"]
    end
    
    subgraph "Deterministic Engines"
        API -->|Rule-Based Analysis| WhyEngines["🎯 Why Explanation Engines (Jobs, COE, HDB)"]
    end
      

🚀 Scaling Up: From 19 to 81 Portals & Preference Controls

With GCP credits in hand and momentum building, I decided to research just how many Singapore government portals actually existed. To my surprise, a thorough audit revealed a staggering total of 81 statutory board and agency portals—ranging from health (HPB) and monetary policy (MAS) to urban planning (URA), defense (OneNS), emergency services (SCDF), and the Judiciary.

Expanding the index fourfold meant the interface needed a major UX overhaul. Showing 81 portals all at once would overwhelm anyone, so I built personal preference settings—allowing users to hover over any card to hide it with a quick eye icon toggle. I also built a Manage Portals control panel at the top of the grid with live text search, visible/hidden filters, multi-select checkboxes, and bulk add-or-hide actions, persisting every user's custom layout directly in localStorage. This turned a massive directory into a clean, personalized civic workspace.

🔍 Intent-Based Search & Plain-English Glossary

Navigating public services often fails because citizens don't know official government terminology. To bridge this gap, I built an Intent-Based Search Bar at the top of the portal grid. Instead of requiring users to know exact agency names, it maps plain-language phrasing—like "change shop address", "top up CPF", or "renew passport"—against a curated dictionary of everyday synonyms, complete with quick-task chips. If a search query matches a live SG Hub dashboard tab (e.g., "COE premium"), the search bar intelligently surfaces a direct link straight to that live panel.

To demystify complex policy jargon, I also created an interactive Plain-English Glossary. Any of 26 common civic terms—such as CPF, SRS, COE, BTO, EHG, PSI, or SSOC—rendered anywhere inside the app gets a subtle dashed underline. Hovering on desktop or tapping on mobile displays a clear, one-sentence explanation in a tooltip. A background MutationObserver continuously scans the DOM so newly loaded panel content is annotated automatically.

🚕 Daily Mobility & Border Safety

Once the portal grid was under control, I turned my attention back to the live dashboard. I wanted to expand beyond basic public transit updates and cover non-public transport options—adding a live islandwide LTA Taxi Availability count paired with an opt-in "Around You" geolocation lookup to locate taxis within 2km, alongside the latest COE bidding premiums across all 5 categories.

To support cross-border commuters and daily safety, I integrated live ICA checkpoint delay advisories for Woodlands and Tuas congestion directly from the official ICA Newsroom, and added real-time PUB flood advisory alerts rendered as priority warning banners at the top of the feed.

🏠 Unlocking Data Insights: Housing, Wages & Wealth

To help homebuyers navigate Singapore's housing market, I built an HDB Resale Flat Price tracker and home loan insights tool. Since many buyers are surprised by the cumulative interest rates and total repayment amounts over 20 to 30 years, this tool makes mortgage calculations, town-by-town median prices, and year-over-year trends transparent at a glance.

Understanding career growth and income trends usually requires digging through complex statistical tables. To solve this, I built the Occupational Wage Explorer to unlock data insights that aren't easily visible at a glance from the MOM website. It indexes over 500 detailed job titles—including newly added SSOC 2024 AI-era roles—featuring real median basic and gross wages, per-title increment rankings, and top-paying tech roles in an interactive, searchable table.

For personal financial planning, I built an interactive IRAS Tax & SRS Relief Optimizer. It combines real-time filing deadlines scraped from IRAS with progressive resident tax calculations, helping citizens maximize tax savings by analyzing CPF SA/MA top-ups, SRS contributions, itemized pre-existing reliefs (capped at S$80,000), and life insurance deductions.

⚡ Environment Feeds & Acquiring the Data.gov.sg API Key

As I expanded environmental tracking beyond basic PSI readings to include PM2.5 forecasts, 24-hour outlooks, live temperature, humidity, wind direction, and a 5-tier UV Index, the app began making frequent live requests to NEA and data.gov.sg endpoints. Relying on unauthenticated public calls quickly led to API throttling during peak hours.

This friction drove a major infrastructure upgrade: registering an official DATA_GOV_SG_API_KEY (applied via the x-api-key header) across all data.gov.sg requests. This unblocked high-frequency environmental polling, eliminated burst-rate limits, and ensured unthrottled, zero-downtime updates across all weather tiles and government feeds (expanding Telegram broadcasts from 7 to 12 official channels).

🎯 Deterministic "Why" Insights & Structured Data

As the feature set matured, the focus shifted from feature expansion to deep architecture hardening and reliability. While AI models are great for conversation, critical financial and economic trends require 100% deterministic accuracy without hallucination.

I built three rule-based "Why" Explanation Engines that analyze existing datasets without extra network calls: cross-referencing Hiring Pressure against multi-year CAGR trends to explain vacancy acceleration vs churn, comparing COE quota and bids round-over-round to explain supply/demand price moves, and comparing flat-type price changes against islandwide figures to flag broad-based price growth versus flat-mix shifts. All three engines stay silent when data is ambiguous, avoiding forced guesses.

Architecturally, I eliminated fragile text-parsing between the backend and dashboard endpoints. Previously, job stats and COE results were computed once as Gemini text blocks and re-parsed via line splits. I refactored the data tools to return structured dictionaries directly consumed by /api/sg-hub/* endpoints, wrapping them in thin formatting helpers for Gemini, ensuring complete decoupling and zero dashboard breakage when chat prompts change.

🔧 Production Hardening, Testing & Mobile UX Polish

To protect the public demo against quota exhaustion, I introduced in-memory per-IP rate limiting (8 requests/minute sliding window) on /api/chat endpoints, safeguarding our shared Gemini free-tier quota.

On the code health front, I centralized TTL caching helpers in tools/core.py to eliminate duplicated cache code, added a unified route decorator in server.py to prevent internal exception leaks, and set up pyflakes alongside automated Python unit tests in GitHub Actions CI gates—achieving full route-level coverage for all API endpoints and decision-boundary testing for the "Why" engines.

Finally, I conducted a comprehensive mobile polish pass—fixing CSS grid descendant bugs on onboarding banners, surfacing the 2km taxi radius directly on action buttons, adding tap-to-tooltip chart interactions, and ensuring Manage Portals dropdowns stay neatly positioned above the Co-Pilot launcher on all screen sizes.

What started as a local script for 19 portals had evolved into a resilient, fast, and secure civic co-pilot, fully containerized and deployed on Google Cloud Run.

💡 Key Takeaways & Lessons Learned

Building MerlionOS taught me that civic tech becomes transformative when developers build tools to solve their own everyday friction. Here are the core lessons I took away from this journey:

Building MerlionOS taught me a simple lesson: the best tools are built when you are the first and most critical user of your own code. It's the micro-optimizations—the mobile layout alignments, the stream controllers, and the silent API fallbacks—that turn a demo into an app you trust to use every single day.

Where to find MerlionOS