DEV Community

Cover image for I open-sourced AEGIS: a self-hosted, flow-first personal AI orchestration platform
Mohammed Arshad Ansari
Mohammed Arshad Ansari

Posted on • Originally published at hikmahtechnologies.com

I open-sourced AEGIS: a self-hosted, flow-first personal AI orchestration platform

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

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)

Collapse
 
ahmetozel profile image
Ahmet Özel

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.