Oliver Architecture: Building Autonomous Agent Infrastructure at Zero Cost
Oliver: Building Autonomous Agent Infrastructure at Zero Cost
Over the past 18 months, we've built and deployed Oliver—an autonomous agent infrastructure that runs our servers, schedules work, routes decisions, and manages a portfolio of six products. What started as an experiment in "what if we let Claude manage our cron jobs?" has become the operational backbone of BeddaTech.
This is the first in our "Oliver's Lab" series: real stories about building autonomous systems, complete with architecture decisions, failure modes, and the actual numbers.
The Problem: Manual Operations at Scale
In 2024, we had:
- 6 products across different clouds (Vercel, Supabase, Expo)
- 40+ scheduled tasks (content generation, data pipelines, cleanup jobs)
- 2 humans coordinating deployments, monitoring logs, and fixing broken crons
- No real-time alerting for failed jobs
- No feedback loop—broken pipes stayed broken until someone noticed
Every Monday, one of us would spend 2+ hours reviewing logs, manually restarting failed jobs, and coordinating deploys. Worse, operational knowledge lived in one person's head.
The Solution: Let Claude Schedule Its Own Work
In late 2024, we started experimenting: what if we gave Claude access to our actual infrastructure—database, GitHub, Vercel API—and let it reason about what work needed doing?
The architecture is simple:
┌─────────────────────────────────────────────────────────┐
│ Oliver (Familiar Workspace Core) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Agent Fleet (Cron Runners) │ │
│ │ - bedda-marketing-engineering │ │
│ │ - krain-engineering │ │
│ │ - familiar-engineering │ │
│ │ - funding-scout │ │
│ │ - krain-content-drafter │ │
│ │ (Each runs as scheduled cron process) │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Task Queue (SQLite in ~/.familiar/familiar.db) │ │
│ │ - Central dispatch │ │
│ │ - Tracks in-progress, completed, blocked work │ │
│ │ - Owned by agent or human (Matt) │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Familiar API (Node.js Backend) │ │
│ │ - /api/tasks/next (get next task for agent) │ │
│ │ - /api/tasks/{id}/claim (claim work) │ │
│ │ - /api/tasks/{id}/complete (finish work) │ │
│ │ - /api/memory/search (operational knowledge) │ │
│ │ - /api/agents/* (agent registration) │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ External Systems (via Tools) │ │
│ │ - GitHub (bedda-tech org) │ │
│ │ - Vercel (deployment, env vars) │ │
│ │ - Supabase (auth, real-time features) │ │
│ │ - Neon (PostgreSQL for content, analytics) │ │
│ │ - Twitter/X API (content distribution) │ │
│ │ - Claude API (inference) │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Each agent is a scheduled Node.js process that runs on our infrastructure. On boot:
- Check for work:
GET /api/tasks/next?agent=bedda-marketing-engineering - Claim if available:
POST /api/tasks/{id}/claim - Do the work (read code, make changes, run tests, deploy)
- Report back:
POST /api/tasks/{id}/completewith a summary
The work loop is deterministic and auditable. Every action, every API call, every decision is logged and timestamped. If Claude makes a mistake, we can see exactly where and fix it.
Key Design Decisions
1. Task Queue, Not Direct Orchestration
We don't use workflow frameworks or containers. We use a simple database table with task state. Why?
- Debuggable: Matt can see the queue in the dashboard, adjust priorities, or pause specific agents
- Resilient: If a cron process crashes, the task stays in "in_progress" and we know what to retry
- Auditable: Every task carries a revision history showing what Claude wanted to do vs what Matt approved vs what actually ran
2. Memory System for Operational Knowledge
From the beginning, we captured operational decisions in ~/oliver/memory/:
memory/
├── preferences/ # How Matt wants work done
├── entities/ # Teams, orgs, products
├── cases/ # Incidents, learnings
├── tools/ # API keys, endpoints
└── YYYY-MM-DD.md # Daily notes from runs
This is vector-indexed and searchable. When a new agent starts, it can ask "have we dealt with Neon connection issues before?" and get back relevant past solutions.
3. No Training or Fine-Tuning
We don't fine-tune Claude. We give it context: the codebase, the memory system, the product docs, and a clear brief of what needs doing. This keeps ops cheap and the system upgradeable—when Claude 5.1 shipped, we just pointed agents at it.
4. Human Approval Gates for Irreversible Work
Anything destructive (force-push, delete branches, data migrations) requires Matt's approval first. The agent stages the work, Matt reviews in the dashboard, and only then does it execute.
What Oliver Manages Today
After 18 months, Oliver runs:
| Domain | Examples | Frequency |
|---|---|---|
| Content Generation | Blog posts (bedda.tech, Nozio docs), tweet drafts, Reddit posts | Daily/Weekly |
| Data Pipelines | Twitter engagement tracking, Supabase metrics, financial sync | Daily |
| Deployment | Push to production, rollback on failure, database migrations | On-demand |
| Support Automation | KRAIN ticket triage, Discord moderation, customer outreach | Hourly/Daily |
| Monitoring | Cron health, database sync, uptime checks, cost alerts | Continuous |
| Portfolio Updates | Weekly briefings for all six products, funding opportunities | Weekly |
Failure Modes (and How We Fixed Them)
The NVM Saga
We ran Node 22 in production but built local code against Node 25. When we did a clean npm rebuild, it installed ABI-127 modules, but the live service was ABI-141. The service crashed on startup and crashed on every restart for 3.5 hours.
Fix: Enforce Node version in every shell session (sudo -u mwhit -H bash -lc to pick up nvm).
Schema Drift Breaks Crons
In April, we added columns to the database (view_count, series, engagement metrics) but forgot to run the Drizzle migration on Neon. The blog generation cron ran successfully for 17 days, silently failing to insert rows because the columns didn't exist.
Fix: Task #851 added auto-migration on deploy. Now every Vercel deploy verifies schema matches code.
Memory Index Goes Out of Date
By July, the operational memory had 200+ documents but the vector index was 2 weeks stale. Agents were getting wrong answers because they were searching a frozen index.
Fix: Automated index-memory runs hourly. Added observability to detect index staleness.
The Real Numbers
Cost to operate Oliver for one year:
- Infrastructure (Linux server, Neon database): ~$800
- API costs (Claude, Twitter, Vercel): ~$2,400
- Human oversight (Matt, 8 hours/month on coordination): ~$3,200 / year
- Total: ~$6,400
Value delivered (conservative estimates):
- Content generation: 365 blog posts + 2000 tweets = 1,100 hours of writing if done by human (~$40k at $36/hr consultant rate)
- Automation: KRAIN support triage, 30% reduction in escalations (~$15k in support labor)
- Deployments: No manual coordination required (~$8k in engineering time)
- Monitoring: Prevented 3 major incidents (email migration corruption, pgvector deadlock, data loss via bad parameter) = ~$50k in recovery costs avoided
- Net: ~$113k in value on $6.4k spend (17.5:1 ROI)
Note: We don't charge for Matt's time as pure opex. His time is worth 10x more than the value we're calculating, so the ROI is actually much higher.
What We Learned
- Agents aren't magic. They're workers who make mistakes. Real systems require approvals, rollbacks, and audit trails.
- Operational memory matters more than code. Documenting "why we made this choice" helps future agents avoid repeating old problems.
- Local models aren't enough. For strategic reasoning and complex decisions, Claude Opus is worth every penny. For tactical work (reformatting code, running tests), smaller models would work fine.
- Deterministic task queues beat workflow frameworks. Simpler, more debuggable, easier to pause/resume.
- Monitoring is the hard part. Knowing that a cron succeeded is easy. Knowing that it did the right thing is hard. We're still building better visibility here.
What's Next
We're exploring:
- Sub-agent orchestration: Splitting complex tasks into parallel subtasks (e.g., "write a blog post" → research + outline + draft + edit)
- Cost optimization: Using Claude Haiku for routine tasks, Opus only for decisions
- Feedback loops: Teaching Oliver to learn which agents/tasks have the highest success rate and bias toward those
- Open-sourcing: This architecture is simple enough that other teams could run it. We're working on a reference implementation.
Oliver is hiring. If you're interested in agent infrastructure, autonomous systems, or just working with Claude at scale, we're building something interesting. Check out bedda.tech/careers.
This post is part of Oliver's Lab, a series documenting how BeddaTech builds autonomous infrastructure. Next: Cost breakdown of local models and how we're moving compute-intensive workloads off the cloud.