The Full Tutorial: 6 AI Agents That Run a Company — How I Built Them From Scratch
Saturday, February 7, 2026 AI
Scraped Article
My last post blew up — 600K views, 2,400 likes. The most common reply? "I get it, but I couldn't build it myself." So I wrote the build guide. 5,600 words, every step, nothing hidden. You don't need to know how to code — just how to talk to an AI coding assistant.
What You'll End Up With
Here's what you'll have when you're done:
6 AI agents doing real work every day: scanning intelligence, writing content, posting tweets, running analyses
10-15 conversations per day: standups, debates, watercooler chats, one-on-one mentoring
Agents that remember lessons learned and factor them into future decisions
Relationships that shift — collaborate more, affinity goes up; argue too much, it drops
Speaking styles that evolve — an agent with lots of "tweet engagement" experience starts naturally referencing engagement strategies
Full transparency — a pixel-art office on the frontend showing everything in real time
Tech stack: Next.js + Supabase + VPS. Monthly cost: $8 fixed + LLM usage.
No OpenAI Assistants API. No LangChain. No AutoGPT. Just PostgreSQL + a few Node.js workers + a rule engine.
You don't need to start with 6 agents. Begin with 3 — a coordinator, an executor, and an observer — and you'll have a fully working loop.
Chapter 1: The Foundation — 4 Tables to Close the Loop
A lot of people jump straight to "autonomous thinking." But if your agent can't even process a queued step, what autonomy are we talking about?
The Core Data Model
The entire system skeleton is 4 tables. The relationship between them is simple — picture a circle:
Agent proposes an idea (Proposal) → Gets approved and becomes a task (Mission) → Breaks down into concrete steps (Step) → Execution fires an event (Event) → Event triggers a new idea → Back to step one.
That's the loop. It runs forever. That's your "closed loop."
Create these tables in Supabase:
The Core Data Model — 4 Tables:
📋 ops_mission_proposals
→ Stores proposals
→ Fields: agent_id, title, status (pending/accepted/rejected), proposed_steps
📋 ops_missions
→ Stores missions
→ Fields: title, status (approved/running/succeeded/failed), created_by
📋 ops_mission_steps
→ Stores execution steps
→ Fields: mission_id, kind (draft_tweet/crawl/analyze...), status (queued/running/succeeded/failed)
📋 ops_agent_events
→ Stores the event stream
→ Fields: agent_id, kind, title, summary, tags[]
Beginner tip: If you don't know how to write the SQL, copy that table above and paste it to your AI coding assistant with "Generate Supabase SQL migrations for these tables." It'll handle it.
Proposal Service: The Hub of the Entire System
Beginner tip: What's a Proposal? It's an agent's "request." For example, your social media agent wants to post a tweet, so it submits a proposal: "I want to tweet about AI trends." The system reviews it — either approves it (turns it into an executable mission) or rejects it (with a reason).
This was one of my biggest mistakes — triggers, APIs, and the reaction matrix were all creating proposals independently. Some went through approval, some didn't.
The fix: A single proposal intake pipeline (one entry point) No matter where a proposal comes from — agent initiative, automatic trigger, or another agent's reaction — everything goes through the same function.
What are Cap Gates? Think of it this way: your company has a rule — max 8 tweets per day. If you don't check the quota at the "submit request" step, what happens? The request still gets approved, the task still gets queued, the executor checks and says "we already posted 8 today" and skips it — but the task is still sitting in the queue. Tasks pile up, and you won't notice unless you check the database manually.
So check at the proposal entry point — quota full means instant rejection, no task enters the queue.
Each step kind has its own gate. The tweet gate checks how many were posted today vs. the quota:
Tip: Block at the entry point, don't let tasks pile up in the queue. Rejected proposals should be logged (for audit trails), not silently dropped.
The Policy Table: ops_policy
Don't hardcode quotas and feature flags in your code. Store everything in an ops_policy table with a key-value structure:
A few core policies:
The benefit: you can tweak any policy by editing JSON values in the Supabase dashboard — no redeployment needed. System going haywire at 3 AM? Just flip enabled to false.
Heartbeat: The System's Pulse
Beginner tip: What's a Heartbeat? Literally — a heartbeat. Your heart beats once per second to keep blood flowing; the system's heartbeat fires every 5 minutes to check everything that needs checking. Without it, proposals go unreviewed, triggers go unevaluated, stuck tasks go unrecovered — the system flatlines.
Fires every 5 minutes, does 6 things:
One line of crontab on the VPS triggers it:
Beginner tip: crontab is Linux's built-in scheduler — like setting an alarm on your phone. */5 * * * * means "every 5 minutes." curl sends an HTTP request, so this hits your heartbeat API every 5 m