Skip to content

Releases: datlechin/pitboard

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 28 Sep 19:11
v0.5.1
d34a1a7

Fixes that writing the documentation site turned up, and pitboard's facts about Claude Code
read again, from 2.1.284.

Added

  • In pitboard-core, assumptions::read_on says which systems' builds a fact is read from,
    as the new assumptions::Platform.

Changed

  • pitboard's facts about Claude Code are read from 2.1.284, and from its macOS build as well
    as its Linux one. The weekly check reported three facts moved from 2.1.281; all three were
    read from the Linux build, which has no keychain code, or from the runtime Claude Code
    ships in. The one real change is that Claude Code no longer moves its login to the
    plaintext file when the keychain is locked, and nothing in pitboard depends on the old
    behaviour.
  • The README introduces pitboard and links to
    docs.usepitboard.com, where the guides and reference are.
  • SECURITY.md is only the security policy: which versions get fixes, how to report a
    vulnerability, and what pitboard does and does not protect against. Where parked logins
    are kept and what leaves your machine are on
    Security and privacy.
  • How to make a release, how to replace the update key, and the Sparkle and Homebrew
    measurements a release rests on, moved from CONTRIBUTING.md to RELEASING.md.
  • How the code is laid out, and the measurements of macOS, Claude Code and Codex it rests
    on, moved to ARCHITECTURE.md.

Fixed

  • pitboard status --fresh, and Refresh in the app, asked Anthropic or OpenAI again during
    a wait the service had asked for. The 0.3.0 notes and pitboard doctor said they did not.
    They keep that wait now, and still ask a service again after it could not be reached.
    When a service had never answered for an account and then could not be reached, pitboard
    said the account was rate limited.
  • With PITBOARD_NO_ARGV=1, renewing a parked login too large for security's standard
    input spent its refresh token and then could not store the new one. The parked login was
    lost. pitboard refuses before asking the service now, and the parked login stays as it was.
  • A switch whose login could not be read back said to run pitboard again, which only
    reads. It names the pitboard use that finishes or undoes the switch.
  • With Codex's auth.json missing, pitboard doctor suggested pitboard use codex/<label>,
    which refuses while nothing is signed in. It says to sign in with codex login.
  • The man page listed a page per command, such as pitboard-status(1), and none of them is
    installed. It sets out every command, with its arguments and options, on its one page.
  • The app never said that Claude Code is not installed: it waited for a read to fail in a
    way no read does. It says so when it finds neither claude nor codex, and neither tool
    has a login or an enrolled account.

Security

  • The menu bar app ignored PITBOARD_NO_ARGV, and so did daily renewal unless its
    scheduler set it. Either could pass a large login to security as an argument, which
    another process running as you could read while the call lasts. The app reads
    PITBOARD_NO_ARGV from its own environment, and a schedule installed while it is set
    keeps it.

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 28 Sep 09:39
v0.5.0
a5d2413

Changed

  • The menu bar item opens a menu instead of a panel, as macOS asks of a menu bar item. Each
    account is an item under its tool, checked when it is the one in use and subtitled with
    what its limits stand at, and choosing another switches to it. Advice to switch, anything
    else worth a look, and an update that is ready come first. It opens at once, closes the
    way every menu does, and works from the keyboard and with VoiceOver.
  • Everything that needs typing or room is in pitboard's window: every account with its
    limits drawn out, everything pitboard has to say in full, the activity log, and what it
    finds about this Mac. Adding an account, signing in again, naming the account in use and
    renaming one are sheets over it, and a sheet stays open while your browser is in front. The
    panel closed the moment the browser came forward, and took the sign-in's code field with
    it.
  • A switch, a rename or a forget that fails says why in an alert, instead of in a line of
    the panel that the next read could replace before anyone saw it. A sign-in or a name that
    fails says so in its sheet, with what you typed still there.
  • Settings has a Command Line tab of its own. "Open pitboard at login" says when macOS is
    waiting for you to allow pitboard in Login Items, and opens them. "Menu bar shows" picks
    the account and its usage, the usage alone, or the icon alone, for a crowded menu bar.

Added

  • Rename an account from the window, which only the command line could do.
  • In the window's account list: Use with a double-click or Return, Forget with Delete, and
    Copy Email Address and Sign In Again in each account's menu.
  • About pitboard in the menu.

