I run a two-person software company. Me and one developer, a full product roadmap, and client engagements with dates on the calendar. In three decades of building software I have watched a lot of things get announced, demoed to applause, and then quietly never mentioned again.
This is a status report, not a launch announcement. I designed nine AI employees this summer, and not one of them has ever worked an unattended shift.
What an AI employee is, and isn’t
Not a login. Not a product. A scoped agent wired to a specific job, a specific set of tools, and a specific data boundary.
Capability was never the constraint. Most of these roles do nothing I can’t do myself — they do the things I do when I remember, which is the part that fails. The standing rule behind the whole exercise came out of a security setting in my own environment that read “Enabled” for months while nothing behind it ran: verify function, not flags.
What the nine roles actually add up to
On July 30 I drafted the org chart and scoped the platform the same day. Two days later the control plane — data model, API, admin screen — was in production. The scheduler host was code-complete that same week, and it has never run a cycle.
Three of the nine are marked “exists today” in my own org chart: two programmer specializations and a QA role. What that status actually means is a repo-scoped configuration file, plus the discipline of running a code review before I merge anything non-trivial. A habit given a name. Not software.
One more, a project manager, is blocked on having task data worth managing. Four are not even named yet, and none of them is built — customer service, marketing, sales, bookkeeping.
Zero have run unattended. Not one role, not once.
You have a pilot running right now that somebody demoed and everybody applauded. You probably can’t say what it did last Tuesday.
The one that’s closest to real
A security and finance officer. It has a written charter, eighteen permission rules, a configuration row in the platform database created paused, and a real research report — which I ran interactively, not on a schedule.
Its boundary is written as may and may not, and the may-not list is the interesting half. It may read cloud configuration, search and read the repos, run read-only queries against the operations database, and read public advisory sources. It may not write to any production database, deploy anything, change a permission or a firewall rule, create a resource, spend money, send an external message, or sign anything. Its reports carry an “(AI)” designation, which is not optional, and agent names never appear in anything a customer sees.
Legal. HIPAA requires a named human Security Official under 45 CFR 164.308(a)(2), and that is me. An agent can’t hold the accountability, so it gets none of the authority.
Separation of duties. The reviewer must not be the doer. It’s the same reason a QA role sits on the far side of the code review from a programmer role.
Blast radius. A security reviewer that can change firewall rules is a new attack surface. Read-only means a bad inference or a prompt injection produces a wrong recommendation that a human filters, rather than a wrong change.
Now the unflattering part. Its own narrowed login is written but not shipped, which means the read-only boundary I just described is enforced by its charter and by me rather than by the database. That distinction is the whole subject of this piece, and on this one I am on the wrong side of it. Its finance half is under-scoped by that same charter, which concedes in writing that it is not a CFO.
What the one real report actually did
The report answered a narrow regulatory question. The answer isn’t the point.
It cited a primary-source query it performed that day. It flagged that secondary sources label a regulatory edition inconsistently while agreeing entirely on the substance. It stated plainly that it could not render one source page directly, so one date rests on multiple independent citations and, in its words, “not my own eyes on the page.” Then it named the publication date of its newest source and declared everything after that date unknown.
That last move is the one I’d hire for. An agent that reports the edge of what it knows is doing the job of a control. An agent that answers smoothly past that edge is not being useful. It is being convincing, which is worse.
How a charter becomes a control
Every employee’s model, working hours, skills, permissions, and daily budget are rows in a database. The design is that before each run the host regenerates that employee’s configuration files from those rows — so “read-only on cloud configuration” stops being a paragraph and becomes generated allow and deny rules, and “recommends only” becomes the absence of write and push permissions. That generator is written. It has never been called by a live run, because there have been no live runs.
A charter that is only prose is not a control.
The strongest version of a data boundary isn’t a rule at all. It’s that the agent’s environment contains no connection string for the system holding the sensitive data. Don’t rely on instructions where you can rely on plumbing.
Two consequences I didn’t anticipate. Editing an agent’s permissions is itself a privilege escalation, so only an admin can do it, and the permission table records its own history — old value, new value, and the login that made the change. That history is kept by the database rather than by the application, because an audit trail that lives in the application never sees somebody editing the table by hand.
And the admin screen renders a preview of the configuration the runtime will receive, on the same tab where you edit the rules. The config writer that comes later has to call the same generator behind that preview rather than reimplement it. Two generators and the preview becomes a lie.
New employees start at default deny. Cloning one copies its configuration and its skills, and deliberately does not copy its permissions.
The decisions worth stealing
“Skipped” is a first-class outcome, with a reason attached. Off shift, budget exhausted, previous run still active, nothing in the queue — all normal, all recorded. “Nothing happened” has to be distinguishable from “nothing ran.” A subtlety that only showed up while writing it: the cadence check has to look at the last run of any kind, including the skips the service writes itself, or an off-shift employee would write 1,440 identical rows a day.
Short polling runs beat one long shift. This is failure economics, not elegance. A crashed seven-hour session costs a day. A crashed sixty-minute run costs an hour, and every run is independently reviewable.
Two consecutive failures are written to notify a human. Written that way specifically so nobody discovers on Friday that a role has been down since Tuesday.
No auto-merge and no auto-deploy, ever. A platform rule rather than a per-role one, because a per-role rule is one checkbox away from not existing. Agents open pull requests and write reports. A person merges, and a person signs.
What the design already bought
None of this is a result. What I have is a list of things that can no longer happen, which is a smaller claim and the only one I’m entitled to.
The one agent that exists cannot fire on a schedule, because its row was created paused and somebody has to change that row on purpose. It cannot recommend its way into a firewall change, because the permission to make one was never granted. A role added next month starts with no access at all rather than inheriting whatever the last one had.
And the report it produced named the edge of its own knowledge without being asked to. That is the only behavior in the whole build I’d call evidence.
What I got wrong
Two premises in the scope document turned out to be false, and they’re marked in the document as corrections rather than quietly edited out. The audit interceptor the design planned to reuse doesn’t exist — it’s an unimplemented spec against a table nothing writes to. And the database scripts the work depended on lived on a different branch than the plan assumed.
Three tests were deleted rather than adapted, with the reasons recorded. One was impossible to run against the stand-in database the test suite uses. Two would have passed trivially against a hardcoded value, which is worse than no test, because it reports green. Two replacements assert the real contract instead.
Not one of those failures was the model’s. Nothing here is blocked because an agent couldn’t do the work.
Why nothing runs
Nothing runs unattended because interactive multi-factor sign-in and unattended agents are incompatible, which is an identity problem rather than an AI problem. That one is its own article, and I’ll write it when I’ve actually solved it.
We are early enough that the announcements are running ahead of the systems. If somebody has sold you nine autonomous agents, ask which ones ran last night unwatched, and what the log says they skipped and why. Designing an agent takes an afternoon. Deciding what it may not touch, proving the boundary holds when a prompt asks it to cross, and giving it an identity of its own is the work, and none of that demos well.
Nine AI employees took me an afternoon to design.
Not one has earned a night alone.
Datos scopes agent work boundaries-first, with a person holding the decisions that matter — see how that work is scoped, or start a conversation.
