Still Open
Your past weeks of Chrome history left you with a mess of still-open tabs with unknown status. StillOpen classifies the unfinished jobs, files what should survive, and closes those pesky tabs you've been avoiding - out of sight, out of mind. And now you can enjoy better performance that those 30 tabs were eating up!
All Things Agentic · Taskmaster · Live API Medium article: https://medium.com/@gregbenja308/your-tabs-arent-a-topic-they-re-unfinished-work-953d17744e8a
Inspiration
Almost everyone has opened their laptop to the dreaded 30+ Chrome tabs. Some tabs stay out of sentiment - I too am often guilty of hanging on to weeks-old tabs just because I get attached. After all, what if I still need that tab later and I delete it? I can't confidently close my tabs without knowing I truly don't need them anymore. This issue is exacerbated by grouping tabs by topic, like "Online Books", "Coding Tools", and "Taxes".
Because conceptually, a topic is never "finished", so how do we easily know when we can close that group? But unlike a "topic", a "task" can be finished and conceptually resolved. Instead of grouping tabs by topic, lets group by actionable tasks. Ex: “Finish biology reading” can close, while “Online Books” cannot.
That is the friction brought to this hackathon. Chrome’s Tab Organizer asks what a pile is about. OneTab hides URLs. Summarizers chat over the mess and leave forty tabs open. I wanted an agent that groups tabs by task (not topic), asks if the task is done, writes down what should outlive the strip, and closes that pile of tabs. When a task is done, so are the related tabs.
Features
StillOpen is a Chrome extension backed by a Cloud Run agent. It has the following features:
Scanning a window's tabs and auto-classifying them into Task groups. Ex: "Finding an Austin Appt to rent" has all your tabs where you browsed Zillow, RedFin, Austin climate, etc.
Users can drag and drop tabs into different/new Task groups if desired. Users can also rename a task to their liking.
A "Finished" section in the extension for tasks that are done and closed. Hitting "Done" on a task closes all of the tabs under it, which stay in memory for 30 days to restore if needed.
Notes for each task, so that you can safely document final decisions (ex: "Chose
<some appt URL>for my Austin rented apartment"). That way, you don't have to dig through Chrome history to find relevant tabs to remind you of your takeaways.A chatbox where you can ask other-heuristic questions like "Close any tabs that haven't been used in the last 30 days". Users get a preview of tabs that fit the criteria => they can remove some of them from the purge => StillOpen will close the rest.
A "Memory" section for judges/users to see what stillOpen learns from the user
"Demo Seed" button to seed example tab data (includes a diverse array of tab topics like house hunting, word definition searches, stackOverflow Qs)
What it Does
StillOpen reads only title, URL, and lastAccessed from tabs — never page HTML, cookies, or history. Gemini 3.5 names tasks from that snapshot: “Find a place in Austin,” not zillow.com. You drag tabs, type notes, hit Done, close!
That click is not a local tabs.remove. The extension calls POST /v1/tasks/finish and an ADK graph runs:
- Surveyor redacts the snapshot. Bank / health / gov / school / auth hosts never reach a model.
- Framer builds a plan. Intent is inferred on the server from sanitized tabs — a hostile client cannot force a filing by lying about
intention. - Clerk (ADK
LlmAgent, Gemini 3.5 Flash) drafts the artifact. Your notes go in as trusted text; a Python guard puts them back verbatim if the model rewrites them. - Runner files into Firestore and returns a permalink at
/v1/filings/{id}. - Verifier re-reads the filing. It requires a citation (a tab host in the body) and the user’s notes in the body. If either fails,
close_tab_idsis empty — the tabs stay open. - Only then does Chrome close the pile. Finished keeps titles, notes, Restore, and links to the filing and an append-only audit:
proposed → clerk_draft → runner_file → verifier_ok → close_applied.
How I built it
Four packages, one GCP project, tools isolated by a gateway allowlist.
| Piece | Role |
|---|---|
packages/ext |
Chrome MV3 workbench (WXT / React) |
packages/core |
Surveyor, Framer, ADK Clerk, Runner, Verifier, MemoryBank, Watch |
packages/api |
FastAPI on Cloud Run |
packages/jobs |
Scheduler → POST /v1/jobs/watch |
Gemini 3.5 on Vertex (global) clusters tabs, chats, and drafts. Google ADK is the SequentialAgent clerk → runner → verifier — Clerk may draft; only Python may write; only the Verifier may green-light a close. Firestore holds plans, filings, watches, and plan events. Secret Manager, Cloud Trace, and inline Model Armor sit on the model path. Tab titles are untrusted data (TITLE_IS_DATA). Undo URLs never leave chrome.storage.session.
Judges can ping the same facts the code believes:
/health—env: cloud,gemini: vertex,bank: firestore,run_graph: clerk>runner>verifier/v1/agents/registry— introspected fromRUN_GRAPHand the loaded gateway policy (cannot drift from a slide)/v1/filings/{id}— the exact bytes Clerk drafted, with citations/v1/plans/{id}/audit— the chain for that close
Optional second models (Gemma 2 for labels, text-embedding-004 for tab vectors) plug in behind flags. I did not stand up Vertex Vector Search serving — an always-on e2-standard-16 is the wrong cost for a solo hackathon Memory Bank.
Hosted API: https://stillopen-tqodm6o6za-uc.a.run.app (use /health; Cloud Run intercepts /healthz). The unpacked extension talks to that URL by default.
Challenges I ran into
The model wanted to lecture. “Which tabs haven’t been opened in 30 days?” came back as a blurb about an inactive group on the board. There is no such group. Listing unused tabs is now a match list under chat, even when Gemini prefers to explain stale cutoffs.
Close is a privilege, not a side effect. Taskmaster wants autonomy. Auto-closing someone’s bank tab is the wrong kind. The human says done; the Verifier can veto. Watch is the loop that runs without a click. Holding that line was harder than calling Gemini.
Deletion is dangerous! Because deletion is more dangerous than adding tabs, for example, I needed to make a "Restore" option and keep the closed tasks for 30 days in case. Past this, the user can always go into Chrome history if needed.
Accomplishments that we're proud of
- A Verifier veto: no citation, no verbatim notes, no close.
- A filing you can click and an audit trail you can read - not a screenshot of “the agent did something.”
- Bank sites (like Chase) stay
blocked_from_modelfor privacy - An agent registry generated from the running gateway
- A trust model we would load on our own profile: redact first, deny-list, session-only undo URLs, SHA-256 user tokens on write paths, job token for Scheduler.
What we learned
Agents that only write text fail this track. Agents that close tabs without a named task fail the user. The split that works: Gemini names and drafts; Python files and proves; the human says done; Watch runs later.
A 30-day Finished search does not need an embedding model on every keystroke. house → apartments is a synonym. Dedicated Vector Search serving is for another scale — and it will eat the credit grant silently.
What's next for StillOpen
- Surface Watch outcomes in the side panel when a tracked page actually changes (the tick already runs).
- Chrome Web Store, so users do not need to load unpacked.
- Finished search across notes and tab titles - synonyms first, Vertex embeddings at close time if the archive grows.
Built With
- fastapi
- firestore
- gemini
- gemma
- model-armor
- vertex
Log in or sign up for Devpost to join the conversation.