# v2026.428.0

> Released: 2026-04-28

## Highlights

- **Pause and resume agents from the sidebar** — The agent sidebar now exposes per-agent edit, pause, and resume actions through a hover/focus action menu, with toast feedback and per-agent pending state. Budget-paused agents are surfaced clearly and intentionally require a non-sidebar path to resume. ([#4616](https://github.com/paperclipai/paperclip/pull/4616))
- **Long issue threads stay smooth** — Issue chat threads now virtualize their rows, bind to a stable scroll container, preserve anchors during incremental loads, and target the absolute latest comment when jumping to the bottom. Long, busy threads scroll predictably without dragging the rest of the UI. ([#4701](https://github.com/paperclipai/paperclip/pull/4701))
- **Productivity review surfaces stalled work** — A new productivity review service automatically opens review issues for no-comment streaks, long-active runs, and high-churn loops, and the board UI now shows a productivity review badge that deep-links to those reviews. ([#4700](https://github.com/paperclipai/paperclip/pull/4700), [#4701](https://github.com/paperclipai/paperclip/pull/4701))

## Improvements

- **Dispatch assigned todo work during recovery sweeps** — The stranded-assignment recovery sweep now dispatches assigned `todo` issues that have no prior heartbeat run, so initial assignments can no longer sit idle. The path reuses budget hard-stops and skips paused agents, and `assignmentDispatched` is now reported in startup and scheduled recovery logs. ([#4614](https://github.com/paperclipai/paperclip/pull/4614))
- **Safer recovery issue handling** — Failed `stranded_issue_recovery` issues are now blocked in place instead of spawning nested recovery loops, retry-failure details are redacted from recovery comments (with reviewers pointed at the linked run evidence), and `maxConcurrentRuns: 1` is honored by heartbeat concurrency normalization. ([#4600](https://github.com/paperclipai/paperclip/pull/4600))
- **New-hire approval is opt-in by default** — Newly created or imported companies no longer require board approval for new agents unless operators explicitly enable that policy. Existing company settings are preserved. ([#4600](https://github.com/paperclipai/paperclip/pull/4600))
- **Steadier inline selector keyboard handling** — Inline entity selectors no longer leak arrow/enter/tab/escape keys to parent shortcuts, the highlighted option commits reliably after keyboard navigation, and the empty `recentOptionIds` default avoids a stale render churn. ([#4617](https://github.com/paperclipai/paperclip/pull/4617))
- **Per-company attachment size limits** — Companies now carry an `attachmentMaxBytes` cap (10 MB default) that flows through the shared portability contract, CLI import/export, and server attachment uploads. The process-level cap still acts as the final ceiling. ([#4700](https://github.com/paperclipai/paperclip/pull/4700))
- **Tighter issue ownership and tree control** — Peer agents can no longer mutate issues they don't own, issue-tree pause/resume reaches dependents predictably, and stranded recovery now reuses a single active recovery origin per source issue instead of spawning duplicates. ([#4700](https://github.com/paperclipai/paperclip/pull/4700))
- **Issue list scales with scroll** — The issues list now paginates over a server offset and loads more rows as you scroll, so long backlogs stay responsive without manual paging. ([#4701](https://github.com/paperclipai/paperclip/pull/4701))
- **Less churn in the new-issue dialog** — Typing in the new-issue dialog no longer re-renders unrelated layout/nav surfaces, and dialog action subscriptions are split so broad shells stay stable while you draft. ([#4701](https://github.com/paperclipai/paperclip/pull/4701))
- **Routine variables are easier to author** — The routine editor now exposes inline help for available variables and supports mentioning users, agents, and projects from the routine description. ([#4701](https://github.com/paperclipai/paperclip/pull/4701))

## Fixes

- **Manual routine runs stay visible in the runner inbox** — Manual routine runs now carry the initiating board or agent actor through dispatch. Fresh routine execution issues record the runner as `createdByUserId`, and coalesced or skipped active routine issues are touched for that user so the work stays in their inbox. ([#4615](https://github.com/paperclipai/paperclip/pull/4615))
- **Reject stale company skill refreshes** — `companySkillService.list()` now checks that the company exists before refreshing bundled and local-path skill state, returning an explicit `404 Company not found` instead of continuing background work for deleted or missing companies. ([#4601](https://github.com/paperclipai/paperclip/pull/4601))
- **Ignore stale stored company selections** — `CompanyProvider` now defers exposing a selected company until the loaded company list validates the stored id, clears storage when no companies are available, and avoids briefly putting downstream UI in an invalid company scope on bootstrap. ([#4602](https://github.com/paperclipai/paperclip/pull/4602))

## Upgrade Guide

Four new database migrations (`0071`–`0074`) will run automatically on startup:

- `0071_default_hire_approval_off` — flips the `companies.require_board_approval_for_new_agents` column default to `false`. Only affects future inserts; existing companies keep their stored values.
- `0072_large_sandman` — adds a partial unique index that prevents duplicate active `stranded_issue_recovery` issues for the same source issue.
- `0073_shiny_salo` — adds `companies.attachment_max_bytes` (default `10485760`, NOT NULL). Existing rows get the 10 MB default; raise the value per company if you need larger attachments.
- `0074_striped_genesis` — adds a partial unique index that prevents duplicate active `issue_productivity_review` issues for the same source issue.

All migrations are additive — no existing data is modified or removed.

If you want new companies to keep requiring board approval for new agents, set that policy explicitly during company creation or import; the stored value still wins over the column default.

## Contributors

Thank you to everyone who contributed to this release!

@cryppadotta
