Skip to main content

Local-first task queue and DAG executor for coding agents

Project description

Praetor

Praetor is a local-first task queue and DAG executor for coding agents; it is not another coding agent.

Install

Praetor requires Python 3.11 or newer.

Primary install:

pipx install praetor-cli

Alternative install:

pip install praetor-cli

The PyPI package is praetor-cli; the installed binary is praetor.

Quickstart

Sequential mode is the default. It runs one ready task at a time in your current checkout.

cd your-project
praetor init
praetor add --title 'Implement auth module' --verify 'pytest tests/test_auth.py'
praetor status
praetor run

Quickstart: Parallel Mode

Parallel mode runs eligible ready tasks in per-task git worktrees. Use it when independent tasks can be verified separately and merged back through Praetor. It requires a git repository and a base branch named main, unless you pass --base-branch.

Replace the --verify commands below with commands that exist in your project:

cd your-project
praetor init
praetor add --title "Refactor user module" --verify "pytest tests/users"
praetor add --title "Refactor billing module" --verify "pytest tests/billing"
praetor run --max-parallel 4
praetor status
praetor merge --all

praetor run --max-parallel 4 enables parallel mode. Ready tasks with parallel_ok: true may run concurrently; tasks with parallel_ok: false run alone after the active pool drains. The default is still --max-parallel 1, which preserves sequential v0 behavior.

Manual merge is the default in parallel mode. After an agent exits, Praetor runs the task's verify command in that task's worktree, commits the verified worktree state to praetor/<task-id>, and marks the task pending_merge. praetor status shows pending_merge when verified work is waiting for integration and merge_failed when an attempted merge failed and needs human recovery.

Merge all waiting tasks:

praetor merge --all

Merge selected tasks:

praetor merge implement-auth-module-a1b2c3d4

For an auto-merge run, opt in explicitly:

praetor run --max-parallel 4 --merge-strategy auto

CLI Reference

Command Key options Purpose
praetor --install-completion, --show-completion Root command; Typer also exposes shell completion helpers.
praetor init none Create .praetor/ state in the current repository.
praetor add --title, --depends-on, --verify, --parallel-ok/--no-parallel-ok, --merge-strategy, --agent Create a task markdown file under .praetor/tasks/.
praetor status none Print task status, dependencies, and verify commands.
praetor run --adapter, --max-parallel, --base-branch, --merge-strategy Drain ready tasks with the selected agent adapter. --max-parallel 1 runs sequentially; values greater than 1 use worktrees.
praetor merge TASK_ID..., --all, --retry, --base-branch Merge pending_merge tasks back to the base branch. With --retry, also retry merge_failed tasks.
praetor logs <task-id> <task-id> Print the saved log for one task.

Merge Strategy

Parallel mode separates "verified in a worktree" from "integrated into the base branch." Manual merge is the default because auto-merging AI-authored commits to main is an explicit trust decision, not a safe default.

Each task has a merge_strategy field:

  • manual parks verified work as pending_merge; a human runs praetor merge <task-id> or praetor merge --all.
  • auto merges the task branch automatically after verify passes.

The CLI --merge-strategy flag on praetor run overrides all tasks for that run, regardless of their per-task field. For example, praetor run --max-parallel 4 --merge-strategy auto attempts to auto-merge every task completed during that run, including tasks whose frontmatter says merge_strategy: manual.

The --merge-strategy flag is only valid in parallel mode; passing it with --max-parallel 1 is rejected with a clear error.

praetor merge uses git merge --no-ff --no-edit from praetor/<task-id> into the base branch. It refuses to merge if the base repo has uncommitted changes, records conflicts in the task log, and leaves the task as merge_failed for retry.

Worktrees

In parallel mode, each running task gets an isolated git worktree at:

.praetor/worktrees/<task-id>/

Praetor records the task branch, base branch, and fork-point SHA in:

.praetor/worktrees/<task-id>/.praetor-meta.json

Worktrees intentionally persist after task completion. They are needed for manual merge, conflict recovery, and post-mortem inspection. Disk-pressure cleanup is not implemented yet; it is tracked as issue #7.

Recovery Flows

If a task is merge_failed, inspect the task log and worktree, resolve the underlying conflict or base-branch issue, then retry:

praetor merge --retry <task-id>

If a previous runner crashed and left a task as running, praetor run fails closed with a stale-running error. Recovery UX is tracked as issue #6. The current manual workaround is to inspect .praetor/worktrees/<task-id>/ and .praetor/logs/<task-id>.log, then edit .praetor/tasks/<task-id>.md to set status: pending before running Praetor again.