Fixed

  • The panel said "updated just now" for as long as nothing else changed. The menu says the
    time of the last read, and the window's reset times move on while it stays open.
  • Giving up on an interrupted switch was reported with a warning sign, as though it had
    failed. It is a note now, which you dismiss once read.
  • A failure to turn daily renewal on or off was said in the panel rather than beside the
    switch in Settings, and a failure to change "Open at login" was not said at all.
  • Switching one tool's account put away the advice about another tool's account that had
    run out, and it was not offered again until that account ran out once more.
  • Advice to switch kept offering the account it first named after that account was
    forgotten, expired or ran out itself, and choosing it failed. It now offers the best
    account there is at each read, and goes away when there is none.
  • A read that was already waiting on Anthropic or OpenAI when you switched landed after the
    switch, with who was signed in before it, and put away what the switch said, such as the
    reminder to restart running codex sessions. A switch made in a terminal during such a
    read was taken as seen, and the menu bar went on naming the account before it until the
    next read.
  • Why an account's numbers are not new was said only for an account that could not be
    used. The window says it for every account, the one in use included: that its service
    could not be reached or is rate limiting, or that Claude Code's session has expired.
  • The panel and the window described accounts differently: the window had no way to sign in
    again or forget an account and did not say how long a parked login lasts, and the panel
    did not say how long the account in use lasts at its rate. Both now say the same things,
    worked out once.

v0.5.0-rc1

v0.5.0-rc1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 28 Sep 09:27
v0.5.0-rc1
a5d2413
pitboard 0.5.0-rc1

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 26 Sep 10:52
v0.4.1
6c1b90b

Changed

  • A usage reading only moves forward. pitboard keeps one reading per account, every front
    end records into it and every front end shows it. A later reset is a newer window, and
    within one window the higher share is the newer, so numbers a session has held since its
    last response can no longer replace newer ones, whoever writes last. Where a window's
    share falls, as it does when a plan is upgraded in the middle of one, the old, higher
    share stands until that window resets.
  • The app's Documentation item opens docs.usepitboard.com.

Fixed

  • Sessions on one account, and the menu bar, disagreed about the account in use. Each
    session showed the numbers of its own last response, so busy sessions read 22%·6% while an
    idle one read 20%·5%, and the menu bar showed what it had last asked Anthropic, or Claude
    Code's own cache. The status line now records what its session's responses bring wherever
    it is newer, every session shows the newest numbers any of them has recorded, pitboard status does the same, and the menu bar follows the readings within seconds without
    asking anyone. The README's status line settings add "refreshInterval": 10, so an idle
    session picks them up too.
  • After a switch, a session still holding the numbers of the account before could record
    them as the account switched to, until the next read. A session's numbers do not say
    whose they are, so the status line now keeps what each session passed at its last run,
    and which account Claude Code's config named then, in ~/.pitboard/sessions.json. It
    records only what a session's response moved with the same account named before and
    after, and nothing in the half minute sessions take to follow a switch, so a session left
    idle is never recorded as anyone, whatever has happened to other accounts since: a
    switch, a /login, an account forgotten. What a session passes the first time pitboard
    sees it is left out, and so is what it passes as the account named changes; its next
    response is recorded. A /login in Claude Code leaves pitboard no time to count from,
    and for the half minute after one a session's response can still be the account
    before's. The status line leaves that out where pitboard's reading of the account before
    has the same window; otherwise, or where the two accounts' windows reset within the same
    minute, the account signed in after can show the higher of their shares until that
    window resets.
  • The panel's advice to switch, once the account in use had run out, went away at the
    app's next read, as soon as the panel was opened again, while the account was still out.
    It now comes as soon as the numbers show the account run out, stays for as long as they
    do, and is told once.

v0.4.1-rc1

v0.4.1-rc1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 26 Sep 10:43
v0.4.1-rc1
6c1b90b
pitboard 0.4.1-rc1

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 12:35
v0.4.0
0edfc0e

