For the past year I've run most of my day on a system I built for exactly one user: me. Last week I open-sourced it. It's called AEGIS, it's MIT-licensed, and this is the honest tour.
The bet
Every week there's a new agent framework that promises to do everything. AEGIS is a smaller, stranger bet: that software can learn the shape of one person's life well enough to interrupt less. It watches the boring things — tasks, email, money, a
knowledge base, homelab alerts — and only reaches for me when a decision is genuinely mine to make. It's not a chatbot I log into; it's a fleet of scheduled and event-driven workflows that mostly run without me.
## The shape
Four named agents, each a permission boundary with a personality: Sebas (GTD), Raphael (research), Maou (money), Pandora's Actor (infrastructure). The spine is FastAPI + Postgres (with pgvector) + Temporal, on a small Docker Swarm at home. Models
resolve through a LiteLLM proxy — local-first, reaching for Claude or GPT only when a job needs the horsepower.
A few design decisions did most of the work.
## One primitive for every interruption
The decision I'm proudest of is a table. Every time the system needs a human, it's the same shape: a row in a Postgres interactions table, a card in my chat app, and a Temporal workflow that durably waits — for days if it has to — until I tap a
button.
Approvals, choices, drafts to review, plain acknowledgements — one mechanism, five card kinds, one callback format. No per-feature approval tables; adding a new "ask the human" moment costs nothing. And because interrupting me is now a formal act with a
paper trail, flows get written to do more work before they ask. That one decision turned AEGIS from a notification machine into a queue of interruptions that have to earn their way in.
## Durability instead of cron-and-hope
A card a workflow waits on for three days is miserable to build with cron and a queue — you hand-roll a state machine and reconcile it after every deploy. Temporal's durable execution is exactly this: the workflow awaits a signal, and the wait survives
restarts, redeploys, and the occasional node reboot. Schedules reconcile from DB config, so changing a flow's cadence needs no redeploy.
## Behavior is data, not code
The change that made AEGIS forkable was deleting every line that said if agent == "sebas". Capabilities, tool grants, and routing now live in database metadata, edited from an admin panel. The code asks "who owns GTD?" and gets an answer; it never
names names. Rename the agents, re-scope them, or add your own — no Python.
## Local-LLM-first, for real
Everything routes through a LiteLLM proxy exposing three tiers — fast / balanced / smart. Each agent is assigned a tier, never a model name, so swapping models is proxy config and the app code never changes. One reasoning-model gotcha is handled
explicitly: reasoning models bill hidden reasoning tokens against max_tokens before any visible output, so a tight cap returns finish_reason=length with empty content — the client detects that and raises a typed truncation error instead of handing
an empty string to json.loads.
## What it is not
Not a SaaS — no hosted version, and it does nothing until you point it at your own accounts and models. Not another framework to build on; it's a complete, opinionated application you fork and configure for your own life. If that sounds like more setup
than you want, reading the code is a perfectly good outcome.
## Take it apart
- Code: https://github.com/hikmahtech/aegis
- The longer tour + design essays: https://hikmahtechnologies.com/aegis
I'd genuinely like to know what breaks — and what you'd reach for on the "smart" tier these days. That's the slot I still escalate most often.
Top comments (1)
The flow-first boundary is useful because it makes the recovery policy explicit instead of hiding it inside prompts. For self-hosted deployments, I would make each node record an input/output schema, retry classification, and idempotency key. That makes a failed run debuggable and lets operators safely resume only the failed step.