DEV Community

Cover image for I moved the agent topology out of my code and into the database
Islomkhon Nizomkhonov
Islomkhon Nizomkhonov

Posted on

I moved the agent topology out of my code and into the database

The brief is always some version of "the agent should answer customer questions about their orders."

Before I can write a single line about orders, I need an agent loop that calls a model and runs the tools it asks for, a registry of those tools, somewhere to keep the customer and order data, a rule for which agent answers first, and a panel so the client can change the wording without calling me.

That is a month of work, and it is invisible in the invoice. So I built it once.

I open-sourced it as CerebrumKit. Here is the design decision I would want to argue about first.

The decision: agents are data

The version of this I had built before kept the topology in source code. Which agents exist, what each one is told, which tools it can call, who answers first - all of it in Python, so every change was a deploy.

The new version keeps all of it in the database:

Thing What it is Where it lives
Tool OpenAI function spec + Python body tools table
Skill Instructions + the tools they need skills table + skill_tool
Agent Description (its system prompt) + skills agents table + agent_skill
Workflow start / group / stop graph projects.workflow JSON
Storage Your own tables + column descriptions real tables in the same database
Context tool A tool run before the agent reads the message agent_context_tools

The tools panel: every tool is an OpenAI function spec plus a Python body, both editable while the app is running

Editing a tool body in the panel takes effect on the next message. The compiled body is cached by (tool id, body hash), so the cost of that is a dictionary miss.

What it buys

The domain expert can change the agent. The valuable sentence in a support agent is not def lookup_order(...). It is "never quote a delivery date you have not read from the order". That belongs to the person who owns the refund policy, and it should be editable on a Tuesday afternoon.

Multi-agent without a framework in your imports. A workflow graph decides which agent or group answers and in what order; a second group can review what the first one produced. One agent can delegate a self-contained task to another, with depth capped at 3.

The model-facing contract and the implementation are one row. When the tool description and the Python body can drift apart, they do. Here they are edited on the same screen.

What it costs

I would not trust a post about an architecture that only lists the good parts.

You give up code. Complex conditional routing becomes a canvas with groups, not an if. If your agent control flow is genuinely a program, this is the wrong tool and a library is the right one.

Tool bodies are code execution. They run with full builtins and are not sandboxed - deliberately, because the shipped tools import requests, SQLAlchemy and app internals, and one passes model-authored SQL to the database. So tool authoring is admin-only, and a tool body is reviewed like a commit.

No transcript in the prompt. Earlier chat messages are not replayed. Memory (a note keyed by agent and user) and tools carry the facts. Runs get cheaper and more predictable, and the tools have to be good enough to compensate.

One process. The websocket registry and in-flight tasks live in process memory, so the documented deploy is one uvicorn worker behind nginx.

The detail I did not expect to matter: column descriptions

When the agent decides which tool to call, what it reads is the text you wrote. The description on a database column - "the delivery date quoted to the customer at checkout" - is a prompt.

Schema design for an agent is prompt engineering with a type system. The panel makes you write a description on every table and every column for that reason, and the tools read them.

Two agents, one catches the other

Here is the run that convinced me the workflow was worth building.

A customer asks why order AC-10477 has not arrived. The first agent finds the customer, reads the order, searches the help articles, and answers: the order is two days past its promised date, so the late-delivery credit applies.

The second agent - a different brief, same tables - reads the same order and points out that the credit only applies while the status is shipped or packed. This order is delayed, so the first agent promise was wrong.

I did not write that check as an if. I wrote it as a second agent with a different instruction, and put it in the next group of the workflow.

The client portal: two agents, the same order, two different conclusions

How to try it

Postgres via docker compose up -d, then seed_all.py, then npm run dev, using the admin and client accounts the seeder creates from your .env. Two commands and a seed, roughly two minutes.

Repo: https://github.com/islomkhon/CerebrumKit

Over to you

If you are building agents for businesses, I would like to hear where you draw the line between data and code - and whether you moved it after your first production incident. That is the question I am still chewing on.

Top comments (2)

Collapse
 
mthburnsbarberweb profile image
mthburnsbarber-web

The "two agents, one catches the other" example is what makes this click — you turned a conditional business rule into a second agent with a different instruction, and let the workflow graph enforce the review rather than writing the check as code. That's the real unlock here. The column descriptions as prompt engineering framing is also a sharp insight; we've seen schema design decisions ripple into model behavior in ways that feel surprising until you realize the description IS the contract. The honest "what it costs" section is refreshing — the no-transcript constraint is a real trade-off that forces discipline in tool design. Excited to dig into CerebrumKit.

Collapse
 
islomkhon_nizomkhonov_a33 profile image
Islomkhon Nizomkhonov

Thank you - that is exactly the trade I was trying to make visible.

On the scale question: there is no cap on the number of agents. You write them as separate briefs over the same tables, then stack them in the workflow to match how the business actually runs - one agent answering, a group of agents working in parallel, a second group reviewing what the first produced. An agent can also hand a self-contained task to another, so the graph composes instead of collapsing into one enormous prompt.

That is why I would call the potential here effectively unlimited: the ceiling is not the framework, it is how clearly you can describe each piece of the work.

Welcome to explore it - github.com/islomkhon/CerebrumKit - and I would genuinely like to hear where it breaks first.