Changed

  • Installing pitboard no longer needs Rust. brew install datlechin/tap/pitboard is now a
    cask, on macOS and Linux, that installs the release's own command line for the machine,
    with its man page and completions: signed and notarised on macOS, attested, and checked
    against the checksums the release took of its own files. It was a formula that fetched
    Rust and compiled pitboard, which took minutes and a toolchain nobody had asked for.
  • The menu bar app's cask is pitboard-app, and the app carries the command line inside
    it, at Pitboard.app/Contents/Helpers/pitboard. The cask links it onto PATH with its
    man page and completions, so an update, from Sparkle or from Homebrew, moves the app and
    the command line together. They used to be two installs that moved separately, and the
    app's cask depended on the formula. The two casks conflict, since both link pitboard.
    The app's bill of materials lists the command line and the crates only it uses. The
    release writes the tap's own README with the casks, so it names both.
  • A release no longer publishes a source tarball. Only the formula installed from it, and
    the source is on crates.io and in the tag.
  • pitboard-core: the report uninstall returns says whether the renewal schedule was
    taken away, and it and doctor::Facts are now #[non_exhaustive], so a later field is
    not a breaking change. A breaking change for anyone who built either with a literal,
    declared as such; nothing changes for the command line or the app.

Added

  • Settings can put the app's command line on the PATH. The Advanced tab says which
    pitboard a terminal runs, whether it is the app's own and how that one is updated, and
    when there is none, "Install command line tool…" links /usr/local/bin/pitboard to the
    one inside the app, once macOS has asked for an administrator's password. It never
    replaces a pitboard somebody installed or a file that is not a link, and never links to
    the temporary copy macOS runs an app from before it is moved to Applications.
  • An account whose parked login has expired has a "Sign in again" button in its row, which
    starts the same sign-in as adding an account. The row used to say to run pitboard enroll <label> --sign-in in a terminal, which somebody with only the app does not use.

Fixed

  • Daily renewal turned on from the app renewed nothing. The schedule recorded the program
    that asked for it, which from the app was the app itself, so launchd started a second
    menu bar app every day and no parked login was renewed. The app now names the command
    line inside it. A schedule an older app wrote starts the app, which now hands the renewal
    to that command line, so the old schedule keeps renewing until the app is opened. Opening
    it then points the schedule at the command line, which pitboard log records. The app
    turns renewal on only where that command line will still be there when the schedule runs:
    not from the temporary copy macOS runs an app from before it is moved to Applications,
    which is gone once the app quits, and not from a build with no command line inside it.
    Settings says why. New codes, from the app's bindings: schedule_program_missing,
    schedule_program_temporary and schedule_program_unnamed. pitboard doctor reads the
    installed schedule back and fails when the pitboard it runs is gone or is an app, and
    says to turn renewal off and on again.
  • On Linux, a renewal schedule turned on from the command line stopped working at the next
    brew upgrade. It named the running pitboard with every link resolved, which from
    Homebrew is inside a directory named after the version, and the upgrade deletes that
    directory, so systemd failed to start it every day after. It now names the path pitboard
    was started by, such as the link in Homebrew's bin, when that leads to the same program.
  • Removing pitboard leaves no renewal schedule behind. pitboard uninstall takes it away
    first and says so, as schedule_removed in --json, where before it was left running
    pitboard renew every day. Both casks take it away on brew uninstall --zap, and not on
    a plain brew uninstall, because Homebrew runs a cask's uninstall steps on every upgrade
    too. Neither touches ~/.pitboard: it is the only index of the parked logins, so run
    pitboard uninstall before removing pitboard.
  • Advice about upgrading and removing pitboard no longer assumes Homebrew. A state file
    from a newer pitboard said to run brew upgrade pitboard, and pitboard uninstall said
    to remove the binary with a package manager. Both now say to update or remove pitboard
    the way it was installed, and the first adds that the app's Check for Updates moves only
    the app and the command line inside it.
  • On Homebrew 6 and later, brew install --cask datlechin/tap/pitboard failed with
    build.rb ... exited with 1 unless the formula was installed first. Homebrew trusts only
    the name it is asked to install, and refused to build the formula the app's cask depended
    on. pitboard-app depends on nothing.
  • cargo binstall pitboard no longer falls back to a third party's build when it cannot
    fetch the release's.

Upgrading from 0.3.0

In the tap, the name pitboard now means the command line.

From the old formula, brew update warns that it did not install the cask that replaces
it, and pitboard stays at 0.3.0. The two commands it prints leave the formula in front of
the cask, so install the cask in its place instead:

