Skip to content

apps: registry gains default=exclude; app-picker gains --installed and --audit - #89

Draft
yulonglin wants to merge 4 commits into
mainfrom
worktree-brewfile-audit
Draft

apps: registry gains default=exclude; app-picker gains --installed and --audit#89
yulonglin wants to merge 4 commits into
mainfrom
worktree-brewfile-audit

Conversation

@yulonglin

@yulonglin yulonglin commented Sep 4, 2026

Copy link
Copy Markdown
Owner

What

The Brewfile listed 40 entries while this Mac carried 53 casks and 20 App Store apps, and nothing compared the two.

  • config/apps.conf: default gains a third value, exclude, for apps considered and rejected. Seven rows carry it (cursor, codex-app, codexbar, conductor, espanso, aqua-voice, cloudflare-warp). Fifteen casks and twelve App Store apps that were installed around the registry get rows; defaults follow whether they run, sit in login items, or were opened this fortnight, then Yulong's review.
  • custom_bins/app-picker: --installed preselects from machine state (deselecting a row is the UI for dropping an app); --audit compares the Mac against the Brewfile and prints uninstall commands, unregistered casks, unregistered App Store apps with a row template, formulae declared nowhere, and third-party taps split into breaches and exceptions config.sh declares. Runs after every write too. Never proposes brew bundle cleanup, which would remove every config.sh formula.
  • custom_bins/mas-get acquires only the Brewfile's App Store lines (--file), falling back to default=true rows without one. Before, it walked the whole registry and would have reacquired deselected apps. auth-setup skips exclude rows.
  • config.sh: PACKAGES_TRIAL_MACOS, tools installed by hand under evaluation that the audit counts as declared (hunk, red; micro as a candidate). install.sh does not read it.
  • config/Brewfile regenerated with --installed: 64 entries.
  • tests/test_app_picker.zsh: 41 checks with a stubbed brew and mas and a fake /Applications.
  • Report: https://claude.ai/code/artifact/1e36e85b-83c6-46e9-9fb7-df929387dbb4 (source under artifacts/brewfile-audit/).

Done on this Mac during review (not part of the diff)

brew uninstall marp-cli graphite age sops, brew untap withgraphite/tap, brew autoremove (removed nothing), and ChatGPT Classic.app moved to the Trash. install_age/install_sops in helpers.sh have no callers; left in place.

Why App Store detection uses receipts

mas list hangs on this machine (mas 7.0.0, macOS 26; a 25 s timeout printed nothing), so the audit scans Contents/_MASReceipt/receipt under /Applications and matches registry rows by name: exact stem, else first word (Things 3Things.app).

Review points

  • The first-word match for App Store apps is deliberately loose; correct for every app here today.
  • declared_elsewhere is a grep -w of the token against config.sh and scripts/shared/helpers.sh; it keeps the codex and antigravity-cli casks out of the unregistered list and would also suppress a formula whose name happens to appear as a word in either file.
  • Codex review (round 1) found the quoted-subscript bug in the audit's Brewfile parser and the mas-get selection gap; both fixed in the second commit with tests.

https://claude.ai/code/session_01NVCGydT8aREk4q6VvzeoBy

…d --audit

The Brewfile listed 40 entries while this Mac carried 53 casks and 20 App
Store apps, and nothing compared the two. Now:

- config/apps.conf: `default=exclude` for apps considered and rejected
  (cursor, codex-app, codexbar, conductor, espanso, aqua-voice); 15 casks
  and 12 App Store apps that were installed around the registry get rows.
- app-picker --installed preselects from machine state; --audit compares
  the Mac against the Brewfile and prints uninstall commands, unregistered
  casks and App Store apps (row template with iTunes id lookup), formulae
  declared nowhere, and third-party taps. App Store apps are detected from
  _MASReceipt files because `mas list` hangs here (mas 7.0.0, macOS 26).
  Never proposes `brew bundle cleanup`, which would remove every config.sh
  formula.
- mas-get and auth-setup skip exclude rows.
- tests/test_app_picker.zsh: 28 checks with a stubbed brew and a fake
  /Applications.
- Brewfile regenerated with --installed: 65 entries.
- artifacts/brewfile-audit: the triage report, published.

Claude-Session: https://claude.ai/code/session_01NVCGydT8aREk4q6VvzeoBy
…ection

Codex review of PR 89 found two real defects and one hardening:

- app-picker --audit built its registry lookup with a quoted associative
  subscript, which zsh can keep literally, so no Brewfile line matched.
  Key goes through a variable now; the test asserts a selected+installed
  app draws no uninstall command and that a hand-added missing cask is
  reported.
- mas-get walked the whole registry and acquired every non-excluded App
  Store row, ignoring what app-picker deselected. It now reads the
  Brewfile's mas lines (--file), falling back to default=true rows when
  there is no Brewfile. Tested with a stubbed mas.
- An empty inventory on a fresh Mac no longer short-circuits the audit;
  only a missing brew does.

Report headline reworded: four of the six excluded casks were never in
the Brewfile, so "leave the Brewfile" overstated the diff.

Claude-Session: https://claude.ai/code/session_01NVCGydT8aREk4q6VvzeoBy
…sanctioned taps

- apps.conf: cloudflare-warp default=exclude ("for now"); visual-studio-code
  default=true; LibreOffice note records that no tool here shells out to it.
- config.sh: PACKAGES_TRIAL_MACOS for tools installed by hand under
  evaluation (hunk, codersauce/tap/red; micro as a commented candidate).
  install.sh does not read it; app-picker --audit counts it as declared.
- app-picker: a third-party tap whose installed formulae are all declared
  is listed as an exception on record instead of a policy breach. Test
  covers both kinds of tap.
- Brewfile regenerated with --installed: 64 entries.
- Report revised with the review decisions, the Codex/ChatGPT answer, the
  LuLu and LibreOffice answers, and a table tracing every library formula
  to the requested tool that needs it (79 formulae, 39 requested, none
  orphaned).

Removed on this Mac during review, not in the diff: marp-cli, graphite
(+untap), age, sops; ChatGPT Classic.app to Trash.

Claude-Session: https://claude.ai/code/session_01NVCGydT8aREk4q6VvzeoBy
- app-picker --deps prints why every installed formula is here: requested
  (and where it is declared: apps.conf, config.sh, helpers.sh, nowhere) or
  pulled in, traced to the requested leaves through runtime_dependencies.
  Every Brewfile write and every --audit rewrites docs/brew-formulae.md, so
  the doc refreshes whenever package state is being looked at; no timer,
  because this repo deploys no user launchd jobs and a scheduled rewrite
  would leave uncommitted drift. CLAUDE.md links it in one clause; nothing
  loads it into agent context.
- config.sh: `tldr` (deprecated C client) leaves PACKAGES_CORE, which also
  feeds apt; tlrc (official Rust client) joins PACKAGES_MACOS and
  PACKAGES_LINUX_BREW. The audit no longer flags tlrc.
- test: stubbed `brew info --json=v2` fixture; 48 checks.
- report: LuLu, provenance and tlrc answers.

Claude-Session: https://claude.ai/code/session_01NVCGydT8aREk4q6VvzeoBy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant