Why I built it
Two annoyances with commercial assistants I wanted to solve for my own daily use:
- Cost. API calls stack up fast on everyday work — research, summaries, scheduling. The ceiling isn't capability; it's a running bill.
- Amnesia. Every context window fills eventually. The fix is either truncation (forget old turns) or lossy summarization (compress them to a gist). Both drop information I wanted kept.
Routing
Two-layer router. An O(1) keyword pre-filter handles direct intent patterns such as "remind me," "search," and "open my calendar." Ambiguous requests go to Qwen3-0.6B with JSON-grammar enforcement to constrain the routing output.
The router emits either a direct answer or a step sequence (tool → model → tool) with variable substitution between steps. Intermediate results are stored, so the chain is inspectable after the fact.
Memory: Lossless Context Management
Older turns are never deleted — they're compressed into a DAG of summary nodes at increasing depths. The fresh tail of the conversation always goes to the model raw. If the summarization policy ever changes, the raw turns are still there and the DAG can be regenerated from scratch.
This preserves access to earlier conversation turns within the context-management design without discarding their raw records.
Under the hood
- Fast path: Qwen3-0.6B with JSON grammar for routing decisions (tight, cheap).
- Reasoning path: Qwen3-4B in full reasoning mode for complex tasks. Decision made by router, not by caller.
- Tools: 16 implementations — web scraping, PDF handling, notes, deep research, calendar, budget, etc.
- Storage: SQLite with WAL mode for session state; vector store over
nomic-embed-textfor semantic notes. - Frontend: static HTML/JS with WebSocket streaming of orchestrator events (routing decision → tool call → model inference).
Where it stands
Built as a local FastAPI app with no cloud dependency in the default configuration, using a 0.6B router and 4B reasoner on the local machine.