← All releases

v2.7.0

September 1, 2026

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 manual run 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 standalone devintern dashboard lists the repo’s own .devintern-code/automations.toml and triggers through the documented manual CLI flow
  • Quiet hours limit unattended work to chosen times: [worker.schedule] in workspace.toml defines active and/or blocked windows in timezone (windows union, may cross midnight, blocked wins). 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 = true drains ready tasks once at startup if the last pickup fell inside a quiet window, and devintern worker run-now forces 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 an id, a ready-task query, and exactly one of cron or interval run one-shot devintern --estimate --query "…" when due, recorded with the estimate run origin in the dashboard. Requires an estimation-capable tracker and live-reloads with the workspace config
  • Workspace config hot reload: the worker watches workspace.toml and reloads it a moment after save (or on SIGHUP) — 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> --force through 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.log in 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 a conflict_resolution_cron or conflict_resolution_interval — conflicted PRs queue durably and agent runs happen only in-window (with a 60-minute grace via WORKER_RESOLVE_WINDOW_GRACE_MINUTES) — reducing AI token spend, and "disabled" opts a workspace out entirely: no detection, no queuing, no agent runs (manual devintern 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_labels under [defaults] (or overridden per [[repos]] entry, GitHub only) applies labels to every PR the fleet creates; outside a workspace, single-repo users set PR_LABELS (comma-separated) in .devintern-code/.env
  • Bot mention aliases: GITHUB_BOT_ALIASES (comma-separated logins) extends @mention matching beyond the resolved slug[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_comments table 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-conflicts cleans 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_REQUESTED reviews, so a COMMENTED review wrapping a @bot mention was silently no-oped. address-review now falls back to the latest COMMENTED review 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 human GITHUB_TOKEN no longer blinds slug[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. buildPromptArgs now 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_days until the next restart. The sweep now runs hourly while the worker is up
  • The workspace.toml scaffold 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”), failing workspace init/import; the scaffold’s comment blocks now use # lines