brew uninstall --formula pitboard
brew install datlechin/tap/pitboard

From the old app cask, brew update replaces the app with the command line, once. Your
settings and ~/.pitboard stay. To get the app back, with the command line inside it, run
these in this order, before or after that brew update:

brew uninstall --cask pitboard
brew uninstall --formula --force pitboard
brew install --cask datlechin/tap/pitboard-app

Leave --zap out when you remove the old app cask. Its zap moves ~/.pitboard to the
Trash, and Homebrew runs the zap of a cask as it was installed, whatever the tap says by
then.

A copy of the app from a release updates itself as before and brings the command line with
it.

If you turned on daily renewal in a 0.3.0 app, its schedule ran the app itself and renewed
nothing. Once the app from this release is in its place, the old schedule keeps renewing,
through the command line inside the app, until you open the app. Opening it then points the
schedule at that command line. A schedule that runs a pitboard that is not there any more
is left as it is. On Linux that includes one turned on with the formula: it ran the copy
inside the formula's own directory, which goes with the formula. Turn such a schedule off
and on again, in the app's Settings or with pitboard schedule uninstall and then
pitboard schedule install. pitboard doctor from this release says whether yours needs
it, and so does Settings, Advanced, "Check this machine".

v0.4.0-rc1

v0.4.0-rc1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 25 Sep 12:24
v0.4.0-rc1
0edfc0e
pitboard 0.4.0-rc1

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 05:33
v0.3.0
4f713e2

