piloop/daemon/scheduler.py and
piloop/daemon/runner.py.
The steps
- Queue. On each tick, the scheduler fills the free worker slots with runnable ideas. An idea is runnable when
it is
readyand each of its prerequisites (anafterlink) isdone. The slot goes to the most urgent idea of the track that is furthest below its share. At least one run in[roles.worker] explore_everystarts from a pinned idea when one is ready. The scheduler inserts aqueuedrun, chooses its harness from the rotation, and inserts arequestedworker row. - Take. In the same tick, the scheduler sets
requestedrows tostarting, up tomax_concurrentfor each role and each harness. Each one goes to a thread of the daemon’s pool. - Launch. The run executor writes the brief and adds a git worktree at the run’s base: the head, or the
candidate that the idea pins. The launcher fills in the harness’s argv and calls
Runtime.start. - Work. The agent reads its brief, implements the idea and commits. It reads and writes the database with
piloop sql. On each tick, the scheduler sends new comments on the run or the idea to the agent. - Close. When the agent ends or times out, the launcher closes the worker row and reads its token usage. The executor commits what is left uncommitted and closes the run. The worker slot is now free for the next run.
- Score. Each new commit becomes a candidate. Commits with the same git tree are the same candidate. The daemon runs the evaluate command in a clean worktree of the commit, stores a measurement, and judges the candidate against the run’s bar. A keep becomes the bar for the run’s next commit.
- Rebase. When a keep’s bar is no longer the head, because another run kept meanwhile, the keep is marked
interesting. The daemon merges it onto the head, measures the merge and judges it there. A merge that conflicts files a seed. - Settle. The idea becomes
done, or goes back toreadywhen its run failed and it has attempts left. The idea staysscheduleduntil every commit is judged, so an idea that waits for it starts from its keeps.