Repository navigation
Releases: mlsimon734/tabglutton
Release list
v0.5.1
Two threads. The Digest panel becomes a desk: a list beside a preview of the row you
focus, with what the page itself said kept visibly apart from what the agent claims, and
its shortlist action changes from Keep in a group to Move to top. Separately, Shift-click
selects a range of tabs in the popup and the full view. The bridge protocol and the
manifest's permissions are unchanged, so no running hub has to be stopped.
Features
- The Digest panel is a desk: a list beside a preview. The shortlist gets a thumbnail
and two lines of the agent's reasoning, filed items one line and where Devour would file
them, and close rows one line with a checkbox. The row you focus opens beside the list
with the page's own image and description, the agent's full reasoning, and Show and the
section keys; in a narrow window it opens under the row instead. Hovering a compact row
pops a small preview card. After Close, the closed rows fold into one line. - What the page said and what the agent claims now look different. Upright text and
images come from the page, recorded by Tabglutton when the agent read the tab: its
og:image (kept as a small thumbnail, so the panel never loads anything from the site), its
description, site, author, date, and favicon, plus a video's length or a thread's comment
count when the page states them. The agent's reasoning is italic behind a dashed rule
labelled "Agent", and its quote is dropped when it only repeats the page's description.
None of this can be supplied by the agent's report. - Untick a close row to leave its tab open. The row moves to "Could not read / leave
open", and ticking it there puts it back.xticks the focused row. - Shift-click selects a range of tabs. In the popup and full view, click a checkbox,
then Shift-click another to select or deselect the rows between them. Ranges follow
the displayed order and skip tabs hidden by filters.
Changed
- Move to top replaces Keep in a group. The shortlist's tabs move to the top of their
own window's tab list, right after your pinned tabs, in the digest's order. Nothing is
grouped, pinned tabs are never touched, and Undo puts every moved tab back where it
was.
v0.5.0
Digests move into the extension. An agent that reads a batch of tabs now hands its verdicts
to Tabglutton through a new digest_report bridge tool, and you keep, close, and undo from a
Digest panel in the full view, while Gullet writes the matching note to your vault. This
release also folds in the never-tagged 0.4.2 work: an optional in-page duplicate notice,
YouTube transcripts in clips, a design polish pass, and a fix for row closes that lagged or
needed a second click. The bridge protocol is unchanged, so no running hub has to be stopped,
but digest_report needs this version of both the extension and Gullet.
Features
- Digests land in Tabglutton, and you act on them there. An agent running the digest
skill (it ships with Gullet) now reads a sitting's tabs and reports its verdicts through a
newdigest_reporttool instead of writing notes and closing tabs itself. The full view
gains a Tabs | Digest switch: the Digest side shows the report in four sections (worth
your time, file for reference, close, could not read), each row with the agent's reason.
Keep in a group puts the open shortlist into a "Worth your time" tab group in its
window; Close closes the close section as one batch, and Undo brings it back, from
the toast or later from the section head. Move a row between sections with 1–4 before
acting. Pinned, active, and hidden tabs are left alone, and a row whose tab has changed or
can't be told apart from another copy is refused rather than guessed at. The popup shows a
Digest ready line until you have opened it. Nothing about the report is trusted: the
panel shows who says they reported it, and renders every word as plain text. - Gullet writes each digest's note to your vault. One markdown note per digest, in
Digests/of the vault you clip to (or any folder, withdigestMirrorin Gullet's
config), written straight to disk and exactly once however often the agent retries.
Agent text in it is escaped, so a hostile page title cannot become a link, an embed, or a
Dataview query. Turn it off with"digestMirror": { "enabled": false }. - An optional notice when duplicates pile up. Switch it on under Deduplication in
Settings and pick a threshold, and once the badge count reaches it a small Tabglutton pill
appears in the corner of the page you are on — the count, a Dedup button, and Undo
after it — then takes itself down after fifteen seconds if left alone. It is a piece of the
extension's own UI inside the browser, never a system notification. One notice per pile: it
comes back only after the count has dropped below the threshold and climbed past it again,
at most every thirty minutes, and restoring closed tabs with Undo counts as keeping them.
Off by default. On Chrome the switch asks for site access, since the pill is placed on the
page; the manifest now lists the notice page underweb_accessible_resourcesso a page
can embed it. - YouTube clips carry the transcript. The extractor now runs Defuddle's async path, which
fetches a video's caption track instead of stopping at the description: two talks that
clipped as 24 and 153 words now clip as 15,189 and 8,847, with timestamps. The same path
reads a Reddit comments page from its feed and a logged-out x.com status through oEmbed when
the page itself has nothing rendered, and falls back to the page as before when those
fetches fail. Everything else extracts exactly as it did.
Changed
- Update both halves together.
digest_reportneeds this version of the extension and of
Gullet; the skill tells the user to update when the extension doesn't know the tool. The
bridge protocol is unchanged, so no running hub has to be stopped. - Design polish. The full view at narrow widths (under 980px) now stacks the inspector
under the queue instead of squeezing both into two columns. The Obsidian handoff page
follows the theme instead of flashing white, and says what it is doing, with a link to open
the note by hand if the launch is blocked. Off toggles in Settings are visible (3:1 against
the page and the track in both themes), its buttons take the same pill shape as everywhere
else, and the Gullet link stops rendering in default blue. The duplicate notice's Dedup
button takes the accent, and the pill keeps its edge on pages the same colour as it. Long
duplicate URLs in the popup end in an ellipsis instead of being cut off. Setup no longer
calls Dedup "exact-duplicate", shows a literal{URL}on Chrome, or says a rules editor is
still to come. The window title and button labels say "full view" rather than "cockpit".
Fixed
- Closing a tab from its row is immediate, and never needs a second click. The row
used to stay until the whole list had been rebuilt — about a quarter of a second on a
backlog of a few thousand tabs — and on Firefox and Zen a click that landed while that
rebuild ran was lost. The row now goes as soon as the tab has closed, and the list never
rebuilds while the mouse button is down, in both the toolbar popup and the Devour page.
v0.4.1
Two threads, and a fix from the security audit. Site rules stop being a built-in pair and
become a system the user writes: editable and ordered, carrying a disposition beyond a
subfolder — never devour, close without saving, always Zotero — and able to write their
matches into the browser's own tab strip. Separately, Tabglutton now remembers what it has
clipped, so a page already filed is marked wherever it turns up again and an agent stops
paying to re-read it. Tab grouping needs the new tabGroups permission, which browsers do
not surface in the install prompt.
Features
- Site rules are user-editable on the options page — add, edit, remove, and reorder them;
the old built-in GitHub/Social entries are now just the seed, and first match (top to
bottom) wins. Patterns run through the same URL canonicalizer as Dedup and can pin a
path (reddit.com/r/rust), not just a host. - A rule can carry a disposition beyond a subfolder: never devour (the tab is kept open and
reported, never clipped — the agent bridge respects this too), close without saving (with
the same undo toast a dedup close gets), or always send to Zotero (skipping the
Connector's detection, whether or not detection-based routing is on). - Rule dispositions are visible before they act: matching tabs carry a pill in the popup
and the Devour cockpit, and the cockpit inspector names the rule, its disposition, and
the folder it files into. - A rule can also carry a tab-group name and colour, and the cockpit's new Group button
writes that grouping into the browser's own tab strip — preview first, always: nothing
moves that the preview did not show. Unmatched tabs are left alone (no fallback
clustering), pinned tabs are excluded because grouping silently unpins them, a skip
list parks sites that must never be reordered, and grouping never moves a tab between
windows. Needs the newtabGroupspermission, which browsers do not surface in the
install prompt. - Tabglutton remembers what it has clipped. Every successful clip — Devour, the bridge's
tab_clip, Obsidian, a markdown file, or a Zotero save — is recorded under the same
normalized URL dedup uses, so a page filed from a newsletter link is still recognised when
it turns up from a group chat. The Devour cockpit marks those rows and can filter the list
down to either half, andtabs_listcarries aclippedfield so an agent stops paying to
re-read pages already filed. The mark says clipped, never "in your vault": alaunched
clip means the handoff was made, and onlyverifiedmeans something that can see the
filesystem saw the note — the browser watching a download complete, or Gullet finding the
note in the vault, which it now tells the extension about. Neither is a claim about what is
on disk now; notes get moved and deleted. The memory holds 5000 pages, dropping the
least recently clipped first. - A "Copy diagnostics" button on the options page, under a new Troubleshooting heading.
One click puts a paste-ready block on the clipboard: extension version and build target,
engine and its full version, platform, tab and duplicate counts, the scope and clip
destination, which of the three optional permissions are actually held, the bridge's state,
and the last ten bridge failures with the ones that repeated collapsed into a count. It
carries no bridge token, no page addresses and no tab titles — the block is assembled from
a fixed set of counts and enum values rather than from a settings object, so there is
nothing in it to redact. The bridge error log is session-scoped, which on Chrome means it
is empty after the service worker has idled out.
Changed
- Devour now dispatches up to three Zotero Connector saves at once instead of one at a time. That
is the save step only — waking each tab and asking the Connector to identify it are unchanged
and usually dominate a backlog run — and the speedup is reasoned from the serial timings rather
than measured against a live Connector. Everything the run reports is unchanged: same counts,
same per-tab failures, same order. The Obsidian handoff stays strictly serial, because it
borrows the OS clipboard.
Fixed
- Gullet's clip verification stays inside the vault. The note path
tab_clipreports comes
off the browser connection, and it was joined onto the vault directory unchecked — so a
../-laden path had Gullet list a directory elsewhere on disk, stat and read any note by that
name in it, and report a verdict on what it found: a weak existence oracle for anything holding
that connection (SECURITY-REVIEW.md§7). A path that resolves outside the vault now answersunknownbefore
anything is read, the same soft contract every other "cannot check" in that module follows.
No in-vault clip verdicts differently. - A clip that extracts almost nothing now keeps its tab instead of filing junk and closing
it. Waking a backlog is the traffic pattern most likely to draw a bot check, and a
challenge served at the parked URL has no translator, so it fell past the Zotero route and
Defuddle's extraction of "Just a moment…" counted as a successful clip. Anything under 512
characters of extracted text is refused: the tab is kept, and the popup's failure row reads
"too little content" with the character count and what to do about it. Where a known
interstitial signature matches too, the message says so outright. For agents,tab_clip
refuses the page with a newthin-contenterror whiletab_read— which files and closes
nothing — still returns the text, with athinnote saying how little there was and
whether it looks like a challenge. (#49) - The agent bridge now obeys the "Route papers to Zotero" setting. With that setting on,
tab_clipsaved papers into Obsidian anyway, so an agent clearing a backlog quietly filed them
in the wrong place; it now runs the same routing the popup's Devour does, reports
destination: "zotero", and closes the tab only once the Connector confirms the save. A
Connector that cannot take a routed tab fails that clip withzotero-failedand leaves the tab
open rather than falling back to Obsidian. Naming avaultin the call still overrides
everything, and the wire protocol is unchanged. - The scrollbar in the Devour cockpit and the popup now spans the list instead of the
window. It ran the full height of the viewport, starting level with — and behind — the
floating header rather than at the first row; in full screen, with no browser chrome above
it, it reached the top edge of the display. Both surfaces scroll a full-height container so
rows pass under the glass, and no engine can inset a native scrollbar to a shorter band, so
the native bar is now hidden on both and the thumb is drawn over the band between the
header and the action bar. It follows the chrome when the warning banner or the failures
panel changes its height, and it can be dragged. Scrolling by wheel, trackpad and keyboard
is unchanged.
v0.4.0
Two threads. Devour no longer requires Obsidian — a clip can land as a plain markdown file
in the download folder, chosen on the options page or during onboarding. And the browser's
bridge connection now outlives the agent session that opened it, so starting a session is a
local attach rather than a fresh hunt for a socket. A third arrived late, from the audit
before Gullet's first npm publish: the bridge handshake had a relayable proof, and closing
it moves the wire protocol.
Breaking
-
The bridge wire protocol is now 3, and the token proof is bound to the channel it is
presented on. Update the extension and Gullet together; there is deliberately no
downgrade path. Protocol 2 hashed only the token and a nonce, in one function used in
both directions, so the proof was a credential anyone could borrow: every honest client
proves first to whatever answers the marker probe, so a local process knowing no token
could bind a free candidate port, wait to be dialled, forward the real hub's challenge as
its own, and replay the answer to that hub as a peer. That yielded the full tool surface —
list, read, clip, close every tab — plus enough to retire a detached hub and hold its
port permanently. Proven against the live hub and re-run against the fix;
SECURITY-REVIEW.mdcarries the exploit and the before/after. The proof now includes the
role it is claimed under and the loopback port it is presented at, so a proof handed to a
squatter is worthless at the real hub. No fallback and no negotiated downgrade: an
attacker who can imitate the marker can also claim to be old.Upgrading needs one manual step, once. A background hub started by the previous
version outlives the session that spawned it and keeps its port, and a protocol bump
cannot ask it to stand aside — retiring requires proving the token, and the proof is
itself protocol-shaped. If the bridge does not come back after updating, stop the old
hub:pkill -f "gullet.*--detached-hub". Tabglutton's settings now say "Sidecar
version mismatch — update both halves" instead of sitting on "Waiting for a sidecar",
and Gullet names the port and this command in its own error.
Features
- Devour can write plain markdown files instead of filing into Obsidian
(#36). Same frontmatter, the same
Clippings/<site subfolder>/layout and the same note names, written to the browser's
download folder.downloadsis an optional permission, requested when you pick the
destination rather than at install. It is a chosen mode and never an automatic fallback:
the extension provably cannot tell a refusedobsidian://handoff from a successful one,
so anything shaped like "we noticed that failed, saving a file instead" would be a guess. - Onboarding asks where clips land, at step 2
(#42). Choosing markdown files hides
the vault field and drops theobsidian://approval step out of the walkthrough entirely
— a walkthrough that files to disk never needed it. Step 2 previously refused to advance
without a vault name, putting the install gate #36 exists to remove straight back on first
run. - The bridge's
tab_clipobeys the same destination setting as the popup's Devour
(#41), with one stated exception: a
vaultoverride still names Obsidian for that call, because it is a destination the
caller asked for outright. Before this the bridge read the vault directly and an agent
clip failed with vault-missing for anyone in file mode. - Duplicates are shown, not just counted
(#39). The popup and the cockpit both
open with a Duplicates section: one group per canonical URL, the copy Dedup keeps marked
keep, and the cost of closing the rest. Select extras puts those copies into the
normal selection, so duplicates can be devoured rather than only closed. - The browser connection outlives the agent session
(#40,
#29). The first Gullet to find no hub
spawns a detached one and attaches to it as a peer, so session start is a local attach and
the socket is won once per browser session rather than once per agent session. The hub
exits by itself after six idle hours, stands aside for a newer Gullet, and takes a
SIGTERM;--no-detachkeeps the old session-scoped shape. The extension arms its
keepalive only while the hub reports at least one attached session, so a hub with nobody
waiting no longer pins the event page.
Changed
tab_clip's result is a discriminated union, and two of its fields are no longer
unconditional.destinationis"obsidian"or"file";vaultandcontentHash
exist only on the Obsidian variant, andfileis absent exactly when nothing could
confirm the write.confirmedBy—"browser","gullet"or"nobody"— names who
proved the clip landed, replacing a boolean whosefalsemeant "could not check" and
read as "did not land". This shape needed no protocol bump of its own — Gullet is its
only consumer and ships alongside the extension — though the handshake fix above moves
the protocol anyway.- A bridge clip's destination follows the user's setting rather than always being the
vault. No existing install can notice the difference: file mode ships in this same
release, so there is no state in which the old and new behaviour disagree. - Revoking the
downloadspermission is now handled instead of merely failing
(#43). The grant is optional and can
be taken back from the browser's own add-on settings, and it is checked once per Devour
run before any tab is woken — with it gone, a run over 50 discarded tabs used to reload
all 50 and then fail every one of them. The options page now re-checks it on load and, if
it is gone, moves the destination back to Obsidian and says so. That revert is the fix,
not the wording: re-selecting an already-checked radio fires no event, so the file
destination previously had no way left to ask for the permission again. Onboarding
already did this; the popup, the background page and the bridge now name a remedy the
user can actually perform. - A clippings folder is sanitized the same way a note name is in file mode. A base
folder containing: " < > ?or a control character reached the downloads API unfiltered,
where Chrome silently rewrote it and Firefox on Windows could refuse the call outright. - Gullet reads
./.envlast, below the global token file, instead of above it. It is
the only token source read out of a directory the user did not choose — an MCP host sets
the sidecar's working directory to whatever project the agent session started in — so a
cloned repository shipping a.envcould silently replace the token the options page
wrote, putting the session in a realm its author also knows. It can still supply a token
when no global one exists, and it never answers for a global file that merely failed to
read, so a locked secret manager still surfaces its own error and still heals on retry. - A hub's log can no longer be flooded by anything that can open a socket. The refused-
upgrade line carried the caller's rawOrigin, which is unauthenticated input: one
loopback client sustained ~480 MB/s intohub.log, a file the README calls small by
construction. It is now one line a minute with a count of what it suppressed, and the
origin is truncated.
v0.3.1
Identical to 0.3.0. That version went to AMO's self-distribution channel by mistake, and
AMO rejects a version number that already exists on the add-on — measured, not assumed:
uploading 0.3.0 to the listed channel answers "Version 0.3.0 already exists." A version's
channel cannot be changed after upload and a number is never freed, so the store release
of this code has to carry the next one.
The submission page is what makes this easy to get wrong. It states the current channel as
prose ("On your own.") with a small Change link, and the file picker sits directly beneath
it — the radio buttons live on a separate /versions/submit/distribution page, defaulting
to whatever was used last, which for this add-on is every sign:dev build ever signed.
Go to that page first: ?channel=listed arrives preselected.
v0.3.0
Mostly about trusting the bridge on a real backlog: a clip is now confirmed on disk
before its tab is closed, and tabs_list is usable at the scale this product is for.
Breaking
- The bridge wire protocol is now 2, and mixed versions are refused rather than
allowed to look successful. Update the extension and Gullet together. A protocol-1
Gullet would omittabs_list's limit and silently lose tabs; a protocol-1 extension
would ignoretab_clip's vault override and file the note somewhere the caller did
not ask for. Neither is recoverable downstream and both would be reported as success.
Features
tabs_listworks on a large backlog. Filter with a query, group by domain, and
cap the result — and every answer reportsmatchedandtruncated, so a complete
listing is distinguishable from a partial one. The tool description now pushes callers
to triage on metadata before reading anything.- A clip is verified on disk before the tab closes. Gullet runs beside the vault, so
it can answer what the browser cannot: a refusedobsidian://handoff is
indistinguishable from a successful one from inside the extension. A note is matched by
freshness, by thesourceit records, and by a SHA-256 of exactly the text handed to
Obsidian — so a clip that never landed can no longer cost you the tab. Being unable to
check is never treated as failure. tab_clipcan name its vault, validated against Obsidian's own registry rather
than trusted blindly.- Academic papers can route to Zotero instead of Obsidian, opt-in and off by default,
using the Zotero Connector's own classification rather than a hostname list. Requires a
Connector exposing the external API — seedocs/ZOTERO_POC.md. - Gullet is globally configurable and publishable. Settings live at
${XDG_CONFIG_HOME:-$HOME/.config}/tabglutton/config.json, which is deliberately safe
to commit — an inline token is refused. Tokens resolve by an additive precedence chain
ending at a0600file.
Fixed
- Obsidian handoffs no longer fail silently on Firefox. The launch now goes through
an extension-origin page, so the one-time external-protocol approval has a principal
the browser can remember (#18). - A transient tab-read failure is retried without masking a genuinely restricted page.
Firefox reports both asMissing host permission for the tab, and a page on its
restricted-domains list can never satisfy a retry, so those report the engine's own
message instead of advice that cannot be followed. - The toolbar icon is the extension's own mark. It had drifted to an unrelated
drawing, unnoticed because the toolbar icon and the popup header are never in frame
together; the copies are now pinned to each other by a test. - The cockpit's chrome floats over the list rather than displacing it.
v0.2.0
Published on AMO: https://addons.mozilla.org/firefox/addon/tabglutton/
First public release. Every earlier 0.1.x was an unlisted build signed for local
testing, so all of this is new to anyone installing from a store.
Features
- Dedup. Finds duplicate tabs by canonicalized URL — fragments and tracking
parameters stripped, with the strip list configurable — and closes all but one
keeper. Scoped to the current window, or to visible tabs where the browser
exposes that. Needs no access to page content. - Devour. A full-screen cockpit over the open tabs, grouped by host with
duplicates flagged and a per-tab inspector showing exactly where a clip will
land. Every close is undoable from a toast. - Obsidian clipping. Pages are extracted with Defuddle and filed as markdown
with Web Clipper-compatible frontmatter, by clipboard handoff orobsidian://.
Per-site subfolder routing and a configurable Clippings folder. - Chrome support alongside Firefox and Zen, from one source tree.
- Agent bridge. An MCP sidecar (Gullet) exposing six tools —
tabs_list,
tabs_load,tab_read,tab_clip,tabs_close,undo_close— over a
token-authenticated loopback WebSocket, so an agent can triage a tab backlog.
Off until switched on. Several agent sessions share one browser connection,
and nothing is closed thatundo_closecould not put back. - Automatic bridge port. Both ends discover each other across a small
ordered candidate set, so there is no port to configure and nothing to keep in
sync. A fixed port remains available for advanced setups. - First-run onboarding, and a settings page that opens in a tab or embedded
in the Add-ons Manager.
Changed
- Chrome asks for site access at first use rather than at install, so the
install prompt no longer warns about reading data on all websites. Dedup — the
default flow — never needs it. - Note names are sanitized per platform (Windows, macOS, other) rather than
applying the macOS rules everywhere, matching Obsidian Web Clipper on each.
v0.1.2.1
Published on AMO: https://addons.mozilla.org/firefox/addon/tabglutton/
Patch release after v0.1.2:
- Update the fullscreen Devour cockpit tab favicon to use the new Tabglutton chomp icon.
Artifacts include the unsigned extension zip, source zip, and signed AMO XPI.
v0.1.2
Published on AMO: https://addons.mozilla.org/firefox/addon/tabglutton/
Changes since v0.1.1:
- Replace the extension icon with the new Tabglutton chomp mark.
- Add onboarding/settings copy for Devour.
- Improve Devour clipping reliability and progress behavior.
- Standardize release signing on a repo-local .env file with .env.sample.
Artifacts include the unsigned extension zip, source zip, and signed AMO XPI.
v0.1.1
Published on AMO: https://addons.mozilla.org/firefox/addon/tabglutton/
Backfilled GitHub release for the version that shipped on AMO. The full changelog for development since then will appear in the next stable release.