On March 18, my AI fleet made its first real phone call. It spoke Russian. The recording showed up in Telegram. I checked a box on a list I've been building for three months and moved on to the next thing.
I don't write code. I'm a non-technical founder who directs AI agents from Buenos Aires. My fleet runs on three dedicated servers connected by a mesh VPN. One team lead, two executors. They handle research, code, content, monitoring, and now—phone calls.
This is a field report covering ten days of work—what broke, what got fixed, and what capabilities the fleet gained. If you're building with AI agents or thinking about it, this is what the day-to-day actually looks like.
Here's what actually happened between March 10 and March 20.
Ten Days at a Glance
I. The Fleet Had a Truth Problem
Three places that claimed to know the fleet's state. None of them agreed.
Three Truths, Zero Agreement
The fleet has three places where state is stored: the local project folder on my laptop, the GitHub backup, and the live servers. By March 10, they'd quietly drifted apart.
How I found out: the fleet dashboard showed "1 agent unreachable" for what turned out to be weeks. There was no unreachable agent. There was a ghost entry—a leftover from a fleet registration test that had been cleaned up in some places but not others. Each truth source had a slightly different picture of reality.
I asked for a full repair pass. What came back: a content-aware scanner that ignores known-safe patterns, a 3-way hash check that runs before every session closes, and a single "desired state" file that acts as the blueprint. If local, GitHub, and the live server don't agree, the session isn't done.
Single source of truth isn't a design choice you make once. It's a maintenance practice. If you have three places that store state, you have three chances for them to disagree. Verify every time.
A Dashboard for a Founder, Not a Developer
The fleet dashboard existed before March 10. It was designed like a developer tool—raw metrics, process states, queue depths. I could look at it and not know whether I needed to do anything.
I asked for a redesign around three questions: "What Needs You?"—things only a human can handle. "Is Everything Working?"—a yes or no, not a wall of numbers. "Is the Fleet Getting Smarter?"—are test counts going up, memory growing, task quality improving.
The new dashboard answers those questions directly. If nothing needs me, the first section is empty. That's the goal—empty is good.
If you need to read through data to decide whether to intervene, the dashboard has failed. Operator attention should be a signal, not a data analysis exercise.
II. The Fleet Stays Alive While You Sleep
Two failure modes that only show up when nobody's watching.
Telegram Sessions That Time Out Silently
The fleet communicates with me through Telegram. I send a message, an AI agent picks it up and responds. Simple enough—except the underlying session can time out. When it does, the agent stops responding. No error message. No notification. Just silence.
Overnight, this meant a dead fleet. Nobody watching, nobody noticing the session went quiet.
The fix is a watchdog process that monitors active Telegram sessions. If a session goes unresponsive, the watchdog restarts it and logs the recovery. If recovery fails three times, then it alerts me. Not before.
Self-healing means: detect stale state, attempt recovery, verify recovery worked, alert only if recovery fails. Four steps. Most systems stop at "detect" and dump the problem on a human.
The Stale Dashboard Problem
The dashboard pulls data from a snapshot file that each agent generates on a timer. If the timer stops running—because the service restarts, or the cron breaks, or the log file fills up—the dashboard shows the last successful snapshot. Which could be hours old.
I was looking at a dashboard that said "all healthy" while one agent had been down for half a day.
The fix: a supervisor process that checks whether the snapshot file is fresh. If it's older than 10 minutes, the supervisor regenerates it. If regeneration fails, the dashboard shows a staleness warning instead of pretending everything is fine.
A dashboard that shows stale data with no warning is worse than no dashboard. Always display when the data was last updated. If it's stale, say so.
III. "Configured" Is Not "Working"
Proving capabilities and discovering what was silently broken.
The Browser Test That Proved Three Agents Can Actually Browse
All three agents had a web browser installed. The configuration said so. The health checks said so. But nobody had actually tested whether an agent could open a webpage, read it, and take a screenshot.
On March 14, I asked for an end-to-end test. Start the browser, open a real page, verify the title, take a screenshot, stop the browser. Run it on all three servers.
All three passed. But that's not the point. The point is that until this test existed, "browser capability" was a line in a config file, not a verified fact. Now it runs automatically every night.
A capability that isn't tested isn't a capability. It's a config file. If you can't prove it works end-to-end, you don't have it.
Seven Days of Silence
This one made me angry.
I run a competitive intelligence pipeline. Every day, it scrapes competitor activity, processes it, and sends me a summary. I'd been reading those summaries all week. They looked fine. Reasonable data. Nothing alarming.
On March 16, I discovered the pipeline had been silently broken since March 9. Seven days. The data I'd been reading was stale—the same information recycled with slightly different formatting. A missing code import had crashed the scraper. It failed silently because the alerting system only watched for timeouts, not crashes.
So when the pipeline crashed instantly instead of timing out, nobody noticed. The report generator kept running with cached data. The Telegram summary kept arriving on schedule. Everything looked normal.
Three changes: crash alerting (not just timeout alerting), error isolation so partial failures don't kill the whole run, and a freshness check on the underlying data—if the latest data point is older than 48 hours, the report says so explicitly. I should have caught this on Day 1. The system should have caught this on Day 1. Neither did.
IV. The Fleet Got a Voice
March 18. The day it made its first phone call.
Adding Voice to a Multi-Agent Fleet
The goal was straightforward: I wanted to be able to instruct the fleet to call someone. Schedule a follow-up, pitch a service, or reach out to a contact. In any language.
The implementation: a voice AI platform handles the actual conversation. It uses the same AI model that runs the fleet. A separate telephony provider handles the phone numbers and routing. The fleet's web server receives the call results via webhook—signed, verified, persisted to disk before acknowledging receipt.
I set up two voice profiles: one for personal calls (bilingual Russian-English), one for business calls (English). Connected a US phone number. Then I ran six test calls.
They all worked. The AI stayed on script, handled language switching, and the recordings arrived in my Telegram within minutes.
It wasn't a dramatic moment. It was more like checking a box. This was the next logical step on a list I've been building for months. Voice was always the plan. March 18 was just the day it finally worked.
The capability itself is less interesting than the infrastructure around it. The voice AI works. What makes it production-ready is: cryptographic signature verification on every incoming result, persistence before acknowledgment (so a crash doesn't lose call data), deduplication of repeated deliveries, and a dedicated signed identity—not impersonating fleet agents.
Governance Before Capability
An AI fleet that can make real phone calls to real people needs rules. Not eventual rules. Rules before the first call ships.
Here's what we put in place:
Only user-initiated tasks can trigger a call. The fleet's own autonomous logic cannot decide to call someone. I have to explicitly assign a task that involves calling.
Business hours enforcement. No calls outside reasonable hours in the recipient's timezone.
Founder blocklist. My own phone numbers are blocklisted from automated dialing. The fleet cannot call me autonomously.
Signed results only. The voice webhook uses a dedicated identity. It doesn't pretend to be one of the fleet agents. It's a separate, auditable channel.
Ship the guardrails with the capability, not after. The fact that the governance was ready on Day 1 is more important to me than the fact that the calls worked.
V. Always On
The fleet used to be available only when my laptop was open. Not anymore.
Claude Code on a Cloud Server, 24/7
Until March 19, the AI CLI I use to direct the fleet ran only on my MacBook. When the laptop was closed, the fleet was on autopilot. I couldn't send it a task, check on a result, or intervene in anything.
Now it runs permanently on a cloud server. I interact with it through Telegram—same interface I use for everything else. I can send a message from my phone at 2 AM and check the results over breakfast.
The cloud instance has the same knowledge base as my laptop. The full shared memory, the daily logs, the session context. It syncs through GitHub—one hub, multiple machines, same canonical state. When I close a session on my laptop, the cloud instance can pick up where I left off.
The fleet went from "available during work hours" to "available always." The practical difference: I can assign tasks from my phone, in any timezone, without touching a laptop. That's the goal I've been building toward since December.
37 API Keys and a One-Command Setup
The cloud server needed access to the same APIs as the fleet: AI models, databases, notification services, scraping tools, email, voice—37 keys in total. Pulling them from the fleet's key store and deploying them took hours the first time.
So I asked for a script that does the entire setup in one command. 474 lines. It provisions the server, installs the CLI, configures Telegram access, pulls all API keys, clones the knowledge base, sets up the sync engine, and starts the service. First run or update—same command.
The second time I needed to rebuild the server, it took under 10 minutes.
If you had to do it manually twice, script it. Not because you'll need a third time (you will). Because the script documents exactly what "set up correctly" means. It's executable documentation.
The Thing That Surprised Me
It wasn't the phone calls. Those felt like the next logical step—I'd been building toward them for months.
What surprised me was coming back to a session and finding that Sky had redesigned the fleet dashboard. Not because I asked. I'd complained about the old design in a handoff note between sessions—something like "this dashboard shows me process noise, not what I need to know." Two sessions later, the dashboard was restructured around my questions instead of its metrics.
An AI read a complaint in a handoff note and reorganized a tool around it. Without a ticket. Without a prompt. I hadn't even remembered writing the complaint by the time the new version showed up.
I don't fully understand what I'm building yet. But I know that ten days ago the fleet couldn't make phone calls, couldn't recover from its own failures overnight, and only existed on my laptop. None of those things are true anymore.
If you're building something similar—or think I've made a mistake somewhere in here—I'd like to hear about it. Find me on X or email vladimir@gusev.work.