Someone on a dev forum is running a public build diary where he staffs a software project entirely with AI agents. On Day 3 he did something that stuck with me. Before letting the models write any code, he added a "company culture" module to his agent system: pick a cultural tone, and those rules get written straight into each AI role's system prompt. He set up four tones ranging from a plain default to a high-pressure "last-place-gets-cut" mode, assigned distinct personalities to the eleven roles that actually make decisions, and left the seven tool roles (packaging, environment setup, clicking through screens) personality-free so they just follow the process.
Then he wrapped it in four one-click team lineups. A balanced default team. A "Silicon Valley geek" team tuned for cutting fake requirements and shipping minimal changes. A "wolf-pack" team that pairs aggressive engineering with one deliberately nitpicky tester as a brake. And a high-pressure team where every stage audits the one above it. He says he'll swap these lineups onto a real project and record delivery time, the token bill, and finished-product quality for each.
What's actually worth copying here
The metrics are the headline, and the metrics are exactly the part you can't trust yet. As of that post he hadn't run the comparison. There's no delivery-time data, no token numbers, no quality verdict. Treat all of that as unverified. Whether "wolf-pack culture ships better software" is true or marketing-flavored intuition is genuinely unknown from the evidence on the table.
But strip away the chase for metrics and there's a solid piece of engineering underneath. The real asset is boring in the best way: an editable, versioned store of personas and team lineups, plus a ledger that records exactly which composed prompt each role ran on a given job. That's the thing that makes an experiment like his repeatable at all. Without it, "I ran the geek team" is a memory, not a record. With it, you can re-run a lineup three weeks later and know you sent the agents the same instructions, byte for byte.
That separation matters for anyone doing serious AI agent development, because the moment you start tweaking system prompts per role, you've created a configuration problem disguised as a creativity problem. You will forget which prompt variant produced which behavior. You will "improve" a persona and quietly lose the one that worked. A composition layer with versions is the cure.
The data model, kept deliberately small
You don't need anything exotic. Four tables carry the whole thing.
A `personas` table holds each personality preset as a row: a stable id, the role it targets (architect, developer, tester, and so on), a human label, the prompt fragment text, and a version number. A `lineups` table names a team. A `lineup_members` table maps a lineup to the specific persona version each role uses, so a lineup is a frozen set of choices rather than a loose reference that drifts when you edit a persona later. And a `runs` table logs each execution: which lineup, a timestamp, and, crucially, the fully composed system prompt that each role actually received.
That last column is the one people skip and regret. Store the composed prompt, not just the persona id. Personas get edited; a run should remember the exact words it ran on even after you've moved on to version 5.
SQLite is the right size for this. It's a single file, it's transactional, and it's trivial to inspect. When you want to eyeball why two runs behaved differently, you open the file in a SQLite editor and diff the stored prompts directly instead of digging through logs. That tight read-write loop is most of the value early on.
Making composition an endpoint
The composition logic is small enough to be a single Python function: take a lineup id, pull its members, fetch each persona version's text, assemble the system prompt per role, write a `runs` row with the composed output, and hand the assembled prompts back to whatever orchestrates the models. Exposing that as a hosted endpoint means your agent runner doesn't carry the persona database around — it asks the endpoint "give me the composed prompts for lineup 3" and gets back both the prompts and a run id to attach to its results.
You can run Python online for the composition service and the SQLite store together, which keeps the whole ledger in one hosted place rather than scattered across a laptop. A rough shape:
import sqlite3, json, datetime
def compose_lineup(db_path, lineup_id):
con = sqlite3.connect(db_path)
con.row_factory = sqlite3.Row
members = con.execute(
"""SELECT m.role, p.text, p.version, p.id AS persona_id
FROM lineup_members m
JOIN personas p ON p.id = m.persona_id
WHERE m.lineup_id = ?""",
(lineup_id,),
).fetchall()
composed = {}
manifest = {}
for row in members:
prompt = row["text"].strip()
composed[row["role"]] = prompt
manifest[row["role"]] = {
"persona_id": row["persona_id"],
"version": row["version"],
}
run_id = con.execute(
"INSERT INTO runs (lineup_id, created_at, composed) VALUES (?, ?, ?)",
(lineup_id, datetime.datetime.utcnow().isoformat(), json.dumps(composed)),
).lastrowid
con.commit()
con.close()
return {"run_id": run_id, "prompts": composed, "manifest": manifest}Nothing clever. The discipline is in always writing the `runs` row before the agents do their work, so every execution is traceable back to an exact composition.
Where the platform line sits
Be honest about the boundary. The original experiment leans on specific models by name. Routing agent calls through Model Center only works for models the platform already offers; if a particular model you want isn't available through it, that part lives outside what you can wire up here, and you'd keep the composition layer platform-side while calling that model wherever it does live. The composition store, the run ledger, and the hosted endpoint are squarely inside the confirmed capabilities. The model roster is the thing to check before you assume parity with someone else's setup.
Similarly, the "does culture improve delivery" question isn't something the infrastructure answers. It gives you clean, comparable runs. Whether the geek team or the pressure-cooker team wins is an experiment you still have to run and measure yourself, and until you do, any claim either way stays unverified.
Why the unglamorous layer is the keeper
The fun of the original diary is the personality cosplay: surgical-strike coder, defensive craftsman, ruthless gatekeeper tester. That's what gets the upvotes. But personalities are cheap to invent and expensive to compare. The piece that survives past the novelty is the plumbing that lets you say, with a straight face, "here is exactly what each role was told, here is when, and here is the version I can roll back to."
Build that first. Swap lineups with a single id, log every composition, and keep the store editable in a file you can open and read. Then, when you finally chase delivery time and token cost, you'll be measuring something real instead of a run you can't reproduce.