autonomy

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.

attended

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
schedules

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.

payload
{
  "rrule": "FREQ=WEEKLY;BYDAY=MO;BYHOUR=9",
  "mode": "spawn",
  "creates": "task -> workflow: bug-sweep"
}
Every fire carries the whole process: recall, run, gate, close.
pools

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.

payload
{
  "slug": "rotting-bugs",
  "filter": {
    "op": "AND",
    "nodes": [
      { "field": "type", "eq": "bug" },
      { "field": "stale_days", "gte": 3 }
    ]
  }
}
Cron fires on time. A pool decides on state.
executors

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.

payload
{
  "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"
}
Swap the backend without touching a single task.
reliability

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
self-hosted

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 timera scheduled workflow
Fires whether or not there is workThe pool answers with one task, or with nothing
Selection logic is a query you maintain in codeA pool is a typed, validated filter resolved live
Retry and dedupe logic is yours to writeOutbox delivery is idempotent by design
The record is a log line on a box somewhereThe record is the task: transcript, retries, cost
Approval means a human watches the clockApproval 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.