Sloop
A job scheduler for coding agents.
Sloop runs each ticket in its own Git worktree, reviews the result, and merges it when it passes.
- Agent orchestration — each ticket picks its agent, model, and effort: design with a powerful model, send implementation and review to specialized workers.
- Agentic loops — combine predefined flows, parallel agents, and scheduled execution.
- Runs while you sleep — set running hours and wake up to finished work.
- Repeatable — tickets are Markdown files in your repo, easy to share and re-run.
Under the hood it's a small Rust daemon that judges outcomes from commits and tests.
Install
|
Prebuilt binaries are also on the releases page.
Initialize
Write a ticket (my-ticket.md)
name: Add request logging
blocked_by: []
target: claude
model: sonnet
effort: medium
Log each HTTP request with its method, path, status, and duration.
Post it
Configuration
sloop init creates .agents/sloop/config.yaml with working targets for
Claude Code, Codex, and OpenCode. To change when work runs or which agent Sloop
uses, edit the generated config:
version: 1
scheduler:
max_parallel_tasks: 2
running_hours:
start: "22:00"
end: "06:00"
agent:
default_target: claude
targets:
claude:
cmd:
opencode:
cmd:
codex:
cmd:
Running hours use local time and may cross midnight; omit them to run at any
time. Custom agent commands must include {prompt} exactly once; {model}
and {effort} come from the ticket. Keep secrets in environment variables.
Flows
Flows define the steps a ticket must pass before its work is merged. sloop init
creates .agents/sloop/flows/default.yaml:
stages:
- name: build
kind: build
- name: review
kind: exec
cmd:
- name: merge
kind: merge
The build stage runs the coding agent. Add exec stages for tests, reviews,
or any other command. Stages run in order and stop on failure; merge lands the
work after every earlier stage passes.
The filename is the flow name. Select one with flow: <name> in the ticket or
with sloop post my-ticket.md --flow <name>.
Logs
Each run's full output is kept as runs/<run-id>/output.ndjson under Sloop's
state directory (on Linux, ~/.local/state/sloop/repositories/<repository>/).
sloop daemon prints the exact log and socket paths on startup, and
sloop logs <run-id> is the normal way to read them.
Tickets and projects
Tickets live under .agents/sloop/tickets/ and projects under
.agents/sloop/projects/ (both configurable). Every ticket belongs to one
project; sloop init creates a default for unassigned tickets. Projects group
and scope tickets, nothing more.
blocked_by lists the ticket IDs that must finish first; [] means none.
Posting rejects a missing name, an empty body, unknown blockers, and
dependency cycles, and assigns an ID and worktree branch (sloop/<id>) unless
you set your own. Reposting an edited file updates the ticket in place.
sloop show <project> lists recent notes and commits per ticket; add --json
for structured data.
Design
Human-authored content lives in committed files. Runtime state lives in a
local SQLite database that only the daemon writes (bundled, nothing to
install). sloop reindex rebuilds whatever can be derived from committed
files and Git; runtime history such as notes may not survive it.
License
Copyright 2026 Hamish Mackie. Licensed under the Apache License, Version 2.0.