Task File Schema

Tasks live in .praetor/tasks/<id>.md. The markdown body is the prompt given to the agent; the frontmatter is Praetor's task metadata.

---
id: implement-auth-module-a1b2c3d4
status: pending
depends_on: []
parallel_ok: true
agent: claude
verify: pytest tests/test_auth.py
review: off
merge_strategy: manual
created: 2026-06-08T14:22:00Z
---

# Implement auth module

## What to do
Add the authentication module and wire it into the existing app.

## How to verify
Run `pytest tests/test_auth.py` and confirm it passes.

## Proof when complete
Summarize the files changed and include the verify output.
Field Description
id Stable task id; also used as the task filename stem.
status Persisted values are pending, running, done, failed, blocked, pending_merge, or merge_failed. The DAG resolver and praetor status derive readiness from pending tasks whose dependencies are all done; readiness is not a persisted status.
depends_on List of task ids that must be done before this task can run.
parallel_ok Whether this task may run concurrently with other ready tasks. Default: true. Set false for cross-cutting or exclusive work.
agent Intended agent for this task. Default: claude. praetor run --adapter selects the runtime adapter for the run.
verify Shell command run after the agent exits. A non-zero exit keeps the task from completing.
review v1+: reviewer mode, one of off, lenient, or strict. Present in v0 files for forward compatibility.
merge_strategy Parallel-mode merge behavior, one of manual or auto. Default: manual. praetor run --merge-strategy overrides this field for all tasks in that run.
created UTC timestamp for task creation.
body Markdown body after the frontmatter. It is parsed into the task model and passed to the agent; it is not written as a frontmatter field.

How It Works

Praetor stores state as files under .praetor/: task markdown in .praetor/tasks/, per-task logs in .praetor/logs/, per-task worktrees in .praetor/worktrees/, and global run metadata in .praetor/state.json. The DAG resolver computes the ready set from pending tasks whose dependencies are all done.

With --max-parallel 1, Praetor runs one ready task at a time in the current checkout. After the agent exits, the task's verify command gates whether the task is marked done or failed.

With --max-parallel > 1, Praetor creates a worktree and branch for each dispatched task, runs the agent and verify command inside that worktree, commits the verified result, then either parks it as pending_merge or merges it automatically depending on the effective merge strategy.

Limitations

v1 parallel execution is functional, but these items are intentionally not implemented yet:

  • Dispatch-time conflict detection for overlapping task scopes: issue #4
  • Post-merge verification on the base branch: issue #5
  • Stale-running recovery command such as praetor reset: issue #6
  • Worktree cleanup flag for disk-pressure management: issue #7
  • Multi-OS CI: issue #8

Docker / Sandboxed Runs

Build the image:

docker build -t praetor-cli .

Run Praetor against the current repository:

docker run --rm -it -v "$PWD:/repo" -w /repo praetor-cli praetor run --adapter claude

Use the container as the trust boundary for permission-bypassing agent runs such as --dangerously-skip-permissions; run that bypass inside the container, not on the host.

docker run --rm -it -v "$PWD:/repo" -w /repo praetor-cli \
  claude --dangerously-skip-permissions

Roadmap

v1 parallel execution adds worktrees, a worker pool, concurrent execution for eligible DAG siblings, and manual or automatic merge integration. v1.1 MCP + Claude Code plugin adds the MCP server and plugin distribution. v2 adds planner mode; v3 adds the meta loop and a GUI over the same file-based state.

License

See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

praetor_cli-1.0.0.tar.gz (23.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

praetor_cli-1.0.0-py3-none-any.whl (25.9 kB view details)

Uploaded Python 3

File details

Details for the file praetor_cli-1.0.0.tar.gz.

File metadata

  • Download URL: praetor_cli-1.0.0.tar.gz
  • Upload date:
  • Size: 23.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for praetor_cli-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ee089f1fb2579cea46f35538e7f34d9bf50818f0e4012d4177e39d26f01f9168
MD5 0373dc6ffda66949fd2fe171ec3f3e8f
BLAKE2b-256 708929644320b699c09ecfb849248f03f5a805c62bff680e81c60bb95d385b2a

See more details on using hashes here.

File details

Details for the file praetor_cli-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: praetor_cli-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 25.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for praetor_cli-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f8c4e203af01c0b1a4c2a38f71a4837892cf0b0c85279a8a1d2a40596bb12d05
MD5 30f3ba1f43df7c83824c0b578b53afa8
BLAKE2b-256 dd1ba112dc425e5346586724965d0649c7a1ca5219b5dc5bf257b5e23d7573ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page