Worker control release: quiet hours, scheduled story-point estimation, config hot reload, dashboard retries and logs, configurable conflict resolution, PR labels — plus review-trigger and dashboard robustness fixes.
Added
- Run scheduled automations now from the dashboard: the new Automations tab lists every configured automation with its schedule, repo, next occurrence, and last run, and a Run now action executes it immediately through the exact scheduled pipeline (occurrence task file, worktree prep, per-repo environment, CLI subprocess) — so a new or edited configuration can be validated in seconds instead of waiting for the next schedule window. Manual runs are recorded with the new
manualrun origin (filterable in the run list) and carry the automation id, keeping them distinguishable from scheduled runs. The loopback-only action refuses disabled automations with an explanation, debounces rapid repeat triggers, and refuses a run while the automation already has one in progress — a scheduled occurrence coming due mid-run follows the usual at-most-once overlap policy. A standalonedevintern dashboardlists the repo’s own.devintern-code/automations.tomland triggers through the documented manual CLI flow - Quiet hours limit unattended work to chosen times:
[worker.schedule]inworkspace.tomldefinesactiveand/orblockedwindows intimezone(windows union, may cross midnight,blockedwins). During quiet hours only new-task pickup is gated — review replies, @mentions, automations, and relay events still run, and in-flight tasks finish.catch_up_missed = truedrains ready tasks once at startup if the last pickup fell inside a quiet window, anddevintern worker run-nowforces one immediate drain past the gate. Quiet-hours edge cases (windows crossing midnight, empty-window configs, catch-up bookkeeping) are hardened with regression coverage - Scheduled story-point estimation via
[[estimations]]: workspace-file entries with anid, a ready-taskquery, and exactly one ofcronorintervalrun one-shotdevintern --estimate --query "…"when due, recorded with theestimaterun origin in the dashboard. Requires an estimation-capable tracker and live-reloads with the workspace config - Workspace config hot reload: the worker watches
workspace.tomland reloads it a moment after save (or onSIGHUP) — routing rules,[[repos]], task query,[[automations]],[[estimations]], poll interval, worktree TTL, and conflict-resolution settings apply without a restart. Edited files are validated first, so a broken config is rejected and the last valid one keeps serving. Tracker credentials,[worker.schedule], and dashboard settings still need a restart - Retry a run from the dashboard: failed, escalated, and abandoned runs show a retry action. Task runs schedule the equivalent of
devintern <TASK> --forcethrough the fleet pipeline — inserted into the shared workspace database and drained by the worker (WORKER_RETRY_INTERVAL_SECONDS, default 5s) — so retries are routed, worktree-prepared, and repo-locked like any other run instead of spawning a bare subprocess. Automation runs show Re-run automation and re-trigger through the same Run-now pipeline: retries are type-aware, so an automation run re-runs the automation rather than replaying its prompt as a plain task. Retries are audited in the queue DB and orphaned retry rows left by a dead worker are settled at startup - Logs tab in the dashboard: the worker tees its console output into
worker.stdout.log/worker.stderr.login the workspace home (rotating at 8 MiB), and the new Logs tab tails them with a level filter (everything / warnings / errors), search, and task-key mentions linking to the run — populated under any launch method, with secrets masked and ANSI stripped. Run enrichment for log lines is batched into one query and rendering is capped for long histories - Automatic conflict resolution is configurable:
[workspace].conflict_resolution = "scheduled"batches base-sync resolution onto aconflict_resolution_cronorconflict_resolution_interval— conflicted PRs queue durably and agent runs happen only in-window (with a 60-minute grace viaWORKER_RESOLVE_WINDOW_GRACE_MINUTES) — reducing AI token spend, and"disabled"opts a workspace out entirely: no detection, no queuing, no agent runs (manualdevintern resolve-conflicts <pr-url>still works; review feedback and @mentions are unaffected). The mode live-reloads and is logged at startup - Labels for generated PRs:
pr_labelsunder[defaults](or overridden per[[repos]]entry, GitHub only) applies labels to every PR the fleet creates; outside a workspace, single-repo users setPR_LABELS(comma-separated) in.devintern-code/.env - Bot mention aliases:
GITHUB_BOT_ALIASES(comma-separated logins) extends @mention matching beyond the resolvedslug[bot]identity, so relay-managed PRs answer to@devintern-ai— relay-connected workers inject the alias into the worker env automatically, covering the mention sweep, the commented-review gate, and per-comment scoping without needing App keys locally - Dashboard status you can trust: the runs list gets compact status/origin dropdown filters and focused columns (task key or automation id, origin, harness, status, result, start time, duration) in a human-friendly order; runs record their git branch and harness at start, shown on the detail page; run details include a snapshot of the tracker task description and link to the ticket; and a new Agent PRs view lists open worker-created PRs with GitHub links, reconciled each poll
Changed
- Addressed review feedback is deduped locally; reactions are visual only: the address-review gate reads and writes an
addressed_commentstable in the local queue database instead of checking for 🎉 reactions on GitHub, so reaction-permission failures can no longer cause feedback to be re-processed. Reactions are still left behind, but purely as visual feedback for humans
Fixed
devintern resolve-conflictscleans up its review worktree: the resolver removes the review worktree it prepared once the run finishes (success, failure, or deferral), instead of leaving the branch-scoped directory behind in/tmp- Commented reviews that mention the bot get addressed: poll/relay review runs only acted on
CHANGES_REQUESTEDreviews, so aCOMMENTEDreview wrapping a @bot mention was silently no-oped. address-review now falls back to the latestCOMMENTEDreview when gated on a bot mention (in the review body, its thread comments, or reviewer conversation comments), scopes each run to that review’s threads plus explicit mentions so stray informal comments are never swept in, and never repeats already-addressed feedback. The address-review CLI also resolves bot identity via GitHub App auth first, so a humanGITHUB_TOKENno longer blindsslug[bot]@mention matching - Dash-leading prompts no longer break positional-prompt harnesses: automation prompts are materialized task files starting with
---frontmatter, and opencode’s argument parser read that as an unknown flag — a usage error with exit 1.buildPromptArgsnow emits an end-of-options marker (--) before any positional prompt that starts with-on the verified positional harnesses (opencode, codex, cursor) - A live workspace lock beats a stale project-dir lock: dashboard status checked the project-dir lock first and trusted any readable lock file, so a stale lock left by a crashed worker shadowed the live workspace-home lock of the running fleet worker — the dashboard kept reporting “worker stopped” mid-run. Both lock locations are now always read, and “stopped” is only reported when every readable lock belongs to a dead process
- Agent PR ticket links survive tracker changes: ticket URLs on the dashboard were re-derived at read time from the dashboard process’s own tracker env, so switching trackers (or running the dashboard standalone without tracker env) broke or mislinked existing PRs. The worker now derives the URL at PR creation and persists it (
agent_prs.ticket_url); the dashboard replays the stored URL verbatim - Stale worktrees are swept while the worker runs: the TTL sweep for leftover task worktrees only ran at startup, so a long-lived worker accumulated worktrees past
worktrees_ttl_daysuntil the next restart. The sweep now runs hourly while the worker is up - The
workspace.tomlscaffold parses under Bun 1.3.2: bare#comment lines before an[[array.of.tables]]header made Bun’s TOML parser mis-attribute keys (“Cannot redefine key”), failingworkspace init/import; the scaffold’s comment blocks now use#lines