Sergey Kopanev: you sleep — agents ship

Go Back
Building AI Autopilot · Part 8

I Built a Beautiful Machine and Then Deleted It


Building AI Autopilot for code, research, and workflows.

After the orchestrator fell apart, I still had the core problem.

Agents are stateless. Every time Claude runs, it starts fresh — no memory of what phase you’re in, what tasks are pending, what failed last time.

If you want autonomous agents, you need to give them state from the outside.

So I built a state machine.

The Architecture

Every HLTM project got a _hltm/ folder.

_hltm/
├── STATE.yaml
├── TASKS.yaml
├── input.md
├── tasks/
│   ├── task-001.md
│   └── task-002.md
└── locks/
    └── execute.lock

STATE.yaml tracked the current phase:

phase: execute

One field. One file.

TASKS.yaml was the task queue:

tasks:
  - id: task-001
    status: in_progress
    retries: 2
  - id: task-002
    status: pending
    retries: 0

The autopilot read STATE.yaml, picked the next phase, spawned the right agent, updated STATE.yaml when done. Max 5 retries per task. Failed tasks preserved. Lock files to prevent double execution.

The FSM had six phases: idle → prd → plan → execute → verify → learning → actualize.

It was clean. Documented. Correct.

What Actualize Was

The smartest part of the system was actualize.

After every task cycle, five analysts ran in parallel — each reading the git diff, each updating a different piece of project knowledge:

analyst 1 → _hltm/snapshot/architecture.md
analyst 2 → _hltm/snapshot/conventions.md
analyst 3 → _hltm/snapshot/infra.md
analyst 4 → _hltm/snapshot/decisions.md
analyst 5 → _hltm/snapshot/project.md

The idea: the next agent that runs reads those files and knows everything about the project without having to re-read the entire codebase.

Filesystem as memory. No database. No embedding search. Just markdown files an agent can read in one shot.

This part worked.

What Didn’t

STATE.yaml had one field.

I was reading and writing a YAML file to track a single string. phase: execute. Could have been a text file with one word. Could have been a filename. Could have been anything.

The YAML was ceremony.

TASKS.yaml was worse. Every status update required the orchestrator to read the file, parse it, update one entry, write it back. In Lua. Then Python. Then I gave up and used sed.

Meanwhile the actual agents — the ones doing real work — had zero knowledge of STATE.yaml or TASKS.yaml. They weren’t allowed to touch them. The orchestrator owned state. Agents just did tasks and reported back.

Which meant the orchestrator was always the bottleneck. And the orchestrator was Claude. Which drifted. Which lost context. Which occasionally forgot what phase it was in and started over.

The state machine was supposed to prevent that.

It didn’t. Because the state machine was running inside the thing that was losing state.

The Delete

v1.0.0 commit message:

Replace LLM-as-orchestrator skills with a bash-based runner that loops any executor with swappable methodology prompts and beads as task tracker.

STATE.yaml — deleted. TASKS.yaml — replaced by beads, a SQLite task queue the bash loop controls. The FSM — replaced by stage flags in bash. The lock files — replaced by the loop itself, which is single-threaded by design.

The actualize snapshots survived. Still there. Still five markdown files. Still the cleanest part of the whole system.

Everything else: gone.

What I Learned

A YAML file is not a database. A YAML file is not a state machine. A YAML file is a config file you’re misusing.

If you need a task queue, use a task queue. Beads is 50 lines to set up and gives you proper status tracking, comments, labels, blocking.

If you need a state machine, use a bash variable. STAGE="review". Done.

The snapshot files — plain markdown, one file per concern, updated by agents after each cycle — those are the right abstraction. Human-readable. Git-trackable. Grep-able. An agent can load the whole project context in one read.

The rule I start with now:

If the complexity doesn’t fit in a terminal command, it’s too complex.

cat _hltm/snapshot/architecture.md

That is enough.


Next: I made the orchestrator as thin as possible. Still wasn’t enough..