sloop-daemon 0.1.0

A small daemon that schedules coding agents
Documentation
# 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**

```sh
curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/hamish-mackie/sloop/releases/latest/download/sloop-installer.sh | sh
```

Prebuilt binaries are also on the [releases page](https://github.com/hamish-mackie/sloop/releases).

**Initialize**

```sh
sloop init    # Configure this repository
sloop daemon  # Start the scheduler
```

**Write a ticket** (`my-ticket.md`)

```markdown
---
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**

```sh
sloop post my-ticket.md
sloop list                # Ticket status, and why pending ones aren't running
sloop logs <run-id>       # Follow a run's output
```

---

## 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:

```yaml
version: 1

scheduler:
  max_parallel_tasks: 2
  running_hours:
    start: "22:00"
    end: "06:00"

agent:
  default_target: claude
  targets:
    claude:
      cmd: ["claude", "--print", "--model", "{model}", "--effort", "{effort}", "{prompt}"]
    opencode:
      cmd: ["opencode", "run", "--model", "{model}", "--variant", "{effort}", "{prompt}"]
    codex:
      cmd: ["codex", "exec", "--model", "{model}", "--config", 'model_reasoning_effort="{effort}"', "--sandbox", "workspace-write", "--ephemeral", "{prompt}"]
```

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`:

```yaml
stages:
  - name: build
    kind: build
  - name: review
    kind: exec
    cmd: [opencode, run, "Read .agents/sloop/prompts/review.md and follow its instructions."]
  - 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](LICENSE).