Added

  • Codex, beside Claude Code. pitboard enroll codex/work records the Codex account signed
    in now, reading its account, email and plan out of its own ID token with no network
    call; pitboard enroll codex/work --sign-in runs codex login in a private
    CODEX_HOME so the account in use stays signed in; pitboard use codex/work switches
    it; and pitboard shows each Codex account's five-hour and weekly limits from the same
    usage read Codex itself makes, which spends no quota. Until a Codex account is enrolled,
    pitboard reads nothing of Codex's and asks OpenAI nothing. Everything pitboard does for Codex
    was read out of codex-cli 0.154.0 and is dated in a register of its own, checked against
    every new build by the conformance run twice a week, and still green on 0.156.1.
    Codex is not Claude Code, and pitboard says where they differ rather than hiding it:
    • A running codex never notices a switch, so a switch says to restart it instead of
      counting down, and names how many sessions are still using the outgoing account.
    • codex login and codex logout revoke the stored refresh token, so a Codex park is
      never a copy: the outgoing login is moved into the vault and read back before
      anything replaces it. Signing out inside a session still running from before a
      switch would revoke the login just parked, and the switch says so.
    • Codex's keychain stores are items Codex made for itself, which every read by another
      program would put a permission prompt in front of, so pitboard handles Codex's
      default store, the auth.json file, and refuses the others with a reason.
    • Codex takes no lock, so a session still running from before a switch can refresh its
      token in the middle of one. The live login is read again just before it is replaced,
      and nothing is written over a login that moved; a login that ends up naming two
      accounts is refused rather than parked.
  • The menu bar app handles both tools. With accounts of both, the panel lists them under a
    heading per tool, and the menu bar follows the signed-in account closest to running out.
    When an account runs out, only another account of the same tool is offered. A Codex
    switch has no countdown: the panel says running codex sessions keep the old account,
    and how many pitboard found, and keeps saying so until that tool switches again rather
    than until anything at all changes. "Add another account" asks which tool when more than
    one is installed, and a Codex sign-in shows the address codex login printed. Cancelling
    a sign-in no longer holds the app until the tool says something, which a Codex sign-in
    never does before the browser is done.
  • Labels belong to a tool. work can be a Claude Code account and a Codex account at
    once, codex/work says which, and a bare work still means what it always did as long
    as it names one account; where it names two, pitboard lists both rather than picking.
    A bare name for a new account means Claude Code, so every command written before there
    was a second tool does what it did. New codes: provider_unknown, label_ambiguous,
    sign_in_not_isolated, live_store_unsupported, state_names_unknown_tool,
    recovery_elsewhere, sessions_still_running, codex_program_missing and
    codex_not_found.
  • No parked login goes unnamed. Every name pitboard is about to write a login into is
    written down first, and the next command resolves any that nothing refers to: given back
    to the account whose name it carries when that account holds nothing, deleted when nobody
    wants it, and left alone when the store could not be read. Before this, a run killed
    between writing a login and recording it left a live refresh token that no entry named,
    never renewed, never deleted by pitboard uninstall, and on macOS not listable by any
    tool a person has. pitboard doctor reports anything still outstanding.
  • pitboard adopt takes over a ~/.pitboard that another computer wrote. The machine
    stamp is right and its reason is sound, but the refusal stopped every command including
    uninstall, so somebody whose home and keychain arrived through Migration Assistant met
    a tool that would not do anything and an error telling them to enrol again with no
    command that made it possible. Adopting keeps what is a fact about an account, the label,
    the email, the uuids and the remembered numbers, and drops every parked login, because a
    login belongs to the computer that signed in. It deliberately does not ask Anthropic
    whether a parked token still works: finding out means exchanging it, and exchanging it is
    the act that would rotate it past the other machine's copy.
  • pitboard repair asks the credential store itself what parked logins are on this
    machine, rather than reading pitboard's own index, and accounts for every one it finds:
    given back to the account whose name it carries, or deleted when no account here wants
    it, or reported and left exactly where it is. Only a name this pitboard wrote down itself
    is ever deleted: a keychain belongs to a whole login session while pitboard's records
    belong to one PITBOARD_HOME, so a parked login it cannot account for is evidence of
    another pitboard rather than of an orphan, and deleting it would end that account's
    session for somebody who never ran the command. Giving one back is additive and safe on a
    guess; deleting one is not, so on macOS a login given back that this pitboard never wrote
    down is deleted only once pitboard has used it, by switching to it or renewing it, even
    when the renewal is stopped before it records what it got back. Parking over it, forget
    and uninstall leave it where it is, and uninstall says how many it left, as
    parks_left in --json. Elsewhere the vault is a directory inside pitboard's own, which
    no other pitboard parks in, so whatever repair finds there is this one's. Measured
    first: security dump-keychain without -d never prompts, takes 0.06 seconds, emits no
    secret of any item, and does not slow later reads.
  • A crash matrix: every durable step of a switch, an enrolment, a renewal and a forget,
    killed where it stands, recovered, and checked against what must be true afterwards
    rather than against a particular outcome. Every case runs recovery twice, because a
    recovery that only works once leaves a machine nobody can fix, and once with Anthropic
    unreachable, because the answer then must be to change nothing. The two windows above
    are what it found on its first run.
  • A failure that came from asking Anthropic now carries a cause beside its code, in both
    --json and the app's bindings: unreachable, rate_limited, server_error,
    answer_not_understood, login_refused or token_expired, each saying whether asking
    again is worth anything. Before this, everything that was not a 401 arrived as
    identity_unverifiable and a sentence of prose, so nothing could tell being offline from
    being rate limited from a login Anthropic had finished with. status tells the same three
    apart too, where they used to share one code.
  • The app follows a switch made anywhere else on the machine. Three front ends ran on one
    machine and none could tell when another had changed something, so a switch typed in a
    terminal left the menu bar naming the account the person had just stopped using for as
    long as five minutes, with a button offering a switch that had already happened. The app
    now asks every couple of seconds when pitboard's account index last changed, which is one
    stat of one file, and re-reads what it already knows when it moves: no network, no
    keychain and nothing asked of Anthropic. Deliberately the index alone and not the whole
    directory, because the status line writes usage readings after every message in every
    open session.
  • The app has a window and a Settings scene. The panel is 400 points wide and everything
    that needed more than that either expanded inside it or sent the person to a terminal,
    and everything configurable lived in an ellipsis menu where opening at login sat between
    hiding the checks and quitting. The window holds each account with what its limits have
    been doing, the whole log of what pitboard has changed, and all of what it found about
    this machine. Settings opens with Command-comma where people look for it, and reaches the
    scheduled renewal the core could already do and the app could not.
  • A first run for somebody who installed only the app. The cask puts the command line on
    the machine too, but an empty panel used to say "Run pitboard enroll <label>" and a
    machine without Claude Code said one line of error, which between them sent every new
    person to a terminal to find out whether the thing they had just installed worked. The
    app now names the state it is in, no Claude Code, nobody signed in, signed in but
    unnamed, or one account with nothing to switch to, and offers the one next step, each of
    which it can do itself. Nothing is asked before the first read. The first launch ever
    opens the window, because a status item is invisible to somebody who has just installed
    it.
  • doctor reads the modes of everything on the disk that holds a login: the plaintext
    credential file, pitboard's vault and every parked login in it, and fails when anyone
    but the owner can read one. Where there is no keychain, a mode bit is the whole of that
    protection, and a backup restore, a cp -r or a careless umask changes one quietly.
  • The app's bindings reach the rest of the core: the offline report, giving up on an
    interrupted switch, the change log, renewing, and the renewal schedule. A read that cannot
    reach Anthropic now falls back to the last numbers measured rather than an empty panel,
    which said the accounts were gone. An interrupted switch that recovery cannot finish has
    a way out in the panel rather than sending somebody to a terminal, which is the...
