Attended today. Unattended when you say so.
The dominant mode needs no infrastructure at all: you sit in Claude Code, Cursor, or ChatGPT, the engine hands out steps over MCP, and the client you already pay for does the work. Autonomy is the same loop with you stepping out of it.
An autonomous system is not an agent with a long prompt and a cron entry. It is a loop that starts itself, decides what to work on from the actual state of the work, runs a governed process, stops where humans are required, and leaves a record. Most teams discover the gap the hard way: the cron half is easy, and everything after it, selection, governance, reliability, attribution, is the actual product.
ConvOps splits the problem in a way that keeps you in control. The engine owns the process: workflows, gates, schedules, pools, and the audit. You own the execution: the AI clients on your desks, your own runners, your self-hosted OpenCode server, or ConvOps cloud when you want it hosted. Nothing about the process changes when you move execution, which is why the same workflow you ran attended this morning can run unattended tonight.
And attended is the default on purpose. Connecting your client over MCP is the entire setup; autonomy is not a migration but a decision you make per workflow, by adding a schedule and stepping out of the loop you already trust.
No backend required. That is the default.
The agent calls the engine, receives the step, does the work, advances. That loop needs an MCP connection and nothing else. Executors and backends exist solely for runs where nobody is at the keyboard.
- Attended: you drive, in your own client, zero infra
- Semi: your own runner takes the envelope and a lease
- Unattended: a schedule fires and ConvOps dispatches
RRULE, not cron. Two modes.
A schedule can spawn a fresh task each fire, carrying the whole process. Or it can resume the same task mid-workflow at its current step: a standing loop that picks itself back up.
{
"rrule": "FREQ=WEEKLY;BYDAY=MO;BYHOUR=9",
"mode": "spawn",
"creates": "task -> workflow: bug-sweep"
}The loop pulls. Nothing pushes.
When a fire lands, the agent asks a pool what to work on: a saved query resolved live on every call. It gets exactly one task or nothing, and empty is an answer it can branch on.
{
"slug": "rotting-bugs",
"filter": {
"op": "AND",
"nodes": [
{ "field": "type", "eq": "bug" },
{ "field": "stale_days", "gte": 3 }
]
}
}Your machines. Your clients. Your rules.
ConvOps never runs your code; it governs whoever does. Named executor profiles target your desktop clients, ConvOps cloud, your own OpenCode server, or a custom runner on your infra that receives a signed envelope and a lease.
{
"executors": [
{ "slug": "local", "is_system": true,
"description": "claude code · kimi code" },
{ "slug": "opencode", "is_system": true },
{ "slug": "conveyor", "is_system": true,
"description": "convops cloud" },
{ "slug": "gpu-box", "runner": "custom",
"description": "your infra" }
],
"precedence": "step > task > org default"
}Built like infrastructure, because it is.
Dispatch events are written in the same transaction as the task, redelivered idempotently, and reaped when orphaned. Every run records its session, execution log, retry count, and cost in dollars.
- Outbox pattern: the dispatch cannot be lost between systems
- Graceful degradation when a backend is unconfigured or unreachable
- Per-run transcript and cost, queryable from your client
Your OpenCode, first-class.
Point ConvOps at your own OpenCode server and unattended runs execute on your hardware, with your connected providers and models, validated at configuration time. Model choice is yours, per run.
Cron vs a governed loop
| a script on a timer | a scheduled workflow |
|---|---|
| Fires whether or not there is work | The pool answers with one task, or with nothing |
| Selection logic is a query you maintain in code | A pool is a typed, validated filter resolved live |
| Retry and dedupe logic is yours to write | Outbox delivery is idempotent by design |
| The record is a log line on a box somewhere | The record is the task: transcript, retries, cost |
| Approval means a human watches the clock | Approval is a gate; the run waits, then continues |
questions
Do I need to deploy anything to start?
No. Attended execution is the default: your AI client, connected over MCP, asks for the step, does the work, and advances. A backend is only involved when a run must happen with nobody at the keyboard.
What actually starts an unattended run?
A schedule. Schedules are RRULE, the calendar standard, not cron strings, and they run in two modes: spawn a fresh task each fire carrying the whole process, or resume the same task mid-workflow at its current step.
How does the agent decide what to work on?
It asks a pool: a saved, typed query over tasks that the engine resolves live on every call. pools_next hands back exactly one task or nothing, and empty is an answer the workflow can branch on. Work is pulled by capacity, never pushed onto a queue.
Where does the work actually execute?
Wherever you point it: the local clients on your machines, a custom runner on your infra that receives an envelope and a lease, your own OpenCode server with your models, or ConvOps cloud. Execution is per-org configuration; switching backends touches zero task definitions.
What happens when a backend is down?
The dispatch event is written in the same transaction as the task, so it cannot be lost. Delivery retries idempotently, unreachable backends degrade gracefully, and orphaned runs are reaped rather than leaking.
What does a run cost me?
Each executed task records its session, execution log, retry count, and cost in dollars, queryable from your client. Autonomy without a cost column is a bill you discover later.