Skip to content

Stet 0.5.0

Latest

Choose a tag to compare

@rainesdrew rainesdrew released this 07 Jul 03:02
1c992f8

Fixed

  • The feedback hub's "Join the Discord" button now uses a permanent invite
    link. The previous invite expired on a Discord timer, which would have
    stranded the button for anyone on an older build after 2026-07-24.
  • Accepting every change on a file now clears its pending indicator. Accept
    wrote the editor's serialized content (which drops the file's final newline)
    to the home branch, while the captured proposal kept the file's exact disk
    bytes (with the newline) — so a one-byte trailing-newline diff survived and
    the blue "still has changes to review" dot never cleared even after you'd
    reviewed everything. Accept now matches the accepted content's trailing
    newline to the captured proposal, so the two come out byte-identical.

Security

  • Markdown previews (change pills, inline proposal previews, and the
    version-history diff) are now sanitized before rendering. Proposal text is
    AI-authored and reviewed by a human — the exact content Stet must treat as
    inert — but it was being parsed straight into innerHTML, so a branch whose
    markdown carried <script>, <img onerror=…>, or a javascript: link would
    execute inside the desktop app's webview (which has IPC to the Rust backend).
    All markdown-to-HTML now routes through a single DOMPurify-backed
    renderSafeMarkdown helper, and the Tauri webview gets a restrictive
    Content-Security-Policy in production builds (with a separate permissive dev
    policy so Vite HMR keeps working) as a second layer.