Read more

v0.3.0-rc1

v0.3.0-rc1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 24 Sep 05:10
v0.3.0-rc1
4f713e2
pitboard 0.3.0-rc1

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 21 Sep 22:09
v0.2.0
5c1b300

Everything a stranger hits in the first ten minutes, every state a person could be stuck in,
and what the app was missing to stand on its own.

Added

  • pitboard log shows what pitboard has changed and when, from the record it was already
    keeping. The log now names which front end asked.
  • pitboard uninstall deletes every parked login and then pitboard's own files, in that
    order, because the account list is the only index of those keychain items.
  • pitboard abandon gives up on an interrupted switch that cannot be finished, keeping
    every login. The way out when recovery cannot reach Anthropic.
  • pitboard status --offline answers from what was last measured, without asking Anthropic
    or touching a login. Milliseconds instead of seconds, and it works with no network.
  • forget asks before deleting a parked login, unless --yes or --json.
  • Each usage row in --json carries severity, Anthropic's own grade for that limit. A
    field added to the v1 envelope; nothing was removed or renamed.
  • The app: each account's email, when each limit resets, when a parked login stops working,
    doctor's checks on demand, its own version, a mark in the menu bar, and VoiceOver labels.
    It can record the account in use, drop an account, and run Claude Code's own sign-in for
    a new one, showing what that sign-in says rather than borrowing a terminal.
  • cargo binstall pitboard fetches the built binary instead of compiling the tree.

Fixed

  • pitboard statusline typed at a prompt waited for input that was never coming. It reads
    stdin only when something is piping into it.
  • Offline, the account in use rendered as one with nothing parked, advising a sign-in it did
    not need.
  • A switch that failed before installing anything left its journal behind, so the next
    command announced a recovery for something that never happened.
  • enroll --sign-in checked what could refuse the enrolment only after the browser sign-in.
  • The status line showed ?·? for every account but the one in use until someone ran
    pitboard by hand. It now keeps the numbers Claude Code hands it.
  • doctor and forget read pitboard's record of its last switch rather than who is signed in,
    so a sign-in made with Claude Code's own /login made both wrong.
  • Three ways a parked login could be left in the keychain with nothing naming it.
  • A renewal that could not be written left the account with a login already spent.
  • The keychain ceiling has its own error, saying the size, the limit, and what to do. A
    login with MCP server tokens in it is past that limit, which is not theory.
  • ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN and CLAUDE_CODE_OAUTH_TOKEN raise a warning
    on every change: Claude Code signs in with those, not with the login pitboard moved.
  • Columns line up in what a terminal draws, so a label in Chinese or Japanese no longer
    pushes everything after it out of line.
  • One state file serves every credential slot, and what was switched to in one slot is no
    longer claimed in another.
  • The menu bar showed the largest percentage of any limit, so a row scoped to one model
    read as though everything had stopped.
  • Windows gets one sentence instead of a screen of type errors.

Internal

  • MSRV is 1.91, measured by building it, and CI builds at whatever the manifest claims.
  • The state file can be read forwards, and says which half to upgrade when it cannot.
  • A release is guarded, re-runnable, and carries build provenance; the macOS command line
    binaries are signed and notarised like the app. A tag like v0.2.0-rc1 is a pre-release:
    no crates.io, no update feed.
  • The app can be tested without a keychain, and is.