Inspiration

We spend 8–12 hours a day inside a browser — yet the browser itself has no awareness of our health. It doesn't know you've been sitting for 45 minutes straight, that it's 2am and you're still on YouTube, or that you're doomscrolling Twitter while your stress levels spike. We wanted to build something that lives inside that environment and intervenes — not with notifications you ignore, but with unavoidable, timed overlays that force a pause.

The name came from biology: a symbiont is an organism that attaches to a host and influences its behaviour. SYMBIONT does exactly that to your browser session.

What it does

SYMBIONT is a Chrome extension paired with a local health server. It silently monitors three behavioural signals — scroll velocity, typing cadence, and tab-switch rate — and runs five specialised agents every 5 seconds:

BurnoutLeech — detects frantic tab-switching and triggers a forced breathing break SleepTapeworm — detects late-night entertainment usage and progressively desaturates your screen (5 escalating stages up to full blackout + slowed video playback) PostureNematode — fires after 45 minutes of sedentary screen time with a stretch prompt DepressionDetector — identifies doomscrolling patterns on social media and inserts a friction pause NutritionGhost — intercepts food delivery orders placed while stressed and offers a healthy recipe instead

Every intervention renders as a full-page overlay directly on the site you're visiting — impossible to miss, but always dismissible.

┌─────────────────────────────────────────────────────────────────┐
│                      CHROME BROWSER                             │
│                                                                 │
│  ┌──────────────┐   messages   ┌──────────────────────────────┐ │
│  │ background.js│◄────────────►│       sidebar.html           │ │
│  │              │              │  (popup UI — dot, stats,     │ │
│  │ tracks tab   │              │   test buttons, dashboard)   │ │
│  │ switches     │              └──────────────────────────────┘ │
│  └──────┬───────┘                                               │
│         │ tab_switch events                                     │
│         ▼                                                       │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                     content.js                           │   │
│  │  (injected into every webpage)                           │   │
│  │                                                          │   │
│  │  Sensors:                    Every 5 seconds:            │   │
│  │  • scroll velocity     ───►  POST /walker/ingest         │   │
│  │  • typing cadence            │                           │   │
│  │  • tab switch rate           ▼                           │   │
│  │  • time on page        interventions returned            │   │
│  │                              │                           │   │
│  │                              ▼                           │   │
│  │                      renderOverlay()                     │   │
│  │                      on the live page                    │   │
│  └──────────────────────────────────────────────────────────┘   │
│                           │  HTTP POST                          │
└───────────────────────────┼─────────────────────────────────────┘
                            │
                    localhost:8080
                            │
┌───────────────────────────▼─────────────────────────────────────┐
│                      BACKEND SERVER                             │
│                                                                 │
│   server.py (Python/FastAPI)  OR  symbiont.jac (Jac-lang)       │
│                                                                 │
│   ┌────────────┐  ┌─────────────────┐  ┌──────────────────┐    │
│   │  Auth      │  │   5 Agents      │  │  Storage         │    │
│   │  /register │  │   BurnoutLeech  │  │  habitats[]      │    │
│   │  /login    │  │   SleepTapeworm │  │  interventions[] │    │
│   │  JWT token │  │   PostureNema   │  │  users{}         │    │
│   └────────────┘  │   DepressionDet │  └──────────────────┘    │
│                   │   NutritionGhost│                           │
│                   └─────────────────┘                           │
└─────────────────────────────────────────────────────────────────┘

How we built it

The backend is written in Jac — a graph-native AI language built on Python. Browsing sessions are modelled as DigitalHabitat nodes connected to Intervention nodes via Triggers edges in a persistent graph. The five agents are Jac walkers that traverse this graph and fire when thresholds are crossed.

The Chrome extension (Manifest V3) consists of three parts:

  • content.js — injected into every page, runs the sensors and renders overlays
  • background.js — service worker that tracks tab switches
  • sidebar.html — popup dashboard showing live health stats, symbiosis score, and test buttons

We also built a Python/FastAPI fallback server (server.py) for reliable API compatibility, and a full offline mode where all five agents run as pure JavaScript inside the browser — no server required.

Layer Technology Why
Language Jac AI-native, graph-first. by llm() turns function signatures into prompts. walker: agents traverse graphs instead of querying databases. Single-file full-stack: backend + frontend + agents in symbiont.jac
Graph Engine Jac Graph Nodes (User, DigitalHabitat, Intervention) and edges (Visits, Triggers, RespondsTo) model the user's digital life natively. No ORM. No SQL. No foreign keys.
Agents Jac Walkers BurnoutLeech, SleepTapeworm, PostureNematode, DepressionDetector, NutritionGhost. Each walker traverses the graph autonomously, detects patterns, spawns interventions.
LLM Integration Jac by llm() Zero prompt engineering. Function name + types + docstring = the prompt. Designed for local Ollama (gemma3:4b). Currently falls back to heuristics while Ollama setup completes.
Deployment Jac deploy {} Auto-provisions MongoDB, Redis, serves WebSocket + HTTP, scales to Kubernetes. jac serve symbiont.jac is the target.
Extension Core Chrome Extension API (Manifest V3) Runs inside user's browser, has access to every webpage, can inject overlays anywhere
Content Script Vanilla JavaScript Injected into every tab. Tracks scroll, typing, tabs. Zero dependencies.
Background Worker Chrome Service Worker Maintains WebSocket connection, survives tab closures, reconnects automatically
Popup UI HTML + CSS Simple iframe to dashboard. No React. No build step.
Intervention Renderer Vanilla JS + CSS Creates DOM overlays, applies animations, auto-removes after timer.
Offline Agents JavaScript (in content.js) When server is down, agents run locally with hardcoded thresholds. Always works.
Runtime (Current) Python 3.12 + FastAPI What powers the demo today. REST API. JWT auth. In-memory storage. Temporary bridge while jac serve deployment completes.
Data Storage Python lists (in-memory) Resets on restart. No database setup needed. Hackathon-fast.
Auth PyJWT + bcrypt Token-based auth between extension and Python server.
Logo Python/PIL Programmatically generated. Medical cross + circuit ring + 8 tendrils. No design tool needed.
LLM (Current) None (heuristics only) Ollama not installed in time. by llm() functions return hardcoded defaults. Future: local gemma3:4b.
Deploy (Current) localhost:8080 Single machine. No cloud. No Docker. No Kubernetes.

Challenges

The hardest part was the version compatibility between jaclang 0.9.0 and jac-cloud 0.2.11. The report statement in walkers produced empty responses in the cloud runtime, forcing us to build a parallel Python server that implements the identical API.

Getting Chrome extension content scripts to communicate correctly with the popup was also tricky — chrome.tabs.query({ currentWindow: true }) returns no tabs when called from a popup (it queries the popup's own window). The fix was switching to lastFocusedWindow: true.

Designing interventions that are firm but not hostile took the most iteration. The sleep enforcement in particular needed to feel escalating and serious without being so aggressive that users immediately uninstall the extension.

What we learned

  • Jac's graph model is a genuinely elegant fit for agent-based behaviour tracking
  • Browser extensions have subtle isolation rules (content scripts, popups, service workers all run in separate contexts)
  • Health tech UX is a balance: interventions need enough friction to be effective, but not so much that users disable them
  • Python 3.14 doesn't have pre-built wheels for Rust-based packages — always test on 3.12

Built With

Share this project:

Updates