LifeGrid
Inspiration
Modern life is made up of hundreds of disconnected tasks: planning family vacations, managing household logistics, tracking budgets, keeping a calendar from turning into chaos.
Today's AI assistants can answer questions, but you still have to coordinate all the actual work. You ask a chatbot for hotel recommendations, but you still have to check flight times, cross-reference family availability, stay within budget, and decide what actually gets booked.
We built LifeGrid to shift that interaction from Questions → Answers to Goals → Coordinated Execution. Instead of juggling tabs, you give LifeGrid one goal — "Plan a 5-day family trip under $4,000" — and a small team of specialized agents does the research, checks it against your budget and your preferences, and stops to ask before anything actually gets booked or spent.
What it does
LifeGrid turns one plain-English goal into a governed, multi-agent run.
Seven specialized agents, one fixed pipeline. A Security Scanner runs first on every request, always. If it's clean, four research agents — Travel, Family, Calendar, Shopping — run at the same time. Then a Finance agent totals the cost and checks it against policy. Then a Plan Writer compiles everything into one final summary. The order is fixed in code (a Google ADK SequentialAgent wrapping a ParallelAgent) — it isn't something the model gets to decide at runtime, on purpose: a fixed sequence can't be prompt-injected into skipping the safety check, because skipping isn't a choice it has the ability to make.
Real human-in-the-loop approval, not a suggestion. A Policy Engine enforces two rules everywhere the same way: any single action over a configurable spend threshold (default $100, adjustable in Settings) pauses and waits for an explicit yes/no; any flight or hotel booking always pauses, regardless of amount. Every flagged item in one agent turn is batched into a single Approval Center so you review everything at once, not one interruption at a time.
A security stop that actually stops things. Every request is scanned for prompt-injection attempts — including ones disguised inside a URL — before any agent acts on it. If something's caught, the run halts immediately: every later agent checks for that before doing any work, so a blocked threat means zero research, zero budgeting, zero booking, not just a logged warning while everything else proceeds anyway.
Persistent preferences, not a blank slate every time. A Firestore-backed Memory Bank remembers things you've told LifeGrid before — a dietary restriction, a lodging preference — and agents read it before making recommendations, so you don't re-explain yourself on every request.
Real Google Calendar, when you want it. Sign in with Google and the Calendar agent checks your actual schedule (read-only) instead of simulated data — it can never write to your calendar.
Per-agent access control. Every agent has a declared, narrow list of what it's allowed to touch. A call to anything outside that list is denied by default, not just discouraged — enforced the same way for every tool call, not something the agent's own good behavior is trusted to uphold.
How we built it
LifeGrid runs on Google's own agent stack end to end, not a third-party framework.
Orchestration: Google ADK (@google/adk) — a SequentialAgent (Security → Research → Finance → Write-up) with a ParallelAgent nested inside it for the four independent research agents. Not a dynamic, LLM-routed graph — a fixed composition, because the one thing we didn't want was the model choosing whether the security check runs.
Models: Gemini 3.5 Flash-Lite by default, with Gemini 3.5 Flash available as a step up — both via Vertex AI, user-selectable per run from a Settings screen. "Auto" lets LifeGrid pick its own default instead.
Memory: Google Cloud Firestore for the Memory Bank in production (a plain in-process store locally, so local dev needs no GCP setup at all). Simple, real preference records — category, key, value, sentiment, source agent — read and written by agents through dedicated tools.
Approvals & session handling: ADK's LongRunningFunctionTool pauses a run mid-turn when the Policy Engine flags something. Resuming it turned out to be the hardest part of this build — see Challenges below.
Frontend: Next.js 16 (App Router, Turbopack), React 19, and a from-scratch Tailwind CSS v4 design system (no component library) — a live activity feed streamed over Server-Sent Events, a mobile bottom-tab layout, and an Approval Center that batches every flagged item from one agent turn into a single review instead of a string of interruptions.
Deployed for real: Google Cloud Run (scale-to-zero, capped instances), Cloud Build for CI, Cloud Trace via OpenTelemetry for observability, and Auth.js for Google sign-in.
Challenges we ran into
A real, reproducible ADK 1.6.0 protocol bug. Resuming an agent's own conversation immediately after a batch of approvals reliably broke Gemini's function-calling protocol, regardless of what the resumed call actually returned. We tried three different in-pipeline mitigations before concluding the fix had to be architectural: the finish line after an approval now bypasses ADK's own continuation entirely and makes one direct, non-agentic Gemini call using the research already gathered plus the user's decisions. It's a deliberate trade-off — that one step isn't "a real agent turn" in the strict sense — made because it's the only version that reliably works.
A fixed pipeline doesn't automatically stop itself. SequentialAgent will happily run every downstream agent even after an earlier one flags a threat — it has no built-in concept of "cancel the rest." We wired a shared state flag and a beforeAgentCallback on every downstream stage so a blocked threat genuinely exits the pipeline, instead of just being logged while everything else ran anyway.
A real security bypass we found by testing our own scanner. Our prompt-injection detector required literal whitespace between words. A malicious phrase embedded in a URL query string — joined with +, standard URL-encoding — slipped past every pattern undetected. Fixed and confirmed live against the exact string that had bypassed it.
A silent production bug that looked like nothing was wrong. A build-time-vs-runtime environment variable mismatch meant our own deployed site's browser code never actually sent the header our own server was checking for — live mode failed on every real user click, with no error shown anywhere, for longer than we'd like to admit, because nothing in the code path treated a failed request as worth surfacing.
Accomplishments that we're proud of
- The security halt isn't a demo trick — we verified live, with the real deployed service, that a detected threat stops every downstream agent, not just logs a warning.
- Most of what we call "governance" is actually enforced, not decorative: per-agent tool permissions, the spend/booking approval gate, and the security scan are all checked in code on every single call, not left to a well-behaved prompt.
- We made the approval threshold something a user controls instead of a number buried in code.
- We kept an honest, running account of what's real versus simulated (flights/hotels/activities are realistic sample data; the security, budget, and permission enforcement around them is not) instead of blurring that line for the pitch.
What we learned
That governance for an agent system has to be structural, not instructional — the moment a rule lives only in a prompt, a clever enough input can talk the model out of it, but a rule enforced in code (a fixed pipeline order, a tool-level permission check) isn't a decision the model gets to make at all. And that "it works" only means something once it's been run for real against the real model, with the real deployed infrastructure — several of the bugs above only existed in production, and were invisible in local testing or in a first read of the code.
What's next for LifeGrid
- Swap the simulated flight/hotel/activity/gear search for real booking APIs — the architecture already isolates that behind each agent's own tools, so it's a contained change, not a rearchitecture.
- Durable session state — runs currently live in memory and don't survive a Cloud Run instance recycling mid-run; move to a persisted session store.
- Broader security scanning — inspecting tool results and external content for exfiltration attempts, not just the user's initial input.
- More household domains: home maintenance scheduling, recurring errands, more than one family's worth of shared context.
Log in or sign up for Devpost to join the conversation.