Internal

  • Split CI to keep the 10x-billed macOS runner off the common PR path.
    Frontend Vitest runs on Linux for every PR; the Rust cargo test runs on
    macOS but only when a PR touches src-tauri/** (it can't run on Linux — the
    crate has macOS/Linux-divergent native deps); and the full suite runs on
    macOS once post-merge on main. Since most pushes are frontend-only, the
    typical PR now costs a cheap Linux run instead of a macOS one.
  • Added a markdown round-trip test harness (src/lib/roundTrip.ts) and a
    golden corpus (src/lib/roundTrip.test.ts) that opens and saves a document
    through the real editor config and asserts it comes back unchanged and never
    grows across repeated save cycles — the guard against silent document
    corruption. The editor's schema/serialization config and the preprocess/
    postprocess passes moved to a shared src/lib/markdownSerialize.ts so the
    test exercises the exact config the live editor uses, not a lookalike.

Fixed

  • A new file's pill no longer touches the document at all when the document
    has content: no hover preview, no click jump. The doc IS the change, so
    there is nothing to reveal; earlier gates tried to detect "already landed"
    from text or provenance and each missed real cases (links and tables defeat
    text matching), letting a duplicate preview shove the layout around. The
    one exception is an empty document (a pending new-file proposal whose disk
    copy is reverted): there the pill still pins the whole-file preview, since
    it is the only way to read what is proposed.

Changed

  • A brand-new auto-accepted file now shows a green "new" badge on its tree
    row, matching the blue "new" badge pending new files get, instead of a
    green count that read as "one edit". Edits to existing files keep the
    green count.

Fixed

  • The seen-on-scroll dwell works again, for real this time: in the packaged
    app's webview, an IntersectionObserver rooted at the editor's scroll
    container never reports these marks as visible at all (verified live in
    the release webview), so "seen" could never fire in any packaged build.
    The observer now measures against the window viewport, which the editor
    fills.
  • A prior fix observed synthetic
    sentinel elements whose geometry was frozen at creation time and computed
    from a viewport height that can be zero for freshly mounted editors, which
    silently killed the dwell for every change: green pills and tree counts
    never cleared no matter how long the content stayed on screen. The observer
    is back on the live margin marks, and marks taller than the viewport (a
    whole-new file's wash) now count as visible when they cover at least half
    the window, so simply having a new document open still earns "seen" after
    the usual dwell.

Fixed

  • Hovering a landed new file's pill no longer inserts a duplicate full-content
    preview above the title and jumps the document. The "already landed"
    check compared the change's raw markdown (including YAML frontmatter)
    against the rendered document, which never contains frontmatter, so it
    failed for every real file and the supposedly suppressed preview rendered
    anyway. The comparison now strips the frontmatter block first.

Fixed

  • The change-mark bar (the colored line in the left margin of changed text)
    now hugs the text column instead of pinning to the window's left edge, so
    it no longer disappears underneath the left sidebar when that's open. It
    sits a fixed gap left of the prose at every sidebar state and window size.
  • Corner icons finally align: the floating panel toggles and the icons inside
    the sidebar headers (hamburger, version-history clock) now share one
    centerline instead of sitting a few pixels apart. The earlier passes
    normalized icon boxes but missed that the toggles and the headers are
    positioned by two different systems; the geometry is now derived from one
    shared constant and documented in the code.
  • The sticky breadcrumb no longer slides halfway under the sidebar header
    while scrolling. The sticky offsets were measured from ResizeObserver's
    contentRect, which excludes padding and the hairline border, so the
    breadcrumb pinned about 15px too high. Offsets now use border-box heights.

Changed

  • Every way a file opens other than clicking it once in the left file tree
    now opens (or focuses, if it's already open) a new tab instead of
    replacing whatever you were looking at: the tray dashboard's "Open in
    Stet ›", clicking a pending proposal from the dashboard, tray notification
    click-through, Finder/open/drag handoff, and New Document. Opening a
    workspace itself from the dashboard (its group row, with no specific file)
    now switches the sidebar over without closing your open tabs, the same
    way it does when you follow a tab into another workspace. The file tree's
    single click is still the one path that replaces the current tab; its
    double-click keeps opening a new tab, now also focusing an existing one
    instead of duplicating it. The shared decision logic is
    openInNewOrFocus in src/lib/tabs.ts.
  • Moved the tray dashboard's "Open in Stet ›" hover action from the Controls
    lens's workspace list to the Review lens's workspace group rows. Hovering a
    workspace's group header in Review now swaps its pending count for
    "Open in Stet ›" and opens that workspace (without navigating to a specific
    file); the Controls lens's workspace rows no longer show this action and
    keep just their effective-summary label and drill-in chevron.
  • Controls list rows for a folder that's "Not watched" now render the folder
    name itself faint too, not just the edge label, so unwatched folders read
    as visually inert at a glance.
  • Controls now has a visible exit affordance: a small back arrow ("‹") at
    the leading edge of the breadcrumb row, in both the sidebar and the tray
    dashboard's Controls lens. It pops one drill level (or exits Controls
    entirely at the top step) through the same path Escape already used, so
    the two can't drift. The dashboard's Controls lens previously did nothing
    at its top step on Escape; both Escape and the new arrow now return to the
    Review lens there.
  • Removed the "Show all previews" eye icon from the Edits header. Showing
    every auto-accepted change's preview at once is now the job of the
    "Unseen" bubble at the top of the right nav, the same floating-pill
    pattern already used for pending change-request bubbles. Click the bubble,
    or its popover's eye button, to show or hide all auto-change previews.
  • The Edits header's remaining controls (Annotate, version-history clock)
    are aligned cleanly now that the odd-sized eye icon is gone from the
    cluster.
  • The sidebar's Files | Controls switcher is gone. Folder controls now open
    from the hamburger menu ("Folder controls…") or a folder's right-click menu
    ("Folder settings…"), same as opening the drill-in itself, just without a
    switcher living in the sidebar full time. The sticky header for a workspace
    tab is now just the menu button, and the subtitle line under it (workspace
    name plus a "waiting in review" count) is gone too — the file tree's own
    per-file dots and counts already show what needs a look.
  • Opening a folder no longer silently turns it into a Stet workspace.
    Browsing is free; initializing is chosen. A folder that isn't already a
    workspace now asks first: "Start watching" sets up history and review
    (the broad-folder safety check still applies), while "Just browse" opens
    a read-only view that creates nothing on disk. Folders that are already
    workspaces open instantly, exactly as before. If the last-opened folder
    is no longer a workspace, startup lands in browse mode quietly instead
    of re-initializing it or interrupting with a dialog.

Added

  • Files with auto-accepted changes you haven't looked at yet now show a green
    count on their row in the file tree, even when the workspace (or one of its
    folders) is set to auto-accept and nothing shows up in the pending-review
    queue. A collapsed folder with unseen changes somewhere inside it shows a
    small green dot. Opening the file and marking its changes seen (or letting
    them dwell-clear) drops the indicator, the same way the "Unseen" bubble in
    the right nav already does. A pending-review indicator still wins over the
    green count when both apply.
  • The right nav (Edits sidebar) is now drag-resizable from its left edge,
    the same way the left files sidebar is resizable. Width is clamped
    between 220 and 480px and persists to localStorage.
  • Browse mode: look around any folder without watching it. The sidebar
    shows the folder's files with a "Browsing · not watched" state line;
    files open as loose documents (edits save straight to disk, no review).
    A "Start watching this folder…" action turns the browsed folder into a
    real workspace when you choose to, keeping your open files open.
  • "All folders" view: a leading crumb in the sidebar's Files breadcrumb now
    backs out to a list of every folder Stet is tracking, with the current one
    marked. Click another to open it; Escape, or clicking the crumb again,
    returns to the tree without switching. This restores the up-navigation
    lost when the breadcrumb stopped offering to open arbitrary parent
    directories, without reintroducing that risk.

Fixed

  • Unseen auto-accepted changes (the green pill, wash, and tree count) now
    clear exactly the way they used to: viewing is what earns "seen", and the
    tree updates live the moment it happens — no clicks needed, and no dead
    green counts left behind.
    • An inline change clears as soon as you scroll it into view and hold it
      there for the usual dwell period — nothing to click. The tree's green
      count updates immediately after, without reopening the file or
      restarting the app.
    • A whole-new file (e.g. an agent creating a brand-new document in an
      auto-accept folder) shows its green pill, wash, and margin mark the
      moment you open it, labeled "new file" and pinned to the top of the
      document. Simply having the new content open and on screen for the
      dwell period clears it — no scrolling and no click required, matching
      how a single-screen inline change already worked. Two earlier passes at
      this got it wrong in opposite directions: one cleared it the instant the
      tab opened (a flash with no chance to actually see the change), the other
      made the dwell mark span the full rendered document, which for a file
      taller than one screen could never reach the visibility threshold the
      dwell timer checks — so the tree's green count stuck around forever. The
      fix observes a viewport-sized region of the change instead of demanding
      the whole thing be on screen at once, so the standard dwell period is
      enough regardless of document length.
    • Opening a file and navigating away before the dwell period elapses still
      leaves it unseen, and the explicit "Mark seen" / "Mark all seen" actions
      keep working exactly as before, independent of the dwell timer.
  • The selected row in the file tree no longer sits slightly cut off under the
    sticky sidebar header when scrolled into view. Its scroll margin now
    accounts for the combined height of both sticky rows above the tree (the
    hamburger header and the breadcrumb, item below), measured at runtime
    instead of a hand-tuned constant that only cleared one row with barely any
    air.
  • The Files sidebar's breadcrumb row ("All folders › workspace › …") now
    sticks directly beneath the hamburger header instead of scrolling away with
    the file tree, matching the header's background and hairline treatment.
  • The right EDITS sidebar's version-history clock icon and the floating
    panel-toggle/close icon above it are now the same rendered size, in
    matching icon boxes, and aligned on the same baseline. A previous pass
    removed the header's "Show all previews" eye icon and claimed that fixed
    the misalignment; it did not — the clock and toggle buttons had different
    icon sizes (15px vs 16px) and different padding/border-radius, which is
    what actually caused the visible mismatch.
  • A whole-new-file change no longer renders a duplicate all-added preview
    widget once its content has actually landed in the document (auto-accepted
    or an auto-landed remote change). Auto-accept never marks a whole-new-file
    proposal's hunk as accepted on its originating branch, so the file kept
    surfacing as a "pending" new-file change indefinitely even after its
    content was already showing in the editor — previously this meant the
    document displayed the content once as real text and once again as a
    pinned preview wash. The preview widget now only renders for the genuinely
    pending case (disk reverted, document blank); a landed new file shows just
    its "NEW FILE" pill.
  • "Folder controls…" now actually opens Controls, whether triggered from the
    native menu bar or the sidebar hamburger menu, and whether or not a
    document tab is currently open. Two bugs combined to make it a silent
    no-op: the menu-bar listener held a stale, mount-time reference to the
    function that switches the sidebar lens (now fixed with a handlers ref so
    it always calls the current version), and the Controls lens had nowhere to
    store its state when no document tab was active (now falls back to a
    workspace-level key). Send-command and Share menu items, which share the
    same listener wiring, are unaffected.
  • A change pill anchored to YAML frontmatter no longer jumps position while
    you hover it. Hovering the frontmatter pill inserts its preview at the top
    of the document, which could shift a neighboring pill's anchor and, in
    turn, flip whether the frontmatter pill itself got pushed down — so it
    visibly snapped between two positions. The frontmatter pill's position is
    now fixed; only its neighbors give way when they sit too close.
  • Hovering a brand-new-file proposal (no prior content to diff against, e.g.
    Stet's own managed CLAUDE.md offer) now shows the full added content in a
    scrollable preview pinned to the top of the document, labeled "New file."
    Previously the preview was silently empty, even though accepting the
    proposal always landed the content correctly.
  • The tray dashboard's Review | Controls switcher is now left-aligned,
    flush with the panel content below it, instead of centered.
  • Hovering a pending-change row in the tray dashboard's Review lens no
    longer highlights identically named rows in other workspaces at once. Two
    workspaces with the same changed filename on same-named branches (e.g.
    CLAUDE.md on claude/notes in both) previously lit up "Open in Stet ›"
    on every matching row simultaneously.
  • The selected file in the sidebar tree is visibly highlighted again. It had
    faded into the same tint as a hovered row after the left-bar lenses
    refactor; selection now gets its own distinct fill. Selecting a file deep
    in a long tree also scrolls it fully clear of the sticky header instead of
    leaving it tucked partly underneath.
  • Sidebar breadcrumb no longer offers to open the workspace root's ancestor
    directories as workspaces. It previously rendered the full absolute path
    (e.g. Users › drew › personal_projects › Stet) with every ancestor a
    button that re-rooted there — one click could initialize an arbitrary parent
    folder, up to the home directory, as a Stet workspace (creating .stet/ and
    a git repo). The breadcrumb is now rooted at the workspace root and navigates
    only within it; switching workspaces goes through the guarded "Open folder…"
    picker.
  • Files no longer stay marked as changed forever after their content was
    accepted. A file whose only remaining difference from the accepted version
    was blank-line placement (no real content left to review) previously kept
    showing a pending-change indicator indefinitely, with no visible pill to
    act on — because a blank-line-only change has no text for the editor to
    anchor a pill to. Accepting a change now also reconciles the proposal
    branch's blank-line layout to match what landed, and the changed-files list
    no longer counts a blank-line-only difference as a pending change.
  • The main window no longer reopens invisibly off-screen. macOS restores a
    window's last position across launches on its own (independent of Tauri —
    there's no window-state plugin in this app); if that saved position was on
    a monitor that's since been unplugged, moved, or resized, the window came
    back focused but with no part of it on any attached display, so an opened
    file looked like it had silently done nothing ("no file selected") even
    though the app was running normally. Every path that brings the window
    forward (file-open handoff, dock click, notification click) now checks the
    restored position against the currently attached monitors and recenters it
    when none overlap.
  • Verified (did not find a live bug to fix): opening a .md file with no
    .stet ancestor — via cold launch, warm launch, or drag-and-drop, including
    deeply nested paths with spaces in folder names — routes to a loose tab and
    never initializes a workspace. Added regression coverage for this shape
    (find_project_root, validate_loose_path, isSupportedLooseFile) given a
    report of a folder being silently initialized after a double-click; the
    most likely actual cause was the off-screen-window bug above making an
    already-correct open look like a no-op.

Internal

  • Left-bar lenses: design system + dead-code cleanup, the last of five
    branches (claude/lens-treerow, claude/controls-drill-in,
    claude/sidebar-lenses, claude/header-lenses, claude/lens-cleanup)
    that replaced the old FileTree/FolderControlsPanel split with one shared
    TreeRow primitive, one LensSwitcher, and one settings surface
    (ControlsPanel) used by both the sidebar (Files | Controls) and the
    tray dashboard (Review | Controls). DESIGN_SYSTEM.md now documents the
    Lenses, Controls surface, and Drill-in/breadcrumb patterns as shipped.
    Confirmed no dead code remains from the transition: no folderControlsOpen
    references, no .fc-* CSS, no FolderControlsPanel file or references, no
    FolderControlsPanel-era props (defaultCollapsed, rootActions,
    rootExtra), and no raw hex colors introduced outside design-tokens.css.

Added

  • Review | Controls lens switcher in the tray dashboard, replacing the old
    "To review / Settings" toggle and finishing the settings-surface
    consolidation the sidebar started last branch. Review is the triage queue
    (workspace groups with counts, file rows, hover a row to reveal "Open in
    Stet ›", a "Just landed" divider for what already landed); clicking a row
    opens that workspace in the main editor and lands on the file with its
    pills visible. Controls is the same drill-in ControlsPanel the sidebar
    uses, reached through a new wslist step listing every watched workspace;
    drilling into one re-points reads and writes at that workspace's path, so
    a folder setting can be flipped for a workspace that isn't the one open in
    the editor. The old per-workspace pill row is gone: "Open in Stet" is now a
    hover action on wslist rows, "Proposals(N)" is superseded by the Review
    lens outright, "Notify" is the workspace root's own Notify pipe inside
    Controls, and "Stop" is a "Stop watching this workspace…" action on that
    workspace's boundary step. FolderControlsPanel, the nested-inspector
    surface it replaces, is deleted; one settings surface (ControlsPanel) now
    serves both the sidebar and the header app. Move root / Split root aren't
    offered from the header app's Controls lens: those act on whichever
    workspace is open in the main editor, not a path, so wiring them to an
    arbitrary drilled workspace here risked silently rerooting or splitting
    the wrong project. They still work as before from the sidebar.
  • Files | Controls lens switcher in the main sidebar. The sticky header above
    the file tree now shows a text-pipe switcher for each workspace tab: Files
    (the tree you know) and Controls (the drill-in settings surface added last
    branch). Each open tab remembers its own lens choice independently, entirely
    in memory. The Files lens gets a subtitle showing how many files are waiting
    in review (e.g. "docs · 3 waiting in review"), and file rows with more than
    one pending proposal show the count directly instead of a plain dot. The
    view menu's "Folder controls…" entry is gone; the switcher is the one entry
    point now, and every place that used to open Folder controls (the menu bar,
    a folder's context menu, the Auto-send badge) opens the Controls lens for
    the active tab instead. Escape inside Controls still pops one level at a
    time and now exits back to the Files lens for that tab. Loose file tabs are
    unchanged: no lens row, no Controls.
  • Join a shared workspace from a link. File → Join Shared Workspace… (or Cmd+Shift+J): paste the clone link from an invite, choose a folder to save it in, and Stet clones the workspace and opens it, no git clone or GitHub Desktop required. If GitHub isn't connected yet, the dialog walks through the same device-code sign-in as sharing.
  • Version history for any document. Click the clock at the top right (or the clock on an unseen change) to open a History panel in the right sidebar, listing every saved version of the open file, newest first, with who made it and when. AI versions carry an "AI" badge. Click a version to view it read only, with the change that version introduced highlighted right in the document: added text is washed, removed text is struck through. A banner lets you jump back to now. Click "Restore this version" and that version comes back as your live document. A restore is not a proposal to approve. You already chose it, so it lands as a fading highlight you can see and revert, the same way an auto-accepted edit does. Bursts of rapid saves collapse into a single "N edits" run so the timeline reads as checkpoints, not per-save noise; expand a run to see the individual saves. History is per document and per workspace, and reads straight from git, so there is no new storage.
  • Re-root a project (Folder controls, root row, Edit). Three ways to change what a project covers, all reachable from the locked root boundary. "Pick new directory" moves the project to a different folder: the old folder stops being watched and the new one takes over your workspace settings (past review history stays with the old folder). Point it at a parent folder instead and Stet widens the project to cover it, folding the old project in; sibling folders come along unwatched so widening never quietly expands what gets reviewed, and any nested project Stet did not create is left untouched. "Split root" turns each checked subfolder into its own separate project and dissolves the parent. Re-rooting a shared workspace is not supported yet, and Stet stops you before it would drop unreviewed changes.
  • The stet moment. Accepting a change now has a quiet signature: the pill dissolves in place, and once the change lands the new text settles into the page with a brief green wash and a dotted "stet" underline that fades. Rejecting lifts the pill off the page instead; nothing red, nothing loud. Accepting a whole branch settles every landed paragraph at once. Unseen highlights stop vanishing abruptly too: when a change is marked seen (by scrolling past it or by hand), the green margin bar dissolves into dots and fades out. The whole choreography collapses to instant under macOS Reduce Motion.
  • Remote review: auto-land a collaborator's changes. On a shared workspace, set a folder's Remote review to "Auto-accept" and when you fetch, a collaborator's edits in that folder land in your document immediately — highlighted as unseen and attributed to them by name — instead of waiting as a proposal. Reverting and mark-seen work just like a local auto-accepted change. Folders left on "Needs approval" still surface remote edits as proposals, and a remote edit that overlaps one of your own pending changes falls back to approval so you resolve the collision by hand. Unshared workspaces are unaffected.
  • Auto-accept review policy. Set a folder to "Auto-accept" in Folder controls and an agent's edits there land in your document immediately instead of waiting as a proposal. They're not silent: each landed change is highlighted in the margin as "unseen" and gets a pill with Revert and Mark-seen. Scroll past a highlight and it clears itself; or clear a whole file from the "Unseen" group in the changes panel. Revert backs a single change out. Folders left on "Needs approval" behave exactly as before. Notifications stay quiet in auto folders (Notify follows Review).
  • Edits made while Stet wasn't running are caught on open. When you open a workspace, Stet now compares what's on disk against the last approved version and turns anything that changed into a proposal (or, in an auto-accept folder, lands it highlighted as unseen). So an agent (or you, in another editor) can edit a file while Stet is quit, and the change waits for review the next time you open it instead of landing unseen. New files created while it was closed are captured too, with their content kept on disk. A stale batch left behind by an interrupted session is cleaned up on open rather than re-proposed, and a file left half-saved by a crash is restored to the approved version instead of showing up as a bogus edit.
  • Background workspaces now capture edits, not just notify. A workspace watched from the menu bar (but not the one you're currently looking at) used to only pop a notification when an agent edited it. Now it turns those external edits into proposals the same way the focused workspace does, so the change is waiting for review when you switch to it. This holds even with the main window closed. Capture is independent of Notify: a folder with notifications turned off still captures the edit as a proposal, it just doesn't ping you.
  • Edits made while Stet was closed are reconciled at launch for every watched workspace, not only the one you open. So an agent (or you, in another editor) can edit a background workspace while Stet is quit, and the change is waiting in the dashboard's pending list the next time you launch, without you having to open that workspace first.
  • Folder controls panel. One inline sidebar surface (File → Folder controls…, the sidebar menu, or right-click a folder → Folder settings…) to manage Watch, Review policy, Notify, and Hooks per folder — plus Remote review on shared workspaces (whether a collaborator's changes land automatically or wait for approval). It's a calm folder tree: each row shows an icon summary and whether it sets the workspace defaults, customizes them, or inherits. Click a row to open its inspector. Workspace defaults live on the root; child folders inherit them unless they override, and any override reverts with one click (the root has Revert all). The root's Watch is a locked project boundary, with Move root, Split root, and Remove Stet grouped under Edit rather than a plain toggle. A control to hide unwatched folders keeps big trees scannable.
  • Auto-send now tells you what it did. When it is on, a quiet "Auto-send on" note sits in the tab bar; click it to open the Send command settings. When a confirmed comment launches your agent, a brief "Sent to your agent" hint appears. If the launch fails, a dismissible "Auto-send failed" message shows in the tab bar instead of vanishing into the console.
  • The sidebar follows the active tab, everywhere. Tabs now remember which workspace they belong to, so documents from different workspaces can be open side by side. Switching to a tab from another workspace switches the whole sidebar (tree, branches, pending changes) to that workspace, with the file highlighted and scrolled into view. Explicitly opening a folder still starts fresh.
  • One window for everything. Opening a loose file when Stet is closed now gives you the full window (tabs, sidebar with the loose-file panel) instead of a separate bare editor. The old standalone loose mode is gone. With nothing open at all, the window shows the welcome screen.
  • Tabs that actually work. Open several documents at once: double-click a file in the sidebar to open it as a new tab (single click still replaces the active tab), switch between tabs, close them with the ×. The tab bar spans the window above the side panels, and everything tucks below it. Double-click had never worked; the native double-click event is unreliable in the webview, so Stet now detects it itself.
  • Loose files join the window. Opening a file that isn't in any workspace no longer replaces your whole view. It opens as a tab next to your workspace documents, and while it's active the left sidebar switches to a loose-file panel: the file's path (none of it watched), plus two actions: watch this folder, or move it into a workspace. Edits to loose files save straight to disk, never through git.
  • Navigate the sidebar without changing the workspace. Double-click a folder to view just that folder's contents. The breadcrumb grows a segment for each level and clicking a segment goes back up. Switching tabs pops the view back so the open file is always visible. The watched workspace never changes when you do this.
  • Resizable files sidebar. Drag its right edge anywhere from 200 to 600 pixels. The width sticks across launches.
  • Show in Finder. Right-click any file or folder in the sidebar.
  • Re-send a collaborator invite. The Share dialog offers "Send invite email" and "Copy invite text" for existing collaborators, with a preview of the message. Before this, the invite could only be sent at the moment of first sharing.
  • Share a workspace. Connect GitHub from the Share dialog, and Stet creates a private repo, pushes your documents, and drafts an email invite for a collaborator. Sync and push from the same dialog.
  • Watched folders for mixed repos. Scope Stet to just the prose folders inside a repo that also holds code, with a tri-state folder picker. Stet places one managed CLAUDE.md at the top of each watched island and removes it cleanly on unwatch.
  • Folder-scoped sidebar. The sidebar lists what is actually in the opened folder, including untracked files, with a navigable breadcrumb and view toggles (watched only, show CLAUDE.md).
  • Manage every watched workspace from the tray dashboard. Each watched root is the Folder controls root row itself: one row with the workspace name, its path, and the settings icon summary. No duplicate header above it. Its chevron unfolds the same Folder controls tree the main sidebar uses (Watch, Review policy, Notify, Hooks, and Remote review per folder), so watch scope is no longer edited with a separate tri-state picker. Each root row also carries an "Open in Stet" button that opens the workspace in the editor, and a "Proposals" count that expands the changes waiting for review in that workspace. Clicking one opens it. Only review-gated changes are counted. Folders set to auto-accept never sit pending.
  • Fold the Folder controls tree from its root. The root row in the left-nav Folder controls panel has the same chevron: collapse the whole tree to one row, expand it again when you need it.
  • New-file proposals. Documents created outside Stet (by an agent, or any other tool) are captured as proposals, marked NEW in the tree, and open like any other file.
  • A NEW badge that means something. NEW marks documents that appeared since watching began, recently, and that you haven't opened yet. Opening clears it; badges fade after seven days. Pre-existing files no longer light up NEW when you first open a folder.
  • Roadmap and release notes links in the feedback hub. Two new cards open the public pages on the marketing site (getstet.app) in your browser, so you can see what's coming and what shipped in each build.

Changed

  • File tree indentation is very slightly wider (16px per level instead of 14px), as part of unifying the tree row styling that Folder controls and future sidebar surfaces will share.
  • One color language for changes, everywhere. A change now reads by three colors and nothing else: blue is a local change waiting for you (and NEW is blue too), yellow is a collaborator's change, green is a change that already landed. The color says the state; the pill says who. So a collaborator's change comes two ways now: yellow when it needs your approval, hidden until you hover its pill like any proposal, or green and already landed with their name on the pill. Gold is no longer part of this; it marks AI notes in the document and only that. Selection in lists is a plain neutral highlight instead of a colored bar, and the accept "settle" wash is green rather than gold.
  • The tray dashboard splits into To review and Settings. To review is a plain queue: what needs a decision sits up top with a count of just those, and changes that already landed drop below a quiet "Just landed" line. Settings holds the folder configuration, without repeating the review count on every row. You glance at review constantly and touch settings rarely, so they no longer share one crowded row.
  • Folder settings read as text, not switches. Watch, Notifications, and Hooks are now "on / off" words with the active one inked, matching the "auto / review" policy selector, so every control in the inspector is the same shape. A collapsed folder row shows a single word only when it differs from what it inherits ("auto-accept", "not watched", "custom"), replacing the row of four small icons that made you decode them.
  • Watched Folders is now Folder controls. The old picker modal is gone; folder settings live inline in the sidebar and cover Notify, Hooks, and Review policy alongside Watch, not just watch/unwatch. The Configure hook command modal (formerly "Configure AI Send Command") now only edits the command template — whether it fires automatically is a per-folder Hooks setting in the panel.
  • The "active watcher" is now called auto-send, everywhere. The old name collided with Stet's file watcher and confused debugging. The setting lives in the same place (Configure AI Send Command), and workspaces that turned it on under the old config key keep it on.
  • One folder controls tree everywhere. The tray dashboard now uses the same Folder controls tree as the main sidebar, instead of its own tri-state watch picker. Watch scope, Review policy, Notify, and Hooks are edited the same way in both places. The dashboard's "Pending proposals" (both the per-root list and the all-workspaces section) now shows only changes waiting for review. Folders set to auto-accept are excluded, since those land without review.
  • Stopping a watch cleans up after itself. Stopping watching from the dashboard now confirms, then removes Stet's .stet folder and its managed CLAUDE.md sections. Your own files and notes are never touched. Before this, a leftover .stet could silently re-adopt the folder as a workspace the next time you opened any file under it.
  • Design system. Centralized color and type tokens, self-hosted fonts, and a full migration of the UI onto them.
  • External-edit capture now happens inside Stet itself. When an AI agent or another editor writes to a watched file, Stet captures the change as a proposal directly, without routing the work back out to the editor window and waiting for a reply. Capture keeps working while the main window is hidden or closed, and a change made during a rapid file switch is no longer missed.

Fixed

  • Changes to a document's frontmatter now show up in review. A proposal that edited the YAML frontmatter (title, status, tags) or inserted a section right below it used to click through to nothing: the editor keeps the --- block out of the document, so the change had no text to anchor a pill or preview to. Now a body change that sits just under the frontmatter anchors to the first real line below it, and a genuine frontmatter edit shows a "Frontmatter" preview pinned at the top of the document with the before/after. This mostly bit frontmatter-first docs like backlog items, where agent edits routinely touch the title or status.
  • A watched folder that wasn't a git repo captured nothing. If you opened a folder that had a .stet directory but had never been turned into a git repo, every external edit vanished with no proposal and no error. Stet now initializes a repo when you open such a folder, using whatever is on disk as the baseline, so review turns on. Combined with reconcile-on-open, edits that were already sitting in that folder surface as proposals once the repo exists.
  • External edits that Stet can't capture now say so. If a watched folder isn't a git repo, or its .git can't be written, the change used to vanish silently with no proposal and no error. Now a red banner names the file: "Stet couldn't capture an external edit to {file}. The change is on disk but not in review." Your content is never blanked on failure.
  • Send command tokens are shell-quoted. {filepath}, {filename}, and {dir} values are single-quoted before substitution, so a file named test $(whoami).md is handed to your agent as a literal name instead of executing inside the command. The default template now keeps the token outside its quotes so the quoting holds; keep tokens outside your own quotes in custom templates too.
  • Stet can no longer watch your whole machine by accident. Creating a workspace at your home folder, a system folder, or the root of a drive is refused outright. Broad folders like Downloads ask for confirmation first. Opening a loose file never creates a workspace as a side effect, and watching a loose file's folder is blocked before anything touches disk when that folder is too broad.
  • Opening a file while Stet was already running could silently do nothing. macOS sometimes delivered the open to a throwaway second process that exited before handling it. Opens now route to the running app, and a missed open is recovered the moment the window regains focus.
  • Loose tabs would not close. The close button on a loose file's tab was a no-op.
  • The first line of a document could sit just above the viewport after switching tabs, because the previous tab's scroll position carried over. Each newly opened document now starts at the top; reloads of the same document keep your place.
  • Transparent sidebar panels. Headers and panels rendered see-through because their colors were never defined in the theme. They are solid now, the selected file is highlighted in gold, and selecting an off-screen file scrolls it clear of the sticky header.
  • Pending proposals in the tray dashboard are clickable. Clicking one opens its workspace with the changed file selected.
  • Second launches reuse the running app. Two Stet instances used to fight over the same workspace and could corrupt proposals.
  • Brand-new documents were blanked by the old proposal capture. New files now keep their content on disk.
  • Ordered and unordered lists render their markers again.
  • Sidebar headers stay pinned while the file list scrolls beneath them.
  • Feedback privacy: submissions with contact info go to Discord only, not into the public feedback repo.

Internal

  • Remote review internals (remote_review.rs): on fetch, each remote-branch file is partitioned by effective_remote_review; auto files land through the same seen-state flow as local auto-accept, committed with the collaborator's authorship (write_file_to_branch_as) and recorded in seen.json with their name. Overlap with a pending local proposal is decided on git2 diff hunk line ranges (no hashing) and falls back to approve. Auto-landed files drop out of the remote-branch proposal listing for free via the existing home-vs-remote content-equality filter, which also makes re-running a no-op (the anti-ping-pong guard). fetch_remote emits workspace:proposals-updated so the open file reloads. The retired ShareMode enum is deleted (old share.json mode fields are ignored on read).
  • Auto-accept internals: a .stet/seen.json store (seen_state.rs) tracks how much auto-landed history each file has shown; accept_change's body factored into commands::apply_accept, shared by manual accept, auto-accept (in proposal_intake), and revert. Auto-accept writes go through the WriteLedger so the watcher can't re-capture them (asserted by an anti-loop test). All hunk hashing stays on the frontend (lib/diff.ts) — the backend treats hashes as opaque strings and hands the UI the two content snapshots to diff — so the two sides can't disagree on a hash (no Rust diff port). Seen-on-scroll uses a pure, unit-tested timing helper (lib/seenScroll.ts) driving an IntersectionObserver. Commands: list_unseen, mark_hunk_seen, mark_all_seen, revert_hunk.
  • Typed tab model (lib/tabs.ts), manual click-intent classification, sidebar width and watch tri-state extracted as pure, unit-tested modules. Test suite grew from 109 frontend + 71 Rust (v0.4.0) to 175 frontend + 133 Rust. QA scripts added per feature under qa/.
  • New shared tree primitives, src/components/tree/TreeRow.tsx and src/components/tree/LensSwitcher.tsx (left-bar lenses Phase 1). FileTree.tsx now renders every row through TreeRow instead of its own markup; behavior (select, double-click new tab, folder navigate-into, context menu, badges) is unchanged, only the indent metric moved to the unified 10 + depth*16. LensSwitcher is not wired into any screen yet — that lands in Phase 3 (sidebar) and Phase 4 (header app). FolderControlsPanel.tsx is untouched.
  • Folder controls becomes a drill-in: ControlsPanel.tsx (left-bar lenses Phase 2) replaces FolderControlsPanel in the main app's sidebar, both from the view-menu "Folder controls…" item and the file tree's "Folder settings…" context menu. Instead of nested inline inspectors, it's one flat step per screen (listfolderboundarysplit) on an inset --surface-controls background, navigated by a breadcrumb (ancestors as links, current segment bold) and Escape (pops one level; exits the lens at the top step via an onExit callback, wired for real once lenses land in Phase 3). Every capability carries over: Watch/Review/Notify/Hooks/Remote review per folder, "Set here · Clear" vs "Inherited from <ancestor>" (ancestor names link to that folder's detail), the root's locked Watch with its Move root/Split root/Remove Stet boundary actions, and the split checklist. State transitions, the breadcrumb builder, and the list step's effective-summary label (Not watched / Needs approval / Auto-accept / Custom / Inherits) are pure, table-tested functions in src/lib/controlsDrill.ts. The reroot/split/move-picker handlers moved (not rewritten) into src/lib/folderActions.ts, shared by both panels during the transition; FolderControlsPanel.tsx is marked deprecated but stays in place — the tray dashboard still embeds it until Phase 4.
  • Config v2: a per-folder settings model (Watch, Notify, Hooks, Review, Remote review) replaces the single global auto-send toggle and the watched/unwatched folder lists as the underlying storage in .stet/config.json. Existing workspaces migrate on first load with behavior unchanged (approval-first review, prior watch scoping and auto-send/hooks state preserved); brand-new workspaces default to auto-accept review. No UI changes yet — get_folder_settings/set_folder_setting and the folder_settings module are the foundation the next phase's Folder controls panel builds on.
  • Folder controls robustness: a Watch change through set_folder_setting now reconciles the managed CLAUDE.md placement (matching the legacy watch-config path); config writes are serialized behind a lock so rapid per-click saves can't clobber each other; folder-tree resolution helpers (hasExplicit, anyExplicit, collapsedSourceLabel, settingSourceLabel) are pure and unit-tested. Move/Split root open their UI but defer execution to the re-root phase.