Repository navigation
Releases: aleandros/powerqueue
Release list
powerqueue v0.18.1
Fixed
- Preserve live session ownership when task controls run without a daemon:
resume returns to the surviving session, and cancel/retry stay queued until
the daemon can stop it. Select the latest session by start time, so resetting
attempts on a terminal-task retry cannot hide the new session behind history
in the scheduler or dashboard (including attachment and resource samples).
Added
- Stateful scheduler coverage for conditional model preferences, policy and
concurrency reloads, dated rolling-window spend, observed provider usage,
historical sessions and offline CLI writers. Forced launch scenarios exercise
draining a lowered concurrency limit, budget expiry and retry deadlines;
minimized bug regressions and an opt-in larger stress run accompany the fixes.
powerqueue v0.18.0
Fixed
-
Bound shared launch failures with persistent project/global backoff. Isolated
setup failures allow other work; repeated setup failures defer that project,
and shared runtime or storage failures stop launching globally. Failed starts
reserve no capacity or predicted budget. Doctor and events expose the failure,
retry deadline and recovery; Rust stateful properties, Quint simulations and
daemon integration tests cover isolation, restart, bounded attempts and recovery. -
Accept dead tmux panes whose process ID has been cleared after exit, so crash
detection and retry continue to work on current macOS tmux versions. -
Update the locked rustls dependency to 0.23.46 to resolve the security
advisories reported by CI. -
Recover abandoned
startingtasks after launch persistence failures or daemon
restarts using normal attempt limits and backoff. Recovery preserves work,
rejects stale task/session observations, and waits for surviving setup processes
or unrecorded agents. Doctor explains the hold and the saved tmux destination;
doctor --fixno longer interrupts starting tasks.
Added
- Quint simulation and event replay cover dependency blocking/unblocking and PR
handoff, session release, review relaunch and merge, including per-round crash
allowances and paused review watches. Synthetic rejection tests check invalid
ordering; existing v0.14.0 event logs work without a daemon upgrade. Human
blockers, containers, PR adoption, live-session retry release, and unsupported
review/relay changes still end the affected prefix. Dependency holds reject
live sessions and check the logged previous state against the model.
powerqueue v0.17.0
Added
- Deterministic repository routing from source repository, Linear team/project
metadata and labels, using typed conditions inconfig.toml. Matching rules
override source fallbacks; conflicting, unmatched and invalid destinations hold
future launches with persisted reasons. Sync previews, task show/explain and
doctor expose routing decisions. Saved assignments and pinned checkouts survive
metadata changes, retries and review; reassignment remains explicit. - Routing properties and integration coverage for conflicting labels, unknown
projects, metadata changes, database restart, project isolation and stale
sync/launch races. Quint trace replay models routing holds independently from
source approval and validates the real daemon routing events. - Tune free-form Markdown intent into validated TOML proposals, with project
selection, intent-change diagnostics, scoped queue simulation and reviewable
working-copy changes for committed repository policies. Stale drafts refuse
to overwrite newer input; applied snapshots remain available for undo.
Changed
- Replace executable Markdown priority rules with strict versioned
priority.toml.
Structured conditions share the existing evaluator and budget behavior. Use
priority migrate --from PRIORITY.md --to priority.tomland update policy paths;
Markdown remains optional intent only. See migration. - Priority commands support execution projects; live simulation and explanation
use each task's policy. Invalid reloads retain the last valid project policy.
Initialization, doctor and tune use TOML and report legacy migration needs. - Rust API:
PriorityRules::parsenow accepts TOML; Markdown conversion is
priority::migration::migrate. Priority show/edit/path command variants now
carryPolicyArgs, and check/simulate arguments include an optional project.
Fixed
- Refuse legacy or stale tune undo operations before touching live files; policy
mutation commands refuse unresolved repository overrides instead of editing
the machine policy by mistake. Intent-only Markdown can seed a new TOML policy. - Preserve the legacy checkout's GitHub approver restrictions and Linear intake
filters when adding execution projects, including daemon reloads. - Treat unreadable committed policy objects as errors, never absent files.
Worktree ownership checks no longer require Git's--path-formatoption. - Persist failed project cleanup for retry after repair or daemon restart;
doctor reports pending cleanup, finished session windows close independently,
and superseded executions cannot be cleaned up. - Isolate GitHub issue collisions and verification failures so healthy issues
still sync, launch and receive lifecycle updates. Source-wide authentication
and rate-limit failures still pause the source, including GraphQL HTTP 200
errors. Repeated issue warnings are deduplicated. - Keep cached project policies through temporary override errors and deduplicate
repeated policy failure events.
powerqueue v0.16.0
Set up one local queue for multiple GitHub repositories with project registration,
explicit issue approval, shared provider budgets and concurrency, and separate
worktrees. See the multi-project setup guide.
Added
- Focused
project register/project listsetup and reconfiguration, project
columns and filters in status/dashboard, per-project doctor cleanup/isolation
checks, and disposable three-project GitHub review lifecycle validation.
Named-only registries work with Linear disabled. Quint now models three projects. - Multiple GitHub intake sources with explicit execution-project mappings,
per-source credentials, filters, polling and lifecycle settings. Preserve legacy
[github]configuration and task assignments; reject unknown or conflicting
routes and report per-source failures in previews, admission and doctor. - Stateful routing checks across setup, retry, restart, review and active work,
including mapping conflicts during a launch pass and shared resource accounting. - Explicit GitHub execution approval with configurable
required_labels(default
agent:ready) and optionaltrusted_approvers. Verify effective label actors and
title/body edit history before starts and after setup; revocation holds future
starts while preserving active work. Persist decisions and explain them in task
inspection, sync previews, events anddoctor. - Stateful daemon/SQLite and Quint admission checks, including revocation during
setup, reapproval, restart, stale candidates and rejection of unapproved event
traces. Advisory CI also replays a real GitHub approval/launch trace.
Changed
- Explicit existing GitHub label settings remain unchanged. Omitted settings now
useagent:ready; empty approval labels are invalid for enabled intake. Title or
body edits require review and label reapplication. Approval verification requires
GraphQL access; unavailable evidence blocks starts, including offline starts. scheduler::launch::on_startingreturnsOption<Start>and refuses unapproved
tasks without mutation.- CLI argument and dashboard structs include project fields;
dashboard::Options
remainsClonebut is no longerCopy.
Fixed
- GitHub review/retry launches now persist the attempt and worktree claim before
rechecking approval, even when the checkout is already bound. Approval reloads
no longer discard the recreated worktree or reset crash accounting. - Make the multi-project cleanup test wait for transcript usage collection,
avoiding a timing race when cleanup finishes before usage is recorded. - Record crash retry deadlines for formal replay, so delayed event logging
cannot make an on-time restart appear premature.
powerqueue v0.15.0
Added
- Execution projects: register multiple checkouts under
[projects.<id>], enqueue
withadd --project, and reassign unstarted tasks withtask project. One
daemon shares slots and provider budgets while resolving setup, prompts,
priority and cleanup per project. Existing tasks migrate todefault; pinned
checkouts and ownership checks protect retries, review and cleanup across
restarts.doctorreports project configuration and binding problems.
Changed
- Testing: extend the Rust daemon model with project reassignment, independent
policies, unavailable/moved checkouts, and stale SQLite launch claims. Extend
Quint with execution-project ownership invariants and a finite model of the
reassignment/launch race, including both models in the simulation checks. - Testing: replace the Python Quint replay adapter with a Rust Cargo example,
reusing application event types and preserving anonymized schedules, coverage
reports, task-prefix cutoffs and invalid-schedule checks. Projection tests run
in the Rust gate; advisory CI runs Quint checks and all three daemon traces.
powerqueue v0.14.0
The stateful model now covers the whole daemon: several tasks sharing
slots, ledgers and rate limits through the real launch pass. It found one
scheduling bug, fixed here: a start that fails before the launch no longer
keeps its slot and its predicted budget for the rest of the pass.
Changed
- Testing: a whole-daemon model (
scheduler/model.rs) runs random
interleavings of launch passes, per-task calls, recorded usage, the
scheduling pause and time against several tasks sharing slots, ledgers
and rate-limit marks. Launches go through the realLaunchPlanneras
launch_tasksdrives it; the checks cover slots (never beyond
max_concurrent), one hand-out per ready task per pass, the retry time
of a throttled candidate, budget (every ledger a pass reserved on stays
within the safety margin), bounded progress (no ready task left
unconsidered while a slot is free) and independence from the order the
store lists the tasks in.
Fixed
- A start that fails before the launch (worktree setup,
repo.setup, the
launcher) no longer uses up its slot and its predicted budget for the
rest of the launch pass: the next candidate is tried in the same tick,
as the planner documents. Found by the whole-daemon model. (A failure
that hits every task, such as a missing repository, now crashes every
ready task in one pass rather than one per tick; each still gets its
backoff andmax_attempts.)
powerqueue v0.13.0
The pure core is now checked by property-based tests and a stateful
model of the daemon's calls, and the bugs they found are fixed: relayed
answers no longer revive finished tasks, stale retry times are cleared,
and a done marker that arrives after the probe still completes the task.
task complete and task block refuse a task the daemon is launching.
Changed
- Testing: the pure core is checked by property-based tests (
proptest)
besides the example tests. Shared generators insrc/strategies.rs
produce tasks, sessions, configs, ledgers, hook outcomes and PR statuses
the daemon could hold; every pure module inschedulerandbudgethas
properties (legal moves, inert terminal states, idempotent commands,
justified effects, backoff arithmetic, review rounds, planner passes,
policy eligibility, period arithmetic, observation history), and a
stateful model test runs random sequences of the daemon's calls against
one task, checking the cross-cutting invariants after each step.
TaskState::can_transition_tonow lists every move the daemon makes
(astartingtask may land in any session state; paused and throttled
tasks keep their session and may complete, crash or ask for a human; a
crashed or failed task completes when the done marker of its last
attempt arrives after the probe; a paused task unskipped while waiting
on a blocker goesblocked). task complete,task complete --prandtask blockare pure
transitions (scheduler::commands::{on_complete, on_hand_off, on_block})
that the CLI persists, so the stateful model runs the real ones. They
refuse astartingtask: the daemon is launching it and would persist
runningover the change. The daemon also re-reads the row after a
launch and keeps whatever was written to it meanwhile (a command applied
offline during a longrepo.setup), logginglaunch.superseded.
Fixed
Found by the new property tests:
- A reply relayed from Linear to a completed, failed or cancelled task no
longer re-queues it; onlytask retryrevives a finished task. - A
Stopwith the done marker or aSessionEnddrained after the
session was already closed no longer completes a cancelled task or one
re-queued since, nor counts a second crash against a re-queued one. A
done marker drained after the probe already crashed or failed the
session still completes the task (the pane died right after printing
it), instead of relaunching the finished work or leaving it failed. - A throttled task whose agent then reports a blocker, hits a permission
prompt or an authentication failure, or finishes, no longer keeps the
stale retry time; neither does a task that starts out of a throttle or
is completed bytask completeor blocked bytask block. - A throttled or paused task whose agent is still in its session (waiting
for a usage reset, finishing its turn) is no longer re-scored, so an
unsatisfied blocker cannot move it toblockedunder the live session,
where nothing would probe the window. - A task parked because its PR URL is unusable is marked parked on its
watch (created when the row had none), sotask resumewatches the PR
again instead of running a pending review round or re-queuing it. Policy::eligibilityagrees withdecidefor a provider disabled in
config that still has a ledger: its models are not eligible.
powerqueue v0.12.0
The scheduler is now a functional core with an imperative shell, the
groundwork for stronger testing of the queue's decisions, and the
default-branch policy reading introduced in 0.11.0 no longer locks the
CLI out or stalls the daemon when the branch cannot be read.
Changed
- The scheduler is a functional core with an imperative shell: every task
and session state change is a pure function returningEffects
(scheduler::{transitions,commands,launch,review}), and the daemon only
loads rows, persists what changed and carries the effects out. The
budget core (Ledger::build,resolve_clock, the observation history
rules) takes plain rows; store access lives inbudget::io.budget planruns the daemon'sLaunchPlanner;priority simulateshares its
preferred-model helper. Events logged from a cancel or retry now carry
the session they ended (a refused retry names none).task pause|resume| cancel|retryapplied offline (no daemon) use the daemon's own
transitions: an offline retry of a finished task starts over (attempts,
error and summary reset) and an offline resume clears a PRIORITY.md
skip, as they do with the daemon running.
Fixed
task retryof a task with a live session no longer keeps the ended
session in the daemon's nudge list.- A task parked because its PR URL is unusable has its retry time
cleared like every other parked task. - A status-line usage payload without readings no longer reads the
observation history before being dropped. - A
.powerqueue.tomlthat cannot be read from the default branch no longer
locks every command out:status,doctor,config show,stop,pause
and the rest run withconfig.tomlalone and say so (status --jsonand
config show --jsoncarry the error); onlyrunrefuses to start. doctor,tuneandconfig validateread.powerqueue.tomlfrom the
commit the daemon loaded it from, even when that file sets
default_branchitself.- Whether
.powerqueue.tomlexists on a branch is now an exit-status probe
(git cat-file -e), and git runs withLC_ALL=C: a localized git no
longer turns a missing file into a hard error. - The daemon retries a reload that failed (a half-written
config.toml, a
git lock) every check instead of waiting for the next change, logs it once,
anddoctorreports a daemon still running the configuration from before
such a change ("config reload"). - A git failure while checking
.powerqueue.tomlfor changes keeps the last
known fingerprint and is logged once (daemon.overrides_check_failed)
instead of causing a spurious reload (which also reset the GitHub
rate-limit backoff) once git recovered. - A reload asked for by
config setmoves the change baseline, so the next
check no longer reloads the same change a second time. - The periodic
git fetchruns on a blocking thread; an unreachable remote
no longer stalls hook processing andstop/pausefor the duration of
the network timeout. A fetch before a task start counts as the periodic one. repo.fetch_interval_secsis capped at a week byconfig validate; an
absurd value no longer panics the daemon's first tick.priority simulate --jsonprints one JSON document when the rules file is
missing (rules_missing: true) instead of two; theprioritycommands'
missing-file hint names the branch when the rules are committed.- A relative
priority_filein.powerqueue.tomlis normalised (./,
doubled slashes) and one that leaves the repository (../x) is rejected
when the file is applied, instead of making the rules permanently
unreadable. config showmarks values from.powerqueue.tomlby editing the parsed
TOML (toml_edit) rather than scanning lines, and a repository
instructionsvalue is attributed toclaude.append_system_prompt, the
key it changes.
powerqueue v0.11.0
The queue's policy can live in the repository: .powerqueue.toml now carries
[linear], [github], [scheduler] and the rules file, and the daemon can
read it from the default branch instead of the working tree.
Added
.powerqueue.tomlaccepts[linear](everything butendpoint),
[github](everything butendpoint),[scheduler](everything but
gh_binary) andpriority_file(the rules file, relative to the repo
root). Precedence is repo over global, key by key; lists replace. Secrets,
[budget]and host settings stay global.repo.overrides_from = "default-branch"reads.powerqueue.tomland a
relativepriority_fileas committed onorigin/<default_branch>(the
local branch without a remote), so agit checkoutin the main checkout
cannot change what the daemon runs;repo.fetch_interval_secs(300) makes
the daemon fetch while idle so a merged change arrives on its own. The
default stays"working-tree".- The daemon reloads its configuration when
.powerqueue.tomlchanges
(working tree: mtime and size; branch: blob ids), withoutconfig setor a
restart: eventsdaemon.reloaded(with the keys taken and the commit) and
daemon.reload_failed(the previous configuration is kept). Committed
rules reload the same way;rules.loadednames the commit. config showmarks every key that came from the repository
(# .powerqueue.toml) and names the file and branch;--jsonadds
repo_overrides.config validatevalidates the merged configuration and
reports what the repo sets.config pathlistsrepo_config.doctor: the.powerqueue.tomlcheck reports the source and the keys set
and fails when the branch cannot be read; a newoverrides sourcecheck
warns when the main checkout is not on the default branch (working-tree
mode), whendefault-branchmode has no remote branch to read, or when the
daemon never fetches. ThePRIORITY.mdcheck reads the committed copy when
that is what the daemon reads.priority show|check|explain|simulateread the committed rules when the
daemon does and say so;priority editreminds you to commit and push;
tunerefuses to rewrite a rules file the repository owns.
Changed
- Shorten the README to an overview and quick start with a Mermaid workflow;
move detailed guides and references intodocs/. The tuning assistant now
embeds the dedicated configuration reference.
powerqueue v0.10.0
Sessions can run inside containers (or anywhere the daemon's powerqueue
binary cannot run); see docs/containers.md.
Added
claude.binary,codex.binaryandgemini.binaryare command templates:
a command line split like a shell would, with per-task placeholders
({key},{slug},{task_id},{session_id},{worktree},
{task_dir},{repo},{attempt},{model}), e.g.docker exec -it --env-file {task_dir}/env -w {worktree} pq-{slug} claude. A plain
program still works as before.config validatereports unbalanced
quotes and unknown placeholders;doctor,service statusand the
usage probes use the template's program, and skip the login check with a
note when the command is per-task.<provider>.shim = true: the launcher writes a POSIX shell shim to
<task dir>/bin/powerqueueand points the hooks, Claude Code's status
line, Codex'snotifyand the prompt's completion protocol at it. The
shim writes one file per call into<task dir>/inbox/; the daemon drains
it every tick (newinboxphase before the hooks) and applies the
messages aspowerqueue hook/task complete/task blockwould
(eventsinbox.complete,inbox.block,inbox.error,inbox.rejected;
doctorreports parked unreadable messages). Claude sessions get
Bash(<shim> task *)in--allowedTools; prompt templates can use
{{powerqueue}}.POWERQUEUE_BINin the session environment names thepowerqueue
command the session should run (the host binary, or the shim) unless the
provider'senvsets it.repo.setupgetsPOWERQUEUE_TASK_SLUG,POWERQUEUE_TASK_DIR,
POWERQUEUE_DATA_DIRandPOWERQUEUE_STATE_DIR;cleanup.rungets
POWERQUEUE_TASK_SLUG.claude.env.CLAUDE_CONFIG_DIRis also where the daemon reads transcripts
and seeds workspace trust (likecodex.env.CODEX_HOMEfor rollouts), so a
config directory mounted into a container at the same path works on both
sides.- docs/containers.md, docs/examples/Dockerfile.agent (Claude Code + Codex
on Node 22) and docs/examples/agent-container.sh (up/down/exec
for a per-task container); end-to-end tests of the shim on the host and,
withPOWERQUEUE_E2E_DOCKER=1, of Claude and Codex sessions through
docker exec.
Fixed
- A task completed by
powerqueue task completewhose session exited
between the hook and probe phases of one tick was released without
cleanup (no push, nocleanup.run, no source-issue update): the probe
marked the session exited andfinalize_terminalnever saw it. The
session is now left live forfinalize_terminal(event
session.pane_gone).