<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Marvellous Codeworks Blog</title>
        <link>https://kb.marvellouscode.works/blog</link>
        <description>Marvellous Codeworks Blog</description>
        <lastBuildDate>Thu, 24 Sep 2026 13:30:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Introducing logdrop: a private way to share debug reports]]></title>
            <link>https://kb.marvellouscode.works/blog/introducing-logdrop</link>
            <guid>https://kb.marvellouscode.works/blog/introducing-logdrop</guid>
            <pubDate>Thu, 24 Sep 2026 13:30:00 GMT</pubDate>
            <description><![CDATA[logdrop is a small, self-hosted, PrivateBin-style drop-off for TMS diagnostic reports: no account to upload, auth-gated reads, auto-expiring. Use it instead of pasting a captureLogs report into a public GitHub issue.]]></description>
            <content:encoded><![CDATA[<p>Diagnosing a tricky TMS bug often means asking for a <code>captureLogs</code>/<code>debug.html</code> report from the <a class="" href="https://kb.marvellouscode.works/docs/TMS/pages/diagnostic-page">Diagnostic page</a>. Those reports are genuinely useful, they bundle your TMS version, browser details, and recent logs into one shareable block, but they're also a dump of real browser state: open tab titles and URLs, timestamps, sometimes local file paths. Pasting that directly into a GitHub issue makes it <strong>public and permanent</strong>, sitting in a thread that has nothing to do with the data itself.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-logdrop-does">What logdrop does<a href="https://kb.marvellouscode.works/blog/introducing-logdrop#what-logdrop-does" class="hash-link" aria-label="Direct link to What logdrop does" title="Direct link to What logdrop does" translate="no">​</a></h2>
<p><a href="https://github.com/Marvellous-Codeworks/logdrop" target="_blank" rel="noopener noreferrer" class="">logdrop</a> is a small, self-hosted, <a href="https://github.com/PrivateBin/PrivateBin" target="_blank" rel="noopener noreferrer" class="">PrivateBin</a>-style drop-off, live now at <a href="https://logdrop.marvellouscode.works/" target="_blank" rel="noopener noreferrer" class="">logdrop.marvellouscode.works</a>:</p>
<ul>
<li class=""><strong>No account needed to upload.</strong> Paste or drop your report, get a link back.</li>
<li class=""><strong>Reading a capture requires maintainer auth.</strong> Even if the link ends up pasted somewhere public, it's useless to anyone but me.</li>
<li class=""><strong>Uploads auto-expire on their own</strong>, no cleanup needed on either side. If you lose track of your own link, just capture and upload again, it's cheap to redo.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="privacy-and-security-notes">Privacy and security notes<a href="https://kb.marvellouscode.works/blog/introducing-logdrop#privacy-and-security-notes" class="hash-link" aria-label="Direct link to Privacy and security notes" title="Direct link to Privacy and security notes" translate="no">​</a></h2>
<p>A few things worth being explicit about, since this exists specifically to handle data you'd rather not have sitting in public:</p>
<ul>
<li class=""><strong>The upload itself travels over HTTPS</strong> and lands on the same hosting as the rest of <code>marvellouscode.works</code>, not a third-party paste service.</li>
<li class=""><strong>Only an authenticated maintainer session can read a capture.</strong> The upload link alone isn't a secret you have to protect, if it leaks, there's nothing to read behind it.</li>
<li class=""><strong>Auto-expiry is enforced on the storage side</strong>, not by a cleanup job that could fail silently. Once a capture's TTL is up, it's gone, there's no "soft delete" or backup copy sitting around afterward.</li>
<li class=""><strong>This isn't end-to-end encrypted like PrivateBin itself is.</strong> Since reads already require maintainer auth, we skipped client-side encryption for now to keep the tool simple, it's still a listed open question for later, not a settled no.</li>
<li class="">A capture only ever contains what your browser already showed you in <code>debug.html</code>, TMS doesn't collect or transmit anything beyond that on its own, logdrop is just a safer place to <em>put</em> it than a public issue thread.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-use-it-for-a-tms-bug-report">How to use it for a TMS bug report<a href="https://kb.marvellouscode.works/blog/introducing-logdrop#how-to-use-it-for-a-tms-bug-report" class="hash-link" aria-label="Direct link to How to use it for a TMS bug report" title="Direct link to How to use it for a TMS bug report" translate="no">​</a></h2>
<p>Instead of pasting a <code>captureLogs</code>/<code>debug.html</code> report straight into a GitHub issue or comment:</p>
<ol>
<li class="">Open the <a class="" href="https://kb.marvellouscode.works/docs/TMS/pages/diagnostic-page">Diagnostic page</a>, enable <strong>captureLogs</strong>, reproduce the issue, then <strong>Copy report</strong> or <strong>Download report</strong>.</li>
<li class="">Upload it to <a href="https://logdrop.marvellouscode.works/" target="_blank" rel="noopener noreferrer" class="">logdrop.marvellouscode.works</a>.</li>
<li class="">Paste the link it gives you into the issue instead of the raw report.</li>
</ol>
<p>The bug report template, the <a class="" href="https://kb.marvellouscode.works/docs/TMS/faq">FAQ</a>, the <a class="" href="https://kb.marvellouscode.works/docs/TMS/pages/diagnostic-page">Diagnostic page</a> guide, the <a class="" href="https://kb.marvellouscode.works/docs/TMS/troubleshooting/help-test-a-fix">test-build troubleshooting page</a>, and the <a href="https://marvellouscode.works/tms/report" target="_blank" rel="noopener noreferrer" class="">report form</a> on the site all point here now.</p>
<p>Tab Health scan reports (favicon/tab-group repair results) aren't affected, they're counts and status labels, not tab content, so pasting those directly into an issue is still fine.</p>
<p>This came out of <a href="https://github.com/gioxx/MarvellousSuspender/issues/518" target="_blank" rel="noopener noreferrer" class="">#518</a>. A few things are still open for later: uploading straight from TMS's own diagnostic UI instead of copy/paste, rate-limiting on the public upload endpoint, and whether client-side encryption is worth the added complexity given reads are already auth-gated.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="its-not-just-for-us">It's not just for us<a href="https://kb.marvellouscode.works/blog/introducing-logdrop#its-not-just-for-us" class="hash-link" aria-label="Direct link to It's not just for us" title="Direct link to It's not just for us" translate="no">​</a></h2>
<p>The <a href="https://github.com/Marvellous-Codeworks/logdrop" target="_blank" rel="noopener noreferrer" class="">logdrop repo</a> is public and open source, this isn't a TMS-only tool bolted onto our infrastructure. If you run your own project and want the same "reporters upload freely, only you can read it, it expires on its own" flow for your own bug reports or support requests, deploy your own instance, it's designed to be self-hosted by anyone. The one at <a href="https://logdrop.marvellouscode.works/" target="_blank" rel="noopener noreferrer" class="">logdrop.marvellouscode.works</a> is simply the instance we run and keep available for TMS users specifically, it's not a shared public service for unrelated projects.</p>
<p>We're wide open to questions, suggestions, and contributions from outside on the project itself, <a href="https://github.com/Marvellous-Codeworks/logdrop" target="_blank" rel="noopener noreferrer" class="">issues and pull requests</a> are welcome if you want to help make logdrop better.</p>
<p><em>Giovanni</em></p>]]></content:encoded>
            <category>Announcement</category>
            <category>The Marvellous Suspender</category>
            <category>logdrop</category>
        </item>
        <item>
            <title><![CDATA[The Marvellous Suspender 9.0.3 - battery-aware suspend, tab-group actions, favicon and Drive fixes]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-release-9-0-3</link>
            <guid>https://kb.marvellouscode.works/blog/tms-release-9-0-3</guid>
            <pubDate>Thu, 17 Sep 2026 11:03:00 GMT</pubDate>
            <description><![CDATA[9.0.3 ships a battery-power auto-suspend timeout, tab-group and app-window suspend controls, a real fix for suspended-tab favicons on Brave/Vivaldi/Dia, and a proper Drive backup fix for Brave and Vivaldi. Live now on the Chrome Web Store.]]></description>
            <content:encoded><![CDATA[<p>TMS 9.0.3 is <a href="https://chromewebstore.google.com/detail/the-marvellous-suspender/noogafoofpebimajpfpamcfhoaifemoa" target="_blank" rel="noopener noreferrer" class="">live on the Chrome Web Store</a> as of today. Two of the fixes in it were significant enough to get their own deep-dive posts while they were still in progress, so this one pulls everything together in one place, plus the smaller things that didn't get their own writeup.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-new">What's new<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#whats-new" class="hash-link" aria-label="Direct link to What's new" title="Direct link to What's new" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="separate-auto-suspend-timeout-for-battery-power">Separate auto-suspend timeout for battery power<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#separate-auto-suspend-timeout-for-battery-power" class="hash-link" aria-label="Direct link to Separate auto-suspend timeout for battery power" title="Direct link to Separate auto-suspend timeout for battery power" translate="no">​</a></h3>
<p>A new "Suspend tabs on battery power after" select, right alongside the existing plugged-in timeout in Settings. Set it once and tabs suspend more aggressively the moment you unplug, without touching your normal AC timeout at all. Defaults to "Same as when plugged in", so nothing changes unless you go set it.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="never-suspend-app-windows">"Never suspend app windows"<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#never-suspend-app-windows" class="hash-link" aria-label="Direct link to &quot;Never suspend app windows&quot;" title="Direct link to &quot;Never suspend app windows&quot;" translate="no">​</a></h3>
<p>On by default, like the pinned/audio/active-tab protections it sits next to. Keeps tabs open in an app-mode window, an installed PWA, or a site opened via "Create Shortcut → Open as window", out of automatic suspension. A manual "suspend this tab now" still works regardless, this only affects the automatic timer.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="suspendunsuspend-every-tab-in-a-tab-group">Suspend/unsuspend every tab in a tab group<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#suspendunsuspend-every-tab-in-a-tab-group" class="hash-link" aria-label="Direct link to Suspend/unsuspend every tab in a tab group" title="Direct link to Suspend/unsuspend every tab in a tab group" translate="no">​</a></h3>
<p>New page and tab-strip right-click menu items, plus two bindable keyboard shortcuts, acting on every tab sharing the clicked tab's group. Thanks to <strong><a href="https://github.com/mherkazandjian" target="_blank" rel="noopener noreferrer" class="">@mherkazandjian</a></strong> for building this, his first contribution to the project (<a href="https://github.com/gioxx/MarvellousSuspender/pull/438" target="_blank" rel="noopener noreferrer" class="">#438</a>) and part of a bigger <a href="https://github.com/gioxx/MarvellousSuspender/issues/133" target="_blank" rel="noopener noreferrer" class="">tab-groups feature set</a> still in progress for upcoming releases.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="always-reopen-suspended-tabs-scrolled-to-the-top">"Always reopen suspended tabs scrolled to the top"<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#always-reopen-suspended-tabs-scrolled-to-the-top" class="hash-link" aria-label="Direct link to &quot;Always reopen suspended tabs scrolled to the top&quot;" title="Direct link to &quot;Always reopen suspended tabs scrolled to the top&quot;" translate="no">​</a></h3>
<p>Opt-in. If you'd rather a suspended tab always reopen at the top of the page instead of wherever you left it scrolled, this does that, and overrides a <code>#section</code> link anchor in the URL too.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="reload-also-unsuspends-background-tabs">Reload also unsuspends background tabs<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#reload-also-unsuspends-background-tabs" class="hash-link" aria-label="Direct link to Reload also unsuspends background tabs" title="Direct link to Reload also unsuspends background tabs" translate="no">​</a></h3>
<p>Reloading a suspended tab you're not currently looking at, via a multi-tab selection, or right-click → Reload on an inactive tab, used to silently do nothing. Turn this on and it counts as an explicit unsuspend request, same as reloading the tab you're actively viewing already did.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-whats-new-screen-after-updates">A "What's new" screen after updates<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#a-whats-new-screen-after-updates" class="hash-link" aria-label="Direct link to A &quot;What's new&quot; screen after updates" title="Direct link to A &quot;What's new&quot; screen after updates" translate="no">​</a></h3>
<p>Exactly what you're reading the substance of right now, just inside the extension: a one-time modal on the Settings page after an update, showing only that version's changes, not the entire history.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-fixed">What's fixed<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#whats-fixed" class="hash-link" aria-label="Direct link to What's fixed" title="Direct link to What's fixed" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-rare-but-real-out-of-memory-crash">A rare but real out-of-memory crash<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#a-rare-but-real-out-of-memory-crash" class="hash-link" aria-label="Direct link to A rare but real out-of-memory crash" title="Direct link to A rare but real out-of-memory crash" translate="no">​</a></h3>
<p>Reproduced live, traced all the way to its actual mechanism, and fixed at the root rather than patched around the symptom: <code>chrome.storage.onChanged</code> was quietly broadcasting a full multi-megabyte copy of the diagnostic log buffer to every open suspended tab, every time anything was logged, and none of those copies ever got released. The whole log buffer moved to IndexedDB, which has no such broadcast, closing the gap entirely. Mostly invisible unless you use the debug page's <code>captureLogs</code> option, but the extension is more resilient across the board regardless. Full story: <a class="" href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page">9.0.3 in progress: chasing down a crash in TMS's own debug tooling</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="google-drive-backup-disconnecting-on-brave-and-vivaldi">Google Drive backup disconnecting on Brave and Vivaldi<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#google-drive-backup-disconnecting-on-brave-and-vivaldi" class="hash-link" aria-label="Direct link to Google Drive backup disconnecting on Brave and Vivaldi" title="Direct link to Google Drive backup disconnecting on Brave and Vivaldi" translate="no">​</a></h3>
<p>9.0.2 stopped the Drive connect flow from hanging on these browsers, but the token it fell back to was still short-lived and unreliable to renew, so accounts kept flipping back to "disconnected" after a backup or two. 9.0.3 replaces it with an authorization-code + PKCE exchange that mints a genuine long-lived refresh token, renewed by a direct call that doesn't depend on the browser at all, with the OAuth client secret moved server-side into a small proxy (<code>tms-oauth-proxy</code>) so it no longer ships inside the extension package. <strong>If you're on Brave or Vivaldi with Drive backup enabled, you'll need to reconnect once</strong> (Options → Backup → Connect) after updating, then it stays connected reliably. Full story: <a class="" href="https://kb.marvellouscode.works/blog/tms903-drive-pkce-refresh-token">9.0.3 in progress: a real fix for Drive backups disconnecting on Brave and Vivaldi</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="suspended-tab-favicons-stuck-on-the-extension-icon-after-a-restart">Suspended-tab favicons stuck on the extension icon after a restart<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#suspended-tab-favicons-stuck-on-the-extension-icon-after-a-restart" class="hash-link" aria-label="Direct link to Suspended-tab favicons stuck on the extension icon after a restart" title="Direct link to Suspended-tab favicons stuck on the extension icon after a restart" translate="no">​</a></h3>
<p>Mostly reported on Brave, Vivaldi, and Dia, where the automatic repair pass depended on a startup event those browsers don't fire reliably, so favicons reverted to TMS's own icon on every restart until manually fixed via Tab Health. A dedicated, restart-independent backstop now retries on its own on every service worker wake, and again the instant you open a suspended tab, so it recovers without you doing anything (<a href="https://github.com/gioxx/MarvellousSuspender/issues/474" target="_blank" rel="noopener noreferrer" class="">#474</a>, <a href="https://github.com/gioxx/MarvellousSuspender/issues/397" target="_blank" rel="noopener noreferrer" class="">#397</a>, <a href="https://github.com/gioxx/MarvellousSuspender/issues/260" target="_blank" rel="noopener noreferrer" class="">#260</a>). Thanks to everyone who tested pre-release builds and sent back debug reports to help pin this down.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-battery-specific-timeout-not-reacting-to-unplugging">The battery-specific timeout not reacting to unplugging<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#the-battery-specific-timeout-not-reacting-to-unplugging" class="hash-link" aria-label="Direct link to The battery-specific timeout not reacting to unplugging" title="Direct link to The battery-specific timeout not reacting to unplugging" translate="no">​</a></h3>
<p>It needed a manual trigger to take effect before; now it responds immediately when you unplug.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-bright-white-flash-switching-between-suspended-tabs">A bright white flash switching between suspended tabs<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#a-bright-white-flash-switching-between-suspended-tabs" class="hash-link" aria-label="Direct link to A bright white flash switching between suspended tabs" title="Direct link to A bright white flash switching between suspended tabs" translate="no">​</a></h3>
<p>Especially noticeable in dark mode. Reported as far back as v7.1.6.2 (<a href="https://github.com/gioxx/MarvellousSuspender/issues/168" target="_blank" rel="noopener noreferrer" class="">#168</a>), finally tracked down: a render-blocking stylesheet now paints the background immediately instead of showing the browser default until the real styles load.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-reload-link-on-suspended-tabs-too-bright-in-dark-mode">The reload link on suspended tabs, too bright in dark mode<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#the-reload-link-on-suspended-tabs-too-bright-in-dark-mode" class="hash-link" aria-label="Direct link to The reload link on suspended tabs, too bright in dark mode" title="Direct link to The reload link on suspended tabs, too bright in dark mode" translate="no">​</a></h3>
<p>Toned down from accent-blue to a subdued gray that actually fits the rest of that page's quiet dark-mode look.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="smaller-fixes">Smaller fixes<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#smaller-fixes" class="hash-link" aria-label="Direct link to Smaller fixes" title="Direct link to Smaller fixes" translate="no">​</a></h3>
<p>Tab reload/unsuspend determinism across a multi-tab selection, the debug page's tab-status list getting permanently stuck on "unknown" for a tab whose script had genuinely died, and a spacing inconsistency in Options.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-3#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>The <a href="https://github.com/gioxx/MarvellousSuspender/issues/133" target="_blank" rel="noopener noreferrer" class="">tab-groups feature set</a> that @mherkazandjian and, more recently, <strong><a href="https://github.com/jadshaker" target="_blank" rel="noopener noreferrer" class="">@jadshaker</a></strong> have been building out continues past this release: a "suspend/unsuspend all tabs not in a group" counterpart and a global "never suspend tabs in a tab group" toggle have already landed on the development branch, with a per-group override still going through review, all targeting the next release. Ukrainian was added as a supported language, with translation now underway thanks to a community volunteer. Beyond that, 9.1.0 is shaping up around wider platform reach (Edge Add-ons Store, Group Policy for managed deployments) and finer control over suspend behaviour and UI.</p>
<p>I wish you all the best on your journey.</p>
<p><em>Giovanni</em></p>
<hr>
<p><em>Full changelog on GitHub: <a href="https://github.com/gioxx/MarvellousSuspender/blob/master/CHANGELOG.md" target="_blank" rel="noopener noreferrer" class="">CHANGELOG.md</a></em></p>]]></content:encoded>
            <category>Release</category>
            <category>The Marvellous Suspender</category>
        </item>
        <item>
            <title><![CDATA[9.0.3 in progress: chasing down a crash in TMS's own debug tooling]]></title>
            <link>https://kb.marvellouscode.works/blog/tms903-stability-debug-page</link>
            <guid>https://kb.marvellouscode.works/blog/tms903-stability-debug-page</guid>
            <pubDate>Wed, 26 Aug 2026 14:40:00 GMT</pubDate>
            <description><![CDATA[A live crash report led to a first, real round of fixes in TMS's log buffer and debug page, and then the crash kept happening anyway. Tracing it further uncovered the actual mechanism: a chrome.storage broadcast quietly duplicating megabytes of log data across every suspended tab, fixed by moving the whole log buffer to IndexedDB.]]></description>
            <content:encoded><![CDATA[<p>TMS's debug page has an optional <strong>captureLogs</strong> toggle for exactly one purpose: when something goes wrong, turn it on, reproduce the issue, and send us the report. It is meant to make diagnosing problems easier, not to become the problem itself.</p>
<p>A few days ago, while stress-testing 9.0.3 in development with dozens of suspended tabs open and <code>captureLogs</code> enabled, the opposite happened: the extension itself crashed, memory exhausted, requiring a full reload to recover. That is not an acceptable outcome for a tool whose entire job is to run quietly in the background and get out of the way, let alone for an extension whose whole purpose is to lighten Chrome's memory load in the first place. What follows is the real, unedited shape of tracking that down: a first round of fixes that were genuinely necessary and genuinely not enough, followed by the investigation that found what actually needed fixing.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>TL;DR</div><div class="admonitionContent_BuS1"><ul>
<li class="">Stress-testing 9.0.3 in development, with lots of suspended tabs and TMS's <code>captureLogs</code> debug option on, hit a real out-of-memory crash.</li>
<li class="">We fixed several genuine bugs in the log buffer and debug page (PR #472), and the crash kept happening anyway.</li>
<li class="">The actual cause: TMS's log storage was quietly sending a copy of itself to <em>every open suspended tab</em> every time it was written, and none of those copies ever got cleaned up. The more you logged, the faster it filled up your memory, regardless of how many tabs you had open.</li>
<li class="">The real fix moves that log storage to a different, safer mechanism (IndexedDB) that doesn't have this problem at all, plus a batch of smaller hardening fixes found along the way (PR #473, in progress).</li>
<li class=""><strong>Affects only people who turn on <code>captureLogs</code></strong> to help us debug something. If you've never touched that setting, none of this ever affected you.</li>
</ul></div></div>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="starting-from-a-real-report-not-a-hypothesis">Starting from a real report, not a hypothesis<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#starting-from-a-real-report-not-a-hypothesis" class="hash-link" aria-label="Direct link to Starting from a real report, not a hypothesis" title="Direct link to Starting from a real report, not a hypothesis" translate="no">​</a></h2>
<p>That crash produced a downloaded debug log, and that log became the map for everything that followed: every fix in this post was found by tracing an actual symptom back to its cause, not by guessing at what might theoretically go wrong.</p>
<p>The short version of what we found first: TMS's log buffer, the piece of code responsible for collecting diagnostic entries so <code>captureLogs</code> reports are useful, had accumulated several real memory and correctness bugs of its own. On top of that, the debug page's own tab-status checker had a design gap that made "unknown" tab statuses effectively permanent, and a runaway event handler that could multiply its own workload without bound.</p>
<p>None of this affects a normal TMS install with <code>captureLogs</code> off. But if you are the kind of user who leaves it on to help us track down a hard-to-reproduce issue, and you run TMS the way it is meant to be run, with a lot of tabs open, these are exactly the conditions that exposed every one of these bugs. They were real, they were fixed, and, as it turned out, they were not the whole story.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="round-one-the-log-buffers-duplicated-memory-unbounded-growth-and-a-crash-under-load">Round one: the log buffer's duplicated memory, unbounded growth, and a crash under load<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#round-one-the-log-buffers-duplicated-memory-unbounded-growth-and-a-crash-under-load" class="hash-link" aria-label="Direct link to Round one: the log buffer's duplicated memory, unbounded growth, and a crash under load" title="Direct link to Round one: the log buffer's duplicated memory, unbounded growth, and a crash under load" translate="no">​</a></h2>
<p>TMS's <code>gsUtils.js</code> module is imported by every page in the extension, the background service worker, every open settings page, and, critically, <strong>every single suspended tab</strong>. Each of those contexts used to keep its own in-memory copy of the recent log history, up to 10,000 entries, even though nothing ever read that copy back except the debug page itself (which reads straight from storage instead). With fifty suspended tabs open, that is fifty redundant buffers sitting in memory for no reason. Removed entirely.</p>
<p>The more serious issue was what happened when the service worker briefly lost contact with a suspended tab, or vice versa, which happens routinely as Chrome recycles the service worker to save memory. A failed log delivery got queued for retry, but nothing ever capped how large that retry queue could grow. Under sustained logging with <code>captureLogs</code> on, that queue could grow without limit until Chrome killed the page for memory pressure, which matched the "insufficient memory, extension disabled" report almost exactly. It was capped at 5,000 entries, oldest dropped first.</p>
<p>Fixing that surfaced the next problem: a burst of near-simultaneous log writes, for example every suspended tab reacting at once to <code>captureLogs</code> being toggled, meant dozens of full-buffer read-modify-write round trips to <code>chrome.storage.local</code> back to back. <code>chrome.storage.local</code> has no append primitive, every single log entry cost a full get-parse-stringify-set of the <em>entire</em> stored history. With ~50 tabs open, this alone was enough to make the extension noticeably sluggish, including pages unrelated to logging that just happened to be loading at the same time. Incoming log messages were coalesced into a single merge every 250ms instead of one merge per message, turning a fifty-tab burst into one round trip.</p>
<p>That coalescing change itself then introduced a genuine crash: if many contexts had each queued up their own maximum backlog while the service worker was briefly unreachable, all of them flushing at once could aggregate well over 100,000 log entries into a single batch. The code merging that batch into storage used JavaScript's spread operator (<code>array.push(...entries)</code>) to append it, and V8 throws a hard <code>RangeError</code> past a few tens of thousands of spread arguments. That failure caused every sender to requeue its batch, which reproduced the exact same oversized merge on the next attempt, forever, a real, repeatable crash that lined up precisely with the original report. Switched to <code>concat()</code>, which has no such limit, and added a hard cap on the aggregated batch itself so it could never grow that large again.</p>
<p>A few more rounds of testing turned up smaller, subtler correctness issues in the same area: log ordering could get scrambled between a page's batched writes and the service worker's own immediate ones, a corrupted or malformed persisted buffer could get the retry logic stuck trying the same broken write forever, and the "Clear log" button had a narrow race where an in-flight batch could resurrect entries the user had just wiped. Each of those was closed. This whole round of fixes <a href="https://github.com/gioxx/MarvellousSuspender/pull/472" target="_blank" rel="noopener noreferrer" class="">merged as PR #472</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-debug-page-unknown-status-that-never-got-better">The debug page: unknown status that never got better<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#the-debug-page-unknown-status-that-never-got-better" class="hash-link" aria-label="Direct link to The debug page: unknown status that never got better" title="Direct link to The debug page: unknown status that never got better" translate="no">​</a></h2>
<p>Separately from the log buffer, the debug page's tab profiler kept showing <code>unknown</code> for the status of certain tabs, indefinitely, surviving repeated manual reloads of the whole extension.</p>
<p>The cause: when a tab's content script genuinely stops responding (the page itself is still alive, just its script has died, a different failure mode from Chrome discarding a tab to save memory), recovering it requires TMS to re-inject and restart that script. The debug page's status check never attempted that recovery step, it did a single quick probe and gave up. Only the extension's own periodic background check ever did the real recovery work, and that check runs on its own schedule, independent of whatever the debug page happens to be showing you at the time.</p>
<p>The fix routed the debug page's checks through the same recovery-capable queue the background process already uses, instead of a shallow one-off probe, so a tab that needs re-injection actually gets it, and the debug page's own table now patches that row live once the real result comes back instead of leaving it stuck on a stale placeholder.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="an-unbounded-event-handler-and-an-unbounded-fan-out">An unbounded event handler and an unbounded fan-out<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#an-unbounded-event-handler-and-an-unbounded-fan-out" class="hash-link" aria-label="Direct link to An unbounded event handler and an unbounded fan-out" title="Direct link to An unbounded event handler and an unbounded fan-out" translate="no">​</a></h2>
<p>Two more issues, both specific to running with a lot of tabs open at once, also went into PR #472:</p>
<p>The debug page refreshes its tab table whenever the window regains focus. With no guard in place, rapid focus changes (multiple monitors, fast alt-tabbing) could trigger overlapping refreshes, each one repeating a full pass over every open tab. That was debounced to at most one refresh per second, with the in-flight run's result never silently dropped if the tab list changed while it was still running.</p>
<p>And the refresh itself, for every profile with more than a handful of tabs, used to fire one request per tab all at once with no cap, hundreds of simultaneous checks against the background process for a heavily-loaded profile. That was capped to a bounded number in flight at a time, spread out instead of bursting, without blocking the table from rendering while slower checks were still queued behind faster ones.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-crash-that-wouldnt-die">The crash that wouldn't die<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#the-crash-that-wouldnt-die" class="hash-link" aria-label="Direct link to The crash that wouldn't die" title="Direct link to The crash that wouldn't die" translate="no">​</a></h2>
<p>PR #472 merged. It fixed several real bugs. And going back to actually using TMS, reloading the extension, opening the debug page, browsing the tab list, it crashed again. Not eventually, not under some extreme stress test: within minutes, sometimes on nothing more than opening the debug page and looking around.</p>
<p>That is the point where a smaller team, or a less patient one, stops at "well, we fixed a bunch of real bugs, maybe it's better now" and ships it. We didn't, because the report was specific and reproducible, and specific reproducible reports deserve a specific reproducible answer, not a hopeful one.</p>
<p>The first real break came from <code>chrome://crashes</code> and the local Crashpad minidumps Chrome keeps on disk even after uploading them. Reading the crash annotations directly (no symbol server access needed, Crashpad embeds a surprising amount of plain-text diagnostic context in every dump) turned up two numbers that mattered: <code>view-count</code>/<code>web-frame-count</code> around 48–49, and <code>loaded-origin-0</code> pointing at TMS's own extension origin. Chrome puts every page sharing the same extension origin into one renderer process: every open <code>suspended.html</code>, plus the debug page itself, all sharing one process, one V8 heap, with a hard ceiling around 4GB regardless of how much physical RAM the machine actually has.</p>
<p>That heap was nearly full: <code>v8-oom-old-space-size</code> (regular JS objects) sat at a tiny ~18MB, while <code>v8-oom-memory-allocator-size</code> (backing store for large binary buffers) was pinned near the 4GB cap. Two theories followed from that, both genuinely tested, both genuinely fixed, and neither the actual answer:</p>
<ul>
<li class=""><strong>Favicon size.</strong> <code>gsFavicon.js</code> built each suspended tab's favicon at the source image's native resolution before scaling anything down, and some sites serve genuinely large "favicons" (a 512×512 apple-touch-icon reused as-is is common). Capped the working canvas to a sane maximum, and, since browsers already suspended before the fix had cached the oversized version, added a version stamp so the cache silently rebuilds at the new size instead of staying oversized forever.</li>
<li class=""><strong>The debug page's own <code>refreshLogs()</code>.</strong> It re-ran on every window focus event with no protection against overlapping calls, unlike the sibling function that debounces exactly this. Each run re-parsed the entire log buffer, including a full-buffer fetch that existed only to display a count. Fixed to coalesce concurrent calls into at most one in flight.</li>
</ul>
<p>Both fixes were correct and shipped. Neither stopped the crash. The tell was in the numbers: the same ~3.7–4GB ceiling kept showing up whether 28 suspended tabs were open or 49. If either theory were the real cause, more tabs should have meant more risk. It didn't. Something else was consuming memory at a rate tied to <em>how often the log buffer was written</em>, not to how many tabs happened to be open at the moment of the crash.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-actual-mechanism-a-broadcast-nobody-asked-for">The actual mechanism: a broadcast nobody asked for<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#the-actual-mechanism-a-broadcast-nobody-asked-for" class="hash-link" aria-label="Direct link to The actual mechanism: a broadcast nobody asked for" title="Direct link to The actual mechanism: a broadcast nobody asked for" translate="no">​</a></h2>
<p>Static analysis of crash dumps had said everything it could. The next step was live memory profiling: <code>chrome://inspect</code>, attached to the shared renderer process, taking heap snapshots at intervals while reproducing the crash, saving each one to disk immediately so a mid-recording crash couldn't take the evidence down with it.</p>
<p>The second snapshot, taken shortly before an actual crash, showed the real shape of the problem directly: dozens of near-duplicate strings, each roughly 6MB, each a full JSON-serialized copy of the log buffer, and their timestamps were <strong>hours old</strong>. Not fresh writes accumulating under load. Frozen, historical copies of the buffer, retained since early in the session, never released.</p>
<p>The mechanism, once we knew what to look for: <code>chrome.storage.onChanged</code> fires in <em>every context that has any listener registered for that storage area</em>, delivering a full copy of whatever changed, regardless of whether that context's own callback cares about the specific keys involved. <code>suspended.js</code> registers exactly such a listener, in every single suspended tab, for one small, entirely unrelated setting. Every time anything wrote to the log buffer (which, with <code>captureLogs</code> on, is constantly), Chrome dutifully constructed and delivered a multi-megabyte <code>oldValue</code>/<code>newValue</code> payload to every one of those listeners, in every suspended tab, all sharing that one renderer process. None of it released once the listener finished ignoring it.</p>
<p>This is not a bug in the sense of a typo or an off-by-one. It is <code>chrome.storage.onChanged</code> behaving exactly as documented. The log buffer's design, one shared blob in <code>chrome.storage.local</code>, read and written across dozens of contexts, was simply the wrong shape for that API's actual delivery semantics, and the more tabs (and the more logging) a session had, the more that mismatch cost, independent of the specific favicon size or refresh cadence either earlier theory had chased.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-fix-move-the-whole-log-buffer-to-indexeddb">The fix: move the whole log buffer to IndexedDB<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#the-fix-move-the-whole-log-buffer-to-indexeddb" class="hash-link" aria-label="Direct link to The fix: move the whole log buffer to IndexedDB" title="Direct link to The fix: move the whole log buffer to IndexedDB" translate="no">​</a></h2>
<p>The whole persistence layer moved from <code>chrome.storage.local</code> to IndexedDB, using the same database TMS already keeps for favicon and session data. Instead of one shared blob, the log buffer is now one record per entry. IndexedDB writes have no cross-context broadcast equivalent to <code>chrome.storage.onChanged</code>, and per-entry records mean every context, every suspended tab included, can write directly, without funneling through the service worker as a single designated writer the way the old design required.</p>
<p>A good deal of complexity the old blob-based design needed went away with it: the version-token optimistic-concurrency retry loop that guarded against two writers racing on one shared value, the 250ms incoming-message coalescing window from the earlier round of fixes, and the dedicated cross-context message action that carried log entries to the service worker in the first place. None of it is needed when every writer can safely touch its own record.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-review-caught-along-the-way">What review caught along the way<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#what-review-caught-along-the-way" class="hash-link" aria-label="Direct link to What review caught along the way" title="Direct link to What review caught along the way" translate="no">​</a></h2>
<p>Several rounds of automated review on the migration itself caught real, live issues before they shipped:</p>
<ul>
<li class="">A write failure being <em>reported</em> through the same logging pipe that had just failed, which could loop indefinitely under a persistent failure (a full disk, a corrupted database) instead of backing off and retrying normally.</li>
<li class="">Multiple contexts flushing independently meant insertion order didn't reliably match chronological order, fixed with a proper timestamp index, so "most recent" and "oldest to evict" both mean what they say.</li>
<li class="">A multi-entry write done as separate transactions per entry, which could leave a partial batch committed and then duplicated on retry after a failure partway through, now one atomic transaction per flush.</li>
<li class="">The "Clear log" button silently reporting success even when the underlying clear had failed.</li>
<li class="">The one-off cleanup of the <em>old</em> <code>chrome.storage.local</code> keys, running from a place that itself ran in every context: for a profile that had already accumulated a multi-megabyte buffer under the old design, that cleanup call was itself a <code>chrome.storage.local</code> mutation, and would have broadcast that same oversized payload to every suspended tab one more time, on exactly the code path meant to eliminate it. Moved to run once, from the service worker only.</li>
<li class="">Trimming the store back down to its cap, if triggered from the same per-context flush path the old design used, would let dozens of tabs each independently decide "trim needed" at once. Replaced with a single periodic <code>chrome.alarms</code> schedule, the same mechanism TMS already uses for backup and news-feed timing.</li>
</ul>
<p>And a real behaviour change worth naming rather than hiding: TMS declares <code>"incognito": "split"</code> in its manifest, so a regular window and an incognito one run fully separate extension instances. <code>chrome.storage.local</code> wasn't partitioned by that split (both instances shared one buffer under the old design), but IndexedDB is. A regular debug session can no longer see what happened in an incognito window. Bridging the two isn't practical without reintroducing some form of cross-context broadcast, which is the exact mechanism this whole migration exists to eliminate, so this is accepted as a known limitation rather than worked around.</p>
<p>Then live testing caught one more thing none of the automated review did: after adding that new timestamp index, the log view briefly showed "No entries" while the entry counter kept climbing normally. IndexedDB only re-runs its schema-upgrade step when the requested database version number goes <em>up</em>: a profile that had already opened the database at its current version earlier the same day, before the index existed, never got it added. A quick version bump forced the upgrade to actually apply. A good reminder that review catches a great deal, but nothing replaces someone actually reloading the extension and using it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-couple-of-other-things-fixed-along-the-way">A couple of other things fixed along the way<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#a-couple-of-other-things-fixed-along-the-way" class="hash-link" aria-label="Direct link to A couple of other things fixed along the way" title="Direct link to A couple of other things fixed along the way" translate="no">​</a></h2>
<p>Chasing the same crash surfaced two more issues in adjacent code, both worth a brief mention even though they're not directly about the log buffer:</p>
<p>A queue used for retrying tab-initialization work during startup had a subtle timing gap: a job that legitimately needed several retries (completely normal when many tabs restore at once) could end up running for minutes with the extension's own startup-completion flag stuck <code>true</code> the whole time, silently disabling recovery behaviour. It now has a real overall time limit alongside its existing retry-count limit, generous enough not to punish normal retries, but no longer effectively unbounded.</p>
<p>And a favicon-related job that starts initializing a suspended tab could keep running against a tab that had already navigated away, been discarded, or closed mid-initialization, in a few different ways depending on exactly when that happened. Each of those was closed with a shared cancellation signal that the job checks at every step, rather than a growing pile of individual point-checks that could only ever catch the specific timing gap someone happened to find.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-this-leaves-things">Where this leaves things<a href="https://kb.marvellouscode.works/blog/tms903-stability-debug-page#where-this-leaves-things" class="hash-link" aria-label="Direct link to Where this leaves things" title="Direct link to Where this leaves things" translate="no">​</a></h2>
<p>None of this changes what TMS does for a normal user with <code>captureLogs</code> off, which is the overwhelming majority of installs. What it changes is whether the diagnostic tooling itself, and the extension underneath it, can be trusted to run for an extended period, under real load, without becoming the thing you have to reload the browser to escape from. That was the actual bar for this work, and every fix above, in both rounds, was driven by hitting it, not by a checklist.</p>
<p>If you are running a build with <code>captureLogs</code> on to help track down an issue and still see something behaving oddly, please <a href="https://github.com/gioxx/MarvellousSuspender/issues" target="_blank" rel="noopener noreferrer" class="">open an issue on GitHub</a> with a downloaded debug report attached. That is exactly the workflow that made this whole investigation possible in the first place.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Both rounds of fixes described above are merged (<a href="https://github.com/gioxx/MarvellousSuspender/pull/472" target="_blank" rel="noopener noreferrer" class="">#472</a> and <a href="https://github.com/gioxx/MarvellousSuspender/pull/473" target="_blank" rel="noopener noreferrer" class="">#473</a> on GitHub) and included in <strong>TMS 9.0.3</strong>, live on the Chrome Web Store. See the <a class="" href="https://kb.marvellouscode.works/blog/tms-release-9-0-3">9.0.3 release post</a> for the full picture.</p></div></div>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Bug</category>
        </item>
        <item>
            <title><![CDATA[9.0.3 in progress: a real fix for Drive backups disconnecting on Brave and Vivaldi]]></title>
            <link>https://kb.marvellouscode.works/blog/tms903-drive-pkce-refresh-token</link>
            <guid>https://kb.marvellouscode.works/blog/tms903-drive-pkce-refresh-token</guid>
            <pubDate>Tue, 25 Aug 2026 09:15:00 GMT</pubDate>
            <description><![CDATA[9.0.2's Brave/Vivaldi Drive fallback stopped the connect flow from hanging, but the underlying token it relied on was still short-lived and unreliable to renew. 9.0.3 replaces it with a proper refresh token.]]></description>
            <content:encoded><![CDATA[<p><a class="" href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#google-drive-connect-account-on-brave-and-vivaldi">9.0.2 shipped a fallback</a> for connecting Google Drive backup on Brave and Vivaldi, browsers where Chrome's own <code>chrome.identity.getAuthToken()</code> doesn't work. That fallback fixed the immediate problem: the connect button no longer hung indefinitely. It did not fully fix the underlying issue, and reports kept coming in of Drive accounts flipping back to "disconnected" after just one or two automatic backups. 9.0.3 replaces the fallback's mechanism entirely.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>TL;DR</div><div class="admonitionContent_BuS1"><ul>
<li class=""><strong>Only affects Drive backup on Brave and Vivaldi.</strong> Chrome users aren't affected at all.</li>
<li class="">The 9.0.2 fallback used a token that expired every hour and needed the browser's help to silently renew it, Brave and Vivaldi don't support that renewal reliably, so accounts kept disconnecting on their own.</li>
<li class="">9.0.3 replaces it with a long-lived token that renews itself directly, no browser dependency, no more surprise disconnects.</li>
<li class="">The token exchange goes through a small Cloudflare Worker we run (<a href="https://github.com/Marvellous-Codeworks/tms-oauth-proxy" target="_blank" rel="noopener noreferrer" class=""><code>tms-oauth-proxy</code></a>), so the OAuth client secret no longer ships inside the extension package.</li>
<li class=""><strong>If you already connected Drive on Brave/Vivaldi</strong>, you'll need to click <strong>Connect</strong> once more in Options → Backup after updating; after that, it just works.</li>
</ul></div></div>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-the-902-fallback-still-disconnected">Why the 9.0.2 fallback still disconnected<a href="https://kb.marvellouscode.works/blog/tms903-drive-pkce-refresh-token#why-the-902-fallback-still-disconnected" class="hash-link" aria-label="Direct link to Why the 9.0.2 fallback still disconnected" title="Direct link to Why the 9.0.2 fallback still disconnected" translate="no">​</a></h2>
<p>The fallback used <code>chrome.identity.launchWebAuthFlow()</code>, which on the first connection opens a real tab for you to sign in and grant access. What it returns is an <strong>implicit-flow access token</strong>, short-lived, about an hour, by design. Renewing it silently before it expires means calling <code>launchWebAuthFlow()</code> again with <code>prompt: 'none'</code>, no visible tab, no interaction, just a background request that depends entirely on the browser already holding an active Google session for that tab.</p>
<p>That dependency is exactly where it broke. Brave and Vivaldi don't maintain that ambient session reliably the way Chrome does, so the silent renewal call would fail once the hour was up, and the account looked disconnected from TMS's side even though nothing the user did caused it.</p>
<p>The root cause sits upstream, in Brave's own <code>chrome.identity</code> implementation, not in TMS. It's tracked in <a href="https://github.com/brave/brave-browser/issues/38066#issuecomment-5395066080" target="_blank" rel="noopener noreferrer" class="">brave-browser#38066</a>, still open as of this writing, no movement from Brave's side yet. We're not waiting on it: 9.0.3 works around it entirely on our end instead.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-903-does-instead">What 9.0.3 does instead<a href="https://kb.marvellouscode.works/blog/tms903-drive-pkce-refresh-token#what-903-does-instead" class="hash-link" aria-label="Direct link to What 9.0.3 does instead" title="Direct link to What 9.0.3 does instead" translate="no">​</a></h2>
<p>The fix is a proper move to <strong>authorization-code flow with PKCE</strong>. The practical difference: instead of a token that expires every hour and needs the browser's help to silently renew, one interactive consent (the same tab you already see the first time you connect) mints a long-lived <strong>refresh token</strong>, stored locally. Every renewal after that is a direct request to Google's token endpoint, no tab, no cookies, no dependency on whatever session state the browser happens to be holding onto at that moment.</p>
<p>This reuses the existing "Web application" OAuth client already registered for TMS (the same one used for <a class="" href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#google-drive-connect-account-on-brave-and-vivaldi">the 9.0.2 fallback</a>) rather than a new one. We looked at switching to a "Desktop app" client type instead, which Google documents as the more natural fit for an installed application, but tested it directly against the live authorization endpoint and confirmed it rejects the redirect URL format Chrome extensions are required to use. The existing client stays.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="if-you-already-connected-drive-on-brave-or-vivaldi">If you already connected Drive on Brave or Vivaldi<a href="https://kb.marvellouscode.works/blog/tms903-drive-pkce-refresh-token#if-you-already-connected-drive-on-brave-or-vivaldi" class="hash-link" aria-label="Direct link to If you already connected Drive on Brave or Vivaldi" title="Direct link to If you already connected Drive on Brave or Vivaldi" translate="no">​</a></h2>
<p>There is one unavoidable step for anyone who connected Drive through the 9.0.2 fallback already: no previous release could have stored a refresh token for you, because the mechanism didn't exist yet. Once your current short-lived session expires, roughly an hour after updating to 9.0.3, the next automatic backup attempt will fail once, and TMS will show the same "Drive disconnected" indicator it already shows for any auth problem.</p>
<p>The fix is a single click on <strong>Connect</strong> in Options → Backup, same as reconnecting for any other reason. After that one-time reconnect, you get the new, reliable renewal path with no further action needed, indefinitely, no more surprise disconnects after a couple of backups.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-client-secret-what-we-got-wrong-and-the-fix">The client secret: what we got wrong, and the fix<a href="https://kb.marvellouscode.works/blog/tms903-drive-pkce-refresh-token#the-client-secret-what-we-got-wrong-and-the-fix" class="hash-link" aria-label="Direct link to The client secret: what we got wrong, and the fix" title="Direct link to The client secret: what we got wrong, and the fix" translate="no">​</a></h2>
<p>An earlier draft of this post described shipping the OAuth client secret inside the extension package as a "known, accepted limitation", on the reasoning that a leak only lets a third party impersonate the app for a phishing consent screen, not touch any user's actual Drive data. That framing undersold the real risk.</p>
<p>The OAuth client TMS uses for this flow is registered as a "Web application" type, which by Google's own policy is expected to keep its client secret confidential, held server-side, never exposed. TMS has no server, so the secret was compiled straight into the extension package, and since a Chrome extension's <code>.crx</code>/<code>.zip</code> is trivially unpacked by anyone, it was effectively public the moment it shipped. The part we underweighted: this isn't just a phishing-blast-radius question, it's a policy compliance problem. Google can flag or suspend an OAuth client that doesn't meet its confidentiality expectations for its registered type, and that would break Drive backup for <em>every</em> TMS user at once, not just enable a narrow impersonation scenario.</p>
<p>We looked again at the client types Google exempts from this requirement, ones built for installed applications, like Chrome extensions, Desktop apps, iOS, and Android. Neither fits here: a "Chrome app" client only works with <code>chrome.identity.getAuthToken()</code>, the exact API that doesn't work on Brave and Vivaldi and is the whole reason this fallback exists, and a "Desktop app" client rejects the redirect URL format this flow has to use, confirmed directly against the live endpoint. So instead of swapping client types, we removed the need for the secret to be embedded at all.</p>
<p><strong><a href="https://github.com/Marvellous-Codeworks/tms-oauth-proxy" target="_blank" rel="noopener noreferrer" class=""><code>tms-oauth-proxy</code></a></strong> is a small Cloudflare Worker, free tier (at least for now), that holds the client secret server-side and does nothing but forward the token exchange to Google: the initial authorization-code grant, and every refresh_token renewal after that. TMS's own code never has the secret at all anymore, <code>gsBackup.js</code> calls the worker instead of Google's token endpoint directly. The worker sees only the exchange request itself (a code or a refresh token, nothing else) and never touches your Drive data, your access token, or anything else, those stay entirely in your own browser's storage as before. As part of shipping this, the previously-exposed secret was rotated in Google Cloud Console, so the earlier one is dead regardless.</p>
<p>This closes the gap the original "known, accepted limitation" note left open, cleanly, for zero added cost, rather than leaving it as a documented tradeoff.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-this-leaves-things">Where this leaves things<a href="https://kb.marvellouscode.works/blog/tms903-drive-pkce-refresh-token#where-this-leaves-things" class="hash-link" aria-label="Direct link to Where this leaves things" title="Direct link to Where this leaves things" translate="no">​</a></h2>
<p>If you're on Chrome, none of this affects you, <code>chrome.identity.getAuthToken()</code> already works there and this fallback never activates. If you're on Brave or Vivaldi and use Drive backup, this closes the gap that made 9.0.2's fix incomplete: one connection, one long-lived token, no more silent disconnects a couple of backups in.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Both pieces of this work are merged (<a href="https://github.com/gioxx/MarvellousSuspender/pull/440" target="_blank" rel="noopener noreferrer" class="">pull request #440</a> for the PKCE fallback, <a href="https://github.com/gioxx/MarvellousSuspender/pull/476" target="_blank" rel="noopener noreferrer" class="">pull request #476</a> for the <code>tms-oauth-proxy</code> move) and included in <strong>TMS 9.0.3</strong>, live on the Chrome Web Store. See the <a class="" href="https://kb.marvellouscode.works/blog/tms-release-9-0-3">9.0.3 release post</a> for the full picture.</p></div></div>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Bug</category>
        </item>
        <item>
            <title><![CDATA[9.0.2 also brings back the classic The Great Suspender artwork, as an option]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-classic-tgs-artwork</link>
            <guid>https://kb.marvellouscode.works/blog/tms-classic-tgs-artwork</guid>
            <pubDate>Sun, 09 Aug 2026 14:21:00 GMT</pubDate>
            <description><![CDATA[A new checkbox in Options → General lets you swap TMS's current mascot and icon set back to the original The Great Suspender artwork, app-wide.]]></description>
            <content:encoded><![CDATA[<p>The new mascot and icon set that shipped with TMS 9 has not landed well with everyone, <a class="" href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#the-generative-image-backlash">some of the feedback on 9.0.2 made that clear</a>. While that discussion continues, 9.0.2 also ships a direct, no-strings-attached answer for anyone who just wants the old look back: a checkbox.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-the-classic-the-great-suspender-artwork">Use the classic The Great Suspender artwork<a href="https://kb.marvellouscode.works/blog/tms-classic-tgs-artwork#use-the-classic-the-great-suspender-artwork" class="hash-link" aria-label="Direct link to Use the classic The Great Suspender artwork" title="Direct link to Use the classic The Great Suspender artwork" translate="no">​</a></h2>
<p>A new option in <strong>Options → General</strong>, "Use the classic The Great Suspender artwork instead of the new mascot", switches TMS's icons and illustrations back to the original The Great Suspender style, the artwork the project was originally built on, wherever a legacy version of the image exists.</p>
<p><img decoding="async" loading="lazy" alt="TMS Options page, General section, with the &amp;quot;Use the classic The Great Suspender artwork&amp;quot; checkbox enabled and the legacy suspendy mascot shown in the welcome panel" src="https://kb.marvellouscode.works/assets/images/tms-classic-tgs-artwork-options-00ac6ad1903c59ec12453a6c0f2a5378.webp" width="2994" height="1722" class="img_ev3q"></p>
<p>It is applied consistently, not just in one corner of the UI: the toolbar icon, the suspended-tab page's favicon fallback, and every extension page's own images and favicon all switch together, resolved through a single mapping so there is no mix-and-match between old and new art on different screens. A couple of illustrations that never existed in the original set (used for less common states) have no legacy equivalent, those keep using the new artwork regardless of the toggle.</p>
<p>Off by default, on-demand, reversible any time. No data migration, no restart required.</p>
<p>Full reference in the <a class="" href="https://kb.marvellouscode.works/docs/TMS/pages/settings#use-the-classic-the-great-suspender-artwork">Settings docs</a>.</p>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Release</category>
            <category>Feature</category>
        </item>
        <item>
            <title><![CDATA[The Marvellous Suspender 9.0.2 - Always-suspend list, Drive OAuth fallback, favicon fix]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-release-9-0-2</link>
            <guid>https://kb.marvellouscode.works/blog/tms-release-9-0-2</guid>
            <pubDate>Wed, 05 Aug 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[9.0.2 ships a new always-suspend list, a Google Drive OAuth fallback for Brave and Vivaldi, and a favicon fix, plus a full triage of the issue tracker and a concrete look at what's next.]]></description>
            <content:encoded><![CDATA[<p>TMS 9.0.2 is ready: one new list-based feature and a handful of confirmed bug fixes. It'll be submitted for Chrome Web Store review in a few days, not today, I'm taking a short break first for family time and some mental rest, so bear with the wait. The bigger news is behind the scenes anyway: every open issue on the tracker got triaged into an actual plan.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-new">What's new<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#whats-new" class="hash-link" aria-label="Direct link to What's new" title="Direct link to What's new" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="always-suspend-list">"Always suspend" list<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#always-suspend-list" class="hash-link" aria-label="Direct link to &quot;Always suspend&quot; list" title="Direct link to &quot;Always suspend&quot; list" translate="no">​</a></h3>
<p>A new list, right next to the whitelist in Settings, of URLs that always suspend after the normal timeout, even past the protections (pinned, audible, unsaved form input) that would otherwise keep a tab open indefinitely. Useful for something like a background Twitch or YouTube tab left playing audio that you still want suspended on schedule. Same matching rules as the whitelist (plain text or <code>/regex/</code>). Manual per-tab pauses and global protections (offline, charging, "never suspend") are still respected, this only overrides the passive automatic ones.</p>
<p>Named "always suspend" rather than "blacklist" to avoid the polarity confusion raised in the original request (<a href="https://github.com/gioxx/MarvellousSuspender/issues/103" target="_blank" rel="noopener noreferrer" class="">#103</a>). It also picked up its own <strong>"Test list"</strong> and <strong>"Suspend matching tabs now"</strong> buttons, mirroring the whitelist's existing test/wake pair, so you can check what matches or force an immediate suspend instead of waiting for the normal timeout.</p>
<p>Speaking of the whitelist: it's now called the <strong>allowlist</strong> everywhere in the UI (tooltips, popup, all 18 locales). Storage key and internal code are untouched, this was a copy pass, not a rename of the feature.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-fixed">What's fixed<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#whats-fixed" class="hash-link" aria-label="Direct link to What's fixed" title="Direct link to What's fixed" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="google-drive-connect-account-on-brave-and-vivaldi">Google Drive "Connect account" on Brave and Vivaldi<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#google-drive-connect-account-on-brave-and-vivaldi" class="hash-link" aria-label="Direct link to Google Drive &quot;Connect account&quot; on Brave and Vivaldi" title="Direct link to Google Drive &quot;Connect account&quot; on Brave and Vivaldi" translate="no">​</a></h3>
<p><code>chrome.identity.getAuthToken()</code> doesn't work on either browser, for different reasons: Brave attaches a custom URI scheme Google's backend rejects outright and shows a raw <code>Error 400: invalid_request</code> page; Vivaldi disables Google sign-in entirely, so the callback just never fires and the connect flow hangs with no feedback. TMS now falls back to <code>chrome.identity.launchWebAuthFlow()</code>, races the original method against a timeout so a Vivaldi-style hang surfaces as a failure instead of hanging forever, and remembers which method worked per install so later calls skip straight to it (<a href="https://github.com/gioxx/MarvellousSuspender/issues/420" target="_blank" rel="noopener noreferrer" class="">#420</a>).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="suspended-tabs-stuck-with-the-default-favicon-after-a-restart">Suspended tabs stuck with the default favicon after a restart<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#suspended-tabs-stuck-with-the-default-favicon-after-a-restart" class="hash-link" aria-label="Direct link to Suspended tabs stuck with the default favicon after a restart" title="Direct link to Suspended tabs stuck with the default favicon after a restart" translate="no">​</a></h3>
<p>The startup check that repairs favicons and titles only ran from events some Chromium builds (notably Brave) never fire after a normal restart, leaving suspended tabs stuck with the generic icon until clicked. A storage-based sentinel now catches this on every service worker wake instead (<a href="https://github.com/gioxx/MarvellousSuspender/issues/397" target="_blank" rel="noopener noreferrer" class="">#397</a>). Thanks to @pbc-commits for the investigation and root-cause writeup.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="allow-access-to-file-urls-toggle-missing">"Allow access to file URLs" toggle missing<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#allow-access-to-file-urls-toggle-missing" class="hash-link" aria-label="Direct link to &quot;Allow access to file URLs&quot; toggle missing" title="Direct link to &quot;Allow access to file URLs&quot; toggle missing" translate="no">​</a></h3>
<p>Chrome only shows this toggle when the manifest declares <code>file://</code> host access, which TMS never did. Added as an optional host permission, on-demand like <code>downloads</code>/<code>identity</code>, no access granted until you flip it yourself (<a href="https://github.com/gioxx/MarvellousSuspender/issues/393" target="_blank" rel="noopener noreferrer" class="">#393</a>, <a href="https://github.com/gioxx/MarvellousSuspender/issues/416" target="_blank" rel="noopener noreferrer" class="">#416</a>, <a href="https://github.com/gioxx/MarvellousSuspender/issues/267" target="_blank" rel="noopener noreferrer" class="">#267</a>).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="suspended-page-waited-on-the-hotkey-label-before-becoming-clickable">Suspended page waited on the hotkey label before becoming clickable<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#suspended-page-waited-on-the-hotkey-label-before-becoming-clickable" class="hash-link" aria-label="Direct link to Suspended page waited on the hotkey label before becoming clickable" title="Direct link to Suspended page waited on the hotkey label before becoming clickable" translate="no">​</a></h3>
<p>Restoring a suspended tab was gated behind a <code>chrome.commands.getAll()</code> call to fetch the shortcut-key label for display, purely cosmetic, but slow enough to make the click handler feel unresponsive. The page now becomes interactive first and fills in the hotkey label after (<a href="https://github.com/gioxx/MarvellousSuspender/issues/320" target="_blank" rel="noopener noreferrer" class="">#320</a>).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="claim-by-default-option">"Claim by default" option<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#claim-by-default-option" class="hash-link" aria-label="Direct link to &quot;Claim by default&quot; option" title="Direct link to &quot;Claim by default&quot; option" translate="no">​</a></h3>
<p>Shortened the option label and moved its explanation into a tooltip instead of a long parenthetical (<a href="https://github.com/gioxx/MarvellousSuspender/issues/151" target="_blank" rel="noopener noreferrer" class="">#151</a>), then reworded again after that first pass still left it meaningless without opening the tooltip: it's now "Claim tabs suspended by other extensions", says what it does without requiring a hover.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="manual-backup-cooldown-had-a-hole-in-it">Manual backup cooldown had a hole in it<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#manual-backup-cooldown-had-a-hole-in-it" class="hash-link" aria-label="Direct link to Manual backup cooldown had a hole in it" title="Direct link to Manual backup cooldown had a hole in it" translate="no">​</a></h3>
<p>The 30-second cooldown after a manual "Backup now" was only ever enforced as a per-page debounce local to the Backup page's own button. The popup has its own "Backup now" menu item, with no cooldown and no shared state with the page, so triggering from both let you fire off backups back-to-back. The cooldown now lives in <code>gsBackup.performManualBackup()</code> itself, tracked in session storage so it's enforced no matter which UI triggers it; the popup shows a live countdown and disables the item if a cooldown from the other surface is already running.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="always-suspend-list-showing-a-literal-undefined">"Always suspend" list showing a literal "undefined"<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#always-suspend-list-showing-a-literal-undefined" class="hash-link" aria-label="Direct link to &quot;Always suspend&quot; list showing a literal &quot;undefined&quot;" title="Direct link to &quot;Always suspend&quot; list showing a literal &quot;undefined&quot;" translate="no">​</a></h3>
<p>Ironic given this ships in the same release that introduced the list: upgrading from an install that predates it left the textarea showing the literal word "undefined" instead of being empty, because settings only got backfilled with new defaults on a brand-new install, not on existing ones. Settings now backfill any missing keys on every load, not just first run.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="locale-drift-closed">Locale drift closed<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#locale-drift-closed" class="hash-link" aria-label="Direct link to Locale drift closed" title="Direct link to Locale drift closed" translate="no">​</a></h3>
<p>A source-string edit had quietly broken Crowdin's fuzzy match on 7 strings, reverting them to English across all 16 non-English/Italian locales, on top of a handful of genuinely new keys. Both are fixed and locales are back in sync. Added <code>scripts/check-locales.js</code> (<code>npm run check-locales</code>) so this kind of drift is caught locally before it ships, not the fix itself, but worth having.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="also-in-this-release">Also in this release<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#also-in-this-release" class="hash-link" aria-label="Direct link to Also in this release" title="Direct link to Also in this release" translate="no">​</a></h2>
<p>A handful of smaller things that don't need their own section:</p>
<ul>
<li class=""><strong>Bulk-delete Drive backups per device.</strong> The Backup page already grouped Drive files by device when more than one machine backs up to the same account, but clearing out one device's files meant deleting them one by one. A "Delete all" button next to each device's group heading now handles it in one go, with the same confirm-before-delete modal as single-file deletes.</li>
<li class=""><strong>Extension description reworded</strong> to match the tone used everywhere else TMS is described: "Free your memory. Suspend the tabs you don't need, right now."</li>
<li class=""><strong>The Backup page now shows which Drive OAuth method is active</strong> for the install (<code>getAuthToken</code> vs. the <code>launchWebAuthFlow</code> fallback from above), as a quiet second line under the "TMS Backups" folder name, mainly useful for support.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-bigger-job-triaging-the-whole-backlog">The bigger job: triaging the whole backlog<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#the-bigger-job-triaging-the-whole-backlog" class="hash-link" aria-label="Direct link to The bigger job: triaging the whole backlog" title="Direct link to The bigger job: triaging the whole backlog" translate="no">​</a></h2>
<p>9.0.2 was the small part of today's work. The real effort went into going through <strong>every open issue on the tracker</strong>, 56 of them, most untouched for months, and sorting each one into an actual plan instead of a flat list.</p>
<p>The outcome: 31 issues now sit in a concrete milestone (9.0.2, 9.0.3, 9.1.0, 9.2.0, or 10.0.0), scoped by what they actually need, a quick fix, a real feature, or a design spike, rather than by how old they are. The remaining 25 are genuinely unclear: duplicates to merge, reports that need reproduction steps, or requests that need a decision before they can be scoped at all, and they'll get worked through the same way.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-other-side-of-a-release-reviews-and-inbox">The other side of a release: reviews and inbox<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#the-other-side-of-a-release-reviews-and-inbox" class="hash-link" aria-label="Direct link to The other side of a release: reviews and inbox" title="Direct link to The other side of a release: reviews and inbox" translate="no">​</a></h2>
<p>Version 9 and its two bugfix releases were rolled out alongside a redesign, changes to permissions, and a new backup feature, and the reviews posted since then on the Chrome Web Store have made it clear that there are a lot of new features to take in all at once in a single update—and, to be honest, we were somewhat expecting this, though perhaps we hadn't factored in the "<em>unwarranted hostility</em>" that is often part of the game in the open-source world (and this is certainly no excuse, because respect, empathy, and tact always come first). It's worth examining them carefully, rather than simply highlighting only the positive aspects (which, fortunately, are there as well).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-does-it-need-all-these-permissions-now">"Why does it need all these permissions now?"<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#why-does-it-need-all-these-permissions-now" class="hash-link" aria-label="Direct link to &quot;Why does it need all these permissions now?&quot;" title="Direct link to &quot;Why does it need all these permissions now?&quot;" translate="no">​</a></h3>
<p>This was the loudest thread, a run of 1-star reviews within hours of each other listing the new permission prompt verbatim: <em>"Read and change all your data on all websites," "Read and change your browsing history on all your signed-in devices," "Manage your downloads," "View and manage your tab groups"</em>. Read cold, with no context, that's a reasonable thing to be alarmed by. One reviewer put it plainly:</p>
<blockquote>
<p>"Now, the app itself is wonderful, but I am fearful about saying yes to so many permissions. [...] Message to the Devs: please provide an explanatory blog post on why you need so many permissions. I will happily update this to 5* if the reasons are convincing".</p>
</blockquote>
<p>The post already exists, <a class="" href="https://kb.marvellouscode.works/blog/tms9-public-permissions-faq">the 9.0 permissions FAQ</a>, and explains each permission against the feature that needs it (<code>downloads</code> for local backup, <code>identity</code> for Drive backup, the broad host permissions for the scripting-based form/scroll detection that predates 9.0). The problem is it was never linked from the Chrome Web Store update notes, so nobody hit it unless they went looking, and one reviewer said as much (<em>"Looks like all the permissions are legitimate. But in the update notice, I didn't see this link"</em>). That's on us, not on the reviewers: the explanation being technically correct and effectively invisible is the same as not having written it. The CWS listing will link it directly going forward.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-generative-image-backlash">The generative-image backlash<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#the-generative-image-backlash" class="hash-link" aria-label="Direct link to The generative-image backlash" title="Direct link to The generative-image backlash" translate="no">​</a></h3>
<p>The new suspended-tab illustration set uses AI-generated art, and the reaction has been unambiguous and consistent, from a 1-star review (<em>"So now I am forced to see garbage genAI images on every suspended tab?"</em>), to a Chinese-language review calling the new icon 丑爆了 (bluntly, "hideously ugly"), to a calm, direct email from a long-time user asking us to either revert to the old artwork or commission an actual illustrator, because shipping AI art "will make it appear cheap and rushed to the users who don't see all the code and scripts you designed for it". That last framing is the one worth sitting with: it's not really about the pixels, it's about what the choice signals for a project that otherwise puts real engineering effort into every release. This is going back into discussion, no decision made here, but the signal is too consistent across independent channels to wave off as noise.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Can you draw better than an AI?</div><div class="admonitionContent_BuS1"><p>If you're reading this and use Photoshop (or any other graphics program, it doesn't matter) every day for a living, why not give us a hand? Neither of us is an illustrator, but we needed to give TMS's graphics a fresh look, so we set out to design a mascot that would be visually appealing. We worked on it with the help of AI and came up with a result we hoped you'd like.</p><p>If you think you can do better, please contact us! Send an email to <a href="mailto:gioxx@marvellouscode.works" target="_blank" rel="noopener noreferrer" class="">gioxx@marvellouscode.works</a> and let's talk about it :-)</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="stop-changing-the-ui">"Stop changing the UI"<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#stop-changing-the-ui" class="hash-link" aria-label="Direct link to &quot;Stop changing the UI&quot;" title="Direct link to &quot;Stop changing the UI&quot;" translate="no">​</a></h3>
<p>A smaller but genuine thread: the redesign changed the suspended-tab screen and, more concretely, removed a state cue some users relied on daily, the toolbar icon used to visibly change when a tab was paused from suspension, now you have to click it to check. One review called this out at length, and re-submitted the same text three times over two days, which reads less like spam and more like someone who really wanted it seen. That one is a legitimate regression report, not a taste complaint, and it's going on the backlog to fix, not just to note.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="real-bugs-found-in-the-noise">Real bugs found in the noise<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#real-bugs-found-in-the-noise" class="hash-link" aria-label="Direct link to Real bugs found in the noise" title="Direct link to Real bugs found in the noise" translate="no">​</a></h3>
<p>Sorting the sharp tone from the substance, three reports didn't match anything already tracked and got opened as issues today:</p>
<ul>
<li class=""><strong><a href="https://github.com/gioxx/MarvellousSuspender/issues/426" target="_blank" rel="noopener noreferrer" class="">#426</a></strong>: a user reported the extension's settings page and keyboard shortcuts becoming unavailable entirely after updating, no repro yet, but too specific to dismiss.</li>
<li class=""><strong><a href="https://github.com/gioxx/MarvellousSuspender/issues/427" target="_blank" rel="noopener noreferrer" class="">#427</a></strong>: automatic local backup apparently writing outside the configured <code>tms-backups</code> folder, with filenames drifting to Chrome's own <code>download.json</code>, <code>download.json (1)</code>, <code>(2)</code>... pattern and the configured file-count limit being ignored.</li>
<li class=""><strong><a href="https://github.com/gioxx/MarvellousSuspender/issues/428" target="_blank" rel="noopener noreferrer" class="">#428</a></strong>: a report that recent updates broke Gmail's own delete/move actions, symptoms that don't persist until a manual refresh. Needs isolating, but too precise a description to be a red herring.</li>
</ul>
<p>A fourth pattern, suspended tabs vanishing without a trace after a crash, showed up again in this batch too, but that one's not new: it matches <a href="https://github.com/gioxx/MarvellousSuspender/issues/396" target="_blank" rel="noopener noreferrer" class="">#396</a> and <a href="https://github.com/gioxx/MarvellousSuspender/issues/402" target="_blank" rel="noopener noreferrer" class="">#402</a>, already on the board.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="on-the-tone">On the tone<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#on-the-tone" class="hash-link" aria-label="Direct link to On the tone" title="Direct link to On the tone" translate="no">​</a></h3>
<p>Some of these criticisms were quite harsh. "Shameful", "crazy", "a terrible, truly terrible change", it's really a lot to read all at once, and a couple of reviews were clearly emotional outbursts rather than concrete reports. That's fine; that's what the reviews section is for, and it doesn't change how the actual bugs mentioned above are handled. But it's also worth stating clearly that the never-out-of-style tactic of posting a barrage of very negative reviews immediately after a release that simultaneously changed permissions, graphics, and the user interface is, in itself, a sign: bundling so many visible changes into a single update has made it much harder for anyone to distinguish at first glance between "this is a real problem" and "this is different, and I don't like the difference".<br>
<!-- -->Change is always <em>scary</em>. This is a lesson on the order of changes to keep in mind for future updates, as well as for this specific case.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="comments-are-now-open-on-the-kb">Comments are now open on the KB<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#comments-are-now-open-on-the-kb" class="hash-link" aria-label="Direct link to Comments are now open on the KB" title="Direct link to Comments are now open on the KB" translate="no">​</a></h2>
<p>Speaking of feedback: every post on the Marvellous Codeworks KB, this one included, now has a comment section right at the bottom. No Chrome Web Store review box, no GitHub account required. If you've got a bug report, a question, or an opinion on any of the above, that's the place for it now, we'll be reading.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next-concretely">What's next, concretely<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-2#whats-next-concretely" class="hash-link" aria-label="Direct link to What's next, concretely" title="Direct link to What's next, concretely" translate="no">​</a></h2>
<ul>
<li class=""><strong>9.0.3</strong>: right after this release, already-scoped quick wins, default branch rename (<code>master</code> to <code>main</code>), a favicon-cleanup follow-up, a handful of small long-standing UX requests, plus one item needing a feasibility spike before work starts, a battery/charging-aware suspend timeout.</li>
<li class=""><strong>9.1.0</strong>: platform reach, an Edge Add-ons Store listing and Group Policy support for managed deployments, plus standalone improvements: a pause button, staggered session restore (so restoring 40 tabs at once doesn't hammer the browser), and a rework of the YouTube screenshot capture path.</li>
<li class=""><strong>9.2.0</strong>: a Session Manager rework, collapsing/reordering windows, deleting a single window without touching the rest, bulk export, plus lifecycle settings like auto-unsuspend on restart, auto-cleanup of old sessions, and an option to disable session tracking entirely.</li>
<li class=""><strong>10.0.0</strong>: no near-term date, this is where larger architecture-level changes land, per-tab-group settings is the first candidate.</li>
</ul>
<p>None of this is set in stone, milestones will keep shifting as issues get re-scoped, but there's now an actual sequence instead of one long undifferentiated backlog.</p>
<p>I wish you all the best on your journey.</p>
<p><em>Giovanni</em></p>
<hr>
<p><em>Full changelog on GitHub: <a href="https://github.com/gioxx/MarvellousSuspender/releases/tag/v9.0.2" target="_blank" rel="noopener noreferrer" class="">v9.0.2 release</a></em></p>]]></content:encoded>
            <category>Release</category>
            <category>The Marvellous Suspender</category>
        </item>
        <item>
            <title><![CDATA[The Marvellous Suspender 9.0.1: on-demand permissions, and closing the gaps from 9.0.0]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-release-9-0-1</link>
            <guid>https://kb.marvellouscode.works/blog/tms-release-9-0-1</guid>
            <pubDate>Tue, 04 Aug 2026 12:00:00 GMT</pubDate>
            <description><![CDATA[9.0.1 delivers on what we promised in the permissions FAQ post: downloads and identity are now requested on demand instead of upfront, the news feed has an opt-out, and the Drive-only local file mystery is explained right on the page.]]></description>
            <content:encoded><![CDATA[<p>We said it was coming in <a class="" href="https://kb.marvellouscode.works/blog/tms9-public-permissions-faq">the last post</a>, and it's here. 9.0.1 is a direct response to <a href="https://github.com/gioxx/MarvellousSuspender/issues/411" target="_blank" rel="noopener noreferrer" class="">issue #411</a> and everything we admitted needed fixing there: permissions requested too early, missing opt-outs, and a couple of things that were working as intended but never explained anywhere.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="permissions-are-now-on-demand-not-upfront">Permissions are now on demand, not upfront<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-1#permissions-are-now-on-demand-not-upfront" class="hash-link" aria-label="Direct link to Permissions are now on demand, not upfront" title="Direct link to Permissions are now on demand, not upfront" translate="no">​</a></h2>
<p>This is the headline change. In 9.0.0, <code>downloads</code> and <code>identity</code> were declared as regular permissions, so Chrome asked for both the moment you updated, whether or not you ever touched the backup feature. That's exactly what triggered the disable-and-reprompt dialog most of you saw, and exactly what <a href="https://github.com/gioxx/MarvellousSuspender/issues/411" target="_blank" rel="noopener noreferrer" class="">issue #411</a> called out as "substantially overprivileged for users who do not use backups."</p>
<p>Starting with 9.0.1:</p>
<ul>
<li class=""><strong><code>downloads</code></strong> is only requested the moment you toggle <strong>Enable automatic backup</strong> on, in <a class="" href="https://kb.marvellouscode.works/docs/TMS/pages/backup-sync">Backup &amp; Sync</a>. Leave it off, and TMS never asks.</li>
<li class=""><strong><code>identity</code></strong> is only requested when you click <strong>Connect</strong> to link a Google account for Drive backup. Never click it, and TMS never asks.</li>
</ul>
<p>If you already had backup enabled under 9.0.0, you won't see anything new, Chrome keeps permissions you already granted when a later update moves them from required to optional. No re-prompt, nothing to redo.</p>
<p>Full breakdown on the <a class="" href="https://kb.marvellouscode.works/docs/TMS/permissions#what-changed-in-9x">permissions page</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-quieter-way-to-be-reminded-backup-exists">A quieter way to be reminded backup exists<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-1#a-quieter-way-to-be-reminded-backup-exists" class="hash-link" aria-label="Direct link to A quieter way to be reminded backup exists" title="Direct link to A quieter way to be reminded backup exists" translate="no">​</a></h2>
<p>Session backup is still, by a wide margin, the most requested feature TMS has ever shipped, and the vast majority of you haven't turned it on yet. Rather than push harder, 9.0.1 adds a deliberately low-key nudge: a small amber badge on the toolbar icon, a banner in the popup, and a note on the Backup &amp; Sync page, all pointing at the same place, all easy to dismiss.</p>
<p><strong>Remind me in 10 days</strong> snoozes it. A permanent <strong>I'm not interested, stop reminding me</strong> checkbox on the Backup &amp; Sync page turns it off entirely. No pop-ups, no repeated interruptions, just a quiet signal that stays out of your way once you've told it to.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="news-feed-opt-out">News feed opt-out<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-1#news-feed-opt-out" class="hash-link" aria-label="Direct link to News feed opt-out" title="Direct link to News feed opt-out" translate="no">​</a></h2>
<p>The daily background check against <code>marvellouscode.works</code> for TMS-related posts (feeding the in-extension News page) had no way to turn off. It does now: <strong>Enable news feed</strong> in Settings → General, on by default. Turn it off and the fetch alarm is cleared immediately, along with the <strong>News</strong> entry in the sidebar.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-drive-only-local-file-explained">The Drive-only local file, explained<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-1#the-drive-only-local-file-explained" class="hash-link" aria-label="Direct link to The Drive-only local file, explained" title="Direct link to The Drive-only local file, explained" translate="no">​</a></h2>
<p>If your backup destination is Google Drive but you still occasionally see a file appear in your Downloads folder, that's not a bug. On browser shutdown, TMS always writes a local safety-net copy first, a Drive upload isn't reliable in that narrow shutdown window, so the file gets queued and uploaded on the next startup instead, then cleaned up automatically once that upload succeeds. This was true since 9.0.0 but never explained anywhere in the UI, <a href="https://github.com/gioxx/MarvellousSuspender/issues/411" target="_blank" rel="noopener noreferrer" class="">issue #411</a> was right to flag it. It's now spelled out directly on the Backup &amp; Sync page.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="in-app-permissions-transparency">In-app permissions transparency<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-1#in-app-permissions-transparency" class="hash-link" aria-label="Direct link to In-app permissions transparency" title="Direct link to In-app permissions transparency" translate="no">​</a></h2>
<p>Two smaller, related additions: a one-time banner on the Settings and Backup &amp; Sync pages explaining the permissions change above (with a link to the docs), and a persistent reference note on the Backup &amp; Sync page for anyone who lands there later and wants the short version without digging through a blog archive. Going forward, this is where permission changes get explained, not just here.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-were-not-doing">What we're not doing<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-1#what-were-not-doing" class="hash-link" aria-label="Direct link to What we're not doing" title="Direct link to What we're not doing" translate="no">​</a></h2>
<p>Backup content encryption came up as a suggestion in issue #411 too. We're not adding it, not in 9.0.1 and not planning to. Backup files carry the same level of protection the manual "Export session" feature has had since 2017 (plain JSON, no encryption), nothing on your machine or your own Drive <code>appdata</code> folder is exposed to anyone else by that choice, and we'd rather keep the feature simple than bolt on a passphrase system nobody asked for twice.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="thanks">Thanks<a href="https://kb.marvellouscode.works/blog/tms-release-9-0-1#thanks" class="hash-link" aria-label="Direct link to Thanks" title="Direct link to Thanks" translate="no">​</a></h2>
<p>To everyone who pushed back on 9.0.0's permission model instead of just uninstalling and moving on: this release exists because you took the time to write it up instead. That's the whole reason <a href="https://github.com/gioxx/MarvellousSuspender/issues/411" target="_blank" rel="noopener noreferrer" class="">issue #411</a> got a direct answer instead of a shrug, and it's why the fix landed this fast.</p>
<p>If something's still off, <a href="https://github.com/gioxx/MarvellousSuspender/issues" target="_blank" rel="noopener noreferrer" class="">open an issue</a> or use the <a href="https://marvellouscode.works/tms/report" target="_blank" rel="noopener noreferrer" class="">report form</a>. We read all of it.</p>
<hr>
<p><em>Full changelog on GitHub: <a href="https://github.com/gioxx/MarvellousSuspender/releases/tag/v9.0.1" target="_blank" rel="noopener noreferrer" class="">v9.0.1 release</a></em></p>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Release</category>
            <category>Announcement</category>
        </item>
        <item>
            <title><![CDATA[TMS 9 is public now: about that permissions dialog, and where your sessions went]]></title>
            <link>https://kb.marvellouscode.works/blog/tms9-public-permissions-faq</link>
            <guid>https://kb.marvellouscode.works/blog/tms9-public-permissions-faq</guid>
            <pubDate>Mon, 03 Aug 2026 20:30:00 GMT</pubDate>
            <description><![CDATA[TMS 9 has finished rolling out to everyone. Some of you hit a scary re-enable dialog, some raised sharp technical questions about backup permissions, some lost sessions to an unrelated Chrome bug. Here's what's actually going on, and what's landing in 9.0.1.]]></description>
            <content:encoded><![CDATA[<p>TMS 9 has now reached everyone on the Chrome Web Store's normal rollout schedule. Good news, mostly. But an update this size doesn't land quietly, and a few things landed in our inbox that deserve a direct answer instead of a buried reply in a GitHub thread.</p>
<!-- -->
<img src="https://kb.marvellouscode.works/assets/images/permissions-reenable-dialog-c1d30d460e4d39a43c1921a81ad360d9.png" alt="Chrome dialog: 'The newest version of The Marvellous Suspender has been disabled because it requires more permissions', listing read/change data on all websites, read/change browsing history, manage downloads, view and manage tab groups, with Re-enable and Cancel buttons" style="max-width:420px">
<p>If you saw this dialog, Chrome disabled TMS on update and is asking you to confirm the new permissions before turning it back on. That's expected, and it's Chrome doing its job. Here's why each one is there, and what to do if you'd rather not grant all of them.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-the-new-permissions">Why the new permissions<a href="https://kb.marvellouscode.works/blog/tms9-public-permissions-faq#why-the-new-permissions" class="hash-link" aria-label="Direct link to Why the new permissions" title="Direct link to Why the new permissions" translate="no">​</a></h2>
<p>Two of the permissions listed, <code>downloads</code> and <code>identity</code>, are new in 9.x. Both exist for exactly one feature: <strong>session backup</strong>, the single most requested thing in TMS's entire history, now finally shipped, either to a local folder or to your own Google Drive.</p>
<ul>
<li class=""><strong><code>downloads</code></strong> lets TMS write backup files to a <code>tms-backups/</code> folder inside your Downloads, and clean up old ones automatically. TMS never reads anything in your Downloads folder beyond the files it wrote itself.</li>
<li class=""><strong><code>identity</code></strong> is used only if you choose Google Drive as your backup destination. It gets an OAuth token to talk to Drive, TMS never sees your Google password, and the token exchange is handled entirely by Chrome.</li>
<li class="">The Drive backup, if enabled, is scoped to <code>drive.appdata</code>, a hidden, app-only folder that isn't visible in your regular Drive and isn't reachable by any other app.</li>
</ul>
<p>Full breakdown, including exactly what changed since 8.x, is on the <a class="" href="https://kb.marvellouscode.works/docs/TMS/permissions#what-changed-in-9x">permissions page</a>.</p>
<p><strong>The important part: both permissions sit dormant until you actually turn on automatic backups in Backup &amp; Sync.</strong> If you never enable that feature, TMS requests no Drive authentication and writes nothing to Downloads. We're aware that Chrome asks for the permission up front regardless, at install/update time, not at first use, which is exactly the kind of thing that reads as scarier than it is. We hear that, and we're working on a setting to opt out of backups and their reminders entirely, which should let us drop these permissions for anyone who doesn't want the feature. That's not shipped yet, it's actively in progress, and we'll cover it here once it lands.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-deeper-questions-and-whats-landing-in-901">The deeper questions, and what's landing in 9.0.1<a href="https://kb.marvellouscode.works/blog/tms9-public-permissions-faq#the-deeper-questions-and-whats-landing-in-901" class="hash-link" aria-label="Direct link to The deeper questions, and what's landing in 9.0.1" title="Direct link to The deeper questions, and what's landing in 9.0.1" translate="no">​</a></h2>
<p><a href="https://github.com/gioxx/MarvellousSuspender/issues/411" target="_blank" rel="noopener noreferrer" class="">Issue #411</a> went further than "why the new permissions," with some sharper technical points worth answering here too, not just in a GitHub thread:</p>
<ul>
<li class=""><strong><code>downloads</code> is requested unconditionally, even if you never enable local backup.</strong> Fair. It's a static manifest permission right now instead of one requested at runtime when you actually turn on local auto-backup. Moving it to on-demand is going into 9.0.1, so most people who don't use backups won't see this prompt at all.</li>
<li class=""><strong>Backup files are plain JSON, and base64 isn't encryption.</strong> Correct, base64 there only builds a <code>data:</code> URL so a service worker can hand the file to <code>chrome.downloads.download()</code> (blob URLs don't survive service worker restarts), it was never meant as protection. Worth noting: it's the same level of protection the manual "Export session" feature has had since 2017, so this isn't a new risk 9.0.0 introduced. Optional passphrase encryption for backup content is a reasonable ask and it's on the list.</li>
<li class=""><strong>A Drive-only configuration can still write a local file.</strong> Also correct. On browser shutdown, TMS runs an emergency backup that always writes locally first, because a Drive upload in that shutdown window isn't reliable, the service worker can get killed mid-request. If your destination is Drive, that file gets queued and uploaded on next startup. A deliberate reliability trade-off, but not currently explained anywhere in the UI. That's getting a note, plus cleanup of the local copy once the queued Drive upload succeeds.</li>
<li class=""><strong>A daily request to <code>kb.marvellouscode.works/blog/rss.xml</code>.</strong> Yes, an alarm every 24h feeding the sidebar News page. The host is already declared in the manifest, nothing hidden, but there's no way to turn it off today. A toggle is coming.</li>
</ul>
<p>One more thing worth admitting straight: the permissions page and the posts covering this were published before 9.0.0 went live, but nowhere the extension itself points to them. That's the actual gap, not the timing. Going forward, whenever a release changes permissions, the options page and changelog will link directly to what changed and why, instead of relying on people finding the blog on their own.</p>
<p>None of this changes what TMS does with your data today, nothing leaves your machine except to your own Drive <code>appdata</code> folder, but the scoping and the missing opt-outs were legitimate gaps, and 9.0.1 is where they get closed.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="it-requires-too-many-permissions-now-wtf">"It requires too many permissions now, wtf?"<a href="https://kb.marvellouscode.works/blog/tms9-public-permissions-faq#it-requires-too-many-permissions-now-wtf" class="hash-link" aria-label="Direct link to &quot;It requires too many permissions now, wtf?&quot;" title="Direct link to &quot;It requires too many permissions now, wtf?&quot;" translate="no">​</a></h2>
<img src="https://kb.marvellouscode.works/assets/images/review-3-stars-permissions-0f717504f365e9c183c70826f89c8dca.png" alt="Chrome Web Store review, 3 stars: 'It requires too many permissions now, wtf?'" style="max-width:460px">
<p>Fair reaction from the outside, and exactly why the section above exists. Short version: nothing new is silently collecting or shipping your data anywhere. <code>tabs</code>, <code>storage</code>, <code>history</code>, <code>contextMenus</code>, <code>alarms</code>, <code>favicon</code>, <code>scripting</code>, and <code>tabGroups</code> were all already there in 8.x, doing the same jobs they always did. <code>downloads</code> and <code>identity</code> are the two genuinely new ones, and they only exist because of the backup feature described above.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="major-updates-too-frequently-cause-suspended-web-pages-to-disappear-please-do-not-always-change-how-the-ui-looks">"Major updates too frequently cause suspended web pages to disappear. Please do not always change how the UI looks."<a href="https://kb.marvellouscode.works/blog/tms9-public-permissions-faq#major-updates-too-frequently-cause-suspended-web-pages-to-disappear-please-do-not-always-change-how-the-ui-looks" class="hash-link" aria-label="Direct link to &quot;Major updates too frequently cause suspended web pages to disappear. Please do not always change how the UI looks.&quot;" title="Direct link to &quot;Major updates too frequently cause suspended web pages to disappear. Please do not always change how the UI looks.&quot;" translate="no">​</a></h2>
<img src="https://kb.marvellouscode.works/assets/images/review-3-stars-major-updates-7dd07f66b5e3f81d124e0e80e99c1a68.png" alt="Chrome Web Store review, 3 stars: 'Major updates too frequently cause suspended web pages to disappear. Please do not always change how the UI looks. It takes time for users to get used to it before you change it again.'" style="max-width:460px">
<p>Two separate points here, and we want to be honest about both.</p>
<p>On the UI: yes, TMS 9 changed how every settings page looks. That was intentional and covered at length in <a class="" href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#not-everyone-will-love-it-and-thats-fine">the launch post</a>, it needed doing, but we know it's disruptive and we're not planning another full repaint anytime soon.</p>
<p>On suspended pages disappearing during updates: that one worries us more, because it shouldn't happen from a TMS update alone, and it's worth separating from a specific incident we're actively helping someone recover from right now.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-sessions-actually-vanish-its-usually-not-the-update-itself">When sessions actually vanish, it's usually not the update itself<a href="https://kb.marvellouscode.works/blog/tms9-public-permissions-faq#when-sessions-actually-vanish-its-usually-not-the-update-itself" class="hash-link" aria-label="Direct link to When sessions actually vanish, it's usually not the update itself" title="Direct link to When sessions actually vanish, it's usually not the update itself" translate="no">​</a></h2>
<p>We got a report of exactly this, sessions gone after an update, and dug into it in <a href="https://github.com/gioxx/MarvellousSuspender/issues/410" target="_blank" rel="noopener noreferrer" class="">issue #410</a>. TMS pins a fixed extension ID in its manifest, so a normal update should never touch your saved sessions in <code>chrome.storage</code>/IndexedDB, they live at that same ID before and after.</p>
<p>What we found instead: Chrome occasionally flags an extension as "corrupted" after an update and offers a repair/reinstall flow, and that repair flow can reset the extension's local storage even though the ID doesn't change. That's a Chrome-side quirk, not something TMS's update logic triggers. Cold comfort if it happens to you, we know, so if you ever hit it:</p>
<ol>
<li class="">Check the extension's History/Manage Sessions page and the Recovery page first, sometimes the data is still there and just needs a poke.</li>
<li class="">Compare the extension ID in <code>chrome://extensions</code> (Developer mode on) against your backed-up <code>IndexedDB</code> folder name, if you have one.</li>
<li class="">If you have a raw IndexedDB backup, tab URLs are recoverable as plain text even from the binary <code>.ldb</code>/<code>.log</code> files, full recovery steps are in the issue thread.</li>
</ol>
<p>If this happens to you, open an issue (or use the <a href="https://marvellouscode.works/tms/report" target="_blank" rel="noopener noreferrer" class="">no-account report form</a>) with what you're seeing, we'll walk through recovery with you the same way.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="we-read-everything">We read everything<a href="https://kb.marvellouscode.works/blog/tms9-public-permissions-faq#we-read-everything" class="hash-link" aria-label="Direct link to We read everything" title="Direct link to We read everything" translate="no">​</a></h2>
<p>As said before, we mean it: reviews, star ratings, GitHub issues, all of it gets read, and this post exists because of exactly that. If something about TMS 9 is bothering you, permissions, the redesign, anything else, <a href="https://github.com/gioxx/MarvellousSuspender/issues" target="_blank" rel="noopener noreferrer" class="">open an issue</a> or use the <a href="https://marvellouscode.works/tms/report" target="_blank" rel="noopener noreferrer" class="">report form</a>. We'd rather answer it directly than have it sit in a star rating we can't reply to.</p>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Release</category>
            <category>Announcement</category>
        </item>
        <item>
            <title><![CDATA[Road to TMS 9: we made it, and it's rolling out Monday!]]></title>
            <link>https://kb.marvellouscode.works/blog/road-to-tms9-launch</link>
            <guid>https://kb.marvellouscode.works/blog/road-to-tms9-launch</guid>
            <pubDate>Thu, 30 Jul 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[TMS 9 has cleared Google's review. Starting Monday, August 3rd, the new version begins rolling out on the Chrome Web Store. A look back at the ride, the chats with Rob, the community that showed up, the new site, and what actually changes for you.]]></description>
            <content:encoded><![CDATA[<p>Five weeks ago we opened this series with <a class="" href="https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign">a new look for a new era</a>. Google just cleared v9.0.0 for review, and starting <strong>Monday morning, August 3rd</strong>, the rollout to the Chrome Web Store begins. This is the last stop on the road.</p>
<img src="https://kb.marvellouscode.works/assets/images/suspendy-summer-vacation-e12524d906044ae8393b6a7b2ff7ccd7.webp" alt="Suspendy Guy in Hawaiian shirt, sunglasses, and sandals, holding a tropical cocktail" style="float:right;margin:0 0 1rem 1.5rem;width:180px">
<p>It's also pushing about 40°C outside as we write this, summer in full swing, and yes, 40°C in Italy is exactly as absurd as it sounds. Wherever you are, we hope you get a good stretch of vacation out of it. We won't really be taking one ourselves, but we'll admit to easing off the throttle a little.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-actually-shipped">What actually shipped<a href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#what-actually-shipped" class="hash-link" aria-label="Direct link to What actually shipped" title="Direct link to What actually shipped" translate="no">​</a></h2>
<ul>
<li class=""><strong>Session backup and restore</strong> (arguably the single most requested feature, since the dawn of time), local or Google Drive, on a schedule or on demand, multi-device aware.</li>
<li class="">A Tab Health page that scans your suspended tabs and repairs the Tab Groups restart bug on Chrome, Edge, and Brave with one click (the underlying bug is fixed now, but we kept the tooling around and available on demand, just in case).</li>
<li class="">A News feed that pulls straight from this blog into the extension's sidebar.</li>
<li class="">A visual redesign that finally makes every settings page look like it belongs to the same product.</li>
<li class="">Sixteen languages brought back up to parity after being left behind for who knows how long.</li>
</ul>
<p>None of that happened in a straight line, and none of it happened alone.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-chats-with-rob">The chats with Rob<a href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#the-chats-with-rob" class="hash-link" aria-label="Direct link to The chats with Rob" title="Direct link to The chats with Rob" translate="no">​</a></h2>
<p>Rob and I don't work in the same office, the same country, or even close to the same timezone half the time. Most of TMS 9 got decided in a Slack channel, at hours that made sense for neither of us, arguing about whether a permission scope was too aggressive, whether a setting needed a tooltip, whether "Restore from backup" should live under Sessions or Backup. Small questions, but the kind that decide whether an extension feels considered or just shipped.</p>
<p>The Great-er Tab Discarder (TGD) and The Marvellous Suspender (TMS) are separate projects with separate codebases, but Marvellous Codeworks only works because there are two of us pulling in the same direction, checking each other's blind spots, and occasionally telling the other one an idea is bad before it ships. TMS 9 is better for it, and we hope to do the same for TGD soon.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-community-that-showed-up">The community that showed up<a href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#the-community-that-showed-up" class="hash-link" aria-label="Direct link to The community that showed up" title="Direct link to The community that showed up" translate="no">​</a></h2>
<p>TMS 9 also has two first-time contributors in the changelog: <a href="https://github.com/MatrixNeoKozak" target="_blank" rel="noopener noreferrer" class="">@MatrixNeoKozak</a>, who refactored the storage layer to drop unnecessary JSON serialization, and <a href="https://github.com/iGhost" target="_blank" rel="noopener noreferrer" class="">@iGhost</a>, who added the option to preserve YouTube playback position on suspend, a small feature, requested and built by someone who actually hit the problem (something I never personally needed, for what it's worth). That is exactly how an open-source project is supposed to grow: not just bug reports, but pull requests from people who decided to fix the thing themselves.</p>
<p>On top of that, sixteen locales got AI-assisted translation passes to close gaps that had been sitting there for versions (Claude had free rein here). They are not perfect. If you read TMS in your language and something sounds off, <a href="https://crowdin.com/project/tms" target="_blank" rel="noopener noreferrer" class="">Crowdin</a> is open and corrections from native speakers are exactly what closes that gap for good.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="reporting-an-issue-without-a-github-account">Reporting an issue without a GitHub account<a href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#reporting-an-issue-without-a-github-account" class="hash-link" aria-label="Direct link to Reporting an issue without a GitHub account" title="Direct link to Reporting an issue without a GitHub account" translate="no">​</a></h2>
<p>For years, the only way to tell us something was broken was to open a GitHub issue, which meant a GitHub account, which meant a wall a lot of people simply weren't willing to climb over just to report a bug. We kept hearing about problems secondhand, in reviews, in Reddit threads, never where we could actually act on them.</p>
<p><a href="https://marvellouscode.works/tms/report" target="_blank" rel="noopener noreferrer" class="">marvellouscode.works/tms/report</a> aims to fix that. Fill in a form, no sign-up, no account, and it opens a proper GitHub issue on your behalf, correctly labeled, with the fields we actually need to reproduce the problem. You get a status link back to follow along, we get a real, actionable report instead of a one-star review that just says "stopped working."</p>
<p>And on that note: we do read everything, including what shows up directly on the Chrome Web Store. Star ratings, written reviews, support requests left in that little review box, all of it gets read. We keep an eye on GitHub Issues specifically because that is where we actually track and act on things, verifying odd behavior, following up on requests, closing things out once they're fixed, but a review left on the Store is not shouting into a void either.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>The web report form is experimental. It exists to lower the barrier for people who won't create a GitHub account just to tell us something is broken, not to replace GitHub entirely. If it ever gets abused, spam, bad-faith noise, whatever form that takes, it's the first thing we'll turn off, and reporting will go back to being GitHub accounts opening Issues under their own name, full stop.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-documentation-site-built-from-scratch">A documentation site built from scratch<a href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#a-documentation-site-built-from-scratch" class="hash-link" aria-label="Direct link to A documentation site built from scratch" title="Direct link to A documentation site built from scratch" translate="no">​</a></h2>
<p>The old TMS wiki lived on the GitHub repo, half-finished, out of date in places, and honestly not the kind of thing you'd send someone to if you wanted them to actually understand the extension. It's disabled now.</p>
<p>In its place: <a class="" href="https://kb.marvellouscode.works/docs/intro">kb.marvellouscode.works/docs</a>, built from the ground up on Docusaurus, page by page, primarily for TMS 9 (though really designed to cover everything that ends up under the Marvellous Codeworks umbrella). Every settings page has its own article, Settings, Sessions, Backup, Tab Health, Quick Actions, Keyboard Shortcuts, News, About, explaining what every toggle actually does, not just what it's labeled. There's a dedicated page on <a class="" href="https://kb.marvellouscode.works/docs/TMS/permissions">permissions</a>, spelling out why TMS asks for what it asks for, and what changed with the narrower Drive scope in this release. FAQ included. Nothing hidden in a stale wiki page nobody updated since 2019.</p>
<p>We built it, page by page, deciding what actually needed explaining versus what was obvious enough to skip. The <code>marvellouscode.works</code> domain has actually been sitting registered for almost a year now, it just took weeks and weeks of actual writing, restructuring, and rewriting to turn it into the site, the docs, and the report flow you can use today.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="everything-changes-nothing-changes">Everything changes. Nothing changes.<a href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#everything-changes-nothing-changes" class="hash-link" aria-label="Direct link to Everything changes. Nothing changes." title="Direct link to Everything changes. Nothing changes." translate="no">​</a></h2>
<p>TMS 9 looks different, is organized differently, backs itself up differently, and speaks more languages correctly than it used to. That is the "everything changes" part, and it took a full rewrite of the settings pages, a new backup system, and a lot of late chats with Rob to get there.</p>
<p>The "nothing changes" part is simpler: TMS still exists to take tabs your browser is hoarding in memory and put them to sleep until you actually need them again. That was true the day <a class="" href="https://kb.marvellouscode.works/blog/the-marvellous-suspender-hello-world">The Great Suspender got rescued</a>, it was true through the Manifest V3 rewrite, and it is still true in v9.0.0. Every feature in this release, Tab Health, backups, the redesign, exists to protect that one job, not to replace it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="not-everyone-will-love-it-and-thats-fine">Not everyone will love it, and that's fine<a href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#not-everyone-will-love-it-and-thats-fine" class="hash-link" aria-label="Direct link to Not everyone will love it, and that's fine" title="Direct link to Not everyone will love it, and that's fine" translate="no">​</a></h2>
<p>We're perfectly aware that not everyone is going to be thrilled with the new look. Change is rarely comfortable, and a redesign this size, new fonts, new colors, new layout on every single page, is exactly the kind of thing some people will need time to get used to, or just won't like at all. That's part of growing a project, it's part of the deal.</p>
<p>We still believe the repaint was necessary, and we think it's only the first big step. There are more ideas in the pipeline, and there are plenty of problems and feature requests already sitting in GitHub Issues that we intend to work through to keep pushing TMS forward. We're listening, we take feedback and constructive criticism seriously, that's the whole point of open source in the first place.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next<a href="https://kb.marvellouscode.works/blog/road-to-tms9-launch#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>Google's review is done, the changelog is final, and the rollout starts Monday morning, August 3rd. Chrome Web Store updates roll out gradually rather than to everyone at once, so don't panic if you don't see v9.0.0 the second you check, it'll reach you within the normal update window. This series is officially done. Thank you for reading along the whole way, for testing feature branches, for opening issues, for the pull requests, and for the patience.</p>
<p>See you on the other side, in v9.0.0.</p>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Road to TMS 9</category>
            <category>Release</category>
            <category>Announcement</category>
        </item>
        <item>
            <title><![CDATA[Road to TMS 9: watching the Tab Health repair work, live, on Brave]]></title>
            <link>https://kb.marvellouscode.works/blog/road-to-tms9-tab-health-repair</link>
            <guid>https://kb.marvellouscode.works/blog/road-to-tms9-tab-health-repair</guid>
            <pubDate>Fri, 03 Jul 2026 15:30:00 GMT</pubDate>
            <description><![CDATA[A quick look at TMS 9's Tab Health page catching and repairing broken grouped tabs on Brave, the same recovery logic we described in the Chrome 150 post, this time in action.]]></description>
            <content:encoded><![CDATA[<p>We spent the last few posts chasing a Chromium regression across three browsers: it <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug">broke grouped tabs on Chrome 149</a>, <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug">reached Edge</a> shortly after, and was finally <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed">fixed upstream in Chrome 150</a>. That last post also introduced the plan for <strong>Brave</strong>, which does not follow Chrome's release schedule and might stay affected for a while: TMS 9's new Tab Health page can detect and repair the broken tabs on demand, without waiting for Brave to catch up.</p>
<p>This week we actually ran that repair on a Brave profile with tab groups in a broken state, and it is worth showing rather than just describing.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="scan-tabs">Scan Tabs<a href="https://kb.marvellouscode.works/blog/road-to-tms9-tab-health-repair#scan-tabs" class="hash-link" aria-label="Direct link to Scan Tabs" title="Direct link to Scan Tabs" translate="no">​</a></h2>
<p>The Tab Health page opens with a single button. Nothing happens until you ask for it.</p>
<p><img decoding="async" loading="lazy" alt="TMS 9 Tab Health page on Brave, before scanning, just the Scan Tabs button" src="https://kb.marvellouscode.works/assets/images/tms9-tab-health-brave-scan-566a58c0af37b3dae247793d23c450d7.webp" width="1400" height="472" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-the-scan-found">What the scan found<a href="https://kb.marvellouscode.works/blog/road-to-tms9-tab-health-repair#what-the-scan-found" class="hash-link" aria-label="Direct link to What the scan found" title="Direct link to What the scan found" translate="no">​</a></h2>
<p>Clicking <strong>Scan Tabs</strong> walks through every tab and reports back. On this Brave profile, out of 28 tabs, TMS found 5 suspended tabs, 20 cached favicons, and <strong>21 grouped tabs in a broken state</strong>, flagged specifically as the Tab Groups bug.</p>
<p>That number is the point of this post. On Brave, those 21 tabs would otherwise sit there as blank <code>chrome://newtab/</code> pages until someone clicked the browser Back button on each one, one at a time. Instead, a <strong>Repair 21 grouped tab(s)</strong> button appears right below the scan results.</p>
<p>One click later: "Restoring favicons... 21 tabs. Done. Re-scan to verify grouped tabs are back to their suspended state." All 21 tabs recovered in a single pass, matched back to their original suspended URLs by window order and tab index, the Brave-specific recovery path described in the <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed#for-brave-and-edge-users">Chrome 150 post</a>.</p>
<p><img decoding="async" loading="lazy" alt="TMS 9 Tab Health page on Brave, after scanning and repairing, scan results showing 21 grouped tabs in broken state, followed by the repair progress and completion message" src="https://kb.marvellouscode.works/assets/images/tms9-tab-health-brave-repair-d1718fc5cfcfee3d6ca73621321bc738.webp" width="1400" height="812" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-matters-for-brave-users-specifically">Why this matters for Brave users specifically<a href="https://kb.marvellouscode.works/blog/road-to-tms9-tab-health-repair#why-this-matters-for-brave-users-specifically" class="hash-link" aria-label="Direct link to Why this matters for Brave users specifically" title="Direct link to Why this matters for Brave users specifically" translate="no">​</a></h2>
<p>Chrome shipped the real fix in version 150. Whether and when Brave aligns with it is out of our hands, Brave tracks upstream Chromium on its own schedule, and there is no guarantee it lands quickly. If it does, this repair simply becomes unnecessary, the same way it already is for Chrome 150 users.</p>
<p>If it does not, TMS 9 gives Brave users a real answer instead of a manual workaround: open the Tab Health page, click Scan Tabs, and if it finds broken grouped tabs, click Repair. No side-loaded companion extension, no clicking Back on every tab, no waiting on a browser vendor's release notes.</p>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_BuS1"><p>TMS 9 is still in development. The screenshots in this post come from a build running on the <code>feature/session-backup</code> branch, not a public release. <strong>Do not side-load TMS 9 branches yourself</strong>, they share the same extension ID as the Chrome Web Store version, and doing so would overwrite your production installation. Wait for the official release.</p></div></div>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Road to TMS 9</category>
        </item>
        <item>
            <title><![CDATA[Chrome 150 fixes the Tab Groups bug, and here is what changed in TMS]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed</link>
            <guid>https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed</guid>
            <pubDate>Tue, 30 Jun 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[Chrome 150.0.7871.47 ships the browser-side fix for the tab group restore regression that broke suspended tabs since version 149. We removed the TMS startup workarounds, but kept the recovery logic where it matters most.]]></description>
            <content:encoded><![CDATA[<p>When Chrome 149 introduced a regression that silently discarded suspended tabs inside tab groups on every browser restart, TMS shipped a workaround in <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug">version 8.1.4</a>. When the same regression reached Microsoft Edge, <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug">we addressed that too</a>. We knew from the start that these were stopgap measures, the right fix had to come from the browser itself.</p>
<p>It is now here. <strong>Chrome 150.0.7871.47</strong> ships the browser-side patch for <a href="https://crbug.com/522338670" target="_blank" rel="noopener noreferrer" class="">crbug.com/522338670</a>. Tab groups restore correctly without any intervention from TMS. We have verified this with a clean restart session and multiple group configurations, and everything behaves as expected.</p>
<p>Here is what that means for TMS, and what we decided to do with the workaround code.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-we-removed-from-the-startup-path">What we removed from the startup path<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed#what-we-removed-from-the-startup-path" class="hash-link" aria-label="Direct link to What we removed from the startup path" title="Direct link to What we removed from the startup path" translate="no">​</a></h2>
<p>The TMS 8.1.4 workaround lived entirely in the extension's startup sequence. Every time the browser launched, TMS would:</p>
<ol>
<li class="">Scan all tabs and cache suspended URLs for grouped tabs as Chrome assigned group IDs.</li>
<li class="">Detect grouped suspended tabs that Chrome marked as discarded before the user could click them.</li>
<li class="">Re-create those tabs in-place, restore their group membership, and remove the broken originals.</li>
<li class="">Handle late <code>onReplaced</code> events that fired after the startup window closed (the Chrome and Edge variant of the bug).</li>
<li class="">For Brave, which doesn't fire <code>onReplaced</code> at all, match broken <code>chrome://newtab/</code> grouped tabs against the last saved session by window order and tab index, then recreate them.</li>
</ol>
<p>With Chrome 150 restoring grouped tabs correctly, all of this runs for nothing on every single startup. Worse, if Chrome and TMS both try to recreate the same tab, the interaction is unpredictable. So we disabled the entire startup path.</p>
<p>The code is still there, commented out in <code>gsSession.js</code> and <code>background.js</code>, clearly marked with <code>// DISABLED FOR TESTING: Chrome 150 Tab Groups fix</code>. If a future Chrome update regresses this behavior, re-enabling it takes minutes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-we-kept-and-where">What we kept, and where<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed#what-we-kept-and-where" class="hash-link" aria-label="Direct link to What we kept, and where" title="Direct link to What we kept, and where" translate="no">​</a></h2>
<img src="https://kb.marvellouscode.works/img/suspendy-guy-doctor.webp" alt="Suspendy Guy: Health" style="float:right;margin:0 0 1rem 1.5rem;width:180px">
<p>Disabling startup recovery does not mean abandoning users who hit broken grouped tabs. It means moving the recovery to the right place: <strong>the Tab Health page</strong>.</p>
<p>The Tab Health page (<code>health.html</code>) is TMS's existing on-demand diagnostic tool. You open it, click Scan Tabs, and TMS checks your suspended tabs for issues, missing favicons, stale cache entries, tabs that haven't fully loaded. It reports what it finds and offers a targeted action to fix it.</p>
<p>We added a new check to this scan: <strong>grouped tabs in broken state</strong>. The scan now detects two failure modes:</p>
<ul>
<li class=""><strong>Chrome / Edge path</strong>: a grouped suspended tab is in a discarded state. This means Chrome started the session restore but did not complete it correctly, leaving the tab with its suspended URL intact but inactive. TMS can re-create the tab in-place, restore its group, and remove the broken copy, without the user having to click anything manually.</li>
<li class=""><strong>Brave path</strong>: a grouped tab is showing <code>chrome://newtab/</code> instead of any content. Brave does not fire the <code>onReplaced</code> events that Chrome and Edge use, so the broken URL is gone. TMS recovers the suspended URL by matching the tab's position (window order and tab index) against the last saved session.</li>
</ul>
<p>If the scan finds zero broken grouped tabs, which will be the case for every Chrome 150+ user, it shows <code>0 ✓</code> and moves on. If it finds any, a <strong>Repair grouped tab(s)</strong> button appears as the first action, above the existing favicon checks, because a structurally broken tab is a more urgent problem than a missing favicon.</p>
<p>The recovery logic itself is identical to what the startup path used. It is just no longer running automatically on every launch.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-split-makes-sense">Why this split makes sense<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed#why-this-split-makes-sense" class="hash-link" aria-label="Direct link to Why this split makes sense" title="Direct link to Why this split makes sense" translate="no">​</a></h2>
<p>The startup workaround had to be aggressive by design: it ran before the user could interact with any tab, because a single click on a broken grouped tab in Chrome's session restore was enough to lose the suspended URL permanently. That aggression was justified when the bug was active. Now that Chrome fixes it natively, running the same code at startup becomes unnecessary noise, and potentially a source of conflicts if Chrome's own restore logic and TMS's recreate logic both fire on the same tab.</p>
<p>Moving recovery to the health page shifts it from "runs automatically every time, no matter what" to "runs when the user explicitly asks." That is the right model for a workaround that is no longer expected to be needed.</p>
<p>The event-driven handlers, the ones that hooked into <code>onReplaced</code> and <code>onUpdated</code> during the startup window, cannot be replicated outside the startup context, so those remain commented out in the background script. They are not lost; they are preserved exactly where they need to be if we ever want to reactivate them.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="for-brave-and-edge-users">For Brave and Edge users<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed#for-brave-and-edge-users" class="hash-link" aria-label="Direct link to For Brave and Edge users" title="Direct link to For Brave and Edge users" translate="no">​</a></h2>
<p>The browser-side fix shipped in Chrome 150. Brave and Edge follow their own Chromium release schedules, so the patch may arrive at different times for those browsers.</p>
<ul>
<li class=""><strong>Brave users</strong>: the Brave path in the health page recovery remains active and will work on any Brave version. If you restart Brave and notice grouped tabs showing as new tabs, open the Tab Health page and run a scan.</li>
<li class=""><strong>Edge users</strong>: Edge 149+ has shown symptoms of the same regression. Once the Chromium 150 patch reaches Edge's stable channel, you will be in the same position as Chrome users today. Until then, the health page recovery is available if you need it.</li>
</ul>
<p>We hope the other Chromium-based browsers catch up with this fix quickly. But if they don't, once <strong>TMS 9</strong> is available you will be able to rely on the new Tab Health page recovery to fix broken grouped tabs on demand, without waiting for a browser-side patch.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-150-fixed#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<table><thead><tr><th>What</th><th>Before (TMS 8.1.4)</th><th>After (TMS + Chrome 150)</th></tr></thead><tbody><tr><td>Chrome grouped tab restore</td><td>Broken, TMS fixed at startup</td><td>Fixed natively by Chrome 150</td></tr><tr><td>Startup workaround</td><td>Active on every launch</td><td>Disabled (code preserved as comments)</td></tr><tr><td>Manual recovery</td><td>Not available</td><td>Tab Health page → Scan Tabs</td></tr><tr><td>Brave recovery</td><td>Active at startup</td><td>Tab Health page → Scan Tabs</td></tr><tr><td>Edge recovery</td><td>Active at startup (8.1.5+)</td><td>Tab Health page → Scan Tabs</td></tr></tbody></table>
<p>If you are on Chrome 150 and everything is working: nothing to do. If you ever hit broken grouped tabs again, on any browser, open the Tab Health page and let TMS sort it out.</p>
<hr>
<p><em>Related posts: <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug">TMS &amp; Chrome 149: the original bug report</a> · <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug">TMS &amp; Microsoft Edge: the Chromium regression hits Edge too</a></em></p>
<p><em>GitHub issues: <a href="https://github.com/gioxx/MarvellousSuspender/issues/369" target="_blank" rel="noopener noreferrer" class="">#369</a> · <a href="https://github.com/gioxx/MarvellousSuspender/issues/374" target="_blank" rel="noopener noreferrer" class="">#374</a></em></p>]]></content:encoded>
            <category>Bug</category>
            <category>News</category>
            <category>The Marvellous Suspender</category>
            <category>Announcement</category>
            <category>Road to TMS 9</category>
        </item>
        <item>
            <title><![CDATA[Under the hood: replacing abandoned libraries in TMS 9]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-dependency-cleanup</link>
            <guid>https://kb.marvellouscode.works/blog/tms-dependency-cleanup</guid>
            <pubDate>Fri, 26 Jun 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[The next TMS update quietly replaces two aging third-party libraries, one abandoned since 2021, one still stuck on a 2020 release candidate. Here is why it matters and what we are asking the community.]]></description>
            <content:encoded><![CDATA[<p>TMS 9 is shaping up to be one of the most significant releases in the extension's history, if you have been following along, you already know about the automatic session backups and the Google Drive integration we covered in the previous posts. But not all of the work that goes into a release shows up in the changelog. Some of the most important changes happen completely out of sight, and this one is a good example of that. We replaced two third-party libraries that had been silently aging inside the extension, and we want to be transparent about what changed and why.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-a-third-party-library-and-why-should-you-care">What is a "third-party library" and why should you care?<a href="https://kb.marvellouscode.works/blog/tms-dependency-cleanup#what-is-a-third-party-library-and-why-should-you-care" class="hash-link" aria-label="Direct link to What is a &quot;third-party library&quot; and why should you care?" title="Direct link to What is a &quot;third-party library&quot; and why should you care?" translate="no">​</a></h2>
<p>TMS is not written from scratch. Like most software, it relies on a handful of external libraries, small pieces of code written by other developers that handle specific tasks so we do not have to reinvent the wheel. These libraries live inside the extension you install, and their health matters: an abandoned library means bugs get no fixes, known vulnerabilities go unpatched, and compatibility with future browser versions is not guaranteed.</p>
<p>Until now, TMS included two such libraries that were overdue for attention.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dbjs-a-quietly-abandoned-dependency">db.js: a quietly abandoned dependency<a href="https://kb.marvellouscode.works/blog/tms-dependency-cleanup#dbjs-a-quietly-abandoned-dependency" class="hash-link" aria-label="Direct link to db.js: a quietly abandoned dependency" title="Direct link to db.js: a quietly abandoned dependency" translate="no">​</a></h2>
<p><strong>db.js</strong>, written by Aaron Powell, is a small wrapper around the browser's IndexedDB storage engine. TMS uses IndexedDB to remember your suspended tabs, saved sessions, favicons, and screenshot previews. db.js was responsible for every read, write, and query against that database.</p>
<p>The problem: development on db.js effectively stopped in 2021. The npm package has been frozen at version 0.15.0 for years. No bug fixes, no security patches, no updates for changes in browser behavior. We were shipping dead code, and dead code carries risk.</p>
<p>We replaced db.js with <strong><a href="https://github.com/jakearchibald/idb" target="_blank" rel="noopener noreferrer" class="">idb</a></strong>, the IndexedDB wrapper maintained by Jake Archibald (a Google engineer who literally helped write the browser storage specs). idb is:</p>
<ul>
<li class="">Actively maintained, currently at version 8</li>
<li class="">Widely used across the web platform ecosystem</li>
<li class="">Lean, well-tested, and licensed under ISC (permissive open source)</li>
</ul>
<p>From your perspective as a user, <strong>nothing changes</strong>. Your sessions, your suspended tabs, your settings, all of it is stored the same way in IndexedDB. The only difference is that the code that reads and writes your data is now backed by a healthy, modern library instead of an abandoned one.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="html2canvas-from-a-2020-release-candidate-to-a-stable-release">html2canvas: from a 2020 release candidate to a stable release<a href="https://kb.marvellouscode.works/blog/tms-dependency-cleanup#html2canvas-from-a-2020-release-candidate-to-a-stable-release" class="hash-link" aria-label="Direct link to html2canvas: from a 2020 release candidate to a stable release" title="Direct link to html2canvas: from a 2020 release candidate to a stable release" translate="no">​</a></h2>
<p>The second change is smaller in scope but still worth mentioning. <strong>html2canvas</strong>, the library TMS uses to generate the screenshot preview shown on suspended tab pages, was pinned at version <strong>1.0.0-rc.7</strong>, a <em>release candidate</em> from 2020. We were shipping pre-release software to everyone.</p>
<p>The library's author, Niklas von Hertzen, published the stable <strong>1.4.1</strong> release in 2022. This version includes several rendering fixes, better SVG support, and improved CORS handling. We updated to it.</p>
<p>For users who have the screenshot preview feature enabled in TMS settings, this may result in slightly more accurate previews on complex pages. For everyone else, there is no visible difference.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="an-open-question-for-the-community-do-you-use-full-page-screenshots">An open question for the community: do you use full-page screenshots?<a href="https://kb.marvellouscode.works/blog/tms-dependency-cleanup#an-open-question-for-the-community-do-you-use-full-page-screenshots" class="hash-link" aria-label="Direct link to An open question for the community: do you use full-page screenshots?" title="Direct link to An open question for the community: do you use full-page screenshots?" translate="no">​</a></h2>
<p>Here is where we need your input.</p>
<p>The screenshot preview in TMS has two modes, configurable in <strong>Settings → Preview</strong>:</p>
<ul>
<li class=""><strong>Viewport</strong>: captures only the visible portion of the page when you suspend it.</li>
<li class=""><strong>Full page</strong>: scrolls and renders the entire page content, even below the fold.</li>
</ul>
<p>html2canvas is the only reason TMS needs to ship a 200 KB library. The <strong>viewport</strong> mode does not actually need it at all, Chrome provides a native API (<code>chrome.tabs.captureVisibleTab</code>) that captures the visible area of a tab directly from the extension, with no third-party code required. Full-page screenshots, however, need html2canvas because no native browser API supports them.</p>
<p>So the question is: <strong>do you actually use full-page screenshots?</strong> If the vast majority of users either have previews disabled or use viewport-only mode, we could remove html2canvas entirely in a future release, replacing the viewport capture with the native Chrome API and dropping full-page support. The result would be a smaller, simpler, more maintainable extension.</p>
<p>We have opened a discussion on GitHub for exactly this:</p>
<p>👉 <strong><a href="https://github.com/gioxx/MarvellousSuspender/discussions/381" target="_blank" rel="noopener noreferrer" class="">Discussion #381, Which screenshot preview mode do you use in TMS?</a></strong></p>
<p>If you have an opinion, whether you love the full-page preview or have never even turned it on, we would genuinely like to hear it. Community input is what drives these decisions.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://kb.marvellouscode.works/blog/tms-dependency-cleanup#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<table><thead><tr><th>Library</th><th>Before</th><th>After</th><th>Why</th></tr></thead><tbody><tr><td>db.js</td><td>0.15.0 (2021, abandoned)</td><td>❌ Removed</td><td>Replaced by idb v8</td></tr><tr><td>idb</td><td>-</td><td>8.0.3</td><td>Modern IndexedDB wrapper, actively maintained</td></tr><tr><td>html2canvas</td><td>1.0.0-rc.7 (2020 RC)</td><td>1.4.1 (2022 stable)</td><td>Updated; future status depends on community feedback</td></tr></tbody></table>
<p>These changes will ship in the next TMS release. If you encounter any regressions with session storage, tab history, or screenshot previews after updating, please <a href="https://github.com/gioxx/MarvellousSuspender/issues" target="_blank" rel="noopener noreferrer" class="">open an issue on GitHub</a>.</p>
<p>Thank you for using TMS, and thank you, as always, for the patience you extend to a small team maintaining this project in their free time.</p>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Road to TMS 9</category>
        </item>
        <item>
            <title><![CDATA[Road to TMS 9: automatic session backup, Drive integration, and what's new in the branch]]></title>
            <link>https://kb.marvellouscode.works/blog/road-to-tms9-session-backup</link>
            <guid>https://kb.marvellouscode.works/blog/road-to-tms9-session-backup</guid>
            <pubDate>Thu, 25 Jun 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[The session-backup branch brings the most-requested feature in TMS history: automatic, scheduled backups of your sessions, locally or to Google Drive. Plus settings export/import, a new Backup page, a diagnostic overhaul, and several bug fixes.]]></description>
            <content:encoded><![CDATA[<p>If there is one thing TMS users have asked for more than anything else over the years, it is this: <em>please don't let me lose my sessions</em>. A browser profile wipe, a clean OS install, an accidental extension removal, and everything is gone. TMS has always saved sessions inside Chrome's storage, but Chrome's storage lives and dies with the browser profile.</p>
<p>The <code>feature/session-backup</code> branch changes that.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="automatic-session-backup">Automatic session backup<a href="https://kb.marvellouscode.works/blog/road-to-tms9-session-backup#automatic-session-backup" class="hash-link" aria-label="Direct link to Automatic session backup" title="Direct link to Automatic session backup" translate="no">​</a></h2>
<p>The headline feature is a new background module, <code>gsBackup.js</code>, that silently saves your current session as a JSON file on a schedule you control. No dialog, no confirmation prompt, no interruption. It just runs.</p>
<p>You configure it from the new dedicated <strong>Backup page</strong> (more on that below):</p>
<ul>
<li class=""><strong>Interval</strong>: 15 minutes, 30 minutes, 1 h, 2 h, 4 h, 8 h, or once a day at a specific time you choose.</li>
<li class=""><strong>Destination</strong>: your local Downloads folder (inside a <code>tms-backups/</code> subfolder) or your Google Drive.</li>
<li class="">TMS retains the <strong>10 most recent backups</strong> and automatically deletes older ones. No manual cleanup needed.</li>
</ul>
<p>One detail worth calling out: backup alarms are now anchored to real clock time, not to browser startup. If you set a 15-minute interval, backups always fire at :00, :15, :30, :45, regardless of when you started Chrome. The daily option lets you pick a specific time of day; it will fire at that time every day, even if you restart the browser in between.</p>
<p>A <strong>"Backup now"</strong> button is also available directly in the popup when backup is enabled, so you can trigger an immediate save without opening the Backup page.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="google-drive-integration">Google Drive integration<a href="https://kb.marvellouscode.works/blog/road-to-tms9-session-backup#google-drive-integration" class="hash-link" aria-label="Direct link to Google Drive integration" title="Direct link to Google Drive integration" translate="no">​</a></h2>
<p>When you choose Drive as your destination, TMS authenticates silently via Chrome's <code>identity</code> API (OAuth 2.0, <code>drive.file</code> scope, access limited to files TMS itself creates) and uploads each backup to a visible <strong>"TMS Backups"</strong> folder in your Drive. Cleanup of old Drive backups (keeping the 10 most recent) is handled automatically, just like local backups.</p>
<p>If a scheduled backup fires while no Google account is connected, or if the token expires, TMS shows a <strong>red badge</strong> on the extension icon and a banner in the popup the next time you open it, so you notice the problem before you actually need a backup.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-dedicated-backup-page">A dedicated Backup page<a href="https://kb.marvellouscode.works/blog/road-to-tms9-session-backup#a-dedicated-backup-page" class="hash-link" aria-label="Direct link to A dedicated Backup page" title="Direct link to A dedicated Backup page" translate="no">​</a></h2>
<p>Previously, backup settings were buried at the bottom of the Options page. In TMS 9 they get their own first-class page, accessible directly from the sidebar on every settings screen.</p>
<p>The Backup page has two clear sections:</p>
<ul>
<li class=""><strong>Settings backup</strong>: export your extension settings to <code>tms-settings.json</code>, or import a previously saved file to restore them. The file is always overwritten on export, settings are not versioned, they are a single point-in-time snapshot. Useful after a reinstall, a machine migration, or just as a safety net before experimenting with settings. When Drive is connected, a "Save settings to Drive" button also appears here, uploading the same file to your TMS Backups folder.</li>
<li class=""><strong>Automatic session backup</strong>: the interval, destination, and Drive account controls described above.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="TMS 9 Backup page, Settings backup section with Export/Import/Drive buttons, Automatic session backup with 30-minute interval and Google Drive selected, and Connected Account panel showing the linked Google account and TMS Backups folder" src="https://kb.marvellouscode.works/assets/images/tms9-backup-page-04ded526b34a55fee0a147c1afe7e1d3.webp" width="1905" height="993" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wake-whitelisted-tabs">Wake whitelisted tabs<a href="https://kb.marvellouscode.works/blog/road-to-tms9-session-backup#wake-whitelisted-tabs" class="hash-link" aria-label="Direct link to Wake whitelisted tabs" title="Direct link to Wake whitelisted tabs" translate="no">​</a></h2>
<p>A smaller but handy addition: a new <strong>"Wake whitelisted tabs"</strong> action finds every suspended tab whose original URL matches your whitelist and unsuspends them all in one shot. It appears in the popup (below "Unsuspend all tabs") and next to the "Test whitelist" link in Options. If you regularly whitelist certain domains but sometimes find them suspended after a restart, this is the button you've been waiting for.</p>
<p><img decoding="async" loading="lazy" alt="TMS 9 popup, the new &amp;quot;Wake whitelisted tabs&amp;quot; and &amp;quot;Backup session now (Cloud)&amp;quot; entries visible alongside the standard actions" src="https://kb.marvellouscode.works/assets/images/tms9-popup-09c1c974d692d2a8d842ef90aa2b686c.webp" width="1284" height="391" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="diagnostic-page-overhaul">Diagnostic page overhaul<a href="https://kb.marvellouscode.works/blog/road-to-tms9-session-backup#diagnostic-page-overhaul" class="hash-link" aria-label="Direct link to Diagnostic page overhaul" title="Direct link to Diagnostic page overhaul" translate="no">​</a></h2>
<p>This one is more for power users and anyone who has ever had to file a bug report.</p>
<p>TMS's old debug page was effectively read-only and required DevTools access to extract anything useful. The redesigned <strong>Diagnostic page</strong> has a proper log viewer (colour-coded by level), a persistent log buffer that survives Service Worker restarts, and three action buttons: <strong>Refresh</strong>, <strong>Clear log</strong>, and <strong>Copy/Download report</strong>.</p>
<p>The downloadable report bundles the extension version, browser user-agent, a tab profiler snapshot, and the full log buffer into a single shareable text file. If you encounter a bug and open an issue on GitHub, this report gives us everything we need to diagnose it, no DevTools required on your end.</p>
<p>The "Capture verbose logs" toggle now persists to storage and wakes the Service Worker immediately when changed, so you don't need to restart Chrome to start capturing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bug-fixes-in-this-branch">Bug fixes in this branch<a href="https://kb.marvellouscode.works/blog/road-to-tms9-session-backup#bug-fixes-in-this-branch" class="hash-link" aria-label="Direct link to Bug fixes in this branch" title="Direct link to Bug fixes in this branch" translate="no">​</a></h2>
<p>Three fixes that ship alongside the new features:</p>
<p><strong>Grouped suspended tabs lost after Chrome restart.</strong> Chrome 149 introduced a bug (<code>crbug.com/522338670</code>) where tabs inside tab groups with non-<code>https://</code> URLs, including TMS suspended tabs, could be navigated to <code>chrome://newtab/</code> instead of being restored. TMS 8.1.4 already included a partial fix; this branch extends it: if the reinitialisation check detects that a suspended tab in a group has been navigated away, TMS creates a fresh tab with the correct suspended URL, places it back in the same group, and removes the broken one. No more "press Back to recover" workaround.</p>
<p><strong>Extension's own pages treated as regular tabs.</strong> TMS's internal pages (<code>options.html</code>, <code>about.html</code>, <code>debug.html</code>, etc.) were not matched by the <code>isBrowserInternalURL</code> check, which tested for <code>chrome:</code> but not <code>chrome-extension://</code>, so they could end up in the suspension queue and generate repeated failed content-script injection attempts. A dedicated <code>startsWith('chrome-extension://')</code> guard now catches them before any of that happens.</p>
<p><strong>Tab profiler showing "unknown" for whitelisted, pinned, and audible tabs.</strong> The profiler was short-circuiting when the content script did not respond and leaving the status as <code>unknown</code> instead of falling through to the correct status calculation. Whitelisted, pinned, audible, and active tabs now show their correct labels.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next<a href="https://kb.marvellouscode.works/blog/road-to-tms9-session-backup#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>The <code>feature/session-backup</code> branch is the last major piece of TMS 9. The branch is public at <a href="https://github.com/gioxx/MarvellousSuspender/tree/feature/session-backup" target="_blank" rel="noopener noreferrer" class=""><code>feature/session-backup</code></a> if you want to follow along with the commits, but read the warning below before you do anything else with it.</p>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_BuS1"><p>The <code>feature/session-backup</code> branch is development code. <strong>Do not install it as a side-loaded extension.</strong> It shares the same extension ID as the Chrome Web Store version, loading it locally would overwrite your production installation and could corrupt your sessions and settings. Wait for the official release.</p></div></div>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Road to TMS 9</category>
        </item>
        <item>
            <title><![CDATA[Road to TMS 9: a new look for a new era]]></title>
            <link>https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign</link>
            <guid>https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign</guid>
            <pubDate>Wed, 24 Jun 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[TMS 9 is coming, and before we ship it we want to bring you along for the ride. The first stop is a complete visual redesign, new design system, new fonts, new brand identity, and a peek at features already living on the feature branch.]]></description>
            <content:encoded><![CDATA[<p>TMS has been quietly getting better for years, new bugfixes, compatibility patches, a full Manifest V3 migration, but the extension's visual identity never kept up. The settings pages still looked like a relic of 2018. The popup was fine, but only barely. Nothing matched the <a href="https://marvellouscode.works/" target="_blank" rel="noopener noreferrer" class="">Marvellous Codeworks website</a>.</p>
<p>That changes with TMS 9.</p>
<p>This is the first in a series of posts we're calling <strong>Road to TMS 9</strong>, a chance to show you what's being built on the feature branches before it ships, explain the decisions behind the changes, and hear from you before things are set in stone. Think of it as development in the open.</p>
<p>Today: the visual redesign.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-design-system-from-scratch">A design system from scratch<a href="https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign#a-design-system-from-scratch" class="hash-link" aria-label="Direct link to A design system from scratch" title="Direct link to A design system from scratch" translate="no">​</a></h2>
<p>The most important change in TMS 9's interface is one you won't immediately see: a proper <strong>design token system</strong>.</p>
<p>Rather than scattering raw hex values and <code>px</code> literals across a dozen CSS files (which is exactly how TMS looked until now), we wrote <a href="https://github.com/gioxx/MarvellousSuspender/blob/feature/visual-redesign/src/css/tokens.css" target="_blank" rel="noopener noreferrer" class=""><code>tokens.css</code></a>, a single source of truth for every color, spacing step, type size, shadow, and animation duration in the extension. Every other stylesheet consumes these tokens. Change one token, the entire UI shifts consistently.</p>
<p>The color palette is built around <strong>OKLCH</strong>, a perceptually uniform color space that produces more predictable results across light and dark modes than the old <code>rgb()</code> / <code>hex</code> approach. The primary accent color is now the same cyan-blue used on marvellouscode.works, carrying the mascot's signature eye-glow right into the UI.</p>
<p>Light and dark mode are properly supported for the first time. The previous implementation layered hardcoded hex overrides inside <code>body.dark { … }</code> blocks, functional, but brittle. The token system drives both modes from the same cascade, and <code>prefers-color-scheme</code> is respected automatically. If you never touch the theme selector, the extension follows your OS.</p>
<p>One small but meaningful detail: <code>@media (prefers-reduced-motion: reduce)</code> sets all animation duration tokens to <code>0ms</code>. If you've told your OS you want less motion, TMS will honor that.</p>
<p><img decoding="async" loading="lazy" alt="TMS 9 Settings page, General section with Language and Theme selectors, brand header, and sidebar navigation" src="https://kb.marvellouscode.works/assets/images/tms9-settings-7aacecbed2f6a0d1b466a4b47b5cd420.webp" width="1905" height="993" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="new-fonts">New fonts<a href="https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign#new-fonts" class="hash-link" aria-label="Direct link to New fonts" title="Direct link to New fonts" translate="no">​</a></h2>
<p>TMS 9 ships two self-hosted variable fonts:</p>
<ul>
<li class=""><strong><a href="https://rsms.me/inter/" target="_blank" rel="noopener noreferrer" class="">Inter</a></strong>, the sans-serif workhorse for all body copy, labels, and form elements. No more system font lottery.</li>
<li class=""><strong><a href="https://www.jetbrains.com/lego/fonts/jetbrains-mono/" target="_blank" rel="noopener noreferrer" class="">JetBrains Mono</a></strong>, the monospace font used for version numbers, code-style strings, and button text. If you've used JetBrains IDEs or VS Code with this font, it'll feel right at home.</li>
</ul>
<p>Both are loaded via <code>@font-face</code> with <code>font-display: swap</code>, so they don't block rendering. Both ship under the SIL Open Font License, along with <a href="https://lucide.dev/" target="_blank" rel="noopener noreferrer" class="">Lucide</a>, which replaces the old custom icon font.</p>
<p><img decoding="async" loading="lazy" alt="TMS 9 About page, version info, credits section listing Inter, JetBrains Mono, Lucide, idb, and html2canvas" src="https://kb.marvellouscode.works/assets/images/tms9-about-cfe4055fd110c84d960735ad18ab2fe8.webp" width="1905" height="993" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="unified-page-identity">Unified page identity<a href="https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign#unified-page-identity" class="hash-link" aria-label="Direct link to Unified page identity" title="Direct link to Unified page identity" translate="no">​</a></h2>
<p>Every settings page in TMS, Options, About, Health, Shortcuts, Sessions, now opens with the same brand header: Suspendy Guy on the left, the extension name in monospace bold, the Marvellous Codeworks logo anchored to the right. Sidebar navigation is now a proper <code>&lt;nav&gt;</code> element. Each content area gets an eyebrow label that anchors it visually before the content starts.</p>
<p>It sounds like a small thing. In practice it makes the extension feel like a coherent product rather than five loosely-related pages that happened to ship together.</p>
<p><img decoding="async" loading="lazy" alt="TMS 9 Sessions page, full-width layout showing brand header, sidebar, in-page tab navigation, and session list" src="https://kb.marvellouscode.works/assets/images/tms9-sessions-bd6c5e961dbe6c4765fe7bd7cd3f412a.webp" width="1905" height="993" class="img_ev3q"></p>
<p>Even the bare pages, Tab Health is a good example, got the full treatment. Same header, same sidebar, same typography system, even when there's almost nothing on the page yet.</p>
<p><img decoding="async" loading="lazy" alt="TMS 9 Tab Health page, minimal content, same brand header and sidebar as every other page" src="https://kb.marvellouscode.works/assets/images/tms9-tab-health-3b83d2dcbde373a32933596992b3de35.webp" width="1905" height="993" class="img_ev3q"></p>
<p>The popup received the same treatment, a new brand bar at the top shows the mascot icon, the extension name, and the current version number. You always know what version you're running without opening the About page.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="new-features-already-on-the-branch">New features already on the branch<a href="https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign#new-features-already-on-the-branch" class="hash-link" aria-label="Direct link to New features already on the branch" title="Direct link to New features already on the branch" translate="no">​</a></h2>
<p>The redesign commit wasn't just cosmetic. Two features worth knowing about landed alongside it.</p>
<p><strong>Language override.</strong> TMS has always followed the browser's locale, if Chrome is set to Italian, TMS speaks Italian. TMS 9 adds a dropdown in General settings that lets you force a specific language regardless of what the browser reports. Useful if your browser is set to English but you'd rather read the extension in Italian (or vice versa). Implemented by <a href="https://github.com/gioxx/MarvellousSuspender/commit/b67f887" target="_blank" rel="noopener noreferrer" class="">fetching the chosen locale's <code>messages.json</code> at page load</a> and using it in place of Chrome's <code>i18n.getMessage()</code>.</p>
<p><strong>Tab strip context menu</strong> <em>(pending Chrome stable rollout)</em>. Chrome is adding support for <code>"tab"</code> as a context type in extension context menus, meaning TMS will be able to add entries to the right-click menu on the tab bar itself, not just on page content. The implementation is already live on the branch: Suspend/Unsuspend, Pause/Unpause, Never suspend domain, Never suspend URL, and the window/all-window variants. The Keyboard Shortcuts page already surfaces the note:</p>
<p><img decoding="async" loading="lazy" alt="TMS 9 Keyboard Shortcuts page, the note at the top confirms all actions are also available via the right-click context menu" src="https://kb.marvellouscode.works/assets/images/tms9-shortcuts-61680eea66cacab7e23d9eaf9dfa6f08.webp" width="1905" height="993" class="img_ev3q"></p>
<p>The catch is that Chrome hasn't shipped the tab strip UI yet (confirmed up to Chrome 149 at the time of writing). When it lands in stable, TMS 9 will support it automatically, no update needed on your end.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="under-the-hood">Under the hood<a href="https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign#under-the-hood" class="hash-link" aria-label="Direct link to Under the hood" title="Direct link to Under the hood" translate="no">​</a></h2>
<p>The visual branch also includes some housekeeping that users won't see but that keeps the codebase healthy:</p>
<ul>
<li class="">All PNG images (except toolbar icons, which Chrome requires as PNG) have been converted to WebP, saving up to 77% in bundle size on some assets.</li>
<li class="">The old custom Fontello icon font (6 glyphs, woff/woff2) has been replaced by a minimal <a href="https://lucide.dev/" target="_blank" rel="noopener noreferrer" class="">Lucide</a> SVG sprite, which is easier to maintain and extend.</li>
<li class="">The Italian locale received a thorough overhaul: ~45 strings that were still in English have been translated, and several grammatical issues have been fixed.</li>
</ul>
<p>The two main commits covering all of this are <a href="https://github.com/gioxx/MarvellousSuspender/commit/1260f94" target="_blank" rel="noopener noreferrer" class=""><code>1260f94</code></a> and <a href="https://github.com/gioxx/MarvellousSuspender/commit/b67f887" target="_blank" rel="noopener noreferrer" class=""><code>b67f887</code></a> on the <a href="https://github.com/gioxx/MarvellousSuspender/tree/feature/visual-redesign" target="_blank" rel="noopener noreferrer" class=""><code>feature/visual-redesign</code></a> branch, which is public if you want to follow along or try it yourself.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="next-in-the-series">Next in the series<a href="https://kb.marvellouscode.works/blog/road-to-tms9-visual-redesign#next-in-the-series" class="hash-link" aria-label="Direct link to Next in the series" title="Direct link to Next in the series" translate="no">​</a></h2>
<p>The visual redesign is one piece of the TMS 9 puzzle. The next post covers something that might seem less exciting but is arguably more important: <strong>replacing the extension's aging third-party libraries</strong>, one abandoned since 2021, one stuck on a 2020 release candidate. We'll also have a question for the community about a feature that may or may not survive into TMS 9.</p>
<p>If you have thoughts on the redesign, what you like, what doesn't work, what you'd change, <a href="https://github.com/gioxx/MarvellousSuspender/discussions" target="_blank" rel="noopener noreferrer" class="">open a discussion on GitHub</a>.</p>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_BuS1"><p>The <code>feature/visual-redesign</code> branch is development code, not a release build. <strong>Do not install it as a side-loaded extension.</strong> The branch deliberately shares the same extension ID as the Chrome Web Store version, which means loading it locally would overwrite your production installation and could corrupt your sessions and settings. The screenshots in this post are all you need, sit tight and wait for the official release.</p></div></div>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Road to TMS 9</category>
            <category>Announcement</category>
        </item>
        <item>
            <title><![CDATA[TMS & Microsoft Edge: the Chromium tab group regression is hitting Edge users too]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug</link>
            <guid>https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug</guid>
            <pubDate>Tue, 16 Jun 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[The same Chromium regression that broke suspended tabs inside tab groups on Chrome 149 is now causing issues for Microsoft Edge users as well. Here is what we know and what we are doing about it.]]></description>
            <content:encoded><![CDATA[<p>If you are using <strong>Microsoft Edge</strong> and noticed that your suspended tabs inside <strong>tab groups</strong> disappear or turn into blank New Tab pages after a browser restart, you are running into the same Chromium-level regression that <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug">first appeared in Chrome 149</a>, and it is now reaching Edge users too.</p>
<img src="https://kb.marvellouscode.works/img/suspendy-guy-oops.webp" alt="Suspendy Guy is not happy about this" style="float:right;margin:0 0 1rem 1.5rem;width:180px">
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-happened">What happened<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug#what-happened" class="hash-link" aria-label="Direct link to What happened" title="Direct link to What happened" translate="no">​</a></h2>
<p>Microsoft Edge is built on the Chromium engine, which means it inherits browser-level changes from the upstream Chromium project, including regressions. The change introduced around Chromium 149 that broke the tab group restore behavior for suspended tabs is now making its way into Edge builds.</p>
<p>As a result, Edge users are experiencing the same symptoms Chrome users saw earlier:</p>
<ul>
<li class="">Suspended tabs <strong>inside tab groups</strong> are silently discarded when the browser restarts.</li>
<li class="">Tabs <strong>outside tab groups</strong> are not affected and restore correctly.</li>
<li class="">The suspended tab URL (<code>chrome-extension://…</code> / <code>extension://…</code>) is apparently filtered out during session restore when inside a group.</li>
</ul>
<p>This is tracked in the dedicated GitHub issue <strong><a href="https://github.com/gioxx/MarvellousSuspender/issues/374" target="_blank" rel="noopener noreferrer" class="">#374</a></strong>, opened specifically for Edge. Issue <strong><a href="https://github.com/gioxx/MarvellousSuspender/issues/369" target="_blank" rel="noopener noreferrer" class="">#369</a></strong>, the original Chrome report, has also been reopened because of these lingering effects across the Chromium ecosystem.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="current-status">Current status<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug#current-status" class="hash-link" aria-label="Direct link to Current status" title="Direct link to Current status" translate="no">​</a></h2>
<p>To be clear about where things stand right now:</p>
<ul>
<li class="">The <strong>browser-side Chromium fix</strong> is <a href="https://chromium-review.googlesource.com/c/chromium/src/+/7933990" target="_blank" rel="noopener noreferrer" class="">under review</a> but has <strong>not yet landed in Chrome's stable channel</strong>, Chrome 149.0.7827.156 is still affected. The fix is expected sometime this weekend or early next week.</li>
<li class=""><strong>Edge will take even longer</strong>, as it follows its own release schedule on top of Chromium's.</li>
<li class=""><strong>TMS 8.1.4</strong> addressed the issue for Chrome users at the extension level, but some edge cases are still being investigated (see <a href="https://github.com/gioxx/MarvellousSuspender/issues/369" target="_blank" rel="noopener noreferrer" class="">#369</a>).</li>
<li class=""><strong>TMS 8.1.5</strong> is in active development and specifically targets the Edge regression. A fix has already been tested and looks solid, we expect a release candidate to be ready very soon.</li>
</ul>
<p>We are not waiting for the browser vendors to ship their fix. We are shipping our own.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>This is not TMS's fault</div><div class="admonitionContent_BuS1"><p>We want to be very clear: <strong>this regression was introduced by a change in the Chromium engine</strong>, not by anything TMS did. We are nonetheless doing everything we can to protect your tabs while the browser-side fix works its way through the release pipeline. We are sorry you are caught in the middle of this.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="temporary-workaround">Temporary workaround<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug#temporary-workaround" class="hash-link" aria-label="Direct link to Temporary workaround" title="Direct link to Temporary workaround" translate="no">​</a></h2>
<p>If you lost tabs, the manual recovery steps still apply:</p>
<ol>
<li class="">Open the tab group that now shows blank New Tab pages.</li>
<li class="">For each empty tab, click the <strong>browser Back button</strong> (top-left arrow) once.</li>
<li class="">The original suspended tab page should reappear.</li>
</ol>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Preventing further losses in the meantime</div><div class="admonitionContent_BuS1"><p>Until TMS 8.1.5 is available, consider <strong>unsuspending tabs before restarting</strong> the browser, or temporarily moving important tabs <strong>out of tab groups</strong>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-we-are-doing-about-it">What we are doing about it<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug#what-we-are-doing-about-it" class="hash-link" aria-label="Direct link to What we are doing about it" title="Direct link to What we are doing about it" translate="no">​</a></h2>
<ul>
<li class=""><strong>TMS 8.1.5</strong> is coming, with a targeted fix for Edge. Follow <a href="https://github.com/gioxx/MarvellousSuspender/pull/376" target="_blank" rel="noopener noreferrer" class="">PR #376</a> for progress.</li>
<li class="">We are tracking the Edge-specific report in <strong><a href="https://github.com/gioxx/MarvellousSuspender/issues/374" target="_blank" rel="noopener noreferrer" class="">issue #374</a></strong>, follow it for real-time updates.</li>
<li class="">Issue <strong><a href="https://github.com/gioxx/MarvellousSuspender/issues/369" target="_blank" rel="noopener noreferrer" class="">#369</a></strong> has been reopened to track lingering issues for Chrome users on TMS 8.1.4 as well.</li>
<li class="">The upstream Chromium fix (<a href="https://chromium-review.googlesource.com/c/chromium/src/+/7933990" target="_blank" rel="noopener noreferrer" class="">chromium-review.googlesource.com</a>) will eventually reach Edge too, but we are not relying on that timeline.</li>
</ul>
<p>We know how frustrating this is, especially after Chrome users already went through it. Thank you for your patience.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="references--links">References / Links<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-edge-chromium-bug#references--links" class="hash-link" aria-label="Direct link to References / Links" title="Direct link to References / Links" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug">TMS &amp; Chrome 149: the original post</a></li>
<li class=""><a href="https://github.com/gioxx/MarvellousSuspender/issues/374" target="_blank" rel="noopener noreferrer" class="">GitHub issue #374 – Edge-specific tab group regression</a></li>
<li class=""><a href="https://github.com/gioxx/MarvellousSuspender/issues/369" target="_blank" rel="noopener noreferrer" class="">GitHub issue #369 – Original Chrome 149 report (reopened)</a></li>
<li class=""><a href="https://github.com/gioxx/MarvellousSuspender/pull/376" target="_blank" rel="noopener noreferrer" class="">PR #376 – TMS 8.1.5 Edge fix</a></li>
<li class=""><a href="https://chromium-review.googlesource.com/c/chromium/src/+/7933990" target="_blank" rel="noopener noreferrer" class="">https://chromium-review.googlesource.com/c/chromium/src/+/7933990</a></li>
</ul>]]></content:encoded>
            <category>Bug</category>
            <category>News</category>
            <category>The Marvellous Suspender</category>
            <category>Announcement</category>
        </item>
        <item>
            <title><![CDATA[The Marvellous Suspender 8.1.4 - Tab group restore fix for Chrome 149]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-release-8-1-4</link>
            <guid>https://kb.marvellouscode.works/blog/tms-release-8-1-4</guid>
            <pubDate>Mon, 15 Jun 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[A targeted fix release addressing the tab group restore regression introduced by Chrome 149, where suspended tabs inside tab groups were silently discarded after a browser restart.]]></description>
            <content:encoded><![CDATA[<p>A targeted fix release addressing the tab group restore regression introduced by Chrome 149, where suspended tabs inside tab groups were silently discarded after a browser restart.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-fixed">What's fixed<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-4#whats-fixed" class="hash-link" aria-label="Direct link to What's fixed" title="Direct link to What's fixed" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="suspended-tabs-inside-tab-groups-restored-correctly-after-restart">Suspended tabs inside tab groups restored correctly after restart<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-4#suspended-tabs-inside-tab-groups-restored-correctly-after-restart" class="hash-link" aria-label="Direct link to Suspended tabs inside tab groups restored correctly after restart" title="Direct link to Suspended tabs inside tab groups restored correctly after restart" translate="no">​</a></h3>
<p>Starting with Chrome 149, a change in the browser's session restore engine caused tabs with non-<code>https://</code> URLs, including TMS suspended tabs, to be skipped when restoring tab groups. This resulted in blank New Tab pages appearing in place of your suspended tabs after every restart.</p>
<p>TMS 8.1.4 works around the Chrome-side behavior and restores suspended tabs inside tab groups correctly again. Tabs outside tab groups were not affected and continue to work as before.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>If you used the <a href="https://github.com/Marvellous-Codeworks/back-grouped-tabs" target="_blank" rel="noopener noreferrer" class="">back-grouped-tabs</a> companion extension as a temporary workaround, you can safely remove it now that TMS includes a built-in fix.</p></div></div>
<hr>
<p><em>Full changelog on GitHub: <a href="https://github.com/gioxx/MarvellousSuspender/releases/tag/v8.1.4" target="_blank" rel="noopener noreferrer" class="">v8.1.4 release</a></em></p>
<p><em>Related: <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug">TMS &amp; Chrome 149: suspended tabs inside tab groups lost after restart</a></em></p>]]></content:encoded>
            <category>Release</category>
            <category>The Marvellous Suspender</category>
        </item>
        <item>
            <title><![CDATA[TMS & Chrome 149: suspended tabs inside tab groups lost after restart]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug</link>
            <guid>https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug</guid>
            <pubDate>Wed, 10 Jun 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[If you are using Chrome 149 and noticed that your suspended tabs inside tab groups turn into blank New Tab pages after a browser restart, you are not alone, and it is not your fault.]]></description>
            <content:encoded><![CDATA[<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p><strong>2026-06-12</strong></p><ul>
<li class="">A companion extension, <a href="https://github.com/Marvellous-Codeworks/back-grouped-tabs" target="_blank" rel="noopener noreferrer" class="">back-grouped-tabs</a>, is now available as a temporary workaround while a proper fix for the Chrome bug is being developed. See the <a class="" href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug#companion-workaround-back-grouped-tabs">companion workaround section</a> for details.</li>
</ul><p><strong>2026-06-15</strong></p><ul>
<li class=""><strong>TMS 8.1.4</strong> has been submitted to the Chrome Web Store and is currently <strong>pending review</strong>. This version includes a fix for the tab group restore issue.</li>
<li class="">The Chrome team is also working on an official browser-side fix: the patch is under review at <a href="https://chromium-review.googlesource.com/c/chromium/src/+/7933990" target="_blank" rel="noopener noreferrer" class="">chromium-review.googlesource.com</a>. It's a race to see who gets there first!</li>
</ul><p><strong>2026-06-16</strong></p><ul>
<li class=""><strong>TMS 8.1.4 is now live on the <a href="https://chromewebstore.google.com/detail/the-marvellous-suspender/noogafoofpebimajpfpamcfhoaifemoa" target="_blank" rel="noopener noreferrer" class="">Chrome Web Store</a></strong>. The tab group restore issue is fixed, update TMS and you are good to go.</li>
<li class="">The <strong>back-grouped-tabs</strong> companion workaround is no longer needed. The repository remains available for anyone who still wants it, but you can safely remove the extension.</li>
</ul></div></div>
<p>If you are using Chrome 149 and noticed that your suspended tabs inside <strong>tab groups</strong> turn into blank New Tab pages after a browser restart, you are not alone, and it is not your fault.</p>
<img src="https://kb.marvellouscode.works/img/suspendy-guy-oops.webp" alt="Suspendy Guy is not happy about this" style="float:right;margin:0 0 1rem 1.5rem;width:180px">
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-happened">What happened<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug#what-happened" class="hash-link" aria-label="Direct link to What happened" title="Direct link to What happened" translate="no">​</a></h2>
<p>Starting from <strong>Chrome 149</strong>, a change in the browser's tab group restore engine broke compatibility with suspended tabs managed by TMS. When Chrome restores a session after a restart, it now skips tabs whose URL does not start with <code>https://</code> inside tab groups. Since TMS suspended tabs use an internal <code>chrome-extension://…</code> URL, they are silently discarded instead of being restored.</p>
<p>Tabs <strong>outside</strong> tab groups are not affected and restore correctly as before.</p>
<p>The issue was <a href="https://github.com/gioxx/MarvellousSuspender/issues/369" target="_blank" rel="noopener noreferrer" class="">reported by users</a> shortly after Chrome 149 rolled out and confirmed by the TMS team. A member of the <strong>Chrome development team</strong> has acknowledged the problem and <a href="https://crbug.com/522338670" target="_blank" rel="noopener noreferrer" class="">filed an internal bug</a> to investigate whether the behavior change was intentional or an unintended side effect.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="temporary-workaround">Temporary workaround<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug#temporary-workaround" class="hash-link" aria-label="Direct link to Temporary workaround" title="Direct link to Temporary workaround" translate="no">​</a></h2>
<p>If you lost tabs, there is a way to recover them without restoring a backup:</p>
<ol>
<li class="">Open the tab group that now shows blank New Tab pages.</li>
<li class="">For each empty tab, click the <strong>browser Back button</strong> (top-left arrow) once.</li>
<li class="">The original suspended tab page should reappear.</li>
</ol>
<p>This is tedious if you have many tabs, but it beats losing them permanently.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Preventing further losses in the meantime</div><div class="admonitionContent_BuS1"><p>Until a fix is available, consider <strong>unsuspending tabs before restarting</strong> Chrome, or temporarily moving important tabs <strong>out of tab groups</strong>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-we-are-doing-about-it">What we are doing about it<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug#what-we-are-doing-about-it" class="hash-link" aria-label="Direct link to What we are doing about it" title="Direct link to What we are doing about it" translate="no">​</a></h2>
<ul>
<li class=""><strong>TMS 8.1.4 is now available on the <a href="https://chromewebstore.google.com/detail/the-marvellous-suspender/noogafoofpebimajpfpamcfhoaifemoa" target="_blank" rel="noopener noreferrer" class="">Chrome Web Store</a>.</strong> It addresses the tab group restore issue directly, suspended tabs inside tab groups will no longer be discarded after a browser restart. Update TMS and the problem goes away.</li>
<li class="">The Chrome team also had an <a href="https://chromium-review.googlesource.com/c/chromium/src/+/7933990" target="_blank" rel="noopener noreferrer" class="">official fix under review</a> on the browser side; TMS shipped the fix first.</li>
</ul>
<p>We know how frustrating data loss is, and we are sorry you hit this. Thank you for your patience while we sort it out.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="companion-workaround-back-grouped-tabs">Companion workaround: back-grouped-tabs<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug#companion-workaround-back-grouped-tabs" class="hash-link" aria-label="Direct link to Companion workaround: back-grouped-tabs" title="Direct link to Companion workaround: back-grouped-tabs" translate="no">​</a></h2>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Workaround no longer needed</div><div class="admonitionContent_BuS1"><p><strong>TMS 8.1.4 is out and fixes the issue natively.</strong> If you have updated TMS, you can safely remove the back-grouped-tabs companion extension. The repository remains available for anyone who still wants to use it.</p></div></div>
<p>While the proper fix was in the works, a small companion extension was made available: <strong><a href="https://github.com/Marvellous-Codeworks/back-grouped-tabs" target="_blank" rel="noopener noreferrer" class="">back-grouped-tabs</a></strong>.</p>
<p>It does one thing: when Chrome restores a session and discards suspended tabs inside tab groups, this extension detects the affected tabs and navigates them back so the suspended page reappears, automatically, without you having to click the Back button on each one.</p>
<p>To install it, clone or download the repository and load it as an unpacked extension in Chrome (<code>chrome://extensions/</code> → enable Developer Mode → <strong>Load unpacked</strong>). The README covers everything you need to know.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="references--links">References / Links<a href="https://kb.marvellouscode.works/blog/tms-tab-groups-chrome-149-bug#references--links" class="hash-link" aria-label="Direct link to References / Links" title="Direct link to References / Links" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://chromium-review.googlesource.com/c/chromium/src/+/7933990" target="_blank" rel="noopener noreferrer" class="">https://chromium-review.googlesource.com/c/chromium/src/+/7933990</a></li>
<li class=""><a href="https://chromium-review.googlesource.com/c/chromium/src/+/7738373" target="_blank" rel="noopener noreferrer" class="">https://chromium-review.googlesource.com/c/chromium/src/+/7738373</a></li>
</ul>
<hr>
<p><em>Follow the original issue on GitHub: <a href="https://github.com/gioxx/MarvellousSuspender/issues/369" target="_blank" rel="noopener noreferrer" class="">#369 – Suspended tabs inside tab groups are lost after browser restart (Chrome 149)</a></em></p>]]></content:encoded>
            <category>Bug</category>
            <category>News</category>
            <category>The Marvellous Suspender</category>
            <category>Announcement</category>
        </item>
        <item>
            <title><![CDATA[Cutting the last thread to The Great Suspender]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-detached-from-tgs-network</link>
            <guid>https://kb.marvellouscode.works/blog/tms-detached-from-tgs-network</guid>
            <pubDate>Tue, 21 Apr 2026 23:00:00 GMT</pubDate>
            <description><![CDATA[TMS has just been detached from The Great Suspender's fork network on GitHub. It's a small technical operation with a big symbolic meaning: the first official step towards Marvellous Codeworks walking its own path.]]></description>
            <content:encoded><![CDATA[<p><a href="https://github.com/gioxx/MarvellousSuspender" target="_blank" rel="noopener noreferrer" class="">The Marvellous Suspender</a> has been a fork since day one, <a href="https://gioxx.org/2021/01/18/the-marvellous-suspender-per-google-chrome/" target="_blank" rel="noopener noreferrer" class="">born in 2021</a> out of The Great Suspender, at a time when that project had been pulled from the Chrome Web Store and flagged as malware. TMS cleaned up what needed cleaning and gave orphaned users somewhere to go. Fair enough, that's exactly what a fork is for.</p>
<p>But five years later, TMS isn't a patched-up copy of someone else's abandoned code anymore. It's had a full Manifest V3 rewrite, a proper visual redesign, its own contributors, and, as of a few months ago, a home under the <a href="https://marvellouscode.works/" target="_blank" rel="noopener noreferrer" class="">Marvellous Codeworks</a> name. The GitHub fork relationship, though, hadn't changed: technically, <code>gioxx/MarvellousSuspender</code> was still listed as a fork of the original repository, tied to its network, its issues, its history.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="asking-github-to-cut-the-thread">Asking GitHub to cut the thread<a href="https://kb.marvellouscode.works/blog/tms-detached-from-tgs-network#asking-github-to-cut-the-thread" class="hash-link" aria-label="Direct link to Asking GitHub to cut the thread" title="Direct link to Asking GitHub to cut the thread" translate="no">​</a></h2>
<p>So I asked GitHub Support to detach it, a "Detach/Extract Fork" request, which pulls a repository (and its own child forks) out of the network it was born in and gives it a clean, independent history on GitHub's side. No more fork badge, no more shared network with the original project.</p>
<p>GitHub got back to me quickly:</p>
<p><img decoding="async" loading="lazy" alt="GitHub Support confirms the detach/extract fork request for gioxx/MarvellousSuspender" src="https://kb.marvellouscode.works/assets/images/github-support-detach-fork-d8ca2e49f9e6832d15ec6185a70c3018.webp" width="1348" height="368" class="img_ev3q"></p>
<blockquote>
<p>I have gone ahead to extract that fork for you. The repository <code>gioxx/MarvellousSuspender</code> and its child forks are now in a new network.</p>
</blockquote>
<p>Done. As of today, TMS no longer carries GitHub's official "forked from" label.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-it-matters">Why it matters<a href="https://kb.marvellouscode.works/blog/tms-detached-from-tgs-network#why-it-matters" class="hash-link" aria-label="Direct link to Why it matters" title="Direct link to Why it matters" translate="no">​</a></h2>
<p>This isn't a cosmetic change, and it isn't really about the label either. It's the first concrete, official move to stop treating TMS as an offshoot of something else and start treating it as what it actually is: a project with its own direction, maintained by Marvellous Codeworks.</p>
<p>It also isn't the last step. Right now <code>gioxx/MarvellousSuspender</code> still lives under my personal GitHub account. The plan is to move it, along with the rest of what makes up TMS, under the <a href="https://github.com/Marvellous-Codeworks" target="_blank" rel="noopener noreferrer" class="">Marvellous Codeworks organization</a> on GitHub, where other projects already live. We're aiming to get that done by the end of summer 2026.</p>
<p>Small steps, but each one makes it a little more true: TMS's future isn't tied to what it was forked from anymore. It's Marvellous Codeworks now.</p>]]></content:encoded>
            <category>The Marvellous Suspender</category>
            <category>Announcement</category>
        </item>
        <item>
            <title><![CDATA[The Marvellous Suspender 8.1.3 - Vivaldi fix]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-release-8-1-3</link>
            <guid>https://kb.marvellouscode.works/blog/tms-release-8-1-3</guid>
            <pubDate>Mon, 22 Dec 2025 08:04:26 GMT</pubDate>
            <description><![CDATA[A targeted patch for Vivaldi users who were experiencing crashes related to a browser-specific API inconsistency.]]></description>
            <content:encoded><![CDATA[<p>A targeted patch for Vivaldi users who were experiencing crashes related to a browser-specific API inconsistency.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-fixed">What's fixed<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-3#whats-fixed" class="hash-link" aria-label="Direct link to What's fixed" title="Direct link to What's fixed" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="vivaldi-getcontexts-workaround">Vivaldi <code>getContexts</code> workaround<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-3#vivaldi-getcontexts-workaround" class="hash-link" aria-label="Direct link to vivaldi-getcontexts-workaround" title="Direct link to vivaldi-getcontexts-workaround" translate="no">​</a></h3>
<p>Vivaldi implements a non-standard version of the <code>chrome.runtime.getContexts</code> API that was causing TMS to throw an unhandled error. This release adds a workaround that detects and handles the inconsistency, restoring normal operation for Vivaldi users.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>This is the current stable release available on the Chrome Web Store. If you are on Vivaldi and experienced unexpected behavior after the 8.1.2 update, updating to 8.1.3 should resolve it.</p></div></div>
<hr>
<p>Special thanks to <strong>@wobondar</strong> for supporting the project! ❤️</p>
<p><em>Full changelog on GitHub: <a href="https://github.com/gioxx/MarvellousSuspender/releases/tag/v8.1.3" target="_blank" rel="noopener noreferrer" class="">v8.1.3 release</a></em></p>]]></content:encoded>
            <category>Release</category>
            <category>The Marvellous Suspender</category>
        </item>
        <item>
            <title><![CDATA[The Marvellous Suspender 8.1.2 - Session export, watermark, and UX fixes]]></title>
            <link>https://kb.marvellouscode.works/blog/tms-release-8-1-2</link>
            <guid>https://kb.marvellouscode.works/blog/tms-release-8-1-2</guid>
            <pubDate>Wed, 19 Nov 2025 14:21:59 GMT</pubDate>
            <description><![CDATA[A maintenance release with a handful of quality-of-life improvements to the session management page, the suspended tab watermark, and the update banner.]]></description>
            <content:encoded><![CDATA[<p>A maintenance release with a handful of quality-of-life improvements to the session management page, the suspended tab watermark, and the update banner.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-new-and-fixed">What's new and fixed<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-2#whats-new-and-fixed" class="hash-link" aria-label="Direct link to What's new and fixed" title="Direct link to What's new and fixed" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="session-export-filename-includes-the-date">Session export filename includes the date<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-2#session-export-filename-includes-the-date" class="hash-link" aria-label="Direct link to Session export filename includes the date" title="Direct link to Session export filename includes the date" translate="no">​</a></h3>
<p>When you export your session from the Session Management page, the downloaded file now includes the current date in its name. This makes it much easier to keep track of multiple backups without manually renaming files.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="suspended-tab-version-watermark">Suspended tab version watermark<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-2#suspended-tab-version-watermark" class="hash-link" aria-label="Direct link to Suspended tab version watermark" title="Direct link to Suspended tab version watermark" translate="no">​</a></h3>
<p>The suspended tab page now displays the TMS version number as a subtle watermark. This small addition makes it easier to identify which version was running when users share screenshots in bug reports.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="update-banner-is-now-clickable">Update banner is now clickable<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-2#update-banner-is-now-clickable" class="hash-link" aria-label="Direct link to Update banner is now clickable" title="Direct link to Update banner is now clickable" translate="no">​</a></h3>
<p>The "a new version is available" notification banner is now interactive, clicking it takes you directly to the release page instead of requiring you to navigate there manually.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="session-page-scroll-fix">Session page scroll fix<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-2#session-page-scroll-fix" class="hash-link" aria-label="Direct link to Session page scroll fix" title="Direct link to Session page scroll fix" translate="no">​</a></h3>
<p>Links within the Session Management page no longer cause the page to jump back to the top when clicked.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="whitelist-test-button-refactored">Whitelist test button refactored<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-2#whitelist-test-button-refactored" class="hash-link" aria-label="Direct link to Whitelist test button refactored" title="Direct link to Whitelist test button refactored" translate="no">​</a></h3>
<p>The "Test whitelist" function has been cleaned up internally for more reliable pattern matching.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="other-changes">Other changes<a href="https://kb.marvellouscode.works/blog/tms-release-8-1-2#other-changes" class="hash-link" aria-label="Direct link to Other changes" title="Direct link to Other changes" translate="no">​</a></h2>
<ul>
<li class="">Localization updates via Crowdin</li>
<li class="">Dependency bump: <code>js-yaml</code> patched for a security advisory</li>
</ul>
<hr>
<p><em>Full changelog on GitHub: <a href="https://github.com/gioxx/MarvellousSuspender/releases/tag/v8.1.2" target="_blank" rel="noopener noreferrer" class="">v8.1.2 release</a></em></p>]]></content:encoded>
            <category>Release</category>
            <category>The Marvellous Suspender</category>
        </item>
    </channel>
</rss>