Skip to content

docs: overhaul README, add a real LICENSE file - #10

Closed
Lixeas wants to merge 31 commits into
mainfrom
docs/readme-overhaul
Closed

Lixeas wants to merge 31 commits into
mainfrom
docs/readme-overhaul

Conversation

@Lixeas

@Lixeas Lixeas commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Logo + name side by side, centered heading
  • Test badge centered; added Release workflow badge and a live release version badge
  • Description/Features/Installation/Usage/Requirements/Development rewritten to match the current app
  • Features section intentionally omits the 5h/7d window display (per request) — the feature itself is unchanged, just not called out in the README
  • Added the actual MIT LICENSE file (was referenced by name only before, no file existed)

Test plan

  • Test workflow still passes (docs-only change, no Swift touched)

🤖 Generated with Claude Code

Lixeas and others added 30 commits September 24, 2026 22:28
Menu bar app for Anthropic API credit monitoring: OAuth token from
Keychain (with manual override), auto-refresh, 3-section popover,
Settings (token/interval/launch-at-login), Host Grotesk + status
colors. Adds CI test workflow and a release workflow that builds a
signed .dmg, publishes a GitHub Release, and bumps the Homebrew cask.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
.accessory apps never become frontmost automatically, so openWindow()
could create the Settings window without focus (hidden behind other
apps). Also documents the Keychain "Always Allow" prompt and why dev
builds via swift run re-prompt after every rebuild.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
Root-caused two issues via console evidence and Apple Developer Forums
(thread 726565, confirms font()/imageScale() are ignored on
MenuBarExtra's label): NSStatusItem.button strips custom Shape fills
and font modifiers from the label view. Workaround: pre-render
MenuBarProgressLabel to an NSImage via ImageRenderer (isTemplate =
false to keep the colors) instead of passing the SwiftUI view
directly.

Also fixes the "Unable to update Font Descriptor's weight" CoreText
warning: chaining .fontWeight() on a custom static font is unreliable
(confirmed via font metadata inspection - SemiBold isn't even grouped
under the "Host Grotesk" legacy family). Each weight now references
its own .ttf by exact PostScript name instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
Primary fix is `claude login` (picked up automatically). Documents
the manual-token fallback in Settings for when that's not an option,
including how to extract the current token from Keychain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
Color.gray tint for the title/bottom sections didn't darken in dark
mode, leaving white button text on a still-light background
(illegible). Color.primary.opacity() adapts automatically (black in
light mode, white in dark mode) - same pattern already used
successfully in MenuBarProgressLabel's track.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
ProgressView's tint wasn't reliably applying in the popover (macOS
native progress indicator limitation). Also .tint() only takes a flat
color, so it couldn't express the requested green->orange->red
gradient anyway. New UsageProgressBar draws the gradient across the
full bar width then crops to the filled portion (rather than scaling
it), keeping the exact threshold hex colors (48655D/F09E7F/D61B66) as
gradient stops at 0%/50%/80%.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
release.yml now prefers .github/release-notes/vX.Y.Z.md when present
(curated changelog) and falls back to --generate-notes otherwise.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
Self-hosted runner logs (Swift build/test output, absolute paths)
were leaking the real macOS username/home path. ::add-mask:: redacts
both wherever they appear in subsequent log output.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
Avoids using the Claude trademark in an unofficial app name, and
doubles as a Night's Watch nod. Renames the Swift package/target/app
struct, bundle identifier (com.lixeas.notchwatch), Keychain/UserDefaults
storage keys, the Homebrew cask (notch-watch), and all docs/workflows.
No functional changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0133Kw22dMTxFkGLc8jCStQi
- VoiceOver labels on the menu bar pill and refresh button (P1)
- Adaptive light/dark error color, fixes AA contrast of magenta in dark mode (P1)
- Debounce Keychain writes for the manual token in Settings (P2)
- Distinguish 401/403 in API errors (invalid/expired token) (P2)
- Move pill rendering into UsageTracker, recomputed only when the value changes (P3)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
fix: address impeccable audit P1/P2/P3 findings
- Numeric values (used/limit, 5h, 7d) roll via .contentTransition(.numericText())
  instead of snapping on refresh
- UsageProgressBar fill eases to its new width instead of jumping
- Error/disabled/normal states in the dropdown crossfade instead of hard-cutting
- Refresh button crossfades between icon and spinner
- All state-change motion respects accessibilityReduceMotion; the refresh
  icon/spinner crossfade stays (opacity-only, confirms the action) per HIG
  guidance to keep essential feedback under reduced motion
- Extracted UsageDetailSection so the reduce-motion environment value is
  readable (Scene bodies can't read it reliably)

Menu bar pill stays a static image; MenuBarExtra's label ignores live view
updates outside the pre-rendered NSImage (existing AppKit constraint), so it
is out of scope for this pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
feat: animate usage values like a cockpit instrument
- New Localization.swift: AppLanguage enum, LanguageManager (UserDefaults-backed,
  defaults to English), Strings namespace with EN/FR pairs for every user-facing
  string
- Segmented picker in Settings switches language app-wide (menu bar dropdown,
  Settings labels, error messages, pill VoiceOver label)
- APIService/UsageTracker error messages now localized via LanguageManager.shared
  (they aren't Views, so read the singleton directly instead of an environment
  value)

Interval picker labels ("30 s", "1 min"...) stay shared between languages;
numeric + unit reads the same in both, not worth a second table.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
feat: add EN/FR language toggle in Settings
- Collapsed pill now shows "42% • $8.40" instead of "$15": percentage first,
  amount with cents, dot separator
- Removed the proportional fill bar; the percentage number now carries the
  status color itself (green/orange/red), dot and amount stay neutral
  (Color.primary)
- Pill keeps its neutral capsule background but is no longer fixed-width
  (content is longer and variable now)
- Added greenText/orangeText alongside the existing redText: each status
  color needs a different light/dark variant to stay AA-contrast as bare
  text instead of white-on-fill

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
feat: replace menu bar fill bar with colored percentage text
Anthropic's usage API does not return real billing-period dates
(extra_usage has only is_enabled/monthly_limit/used_credits/currency, no
period_start/period_end) -- confirmed by searching public API discussions,
no such field exists to read. This shows the current calendar month as a
proxy instead, explicitly labeled "(estimate)" / "(estim.)" in both
languages so it's never mistaken for Anthropic's actual cycle date.

Recomputed on every render rather than cached, so a month rollover is
picked up for free without a dedicated refresh path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
feat: show an estimated billing cycle range below the usage bar
- Label back to plain "Billing cycle:" / "Cycle facturation :"
- Date range now day+month only (DateIntervalFormatter dateTemplate
  "MMMd" instead of dateStyle .medium, which included the year)

The month-boundary approximation itself is unchanged (still no real
period_start/period_end from the API), just no longer called out in the UI.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
fix: drop year and estimate label from billing cycle
DateIntervalFormatter.string(from:to:) returns non-optional String,
unlike DateFormatter.string(from:) -- the ?? "" was always dead code
(compiler warning caught in a real Xcode build).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
Window("Reglages", id: "settings") was a hardcoded literal, never routed
through Strings when the EN/FR toggle was added -- title stayed "Reglages"
regardless of the selected language.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
fix: remove dead nil-coalescing on DateIntervalFormatter.string
fix: localize the Settings window title
- Package.swift bundles Resources/Images (mirrors the existing Fonts
  resource), loaded via Bundle.module same as AppFonts
- BrandMark: loads the light/dark SVG (NSImage supports SVG natively on
  macOS 12+) matching the current colorScheme, cached per appearance;
  extracted as its own View since colorScheme isn't reliably readable from
  the App/Scene body
- Dropped .foregroundColor(.secondary): the SVGs are already colored
  images, not a template glyph
- README header now shows the 16-plate logo variant (has its own
  background, meant standalone)

Not done: no .icns/.dmg icon pipeline in release.yml yet (there wasn't one
before this change either) -- the app and .dmg still ship with no custom
icon. Separate follow-up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
feat: wire the custom brand mark, replace the cpu SF Symbol
- Logo + name side by side, centered heading
- Test badge centered; added Release workflow badge and a live release
  version badge (shields.io)
- Description, Features, Installation, Usage, Requirements and Development
  sections rewritten to match the current app (colored-text pill instead of
  a fill bar, estimated billing cycle, EN/FR toggle)
- Features intentionally omits the 5h/7d window display (per request) --
  the feature itself is untouched, just not called out in the README
- LICENSE was referenced by name only (no file); added the actual MIT text

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vag2FZvTekVg34kUeb791Q
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